ret2lic1
程序给出了system的plt和字符串/bin/sh,直接构造payload,可以使用IDA Pro手动找system函数的plt表项地址,也可以使用pwntools的ELF对象自动找
完整exp如下
1 | #! /usr/bin/env python |
ret2lic2
这里缺少/bin/sh字符串,没有现成的,甚至sh\x00都没有,只能在构造ROP链中加上gets函数输入一个/bin/sh,第一个gadget读取字符串(可以使用gets函数的plt),第二个gadget执行 system("/bin/sh"),这里因为ROP链只有两个函数,所以可以不加pop_ret来平衡栈,即
1 | payload = b'a'*(108+4) + p32(gets_addr) + p32(system_addr) + p32(bin_sh_addr) + p32(bin_sh_addr) |
若寻找pop_ret如下(只要是通用寄存器都行,不一定是ebx,不选ebp和esp担心影响函数栈帧)
1 | (pwn) ~/Desktop/buuctf/ctf-wiki-20:52 >>> ROPgadget --bin ret2libc2 --only 'pop|ret' | grep 'ebx' |
完整exp如下
1 | #! /usr/bin/env python |
ret2lic3
system的plt和字符串/bin/sh都没有给,由于延迟绑定机制,如果程序中没有调用到system函数,就不会有system函数的plt表项,那就只能找到system函数在libc中的真实地址
首先使用一些方法泄露其他函数的GOT表项的地址(即Libc中该函数的地址),然后再泄露远程主机的Libc版本(比如LibcSearcher),就可以通过偏移量计算出远程主机所使用的Libc下system函数的地址,CTF Wiki给我总结了流程:
- 泄露
__libc_start_main地址 - 获取 libc 版本
- 获取
system地址与/bin/sh的地址 - 返回程序入口,再次执行源程序
- 触发栈溢出执行
system("/bin/sh")
因为开启了ASLR但没有开启PIE,可以在ROP链中使用puts函数将要泄露的地址输出到前端,从IDA Pro中找到GOT表项地址,将地址中存储的内容(要泄露的libc地址)输出在前端
因为__libc_start_main是程序的入口,GOT表中肯定存在__libc_start_main这一项,所以一般选取__libc_start_main作为要泄露的地址,返回地址的选取有main函数和_start函数两种,注意PLT表中只有链接的标准函数,所以不会有_start和main表项,这两个作为程序入口是放在程序代码段的,但libc_start_main是动态链接的函数
在程序的执行过程中,
_start调用了libc_start_main,libc_start_main调用了main
__start这个符号是程序的起始;main是被标准库调用的一个符号
Linux x86 Program Start Up (dbp-consulting.com)这篇文章把整个程序运行到main函数被调用的过程都讲了一遍,有时间看完后再总结一篇博客,_start函数如下(汇编实现的)
1 | 080482e0 <_start>: |
重点在于第三和第四行,直接引用原文
The mov puts argv into %ecx without moving the stack pointer. Then we and the stack pointer with a mask that clears off the bottom four bits
也就是操作系统会使用execve函数开启进程执行程序,pop %esi将参数argc赋给esi,此时esp指向第二个参数argv,使用mov指令赋给ecx,使用AND逻辑操作将esp的最后四个字节变成0,esp会减小0-15个字节大小,起到了内存对齐的作用,有利于*“aligned for memory and cache efficiency”*,最重要的是这个语句起到了平衡堆栈的作用
所以这里使用_start函数作为返回地址时,第二个发生payload的填充数据长度和第一次相同,而选择main函数的话,main没有平衡堆栈的操作,会使esp的值变大,相当于栈空间减小了,填充数据的长度也减小了,因为我们的libc版本
使用gdb跟进调试会发现返回main函数后,栈的空间是0xfff7c150 - 0xfff7c0d0 = 0x80 = 128,栈的空间减小了8,所以填充数据长度从112变成了104
1 | EBP 0xfff7c150 ◂— 0x61616161 ('aaaa') |
原来大小是0xffffcf08 - 0xffffce80 = 0x88 = 136
1 | EBP 0xffffcf08 ◂— 0x0 |
这里可能因为LibcSeacher找不到正确的版本,没有打通
我的exp如下
1 | #! /usr/bin/env python |
本着互联网开源的性质,欢迎分享这篇文章,以帮助到更多的人,谢谢!