2025帕鲁杯线上 WP
应急响应主线
1
提交堡垒机中留下的flag

palu{2025_qiandao_flag}
2
提交WAF中隐藏的flag

palu{2025_waf}
3
提交Mysql中留下的flag

palu{Mysql_@2025}
4
提交攻击者的攻击IP
palu{192.168.20.107}
5
提交攻攻击者最早攻击时间flag格式为palu{xxxx-xx-xx-xx-xx-xx}
去看雷池 WAF 的面板。

palu{2025-05-05-00:04:40}
6
提交web服务泄露的关键文件名

palu{key.txt}
7
题解泄露的邮箱地址

palu{parloo@parloo.com}
8
提交立足点服务器ip地址

palu{192.168.20.108}
9
提交攻击者使用的提权的用户和密码

palu{parloo/parloo}
10
提交攻击者留下的的文件内容作为flag提交

palu{hi_2025_parloo_is_hack}
11
提交权限维持方法服务的名称

palu{rootset}
12
提交攻击者攻击恶意服务器连接地址作为flag提交
server 里面有一个 aa 程序。


palu{47.101.213.153}
13
找到系统中被劫持的程序程序名作为flag提交

按照修改时间排序,发现 id 很可疑。
palu{id}
14
找到系统中存在信息泄露的服务运行端口作为flag提交

palu{8081}
15
提交Parloo公司项目经理的身份证号作为flag提交

palu{310105198512123456}
18
提交攻击者留下的恶意账户名称md5后作为flag进行提交。 格式为palu{md5{xxxxx}}
进源机器开机可以选用户,发现一个 hack 用户。
palu{d78b6f30225cdc811adfe8d4e7c9fd34}
19
提交内部群中留下的flag并提交

palu{nbq_nbq_parloo}
20
请提交攻击者使用维护页面获取到的敏感内容作为flag进行提交

后门程序的源码在 gitea 里面,可以发现把日志放在了 command.log 里面。

palu{Server_Parloo_2025}
21
提交获取敏感内容IP的第一次执行命令时间作为flag进行提交。flag格式为palu{xxxx-xx-xx:xx:xx:xx}

palu{2025-05-04:15:30:38}
22
提交攻击者使用的恶意ip和端口flag格式为palu{xx.xx.xx.xx:xxxx}

