DASCTF2025下半年赛Misc

官方wp:

https://www.yuque.com/chuangfeimeiyigeren/eeii37/pyuic5kgzp3xe3tg?singleDoc#RCpLM

DigitalSignature

题目描述:

1
2
Find out the signer. Maybe you need EIP-191. Flag is account address that wrapped by DASCTF{}.
找出签名者。可能需要使用EIP-191。Flag是包裹在DASCTF{}中的账户地址。

附件task.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
from web3 import Web3
from eth_account.messages import encode_defunct
from Crypto.Util.number import bytes_to_long


def SignMessage(Message: str, PrivateKey: str) -> dict:
Provider = Web3()
Temp = encode_defunct(text=Message)
SignedMessage = Provider.eth.account.sign_message(Temp, private_key=PrivateKey)
SignedMessageHash = SignedMessage.messageHash.hex()
SignedMessageSignature = SignedMessage.signature.hex()
return {"Message": Message, "SignedMessageHash": SignedMessageHash, "SignedMessageSignature": SignedMessageSignature}


def CreateNewAccount() -> tuple:
Provider = Web3()
Keys = Provider.eth.account.create()
Address = Provider.toChecksumAddress(Keys.address)
PrivateKey = hex(bytes_to_long(Keys.privateKey))
return (Address, PrivateKey)


(Address, PrivateKey) = CreateNewAccount()
SignData = SignMessage("Find out the signer. Flag is account address that wrapped by DASCTF{}.", PrivateKey)
print(f"MessageHash:{SignData['SignedMessageHash']}\nSignature:{SignData['SignedMessageSignature']}")

'''
MessageHash:0x61a78e3c572c1615a6ddd0a0e20157d22b72b8c217cb247318f2c791f4ab6b85
Signature:0x019c4c2968032373cb8e19f13450e93a1abf8658097405cda5489ea22d3779b57815a7e27498057a8c29bcd38f9678b917a887665c1f0d970761cacdd8c41fb61b
'''

这是一道与区块链合约有关的赛题,通过题目代码分析得知,需要根据给出的MessageHashSignature还原出签名该消息的账户的地址。随便问问ai就能解决

exp:

1
2
3
4
5
6
7
8
9
from eth_account import Account

msg_hash = "0x61a78e3c572c1615a6ddd0a0e20157d22b72b8c217cb247318f2c791f4ab6b85"
signature = "0x019c4c2968032373cb8e19f13450e93a1abf8658097405cda5489ea22d3779b57815a7e27498057a8c29bcd38f9678b917a887665c1f0d970761cacdd8c41fb61b"

signer_address = Account._recover_hash(msg_hash, signature=signature)

print(f"Signer Address: {signer_address}")
print(f"Flag: DASCTF{{{signer_address}}}")

得到

1
2
Signer Address: 0x2b2D44D5325F0d3550296686BE2a7b5Fecb952cB
Flag: DASCTF{0x2b2D44D5325F0d3550296686BE2a7b5Fecb952cB}

stegh小鬼

提示是

1
新佛曰挂了,解码出来--pass:2333333

下载附件,发现是一个加密压缩包和一个无后缀文件

将无后缀文件拖入010editor里面查看文件结构

发现这是一个反转的jpg文件,脚本反转

1
2
3
4
5
6
7
with open('快乐小鬼', 'rb') as f:
hex_data = f.read().hex()[::-1]

with open('1.jpg', 'wb') as f:
f.write(bytes.fromhex(hex_data))

print("转换完成,已生成 1.jpg")

得到以下图片

将图片拖入随波逐流会发现还有一个jpg文件,分离文件

cGFzczpLQUdfZ2thX2thZ19HS0E=解码为pass:KAG_gka_kag_GKA

其中分离出来的jpg中有新佛曰

也就是提示说的pass:2333333

这里有两个pass,经过尝试,被分离出的这张图片有steghide隐写,pass为2333333

