CTF-2021中国能源⽹络WEB题⽬全解
0x01 前⾔
在2021年10⽉15⽇的“中国能源⽹络安全⼤赛”,笔者对WEB题⽬进⾏了尝试,幸运的做出了所有题⽬。
感觉WEB的考点形形⾊⾊,其中有1道偏于⿊盒测试的简单题⽬,4道是⽩盒审计类题⽬,还有⼀道是Python的反序列化题⽬,题⽬名称⼤致如下:
因为唯⼀的⼀道⿊盒题⽬还是⽂件包含题⽬,所以笔者将题⽬源代码全部扒下来了,给⼤家提供复现环境。(flag⾃⼰创建)。
下⾯笔者将分享这次⽐赛的解题过程。
0x02 ezphp
这是⼀道很简单的题⽬,同时也被⼤家刷成了签到题。
打开界⾯显⽰如下:
单机按钮后会返回源代码,如图:
这⾥MD5的判断已经是千年⽼题了,使⽤数组就可以绕过。
问题是下⾯的$res的结果不可以包含flag字符串,这⾥的话我们可以通过php伪协议将它进⾏base64加密绕过即可。但是我们可以注意到$request_url中间是拼接了⼀个url地址的,如图:
这⾥我们可以将php伪协议拆分成两段,例如:
php://filter/read=convert.base64-encode/v/popular/all/resource=/flag,这样虽然PHP会抛出异常,但是也是可以正常运⾏的,如图:
Base64解密获得flag:
0x03 phar
这道题有⼀定的⿊盒成分,也是⽐较简单的⼀道题⽬,⾸页如下:
我们可以看到这⾥给出了⼀个hint,那么访问include.php看⼀下,如图:
给出了提⽰,说参数的key值为file,那么包含/etc/passwd看⼀下结果:
显然这⾥包含失败了,在这⾥我们只能对源代码的编写进⾏猜测,这⾥有两条路可选:
1: 程序写法为 include $_GET[file] . '.xxx'; 针对这⼀种情况,我们可以fuzz后缀到底是什么,然后再进⾏读源码或包含⼀系列操作。
2: 显然这⼀条路是⽐较离谱的,也就是说,根据题⽬名为phar,是否考点为phar反序列化?或者这⾥存在⼀个辅助的class.php⽂件,只是我们不知道class的⽂件名⽽已,但是由于这⾥的hint为include.php,显然这⼀条路是⽐较离谱的。
那么这⾥可以包含以下include,如图:
import pickle
显然形成⾃⼰包含⾃⼰,后缀确定为.php,使⽤伪协议阅读源码:
这⾥不让使⽤base,那么我们可以使⽤url⼆次编码绕过,将“e”字符进⾏⼆次编码,如图:
怼出php源码:
根据hint.php到上传点upload.php,这⾥读取upload.php源码,如图:
这⾥限制了后缀与mime类型,但是没关系,我们可以上传后缀为jpg的phar⽂件,在phar⽂件中存放⼀个1.php为⼀句话⽊马,包含即可,如图:
然后phar包含:
0x04 HardCode
这⾥第⼀个if判断使⽤md5强碰撞即可。
下⾯的preg_match过滤也是⽐较严格的,这⾥⾸先判断版本号,笔者通过http头发现php版本为5.2.9版本,如图:
显然这⾥的preg_match只是多了⼀个@符号的限制,但是我们还是可以通过Linux的通配符来匹配的,如图:@的ASCII:
那么根据题⽬中的过滤0-9,我们可取的也就是@与数字9中间的特殊符号:
这⾥笔者取“>”,完整的正则写为[\>-[]。
构造Payload:
如图:
睡眠3秒,这⾥可以直接反弹shell。
0x05 CODE
毫⽆卵⽤的加密,然后对eval⼀步⼀步echo得出如下源代码:
<?php
// error_reporting(E_NOTICE);
highlight_file(__FILE__);
@session_start();
$username = @$_GET['whoami'];
if(!@isset($username['admin'])||$username['admin'] != @md5($_SESSION['username'])) {
die('error!');
} else {
if(isset($_GET['code'])) {
$admin = $_GET['code'];
$admin = addslashes($admin);
if(preg_match('/\
{openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|system|chroot|chgrp|chown|sh $admin)) {
die('error!');
}
if (intval($admin)) {
eval('"' .$admin .('"./hh.php"') .')}}";');
}
} else {
eval('$flag="' .$admin . '";');
}
}
>
这⾥$_SESSION[username]是null,所以我们只要使⽤⼀个空的md5串就⾏:whoami[admin]=d41d8cd98f00b204e9800998ecf8427e
下⾯$_GET[code]经过了addslashes函数,⽆法闭合下⾯eval('"' .$admin .('"./hh.php"') .')}}";');的双引号,我们打印⼀下如图:
这⾥肯定回抛出⼀个语法错误的,因为语法格式是错误的。
但是在双引号包裹${}进⾏执⾏还有⼀个姿势,如图:
这种写法就允许了两对双引号在未经反斜杠转义下的解析。
那么构造Payload:?whoami[admin]=d41d8cd98f00b204e9800998ecf8427e&code=1${${print(