2024第七届浙江省大学生网络与信息安全竞赛预赛
城南花已开 Lv5

有些题目没法赛后复现,只能借鉴其他师傅的WP了

附件下载:https://github.com/primaryonetwo/2024zjdxs

签到

网安知识大挑战

这题我们队是在最后做出来的,比较菜,刚开局没做我没做这题,反倒最先做出来是Misc01

打开网址是以vue为框架的页面,只有全部题目做对才给flag

在网页的js源文件中Ctrl+F搜索DASCTF关键字可以搜到关键信息,随便翻翻可以找到题目对应的答案

image

image

最后提交就给出flag了

其实还有另一种更快的方式,你仔细观察发现flag数据就在源码中,只不过进行了AES加密了

image

这里引用其他师傅更加清晰的图片,从p7到p22文本进行处理一下,最后再进行AES解密即可,key则为图中n的变量

image

image

签到题

欢迎来到2024年浙江省大学生网安竞赛,下面是一个签到题,解码即可获取flag,flag格式为 DASCTF{xxx},提交flag时只需要提交括号内的内容。

6L<Ak3,@VM*>7U&FZFNWc,Ib=t,X!+,BnSDfoaNhdiO][5F];eV^]Lm&?$’<oeGH&6tqcgK_JDp-3;8wh?Si,G$BarTFjE?b$eR/,Igij<({u90M$5If589[<4+jp%3_%R(526#1J|m5p&H+%.#d0<DmLK*#-\8w:xD2Y[3jO{l8[)<(F[=Bcixb>Jp^%L2XvVTzW@9OTko/P74d1sFscEbMO7Vhp&HM;+ww/v[KM1%2M*7O}rEZM.LM0’\iwK:])pg-nJef\Rt4

这签到题我硬生生没做出来,难受了,还是题目做的太少了,典型的套娃题,这里被CyberChef误导了好久,这个编码工具有个功能就是自动识别编码类型,点击魔法棒即可自动帮你完成解密,这里提示是HTML Entity加密,比赛结束看WP才知道

image

其实直接CyberChefBASE家族的编码全部点一遍即可

image

Web

easyjs

这题没法赛后复现,不过也可以了解下解题流程

题目给了附件,就是网页源代码

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
const express = require('express');
const _ = require('lodash');
const fs = require('fs');
const app = express();

app.use(express.json());

// 存储笔记的对象
const notes = {};

// 创建新笔记
app.post('/api/notes', (req, res) => {
const noteId = req.body.id;
const noteData = req.body;

if (!noteId) {
return res.status(400).json({ error: 'Missing id' });
}

// 使用lodash.merge,该版本存在原型链污染漏洞
notes[noteId] = {};
_.merge(notes[noteId], noteData);
console.log('Note prototype:', Object.getPrototypeOf(notes[noteId]));
console.log('Note properties:', notes[noteId]);
res.json(notes[noteId]);
});

// 获取笔记
app.get('/api/notes/:id', (req, res) => {
const noteId = req.params.id;

if (!notes[noteId]) {
return res.status(404).json({ error: 'Note not found' });
}

res.json(notes[noteId]);
});

// 获取flag (仅管理员可访问)
app.get('/api/flag', (req, res) => {
const noteId = req.headers['note-id'];

if (!noteId || !notes[noteId]) {
return res.status(403).json({ error: 'Authentication required' });
}

if (!notes[noteId].isAdmin) {
return res.status(403).json({ error: 'Admin access required' });
}

try {
const flag = fs.readFileSync('/flag', 'utf8');
res.json({ flag: flag.trim() });
} catch (err) {
res.status(500).json({ error: 'Error reading flag' });
}
});

app.listen(8000, () => {
console.log('Server running on port 8000');
});
  • 首先,从请求的headers中获取’note-id’字段的值作为noteId变量。
  • 然后,检查noteId是否存在以及对应的note是否存在。如果noteId不存在或对应的note不存在,则返回状态码403和错误消息’Authentication required’。
  • 接着,检查对应的note是否有isAdmin字段,如果没有则返回状态码403和错误消息’Admin access required’。
  • 然后,尝试读取文件’/flag’的内容作为flag变量,并将其去掉首尾空格后返回给客户端。
  • 如果读取文件时出现错误,会返回状态码500和错误消息’Error reading flag’。

当你访问/api/notes的时候会提示Missing id因为你的请求头headers没有指定noteId所以可以新建一个笔记id随便取名字,只要isAdmin字段为True

image

然后再次访问/api/flag在请求头headers中设置note-id字段为你上面取的名字,即可获取flag

image

hack memory

由于没有附件,后续也无法复现,总结就是通过扫目录发现有个upload目录,直接上传个木马即可,方案有很多反弹Shell 冰蝎 蚁剑在根目录即可找到flag文件cat /fffffllllagggg就行了

这里推荐一个反弹Shell的网站 https://www.revshells.com/

image

QL_again

附件到手是个jar文件,java涉及到盲区了,尝试利用java启动一下,发现是个基于spring boot框架的,不会,遂放弃

Misc

RealSignin

这题我觉得算是最简单的了,是真签到题,比起上面的签到来说,附件到手就是一个图片

利用zsteg直接梭哈,发现除了PNG内容外有个额外数据信息,大概率就是密文了,而且发现再lsb 通道中发现加密的字母表

1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~]
└─$ zsteg out.png
[?] 38 bytes of extra data after image end (IEND), offset = 0x36002
extradata:0 .. text: "dEFfc1dGq1pxMgMWnihrMx9mewNgdvIWMvctrc"
b1,r,lsb,xy .. text: ";>RWz|PUxbgCN?"
b1,rgb,lsb,xy .. text: "ABCDEFGHIJKLMNabcdefghijklmnopqrstuvwxyzOPQRSTUVWXYZ0123456789+/"
b4,g,msb,xy .. file: RDI Acoustic Doppler Current Profiler (ADCP)
b4,abgr,msb,xy .. file: RDI Acoustic Doppler Current Profiler (ADCP)

如果没装可以sudo gem install zsteg装一下

利用CyberChef进行Base64换个表解密下就出来了

image

机密文档

拿到附件是个加密的压缩包发现压缩包里还有个压缩包the_secret_you_never_ever_know_hahahaha.zip,这题我头都大了,一直在John无脑爆破,当我丢进PasswareKit Forensic再尝试下发现这个可以进行zip明文攻击,不过当时没做出来

image

这里我们可以在Github上找到bkcrack这个zip明文攻击工具,在release中下载编译好的文件直接运行即可

但是这个竞赛又不让主动访问互联网,做个头啊,只能怪自己没有做到类似的题目,提前安装

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ ./bkcrack -L 机密文档.zip ##查看条目名称和元数据列表
bkcrack 1.7.0 - 2024-05-26
Archive: 机密文档.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
0 ZipCrypto Store 0c583fae 60421 60433 the_secret_you_never_ever_know_hahahaha.zip

发现是个ZipCrypto加密同时又是Store未压缩的,这恰恰符合明文攻击的特征,推测the_secret_you_never_ever_know_hahahaha作为明文

明文攻击主要利用大于 12 字节的一段已知明文数据进行攻击,从而获取整个加密文档的数据。也就是说,如果我手里有一个未知密码的压缩包和压缩包内某个文件的一部分明文(不一定非要从头开始,能确定偏移就行),那么我就可以通过这种攻击来解开整个压缩包。比如压缩包里有一个常见的 license 文件,或者是某个常用的 dll 库,或者是带有固定头部的文件(比如 xml、exe、png 等容易推导出原始内容的文件),那么就可以运用这种攻击。当然,前提是压缩包要用 ZipCrypto 加密。

reference:https://www.poboke.com/crack-encrypted-zip-file-with-plaintext-attack.html

https://www.bilibili.com/video/BV1iG411A7yJ/

一般来说密文也就是the_secret_you_never_ever_know_hahahaha.zip的开头部分并不是明文the_secret_you_never_ever_know_hahahaha所以需要指定偏移量,偏移30字节,偏移后的明文就是zip的文件头

504b030414000000

image

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ echo -n "the_secret_you_never_ever_know_hahahaha" > plain.txt ##推测的明文保存到文件plain.txt

┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ ./bkcrack -C 机密文档.zip -c the_secret_you_never_ever_know_hahahaha.zip -p plain.txt -o 30 -x 0 504b030414000000
bkcrack 1.7.0 - 2024-05-26
[07:56:45] Z reduction using 31 bytes of known plaintext
100.0 % (31 / 31)
[07:56:45] Attack on 252307 Z values at index 37
Keys: b8edf1ff c1f93a7e f93d08e0
81.3 % (205102 / 252307)
Found a solution. Stopping.
You may resume the attack with the option: --continue-attack 205102
[07:59:12] Keys
b8edf1ff c1f93a7e f93d08e0 ##keys找到了
  • -C 加密的压缩包
  • -c 存在明文的文件
  • -p 存储了明文的文本
  • -o 抵消指定偏移量
  • -x 偏移值 十六进制字节数据
  • -k 已知key
  • -U 使用已知的key将压缩包改成密码为easy并新生成一个decode.zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ ./bkcrack -C 机密文档.zip -k b8edf1ff c1f93a7e f93d08e0 -U decode.zip easy
bkcrack 1.7.0 - 2024-05-26
[10:49:47] Writing unlocked archive decode.zip with password "easy"
100.0 % (1 / 1)
Wrote unlocked archive.
┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ unzip decode.zip ##使用easy密码解压decode.zip
Archive: decode.zip
[decode.zip] the_secret_you_never_ever_know_hahahaha.zip password:
extracting: the_secret_you_never_ever_know_hahahaha.zip ##得到一个新的压缩包
┌──(kali㉿kali)-[~/Desktop/bkcrack-1.7.0-Linux]
└─$ unzip the_secret_you_never_ever_know_hahahaha.zip ##再次解压
Archive: the_secret_you_never_ever_know_hahahaha.zip
inflating: the_secret_you_never_ever_know_hahahaha.docm ##得到docm文件

Microsoft Word中尝试打开有个安全提示宏已被禁用,其中word中还有一张png图片

image

其实不用打开word也大概能猜到是带宏的文档,关于word这类的题目大多都是这样

我们启用宏内容,在视图-宏-查看宏可以发现名为key的宏文件,或者alt+f8也行

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Sub key()
Dim decValues As Variant
Dim str As String
Dim result As String
Dim i As Integer
Dim xorValue As Integer

decValues = Array(26, 25, 28, 0, 16, 1, 74, 75, 45, 29, 19, 49, 61, 60, 3)
str = "outguess"
result = ""

For i = LBound(decValues) To UBound(decValues)
xorValue = decValues(i) Xor Asc(Mid(str, (i Mod Len(str)) + 1, 1))
result = result & Chr(xorValue)
Next i

End Sub

说白了就是将decValues数组中的数字和str字符串outguess进行进行异或运算,并将结果存储到xorValue中,异或运算的结果转换成字符,然后拼接到result字符串中,很简单的一段代码

利用python将答案复现,

1
2
3
4
5
6
7
8
9
10
a=[26, 25, 28, 0, 16, 1, 74, 75, 45, 29, 19, 49, 61, 60, 3]
b=b'outguess'
d=[]
for i,k in enumerate(a): ### 对列表a中的元素进行遍历,i为索引,k为元素值
d.append(b[i%len(b)]^k) ### 实现循环使用字节字符串b中的字符对k进行异或
##效果相同
#for i in range(len(a)):
# k = a[i]
# d.append(b[i%len(b)] ^ k)
print(bytes(d))

image

根据关键字outguess其实就能猜出这是个图片隐写,word中的图片就是隐藏信息的图片

不要使用word中的图片另存为功能

image

docm后缀名改为zip解压打开,可以在the_secret_you_never_ever_know_hahahaha\word\media路径下找到源文件,相比发现源文件会比另存为多一些内容,再将image1.jpeg改为image1.jpg否则outguess不认,我也不知道为啥,可能原来的文件就是jpg只不过被word改了

image

1
2
3
4
5
6
7
8
9
┌──(kali㉿kali)-[~]
└─$ outguess -k 'ulhged98BhgVHYp' -r image1.jpg -t 1.txt
Reading image1.jpg....
Extracting usable bits: 44417 bits
Steg retrieve: seed: 156, len: 26

┌──(kali㉿kali)-[~]
└─$ cat 1.txt
DASCTF{B1g_S3CR3t_F0R_Y0u}

如果没装outguess可以执行sudo apt install outguess

另外如果不想使用word查看宏也可以装个python-oletools工具包中的olevba

如果你既不想装这装那,还有个在线网站可供你提取vba

http://tools.bugscaner.com/office/word-parser-vba.html

执行pipx install oletools 即可使用olevba

olevba 是一个用于解析 OLE 和 OpenXML 文件(如 MS Office 文档(例如 Word,Excel)的脚本,以检测 VBA 宏,提取其源代码以明文显示,并检测安全相关模式,如自动执行宏,恶意软件使用的可疑 VBA 关键字,反沙箱和反虚拟化技术,以及潜在的 IOCs(IP 地址,URL,可执行文件名等)。它还检测和解码几种常见的混淆方法,包括十六进制编码,StrReverse,Base64,Dridex,VBA 表达式,并从解码的字符串中提取 IOCs。XLM/Excel 4 宏也受支持,可在 Excel 和 SLK 文件中使用。

EZtraffic

看到附件名字就猜到是个流量分析题了,打开wireshark看了一下,大多都是smb2的报文,使用wireshark - 文件 - 导出对象 - SMB导出smb的全部文件,发现有个压缩包打开发现添加了注释

image

提示是NTLM V2明文+5位数字,大概率就是压缩包的密码,那我们先尝试获取NTLM V2的明文

wireshark中找到两个主要的报文STATUS_MORE_PROCESSING_REQUIRED (0xc0000016)NTLMSSP_AUTH,User:MicrosoftAccount\rockyou图中就简称srecvcsend

image

NTLMv2的格式为:

1
username::domain:challenge:HMAC-MD5:blob

其中的challenge可以在srecv中找到,其他的均可以在csend中找到

image

image

image

拼接后得到完整的NTLM V2

1
rockyou::MicrosoftAccount:4936df20962cae6d:db12ced50faf52f141636e80205e8f28:01010000000000003604281b951fdb017b4045aa008508eb0000000002001e00440042004500440036004200350041002d0035003100430032002d00340001001e00440042004500440036004200350041002d0035003100430032002d00340004004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d0064006400320062003500370030006400350030003900360003004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d00640064003200620035003700300064003500300039003600070008003604281b951fdb01060004000200000008003000300000000000000001000000002000008029a5d8256e5c2762f439df5c06f3bc411fb0faeb3a6fa52d9273c57b09f2d10a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e0031002e00380031000000000000000000

通常是指网络环境下NTLM认证中的hash

NTLM认证采用质询/应答(Challenge/Response)的消息交换模式,流程如下:

  1. 客户端向服务器发送一个请求,请求中包含明文的登录用户名。服务器会提前存储登录用户名和对应的密码hash
  2. 服务器接收到请求后,生成一个16位的随机数(这个随机数被称为Challenge),明文发送回客户端。使用存储的登录用户密码hash加密Challenge,获得Challenge1
  3. 客户端接收到Challenge后,使用登录用户的密码hash对Challenge加密,获得Challenge2(这个结果被称为response),将response发送给服务器
  4. 服务器接收客户端加密后的response,比较Challenge1和response,如果相同,验证成功

尝试利用hashcat进行NTLM V2爆破,我用cpu硬解也很快

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
┌──(kali㉿kali)-[~]
└─$ hashcat -a 0 -m 5600 hash.txt /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 6.0+debian Linux, None+Asserts, RELOC, LLVM 17.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
============================================================================================================================================
* Device #1: cpu-sandybridge-12th Gen Intel(R) Core(TM) i5-12600KF, 2915/5894 MB (1024 MB allocatable), 8MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 2 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

ROCKYOU::MicrosoftAccount:4936df20962cae6d:db12ced50faf52f141636e80205e8f28:01010000000000003604281b951fdb017b4045aa008508eb0000000002001e00440042004500440036004200350041002d0035003100430032002d00340001001e00440042004500440036004200350041002d0035003100430032002d00340004004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d0064006400320062003500370030006400350030003900360003004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d00640064003200620035003700300064003500300039003600070008003604281b951fdb01060004000200000008003000300000000000000001000000002000008029a5d8256e5c2762f439df5c06f3bc411fb0faeb3a6fa52d9273c57b09f2d10a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e0031002e00380031000000000000000000:haticehatice ##密码在这

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
Hash.Target......: ROCKYOU::MicrosoftAccount:4936df20962cae6d:db12ced5...000000
Time.Started.....: Thu Nov 7 03:15:19 2024 (5 secs)
Time.Estimated...: Thu Nov 7 03:15:24 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 1633.5 kH/s (1.00ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 7671808/14344385 (53.48%)
Rejected.........: 0/7671808 (0.00%)
Restore.Point....: 7667712/14344385 (53.45%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: havita -> hatefuckers
Hardware.Mon.#1..: Util: 52%

[!TIP]

reference:https://daiker.gitbook.io/windows-protocol/ntlm-pian/4

https://blog.csdn.net/weixin_43178927/article/details/108184017

https://3gstudent.github.io/Windows%E4%B8%8B%E7%9A%84%E5%AF%86%E7%A0%81hash-NTLM-hash%E5%92%8CNet-NTLM-hash%E4%BB%8B%E7%BB%8D

https://davenport.sourceforge.net/ntlm.html#ntlmVersion2

得到密码后再根据上文提到的提示掩码爆破,再次上hashcat,先通过zip2john将压缩包的hash导出来再查询hashcat wiki得知以$zip2$*0*3*0*开头的hash为WinZip或者查看hashcat的help

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
┌──(kali㉿kali)-[~/zjdxs]
└─$ zip2john final_out.zip >hash.txt
ver 2.0 final_out.zip/final_out/ is not encrypted, or stored with non-handled compression type
Error, in fread of salt!
Skipping bad AES entry
-------------------------------------------------------------------------------
┌──(kali㉿kali)-[~/zjdxs]
└─$ head -n1 hash.txt
final_out.zip/final_out/0vP5BE3z.png:$zip2$*0*3*0*b0d81edc70943b2f58b3a8fac17f4adb*d610*33d*af0ea4d57204185c3391474c9c56b8e862876ce654ab6c36e73992332c3145c8e34e52600d55cab7e26438f3d66f953cadf619f8597bfda2ffab6ec18425bd8c8bc0f8b5ead1c530881daf903e05741a5842a9e9ff66a08f246d3900431ce11f2eba82f2880bbb6d888f7724bfdc36de40459e64e4ee8dcb1811934a1a525fd2e694ba795776b20f9c9f24a327dcd251f389a0a050dbba47c6f0097a6d955e3a22ecfc106117f9d85ed99b28728e3770fae86c6e34f1c34884a0fbedb634f55bf3fae182dca5ab0c58161df37071c319e3a98a488fa186e8a39e74f40f31cb8fbd5ef229dc1c439e9cefb9cfe0aac3a05b7a926d30e5410457c9902529b967aed4ed298e398045dd67bb8f67d9bbc7b480cf6ded6d190411245025426935c223525bdadeac02761a7ac39f140119161a7cf53b6dfea21bedad3c5b63e2fabdba3196ddf1b8011709328fefe42db417b35868f4b0b00877417ba85ee34b55b185d50dd68fca9e79516f7248a8090ec177325a5884dc38f65796213f537fa3cbe92c3aaed83ee9e75cf05b488ad1bb6e030740ba4d79219f87fa507beb9fa26eaa28bae82a060c5028727eae5503719bf75cdda3f8da2717b53655980c24141b11240c3c3b32506ab3a2018bba2ac699df326527f97632148b1fb37df17bab648d24e075512623c1eba397fb3316ddf5e91ac3d01e1facebfc94922c4ba9bdb3274bd441bb1a26b5d34da79b635780587a54f25c766508362f9cc6eaab19bcf3f08615e7a0ba0503e63f31f612a3642f2e9d4dd51228044cc2391ccecc27f7ff5395bd3e0133d610ffbacc2b86d8eefa22fa8e609613a16ced1ee9abb00fe8e437da94a38e5a83b0ba236cb887c342432a2bda4d29497d33bae4e268b1d6d16c89c1c7d4c17cc67ce36f4ca87343792c4551c4605446a3a2d13aa34287062f0d8577651bf3eb5351b1e2b7dda79f3d59b26d8e37a645c5ede3b980af25fa64fa5137c9b26166c8a155f8140806224cf6dabe198515a9e2306f74cd2a633620b4b80c8dfc4e63c7a6cdeb59411aa37bf5749c78738e6322492c9f8686925545014b3a49d82644e96f62aea0656ca8f4f7075534ad8a6d3e5620185c57206bd83f63ff16d2ccdaa00f793b9db9749953c62781c4882c789042532e8189221a*ebf60c352053c6a2a99e*$/zip2$:final_out/0vP5BE3z.png:final_out.zip:final_out.zip
┌──(kali㉿kali)-[~/zjdxs]
└─$ hashcat --help |grep -i "zip"
11600 | 7-Zip | Archive
17220 | PKZIP (Compressed Multi-File) | Archive
17200 | PKZIP (Compressed) | Archive
17225 | PKZIP (Mixed Multi-File) | Archive
17230 | PKZIP (Mixed Multi-File Checksum-Only) | Archive
17210 | PKZIP (Uncompressed) | Archive
20500 | PKZIP Master Key | Archive
20510 | PKZIP Master Key (6 byte optimization) | Archive
23001 | SecureZIP AES-128 | Archive
23002 | SecureZIP AES-192 | Archive
23003 | SecureZIP AES-256 | Archive
13600 | WinZip | Archive
┌──(kali㉿kali)-[~/zjdxs]
└─$ awk '{ match($0, /\$.+\$/, result); print result[0] }' hash.txt >output.txt
┌──(kali㉿kali)-[~/zjdxs]
└─$ hashcat -a 3 -m 13600 output.txt haticehatice?d?d?d?d?d
$zip2$*0*3*0*d03ba5ee8129058cc0b97bec667c259a*75fc*1f3*6faa12b15d4b4ece5e08ef1b77d676d33eed0270d4116be66b98656e4b59026a5c6205096b22a3b440be37b8c12b2e894b7a98c989c9c2770e13a5c76dc36819856658165c5b76e3985b4ad59be9ff687fbabd9fc406e94347dc2b1d5bc34a0bb9cdf38b2656d4d9845702e5dc6e925b1707ce8fa449181445c938e394db87ea7ab78b7835094c46b727854bae5578dbe73a608841ea150de441a6b1b9d303ab637d4b977c29ce1a2cedf12e2689ebcdb7b4f53942bc9127f0f052e083de31f8e7dce70bf7dcaa062355a38042640fda2e27119e92f6fee0c3a2049a063935b36ee7795e6bbdd4fe1cd0874d601ee149dbd7a2acde1d80eba470351fc177b9884bde72ffd2a06696b18fea20346f84b55a146fcad05a9fe67d1c01fbdc4bcc9a6e16c0e66d60e5beff59c00eca5ef6e907b0e5cde850898f1befbe0db927639f980fbe309dadfa37a6f02bee533d0087c7b73a305a8483729d5dc002127c344666c7f49583c6b2898e56d3aea8a51450dda2dc3f110af48da707c062ca9c5741e00381e7dfd43a173f5510e96230bbf18f4efd597c54bedec93555f5ad7617fc5e074155037adb3d4119ca0ed4421addebbc2c74e5f47656e31a42e37281fd3c35bfa0dfb309eb60e3798c7304605173dc59ed2217253a2acd7cbb81a76362121bff893ffb89e972f1f8860e70baa7230d6f61*b3dd9cf7bd682b10e7bb*$/zip2$:haticehatice12580

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 13600 (WinZip)
Hash.Target......: output.txt
Time.Started.....: Thu Nov 7 03:40:34 2024 (12 secs)
Time.Estimated...: Thu Nov 7 03:40:46 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: haticehatice?d?d?d?d?d [17]
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 83861 H/s (9.38ms) @ Accel:128 Loops:999 Thr:1 Vec:8
Recovered........: 25/25 (100.00%) Digests (total), 25/25 (100.00%) Digests (new), 25/25 (100.00%) Salts
Progress.........: 972800/2500000 (38.91%)
Rejected.........: 0/972800 (0.00%)
Restore.Point....: 37888/100000 (37.89%)
Restore.Sub.#1...: Salt:24 Amplifier:0-1 Iteration:0-999
Candidate.Engine.: Device Generator
Candidates.#1....: haticehatice74808 -> haticehatice20480
Hardware.Mon.#1..: Util: 79%

Started: Thu Nov 7 03:40:19 2024
Stopped: Thu Nov 7 03:40:47 2024

得到压缩包密码为haticehatice12580

其实上面这一连串丝滑连招,可以用ARCHPR软件直接爆破,由于我没装又懒的下所以就用hashcat

image

解压打开发现疑似flag图片拆散成100张,通过StegSolve随意打开一张图片发现在LSB Red 0通道中藏有二维码,扫码后得到数字,大概率是图片的拼图顺序

image

下面贴两个其他师傅写的脚本

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
from PIL import image as Image		#用于图片文件读取
import pyzbar.pyzbar as pyzbar #用于二维码识别
import os

path = "./final_out"

orders = []
names = []

for root, dirs, files in os.walk(path):
for file in files:
img = Image.open(os.path.join(root, file))
img = img.convert('RGB')
width,height=img.size
result = ""
for i in range(0,height):
for j in range(0,width):
tmp = img.getpixel((j,i))
result += bin(tmp[0])[-1]
a = 0
pic = Image.new("RGB",(50,50))
for y in range(0,50):
for x in range(0,50):
if result[a] == '0':
pic.putpixel([x,y],(0,0,0))
else:
pic.putpixel([x,y],(255,255,255))
a += 1
pic = pic.resize((500,500))
barcodes = pyzbar.decode(pic)
for barcode in barcodes:
barcodeDATA = barcode.data.decode("utf-8")
orders.append(barcodeDATA)
names.append(os.path.join(root, file))

#图片大小
width_i = 50
height_i = 50
#每行每列显示图片数量
line_max = 10
row_max = 10
#参数初始化
all_path = []
num = 0
pic_max=line_max*row_max
toImage = Image.new('RGB',(width_i*line_max,height_i*row_max))

pos = 1
for j in range(0,row_max):
for i in range(0,line_max):
pic_path = names[orders.index(str(pos))]
pic_fole_head = Image.open(pic_path)
width,height = pic_fole_head.size
tmppic = pic_fole_head.resize((width_i,height_i))
loc = (int(i%line_max*width_i),int(j%line_max*height_i))
toImage.paste(tmppic,loc)
pos += 1
toImage.save('merged.png')
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
from PIL import Image
import zxing
import os


def process_image_to_qrcode(image_path):
# 读取图片Red 0通道数据
img = Image.open(image_path)
w, h = img.size
rgb = ['']
for j in range(h):
for i in range(w):
data = img.getpixel((i, j))
rgb[0] += str(data[0] % 2)

# 转成二维码
img = Image.new('1', (w, h))
for j in range(h):
for i in range(w):
img.putpixel((i, j), int(rgb[0][j * w + i]))
img.save('./out/' + image_path.split('\\')[-1])

# 扫描二维码
reader = zxing.BarCodeReader()
barcode = reader.decode('./out/' + image_path.split('\\')[-1])

return image_path, barcode.parsed


path = "./final_out"
names = []
for root, dirs, files in os.walk(path):
for file in files:
names.append(os.path.join(root, file))

results = []
for name in names:
results.append(process_image_to_qrcode(name))
print(results[-1])


# 根据二维码内容排序,将图片合并 10*10
results.sort(key=lambda x: int(x[1]))
print(results)
width_i = 50
height_i = 50
line_max = 10
row_max = 10
pic_max = line_max * row_max
toImage = Image.new('RGB', (width_i * line_max, height_i * row_max))
for i in range(pic_max):
pic_path = results[i][0]
pic_fole_head = Image.open(pic_path)
tmppic = pic_fole_head.resize((width_i, height_i))
loc = (int(i % line_max * width_i), int(i // line_max * height_i))
toImage.paste(tmppic, loc)
toImage.save('merged.png')

这里我反倒觉得第二个代码更好,不过你需要新建out文件夹,他会将所有在LSB Red 0通道的二维码图片导出到out文件夹中

image

Crypto

Reverse

ezRe

附件到手使用file检查一下,是个python编译后的文件

1
2
❯ file ezRe
ezRe: Byte-compiled Python module for CPython 3.9, timestamp-based, .py timestamp: Mon Oct 21 03:17:07 2024 UTC, .py size: 722 bytes

尝试通过pycdas进行反编译

  • pycdas 是 Decompyle++ 项目中的一个工具,它与 pycdc 一起工作,专门设计用来解码那些难以捉摸的 Python 3.9 至 3.12 版本的编译代码文件 。pycdas 的作用是提供深度的反编译过程分析,帮助用户理解反编译的每一个细节 。它可以单独使用来打印出 .pyc 文件的字节码反汇编输出,这对于理解 Python 代码编译后的字节码结构非常有用,尤其是在进行代码审计或者逆向工程时 。pycdas 通过提供额外的反编译信息,提升问题诊断效率 。简而言之,pycdas 是一个辅助工具,用于辅助 pycdc 更好地进行 Python 字节码的反编译工作,尤其在面对复杂或难以反编译的代码时,pycdas 能够提供更多的信息和细节 。
  • 我理解的是这个就类似于IDA Pro那种反汇编的工具就可以了
  • pycdas默认是未编译的,需要编译成exe后可以使用
  • 编译前需要安装Visual Studio 这个IDE见下文引用链接

得到混淆前的代码

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
ezRe (Python 3.9)
[Code]
File Name: flag_checker.py
Object Name: <module>
Arg Count: 0
Pos Only Arg Count: 0
KW Only Arg Count: 0
Locals: 0
Stack Size: 7
Flags: 0x00000040 (CO_NOFREE)
[Names]
'base64'
'input'
'text'
'key'
'list'
'range'
's'
'j'
'i'
'len'
'data'
'_'
'append'
'result'
'zip'
'c'
'k'
'chr'
'ord'
'b64encode'
'encode'
'decode'
'enc'
'print'
[Var Names]
[Free Vars]
[Cell Vars]
[Constants]
0
None
'Flag: '
'7e021a7dd49e4bd0837e22129682551b'
[Code]
File Name: flag_checker.py
Object Name: <listcomp>
Arg Count: 1
Pos Only Arg Count: 0
KW Only Arg Count: 0
Locals: 2
Stack Size: 4
Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
[Names]
'ord'
[Var Names]
'.0'
'i'
[Free Vars]
[Cell Vars]
[Constants]
102
[Disassembly]
0 BUILD_LIST 0
2 LOAD_FAST 0: .0
4 FOR_ITER 16 (to 22)
6 STORE_FAST 1: i
8 LOAD_GLOBAL 0: ord
10 LOAD_FAST 1: i
12 CALL_FUNCTION 1
14 LOAD_CONST 0: 102
16 BINARY_XOR
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
22 RETURN_VALUE
'<listcomp>'
256
50
1
''
51
'w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg=='
'yes!'
'try again...'
[Disassembly]
0 LOAD_CONST 0: 0
2 LOAD_CONST 1: None
4 JUMP_FORWARD 0 (to 6)
6 JUMP_FORWARD 0 (to 8)
8 JUMP_FORWARD 0 (to 10)
10 IMPORT_NAME 0: base64
12 STORE_NAME 0: base64
14 LOAD_NAME 1: input
16 LOAD_CONST 2: 'Flag: '
18 CALL_FUNCTION 1
20 STORE_NAME 2: text
22 LOAD_CONST 3: '7e021a7dd49e4bd0837e22129682551b'
24 STORE_NAME 3: key
26 LOAD_CONST 4: <CODE> <listcomp>
28 LOAD_CONST 5: '<listcomp>'
30 MAKE_FUNCTION 0
32 LOAD_NAME 3: key
34 GET_ITER
36 CALL_FUNCTION 1
38 STORE_NAME 3: key
40 LOAD_NAME 4: list
42 LOAD_NAME 5: range
44 LOAD_CONST 6: 256
46 CALL_FUNCTION 1
48 CALL_FUNCTION 1
50 STORE_NAME 6: s
52 LOAD_CONST 0: 0
54 STORE_NAME 7: j
56 LOAD_NAME 5: range
58 LOAD_CONST 6: 256
60 CALL_FUNCTION 1
62 GET_ITER
64 FOR_ITER 62 (to 128)
66 STORE_NAME 8: i
68 LOAD_NAME 7: j
70 LOAD_NAME 6: s
72 LOAD_NAME 8: i
74 BINARY_SUBSCR
76 BINARY_ADD
78 LOAD_NAME 3: key
80 LOAD_NAME 8: i
82 LOAD_NAME 9: len
84 LOAD_NAME 3: key
86 CALL_FUNCTION 1
88 BINARY_MODULO
90 BINARY_SUBSCR
92 BINARY_ADD
94 LOAD_CONST 6: 256
96 BINARY_MODULO
98 STORE_NAME 7: j
100 LOAD_NAME 6: s
102 LOAD_NAME 7: j
104 BINARY_SUBSCR
106 LOAD_NAME 6: s
108 LOAD_NAME 8: i
110 BINARY_SUBSCR
112 ROT_TWO
114 LOAD_NAME 6: s
116 LOAD_NAME 8: i
118 STORE_SUBSCR
120 LOAD_NAME 6: s
122 LOAD_NAME 7: j
124 STORE_SUBSCR
126 JUMP_ABSOLUTE 64
128 LOAD_CONST 0: 0
130 DUP_TOP
132 STORE_NAME 8: i
134 STORE_NAME 7: j
136 BUILD_LIST 0
138 STORE_NAME 10: data
140 LOAD_NAME 5: range
142 LOAD_CONST 7: 50
144 CALL_FUNCTION 1
146 GET_ITER
148 FOR_ITER 88 (to 238)
150 STORE_NAME 11: _
152 LOAD_NAME 8: i
154 LOAD_CONST 8: 1
156 BINARY_ADD
158 LOAD_CONST 6: 256
160 BINARY_MODULO
162 STORE_NAME 8: i
164 LOAD_NAME 7: j
166 LOAD_NAME 6: s
168 LOAD_NAME 8: i
170 BINARY_SUBSCR
172 BINARY_ADD
174 LOAD_CONST 6: 256
176 BINARY_MODULO
178 STORE_NAME 7: j
180 LOAD_NAME 6: s
182 LOAD_NAME 7: j
184 BINARY_SUBSCR
186 LOAD_NAME 6: s
188 LOAD_NAME 8: i
190 BINARY_SUBSCR
192 ROT_TWO
194 LOAD_NAME 6: s
196 LOAD_NAME 8: i
198 STORE_SUBSCR
200 LOAD_NAME 6: s
202 LOAD_NAME 7: j
204 STORE_SUBSCR
206 LOAD_NAME 10: data
208 LOAD_METHOD 12: append
210 LOAD_NAME 6: s
212 LOAD_NAME 6: s
214 LOAD_NAME 8: i
216 BINARY_SUBSCR
218 LOAD_NAME 6: s
220 LOAD_NAME 7: j
222 BINARY_SUBSCR
224 BINARY_ADD
226 LOAD_CONST 6: 256
228 BINARY_MODULO
230 BINARY_SUBSCR
232 CALL_METHOD 1
234 POP_TOP
236 JUMP_ABSOLUTE 148
238 LOAD_CONST 9: ''
240 STORE_NAME 13: result
242 LOAD_NAME 14: zip
244 LOAD_NAME 2: text
246 LOAD_NAME 10: data
248 CALL_FUNCTION 2
250 GET_ITER
252 FOR_ITER 32 (to 286)
254 UNPACK_SEQUENCE 2
256 STORE_NAME 15: c
258 STORE_NAME 16: k
260 LOAD_NAME 13: result
262 LOAD_NAME 17: chr
264 LOAD_NAME 18: ord
266 LOAD_NAME 15: c
268 CALL_FUNCTION 1
270 LOAD_NAME 16: k
272 BINARY_XOR
274 LOAD_CONST 10: 51
276 BINARY_XOR
278 CALL_FUNCTION 1
280 INPLACE_ADD
282 STORE_NAME 13: result
284 JUMP_ABSOLUTE 252
286 LOAD_NAME 0: base64
288 LOAD_METHOD 19: b64encode
290 LOAD_NAME 13: result
292 LOAD_METHOD 20: encode
294 CALL_METHOD 0
296 CALL_METHOD 1
298 LOAD_METHOD 21: decode
300 CALL_METHOD 0
302 STORE_NAME 22: enc
304 LOAD_NAME 22: enc
306 LOAD_CONST 11: 'w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg=='
308 COMPARE_OP 2 (==)
310 POP_JUMP_IF_FALSE 324
314 LOAD_NAME 23: print
316 LOAD_CONST 12: 'yes!'
318 CALL_FUNCTION 1
320 POP_TOP
322 JUMP_FORWARD 8 (to 332)
324 LOAD_NAME 23: print
326 LOAD_CONST 13: 'try again...'
328 CALL_FUNCTION 1
330 POP_TOP
332 LOAD_CONST 1: None
334 RETURN_VALUE

直接全部丢个AI让他分析下

  1. 导入模块:代码中导入了base64模块,用于处理Base64编码和解码。
  2. 输入处理:代码从用户那里接收输入,并将输入存储在变量text中,提示信息为'Flag: '
  3. 密钥处理:代码中有一个固定的密钥'7e021a7dd49e4bd0837e22129682551b',它被用于后续的加密逻辑。
  4. RC4算法实现:代码中实现了一个简化版的RC4算法。RC4算法是一种流密码算法,它通过生成一个伪随机的密钥流来加密数据。在这段代码中,算法的核心逻辑是通过一个循环来更新一个256长度的数组s,然后使用这个数组来生成密钥流。
  5. 数据加密:代码中有一个列表推导式,它创建了一个列表,其中的每个元素都是通过对密钥字符的ASCII值进行XOR操作得到的。
  6. 验证逻辑:代码中有一个验证逻辑,它将用户输入的text与通过RC4算法加密后的数据进行XOR操作,然后将结果进行Base64编码和解码,最后与一个固定的Base64字符串进行比较。如果比较结果相同,则输出'yes!',表示验证成功;否则输出'try again...'
  7. 结束:代码最后返回None,表示程序执行结束。

直接改个RC4加密代码,把密文和密钥放进去

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
class rc4():
def toBytes(self,data):
if type(data)==str:
return data.encode()
elif type(data)==bytes:
return data
else:
raise Exception("data Type Error")

def GetKey(self,data):
k=[132, 206, 173, 4, 211, 121, 250, 202, 41, 13, 59, 166, 91, 116, 34, 200, 248, 49, 102, 215, 63, 160, 21, 103, 135, 68, 208, 175, 36, 30, 146, 181, 38, 64, 194, 57, 165, 195, 79, 99, 141, 0, 145, 96, 189, 128, 5, 170, 90, 55, 148, 229, 73, 219, 104, 243, 15, 77, 123, 152, 111, 239, 2, 35, 93, 190, 9, 26, 105, 199, 167, 228, 84, 124, 143, 252, 232, 66, 130, 122, 8, 71, 28, 53, 172, 251, 203, 89, 209, 23, 147, 101, 127, 86, 137, 236, 184, 1, 185, 134, 24, 16, 50, 32, 100, 76, 230, 88, 19, 225, 168, 87, 43, 94, 207, 46, 22, 214, 136, 54, 164, 106, 133, 10, 198, 60, 98, 142, 110, 192, 220, 201, 222, 140, 82, 95, 51, 154, 62, 118, 221, 11, 125, 233, 108, 52, 17, 234, 254, 14, 18, 255, 120, 29, 155, 126, 153, 40, 176, 12, 177, 245, 171, 83, 156, 187, 191, 112, 80, 235, 244, 237, 109, 78, 249, 231, 149, 72, 216, 107, 241, 69, 174, 253, 27, 144, 182, 180, 150, 61, 162, 56, 163, 186, 37, 131, 65, 223, 39, 115, 138, 33, 218, 42, 157, 3, 97, 246, 210, 178, 158, 92, 240, 117, 47, 217, 205, 196, 70, 159, 129, 58, 81, 227, 6, 213, 74, 113, 151, 7, 67, 20, 45, 75, 139, 204, 44, 161, 226, 179, 119, 188, 247, 25, 31, 48, 242, 183, 197, 238, 193, 85, 114, 169, 224, 212]
return k

def Cipher(self,data):
data=self.toBytes(data)
enc=[]
k=self.Key.copy()
n=0
n1=0
tmp=0
key=[]
print(k)
for _ in range(50):
n=(n+1)&0xff
n1=(n1+k[n])&0xff
tmp=k[n]
k[n]=k[n1]
k[n1]=tmp
key.append(k[(k[n]+k[n1])%256])
print(key)
for c,k in zip(data,key):
enc.append(c^k^51)
return bytes(enc)


def __init__(self,key):
key=self.toBytes(key)
self.Key=self.GetKey(key)
self.__Key=key

def SetKey(self,key):
key=self.toBytes(key)
self.Key=self.GetKey(key)
self.__Key=key
#########################手动分割#######################
import base64
b=base64.b64decode("w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg==").decode("utf-8")
b_=[]
for i in b:
b_.append(ord(i))
key=b"7e021a7dd49e4bd0837e22129682551b"
key_=[]
for i in key:
key_.append(i^102)
r=rc4(bytes(key_))
print(r.Cipher(bytes(b_)))

参考:zrax/pycdc: C++ python bytecode disassembler and decompiler

Windows 如何仅安装 MSVC 而不安装 Visual Studio_msvc v143-CSDN博客

Pycdc install | Pycdas install | Pycdc And Pycdas install video | python Decompile #decompile

第七届浙江省大学生网络与信息安全竞赛预赛-WP - Dr0n’s blog

PWN

shellcode

参考杭师大网安:https://www.bilibili.com/video/BV1yiD8YtEPB/

数据安全

ds-enen

附件给到是个vhd文件,在diskgenius中挂载查看发现啥都木有,原来在磁盘文件中藏了点东西,用foremost分离可以得到压缩包,需要密码,没有任何提示哇,只能尝试john硬爆破了,大概率是纯数字,如果+字母和特殊符号的话时间太久了,至于为啥不用hashcat,因为hash值太长了,hashcat识别不到hash,后面还是看的wp得知是8位密码,用crunch生成8位纯数字字典,也不大800多兆吧

https://bbs.2ba.cc:8888/Crunch.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
31
32
33
34
35
36
37
38
39
40
41
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ zip2john 00002390.zip>hash
ver 2.0 00002390.zip/data.csv PKZIP Encr: TS_chk, cmplen=454648, decmplen=628623, crc=75334E90 ts=AD29 cs=ad29 type=8
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ awk '{ match($0, /\$.+\$/, result); print result[0] }' hash >output
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ hashcat -a 3 -m 17200 output ?d?d?d?d?d?d?d?d?d --increment --increment-min 4 --increment-max 10
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 6.0+debian Linux, None+Asserts, RELOC, LLVM 17.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
============================================================================================================================================
* Device #1: cpu-sandybridge-12th Gen Intel(R) Core(TM) i5-12600KF, 2913/5891 MB (1024 MB allocatable), 8MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashfile 'output' on line 1 ($pkzip...b383c211a597189fc2468b2*$/pkzip$): Token length exception

* Token length exception: 1/1 hashes
This error happens if the wrong hash type is specified, if the hashes are
malformed, or if input is otherwise not as expected (for example, if the
--username option is used but no username is present)

No hashes loaded.

Started: Fri Nov 8 07:05:47 2024
Stopped: Fri Nov 8 07:05:48 2024
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ crunch 8 8 -f /usr/share/crunch/charset.lst numeric -o pass
Crunch will now generate the following amount of data: 900000000 bytes
858 MB
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ john hash --wordlist=pass
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
60111106 (00002390.zip/data.csv)
1g 0:00:01:05 DONE (2024-11-08 06:55) 0.01525g/s 916774p/s 916774c/s 916774C/s 60096512..60112895
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

使用密码60111106解压后发现是个data.csv使用Microsoft Excel打开全是乱码

image

查询得知使用数据-从文本/CSV导入编码改成UTF-8即可正常显示

image

有个密码个性签名(加密版)疑似是AES加密尝试解密下,密码为key,长度不够16位所以填充空字节位,由于是AES MODEECB(NoPadding)无填充所以无需填写IV

0x00(空字节)和空格是两个不同的概念。

  • 0x00:0x00是一个16进制数,对应的十进制数是0。在计算机中,0x00被称为空字节(null byte),它是一个8位二进制数,所有位都为0。空字节在字符串处理中常用于表示字符串的结束或者作为字符串中的间隔符。空字节通常不显示在文本编辑器或终端中,但在内存中是存在的。
  • 空格:空格是一个可见字符,在ASCII编码中对应的字符是空格符。空格用于文本中表示空白或分隔不同的单词或数字。空格在文本处理中经常被用来增加内容的可读性。在文本编辑器或终端中,空格通常可以看到并占据一定的显示空间。

这里贴一下其他师傅的脚本,使用python批量对CSV进行AES ECB解密,这两个脚本都比较类似任选其一即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES
import pandas as pd
import base64

data = pd.read_csv('data.csv')
password = data['密码']
signature = data['个性签名(加密版)']


def aes_decrypt(ciphertext, key):
key = key.encode('utf-8') + (16 - len(key)) * b'\0'
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
return plaintext


for i in range(len(password)):
if 'DASCTF' in aes_decrypt(signature[i], password[i]).decode('utf-8'):
print(aes_decrypt(signature[i], password[i]).decode('utf-8'))
break
else:
continue
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
import csv
import base64
from Crypto.Cipher import AES

def zeropadding(password):
password = password + b"\x00"*(16 - len(password) % 16)
return password


list1 = []
with open('data.csv',encoding="utf8") as f:
reader = csv.reader(f)
for row in reader:
list1.append(row)

for i in range(1,len(list1)):
cipher = list1[i][6]
key = zeropadding(list1[i][2].encode())
text = base64.b64decode(cipher.encode())
aes = AES.new(key,AES.MODE_ECB)
den_text = aes.decrypt(text)
try:
if("DAS" in den_text.decode("utf8")):
print(den_text.decode("utf8"))
except:
continue

在Python中,b'\0'表示一个字节序列,其中\0表示一个空字节(null byte)。这是因为Python中的字节字面值通过前缀b来表示。空字节通常用来表示字符串的结尾或作为字符串中的间隔符。

在Python中,\0对应的是空字节的ASCII字符,即NUL(NULL)字符。空字节可以在字符串处理中发挥作用,如在字符串处理和二进制数据处理时,用来表示特殊意义。需要注意的是,Python中使用\0来表示空字节,并不是所有编程语言都支持这种方式。

我将每次解密的文本都打印出来可以更加直观的看到解密的后的信息是一段话,flag就藏在其中,只要上面添加if语句即可,判断DASCTF是否在其中,就能找到flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(kali㉿kali)-[~/zjdxs/output/zip]
└─$ python exp.py
text: b'Give more than you planned to.\x00\x00'
text: b'To read without reflecting is like eating without digesting.\x00\x00\x00\x00'
text: b'Difficult circumstances serve as a textbook of life for people.\x00'
text: b'Pursue your object, be it what it will, steadily and indefatigably.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
text: b"Wise men learn by other men's mistakes; fools by their own.\x00\x00\x00\x00\x00"
text: b'Swim against the stream.\x00\x00\x00\x00\x00\x00\x00\x00'
text: b'Live well, love lots, and laugh often.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
text: b'Life is short and you deserve to be happy.\x00\x00\x00\x00\x00\x00'
text: b'Go ahead, make my day.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
text: b'No cross, no crown.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
text: b'Some people can not tell where good, but who can not be replaced.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
---------------------------------------------------------------------------手动分隔符
text: b'DASCTF{dcd85182008e3a2d51b37f9845df3312}\x00\x00\x00\x00\x00\x00\x00\x00'
DASCTF{dcd85182008e3a2d51b37f9845df3312}

ds-encode

附件中有两个文件,PDFZIP压缩包,解压后得到Mysql的数据文件,由于我电脑上没装类似SQLyolNavicat的数据库管理软件,正巧我电脑有PHPStudy以前用来玩本地Web靶场的,直接将数据库文件拷贝到PHPStudyMysql文件夹中

image

启动了MysqlNginx打开phpMyAdmin网页,用户名和密码都是root

image

打开后发现有个person库中有个data表,总共5000条数据,导出为csv,其实题目名也能看出,使用不同的编码来解码,根据cryptoType字段中的编码来解码这一行中的除了userid所有数据即可

image

这么多数据量,可以尝试利用编写python批量解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import json
import base64
# 假设你的JSON文件名为'data.json'
file_name = 'data.json'
def processBase(name, v):
if name == "Base64":
return base64.b64decode(v).decode()
elif name == "Base32":
return base64.b32decode(v).decode()
elif name == "Base85":
return base64.b85decode(v).decode()

# 打开并读取JSON文件
with open(file_name, 'r', encoding='utf-8') as file:
# 将文件内容解析为JSON列表
data_list = json.load(file)

for ob in data_list:
if ob["cryptoType"] != None:
for k, v in ob.items():
if k != "cryptoType" and k != "userid":
ob[k] = processBase(ob["cryptoType"], v)
print(ob)

image

得到正常数据后,查看题目附件还有个PDF文件

image

要求是这样的,那就根据规范文档再对数据进行脱敏处理,根据上传规范定义了CSV文件的列标题,删除cryptoType字段,最终脚本如下

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
import json
import base64
import hashlib
import csv

# 假设你的JSON文件名为'data.json'
file_name = 'data.json'
def processBase(name, v):
if name == "Base64":
return base64.b64decode(v).decode()
elif name == "Base32":
return base64.b32decode(v).decode()
elif name == "Base85":
return base64.b85decode(v).decode()

# 打开并读取JSON文件
with open(file_name, 'r', encoding='utf-8') as file:
# 将文件内容解析为JSON列表
data_list = json.load(file)

for ob in data_list:
if ob["cryptoType"] != None:
for k, v in ob.items():
if k != "cryptoType" and k != "userid":
ob[k] = processBase(ob["cryptoType"], v)
username = ob["username"]

##脱敏处理
##若只有两个字符则只对最后一位使用本号代替,否则只保留第一位和最后一位字符, 其余都用*代替
username = username[0] + '*' if len(username) == 2 else username[0] + '*' * (len(username) - 2) + username[-1]
ob["username"] = username

##对密码进行MD5加密
md = hashlib.md5()
md.update(ob["password"].encode())
ob["password"] = md.hexdigest()

##对姓名进行SHA1加密
sha1 = hashlib.sha1()
sha1.update(ob["name"].encode())
ob["name"] = sha1.hexdigest()

##对身份证号进行脱敏处理,只保留年份,其余*代替
idcard = ob["idcard"]
idcard = '*' * 6 + idcard[6:6+4] + '*' * (len(idcard) - 10)
ob["idcard"] = idcard

##对手机号进行脱敏处理,只保留前三位和后四位,其余*代替
phone = ob["phone"]
phone = phone[:3] + "*" * 4 + phone[7:]
ob["phone"] = phone

##去除cryptoType字段
ob.pop("cryptoType")

with open('output.csv', 'w', newline='', encoding="utf-8") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=["userid", "username", "password", "name", "idcard", "phone"])
writer.writeheader()
for row in data_list:
writer.writerow(row)
print(data_list)

image

最后将output.csv文件上传即可获得flag

信创安全

sm4rev

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 258.9k