能发现有一堆的颜文字,但是中间穿插了许多表情,根据表情和颜文字的编码能想到这是aaencode和base100编码,将表情单独按照顺序分出来,作为base100解密

aaencode:

1
Look carefully at the middle of the picture

去看了一下,其实就是前面的cGFzczpLQUdfZ2thX2thZ19HS0E=解码为pass:KAG_gka_kag_GKA,也就是解压加密压缩包的密码

base100:

1
👋👟👠👪👖🐨👪👖👇🐫👪👪👮🐧👩👛

This_1s_P4ssw0rd

加密压缩包里面的flag.txt内容是:

1
🙃💵🌿🎤🚪🌏🐎🥋🚫😆🎃😊😆🎅🚫👉❓💧🌿🍍✉🐎📮☺☀🙃🛩🔬🚰✖😎🍵👣🌿👉🚪🍎😍🤣😎🍌🖐🌏👌👌🥋👑🍎🍵🍌😎☃🍌🐎✖🔪📂😁👣✖🐘👑📮ℹ

可以联想到emoji-AES解密,还有This_1s_P4ssw0rd没有用到

https://ruotian.io/2020/02/emoji-aes/

解密得到DASCTF{Y0u_are_4_1ovely_Gh0st}

Steganography_challenges0.2

附件只有一张图片,很奇怪,拖入随波逐流得到字符串

1
ZnJvbSBQSUwgaW1wb3J0IEltYWdlDQpFPXJhbmdlDQpSPWJ5dGVzDQpGPUltYWdlLm5ldw0KeD1JbWFnZS5vcGVuDQpmcm9tIENyeXB0by5DaXBoZXIgaW1wb3J0IEFSQzQNCmk9QVJDNC5uZXcNCmRlZiB0KGRhdGEsTyk6DQogcmV0dXJuDQpkZWYgdyhkYXRhLE8pOg0KIGE9aShPLmVuY29kZSgpKQ0KIHJldHVybiBhLncoZGF0YSkNCkk9eCgneW91cl9pbWFnZS5wbmcnKS5jb252ZXJ0KCdSR0InKQ0KTSxqPUkuc2l6ZQ0KWT1GKCdSR0InLChNLGopKQ0KTz0nbW9ua2V5Jw0KZm9yIHkgaW4gRShqKToNCiBmb3IgeCBpbiBFKE0pOg0KICByLGcsYj1JLmdldHBpeGVsKCh4LHkpKQ0KICBuPVIoW3IsZyxiXSkNCiAgSj13KG4sTykNCiAgWS5wdXRwaXhlbCgoeCx5KSwoSlswXSxKWzFdLEpbMl0pKQ0KWS5zYXZlKCdlbmNyeXB0ZWRfaW1hZ2UucG5nJykNCiMgQ3JlYXRlZCBieSBweW1pbmlmaWVyIChodHRwczovL2dpdGh1Yi5jb20vbGlmdG9mZi9weW1pbmlmaWVyKQ0KDQo=

base64解码得到

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
from PIL import Image

E=range

R=bytes

F=Image.new

x=Image.open

from Crypto.Cipher import ARC4

i=ARC4.new

def t(data,O):

return

def w(data,O):

a=i(O.encode())

return a.w(data)

I=x('your_image.png').convert('RGB')

M,j=I.size

Y=F('RGB',(M,j))

O='monkey'

for y in E(j):

for x in E(M):

r,g,b=I.getpixel((x,y))

n=R([r,g,b])

J=w(n,O)

Y.putpixel((x,y),(J[0],J[1],J[2]))

Y.save('encrypted_image.png')

# Created by pyminifier (https://github.com/liftoff/pyminifier)

可读性很差,我们打开后面的注释https://github.com/liftoff/pyminifier,发现这是有python混淆

这里可以直接使用ai还原出可读性较好的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
41
42
43
from PIL import Image
from Crypto.Cipher import ARC4

