浅谈web app二次漏洞

作者:T_Torchidy (jnchaha_at_163.com)
来源:安全焦点

在假设设计上不存在问题(即人解决某个应用的方式不存在问题)以及所采用的语言以及其他周边组件是安全的情况下,程序的漏洞就大部分就是由于在实现问题的过程中,程序员对安全的漠视或是对安全的不太了解造成的,而从程序的角度看,这种漏洞不外乎是不安全的参数进入不安全的操作中引起的。
不安全的操作大家都知道有很多,譬如文件读写,数据库查询,代码执行以及其他的一些危险函数的使用等等,那么不安全的参数主要是哪些呢?有人说所有用户的输入都是有害的,在我看来输入可以分两种,直接的输入与间接的输入。直接的输入是可以看到的,如url里的参数,浏览器与服务器的一些环境变量,用户提交的Cookie,用户通过表单进行的输入等等,对于这些输入大部分的程序员都会在安全上比较在意,比较注意参数的过滤,因为这些输入是显而易见的,触发比较简单,甚至一些输入如果不做过滤的话会导致程序出错,再加上PHP这种语言对于一些进入的参数的默认保护(Magic Quote选项),所以这种参数现在在大的程序里比较少出问题,但是另外一种隐式的输入却被人们忽略了,那就是来自数据库(包括Mysql这种数据库,文本数据库和一些人常用的cache以及php配置文件等等),可以尝试为程序做一个流程图:

处理流程 用户的输入==========> 程序处理(过滤)=========> 数据存储 ==========> 程序处理==========>输出给用户
数据流程 原始的数据如'=======> 程序处理(安全的数据如\')==> Mysql里存储(原始的数据如')========>程序处理(处理的是')=========>输出给用户

可以看到,如果用户的输入暂时性地存储在数据库里然后被取出来使用而没有加过滤的话是很危险的,因为这个时候数据就是用户输入的最原始的数据不受GPC等安全措施保护,另外就是这种漏洞触发的条件比直接用户的输入要多一些操作,所以一般的测试比较难发现,而会被误认为是安全的。
上面的模型只是简单地说明问题的存在,实际情况里完全不局限于上面提到的'和mysql等等,实际上,动网使用的将一个'转换成''的处理Sql 注射的方法还是很危险的,就很容易遭受这种攻击,事实上我也发现过这种问题:)从程序员的角度想想,什么时候会现这种安全问题呢?数据需要暂时地存储在某个地方,然后在另外的地方需要从里面取出来进行操作,那么什么时候会这样什么时候容易出现问题呢?譬如注册的时候的用户名,如果允许'的话就等于是把祸根引入了,因为很多地方都需要使用用户名,而且用户名是存储在数据库里的,如果在后面的操作里不小心把用户名取出来直接送到数据库操作里就会出现问题(或者是将用户名放到session里然后进行操作),这种情况下可以看成是数据库到数据库的操作,不受GPC影响当然会出问题啦!当然问题不只是',用于文件操作的\0呢?通常会被addslashe的\0,如果有从数据库直接到文件操作的数据流程,危险是很大的。而且在程序员的眼睛里,可能无意识地认为从数据库里出来的东西都是经过检查的东西,但是事实上常常相反。
那么如何避免并且检测这种漏洞呢?对于开发者首先就是良好的编程习惯以及安全意识,明白数据库以及缓存文件里出来的东西一样不安全,其次就是在进行数据过滤的时候,不要只是暂时地让数据失去危害,可以考虑永久地让数据失去危害,譬如在过滤的时候不是将'变成\'等,而是在条件允许的情况下将其直接转换成HTML字符',这样并不影响显示但是数据却不再会包含让数据库的元字符所以不用担心注射了,其他的字符可以一样考虑处理。另外就是尽量对数据库进行严格的设计,实际上在存储的过程中有一层隐含的数据过滤,譬如数据字段的大小限制了数据的长度,数据字段的类型限制了数据的类型,所以我们尽量在允许的条件下使用数字类型的字段,并且尽量将数据字段的大小缩小,无论是在存储还是安全上还是很有意义的。对于检测的人员来说,如果是白盒操作,可以将数据库的字符类型的字段取出来,然后在程序里检查这些字段的去向,实际上就是将视角放到隐含的输入上检查问题,譬如我这里就有段检查类型的代码:

<?php
/*Codz By 剑心*/
$host='localhost';
$user='root';
$password='loveshell';
$dbname='discuzl';

$link = mysql_connect($host, $user, $password);
if (!$link) {
die('Could not connect: ' . mysql_error());
}
echo "Connected successfully\r\n";
if(mysql_select_db($dbname, $link)) {
echo "Select Database successfully\r\n";
}

$result=mysql_list_tables($dbname);

while ($row = mysql_fetch_row($result)) {
print "Table: $row[0]\r\n";
print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n";
$result2=mysql_query("show full fields from `$dbname`.`$row[0]`");
while ($row2 = mysql_fetch_row($result2)) {
if(strpos($row2[1],'int')===false&&strpos($row2[1],'enum')===false&&strpos($row2[1],'decimal')===false&&strpos($row2[1],'date')===false){
print "字段: $row2[0]\t\t属性: $row2[1]\r\n";
}
}
print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n";
}
?>

然后就可以关注这些字段来检查问题了,当然并不是所有的字段都是可以控制的,关注对字段的insert update 操作可以知道输入可以有哪些更改,而select之后的操作可以检查这些字段将会进入哪些危险的操作,而如果是黑盒操作,因为代码的不透明就只能根据自己的一些探测来猜测对方的代码是如何实现的来检测是否含有二次漏洞了。
文章比较简单,期待更有意义的东西出来,譬如基于数据库的Fuzz等等。

相关日志

发表评论