palu{10.12.12.13:9999}
23
提交重要数据的名文内容作为flag提交
palu03 桌面有个重要的数据.txt,但是交了不对,被加密了。
之前 Gitea 里面还有一个 hack 用户,他的仓库里面有一个加密脚本,但只提供了一个加密函数:
def custom_encrypt(text, key):
encrypted = []
key_bytes = [ord(c) for c in key]
for i, char in enumerate(text):
shifted = ord(char) + (i % 5 + 1)
xor_key = key_bytes[i % len(key_bytes)]
xored = shifted ^ xor_key
substituted = ((xored & 0x0F) << 4) | ((xored & 0xF0) >> 4)
encrypted.append(f"{substituted:02x}")
return "".join(encrypted)
自己传个参数进去,发现密文的格式和重要的数据.txt 的内容一致,尝试去解密。
这里不知道密钥,我们猜测解密出来的内容的头部是 palu{,由于明文和密钥是一位一位进行加密的,我们可以进行明文攻击,反推出密钥,最后手动试出来密钥是 MySecretKey。
def custom_decrypt(ciphertext, key):
decrypted = []
key_bytes = [ord(c) for c in key]
for i in range(0, len(ciphertext), 2):
hex_byte = ciphertext[i:i+2]
substituted = int(hex_byte, 16)
xored = ((substituted & 0x0F) << 4) | ((substituted & 0xF0) >> 4)
xor_key = key_bytes[(i // 2) % len(key_bytes)]
shifted = xored ^ xor_key
original_char_code = shifted - ((i // 2) % 5 + 1)
decrypted.append(chr(original_char_code))
return ''.join(decrypted)
key = "MySecretKey"
ciphertext = "c3a1c3c13e326020c3919093e1260525045e"
plaintext = custom_decrypt(ciphertext, key)
print(plaintext)

palu{Password-000}
24
提交恶意维权软件的名称作为flag进行提交


palu{svhost}
25
提交恶意程序的外联地址
这个程序在 palu03 里面,叫 ipconfig.exe,python 写的。

palu{88.173.90.103}
26
提交攻击这使用的恶意dnslog域名作为flag进行提交

palu{np85qqde.requestrepo.com}
27
提交寻找反序列化漏洞的端口作为flag进行提交


palu{9999}
28
提交web服务泄露的密钥作为flag进行提交

palu{QZYysgMYhG6/CzIJlVpR2g==}
30
提交攻击者在server中留下的账户密码作为flag进行提交。flag格式为palu{username/password}

爆出来密码是 123456
palu{parloohack/123456}
32
提交攻击者留下的木马md5后作为flag进行提交
在 parloohack 的用户文件夹里面,有一个叫 aa 的文件。

palu{4123940b3911556d4bf79196cc008bf4}
33
提交攻击者留下的溯源信息作为flag进行提交
神人题。
先做的 46 题,想了想发现不对劲,还有一个保存的用户。

用户名就是 QQ 号,去看他的空间。

不过 flag 不在这里,还是在保存的密码里面。

palu{X5E1yklz1oAdyHBZ}
34
提交攻击者的githubID作为flag进行提交

palu{ParlooSEc}
35
提交攻击者在github下留下的的内容作为flag进行提交

palu{s5o3WkX33hptyJjk}
36
提交恶意用户的数量作为flag进行提交
看 palu01,在登录系统的时候有一堆用户,除了 Parloo 以外还有 99 个账户。
palu{99}
37
提交恶意用户的默认密码作为flag进行提交

palu{123456}
39
提交私人git仓库中留下的内容作为flag进行提交
连接 gitea 的数据库。



新建一个用户,然后覆盖 admin 的数据。

发现 base64 编码的 flag。

palu{FO65SruuTukdpBS5}
40
提交存在在mysql服务器中的恶意程序的MD5作为flag进行提交

palu{ba7c9fc1ff58b48d0df5c88d2fcc5cd1}
41
提交恶意程序中模拟c2通信的函数名称作为flag进行提交

palu{simulate_network_communication}
42
提交恶意程序创建隐藏文件的名称作为flag提交

palu{.malware_log.txt}
43
提交恶意程序中模拟权限提升的函数作为flag进行提交

palu{simulate_privilege_escalation}
44
提交被钓鱼上线的用户名作为flag进行提交

palu{Parloo-子怡}
45
提交恶意程序的所在路径作为flag进行提交

palu{C:\Users\Public\Nwt\cache\recv\Parloo-沉沉}
46
分析恶意程序的反连地址作为flag进行提交

palu{47.101.213.153}
47
提交恶意c2的服务器登录的账号密码作为flag进行提交。flag格式为palu{username/password}
在 palu02 里面,看谷歌浏览器保存的密码。

palu{admin/admin@qwer}
畸形的爱
WebServer
root/root
webserver/webserver
SQL服务器
sql/sql
Windows7 PC 1
administrator/wmx666
Windows10 PC2
administrator/zjl@123

1
提交攻击者使用的攻击ip地址1
flag格式为:palu{xxxx}
看 webserver 的 nginx 日志。

palu{192.168.31.240}
2
提交攻击者使用的攻击ip地址2.
flag格式为:palu{xxxx}

palu{192.168.31.11}
4
提交攻击者留下的flag1
格式为palu{xxx}


palu{pc3_zgsfqwerlkssaw}
5
提交攻击者留下的flag2
格式为:palu{xxxx}


palu{nizhidaowoyouduoainima}
6
提交攻击者留下的flag3
提交格式为:palu{xxxx}


palu{sqlaabbccsbwindows}
7
提交钓鱼文件的哈希32位大写
回收站里面,捡出来解压,有个简历.exe。
palu{2977CDAB8F3EE5EFDDAE61AD9F6CF203}
8
提交攻击者留下的webshell-1密码
格式为:palu{xxxx}

palu{hack}
10
提交攻击者留下的webshell密码2
格式为:palu{xxxx}

palu{00232}
11


去看一下历史命令,没找到.....
13
提交溯源后得到的flag
flag格式为:palu{xxx}


palu{loveyouibiejv}
Reverse
PositionalXOR
Flag 被一种基于位置的异或加密算法混淆。加密后数据保存在 encrypted.bin 中,每个字符的加密方式与其在字符串中的位置相关。你需要逆向加密逻辑,恢复原始 Flag。


PaluFlat
帕鲁不是死肥宅,帕鲁不胖!帕鲁头晕目眩绝对不是炫多了
附件是个 7z 压缩包,解压后拿到一个 1G 的 exe,010 查看发现末尾都是 0x00,删去后用 IDA 打开分析。
def reverse_shift(byte):
for x in range(256):
if ((16 * x) | (x >> 4)) & 0xFF == byte:
return x
raise ValueError(f"No match found for byte: {byte}")
def decrypt(data_hex: str) -> str:
data = bytes.fromhex(data_hex)
str_key = b"palu"
alt_key = b"flat"
result = []
for i, b in enumerate(data):
b = ~b & 0xFF
b = (b + 85) & 0xFF
b = reverse_shift(b)
key = alt_key if (i % 2) else str_key
k = key[i % len(key)]
b ^= k
result.append(b)
return bytes(result).decode('utf-8', errors='ignore')
# 示例用法
if __name__ == "__main__":
hex_input = input("Enter hex-encoded encrypted data: ").strip()
print("Decrypted output:", decrypt(hex_input))

PaluGOGOGO
帕鲁该走了,要去当苦命打工人了,GOGOGO!
有个反调试,jnz 改成 jz 绕过。


打个断点,动调把 value 取出来。
main_complexEncrypt 函数其实就是一个类似凯撒的函数,直接写脚本解密。
def decrypt(cipher_bytes: bytes, key: int) -> str:
cipher_text = cipher_bytes
plain_chars = []
for i, ch in enumerate(cipher_text):
orig = ch - key - (i % 5)
orig &= 0x10FFFF
plain_chars.append(chr(orig))
return ''.join(plain_chars)
cipher_hex = [
0xbf, 0xb1, 0xbd, 0xc7, 0xce, 0x96, 0x80, 0x98,
0x82, 0x9a, 0x7f, 0xaf, 0xc1, 0xb3, 0xbf, 0xc4, 0xcd
]
cipher_bytes = bytes(cipher_hex)
key = 0x4F
plain = decrypt(cipher_bytes, key)
print("解密结果:", plain)

palu{G0G0G0_palu}
CatchPalu
主人给了帕鲁好多花花,帕鲁好开心呀!可是主人骗帕鲁,还把帕鲁抓了起来...
先去花指令,就是一堆 jz 和 jnz 互补跳转这种结构,把下面 jmp 的第一个字节 NOP 掉即可。


然后 UCP,把所有的处理好即可,接下来逆向程序。
直接下个断点,输入一个假 flag,可以进到解密的地方,直接取出来最终的真 flag。

palu{G00d_P1au_Kn0w_H00K}
帕鲁迷宫
贪玩的帕鲁来走迷宫啦,主人要求我以最短路径完成全部出口!太难了...
flag格式:palu{md5(最短路径步骤)}
Eg:awsd是最短路径 则计算其MD5值得到palu{2f724716d49d79e1fd0d71d57d451de0}
最短路径使用BFS算法,flag唯一,核对最后四步为ssds
懒得写脚本了,直接手动走。
无语了......有多解,多试几次。
最后走出来这条路径是对的:
ssssddssddwwddwwddddddddssssssssddssaaaaaaaaaawwddddwwddwwaaaassaaaaaaaassddssssasadsdssssddssddssaassddssaaaaasadwdddddddwwddssddwwwwddddddwwaaaaaaaaaawwwwddssddwwddssddwwwwaawwddddwwwwddddddddddwwwwaawwddwwaawwdddaaassddssaassddssssssssaawwaaaaaassssssssssssssssaaaasadwddddddddddwwddssds

palu{990fd7773f450f1f13bf08a367fe95ea}
PaluArray
帕鲁有自己的数组,帕鲁有自己的字典,帕鲁就是帕鲁!帕鲁不要996!
魔改 UPX,改回去。

脱壳后直接问 GPT,有一个表是 Palu_996!?,要求输入一个字符串,对应的索引是 1145141919810。

flag 的内容就是最后输入的字符串的 md5,当然如果字符串输对的话,也会弹出来一个带有 flag 的提示框。
手动构造,最后的字符串是 aa_9a_a?a?!aP。

palu{1b501325fc96d5a845cbdd2ba4f01cd7}