def encrypt_pixel(data, key):
"""
使用 RC4 算法加密单个像素点的 RGB 数据。
注意:这里的逻辑会在每次调用时重新初始化 Cipher,
这意味着每个像素都使用相同的密钥流进行异或 (XOR) 操作。
"""
cipher = ARC4.new(key.encode())
return cipher.encrypt(data)

def main():
# 加载原始图片
original_img = Image.open('Steganography_challenges0.2.png').convert('RGB')
width, height = original_img.size

# 创建一个新的画布用于存放加密后的像素
encrypted_img = Image.new('RGB', (width, height))

# 密钥
key_string = 'monkey'

# 遍历每一个像素点
for y in range(height):
for x in range(width):
# 获取原始像素 (R, G, B)
r, g, b = original_img.getpixel((x, y))

# 将 RGB 转为 bytes
pixel_data = bytes([r, g, b])

# 加密像素
encrypted_pixel = encrypt_pixel(pixel_data, key_string)

# 将加密后的数据填入新图片
encrypted_img.putpixel((x, y), (encrypted_pixel[0], encrypted_pixel[1], encrypted_pixel[2]))

# 保存加密图片
encrypted_img.save('encrypted_image.png')

if __name__ == '__main__':
main()

写一个解密脚本:

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
from PIL import Image
from Crypto.Cipher import ARC4
import os

def decrypt_pixel(data, key):
"""
RC4 是对称加密 (异或运算)。
对密文再次进行相同的异或操作,即可还原明文。
"""
cipher = ARC4.new(key.encode())
return cipher.encrypt(data)

def main():
input_filename = 'Steganography_challenges0.2.png'
output_filename = 'decrypted_image.png'

if not os.path.exists(input_filename):
print(f"错误: 找不到文件 {input_filename}")
return

encrypted_img = Image.open(input_filename).convert('RGB')
width, height = encrypted_img.size

decrypted_img = Image.new('RGB', (width, height))

key_string = 'monkey'

print("正在解密,请稍候... (由于是像素级循环,大图可能比较慢)")

for y in range(height):
for x in range(width):
r, g, b = encrypted_img.getpixel((x, y))

pixel_data = bytes([r, g, b])

decrypted_pixel_data = decrypt_pixel(pixel_data, key_string)

decrypted_img.putpixel((x, y), (decrypted_pixel_data[0], decrypted_pixel_data[1], decrypted_pixel_data[2]))

decrypted_img.save(output_filename)
print(f"解密完成! 已保存为 {output_filename}")

if __name__ == '__main__':
main()

得到decrypted_image.png

stegsolve打开发现存在LSB隐写

坐标问题:

接下来可以参考官方wp,像这样取一小块部分解隐写比全部解隐写方便多了,针对性更强

先确认小块部分的隐写区域(1243,1243)(1257,1254)

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
from PIL import Image


def extract_lsb(image_path, start_x, start_y, end_x, end_y):

img = Image.open(image_path)
pixels = img.load()

binary_data = ""

for y in range(start_y, end_y + 1):
for x in range(start_x, end_x + 1):

pixel = pixels[x, y]

if len(pixel) == 4:
r, g, b, _ = pixel
else:
r, g, b = pixel

binary_data += bin(r)[-1] # Red channel LSB
binary_data += bin(g)[-1] # Green channel LSB
binary_data += bin(b)[-1] # Blue channel LSB

hidden_data = ""
for i in range(0, len(binary_data), 8):
byte = binary_data[i:i + 8]
hidden_data += chr(int(byte, 2))

return hidden_data

image_path = "decrypted_image.png"
start_x, start_y = 1243, 1243
end_x, end_y = 1257,1254
hidden_message = extract_lsb(image_path, start_x, start_y, end_x, end_y)

print("Hidden Message:", hidden_message)

得到加密lsb的key:Oversized_chips

1
python2 lsb.py extract decrypted_image.png 11 Oversized_chips

得到图片

猜测是盲水印,对该图片进行单图盲水印提取:

得到flag