Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Wladimir van der Laan 2016. This document is in the public domain.
BLATSTING reverse-engineering notes. Based on files from the EQGRP free dump,
more specifically in Firewall/BLATSTING/BLATSTING_201381/LP/lpconfig.
BLATSTING is described as "A firewall software implant that is used with EGREGIOUSBLUNDER
If true, it's interesting how this implant can target both vendors. Presumably they both use the same Linux
kernel version (2.4.x = FortiOS 5.2). Possibly, one series of network devices is a "whitelabel" variant of the other.
Ironically they have both been part of GPL disputes:
> TOPSEC is a chinese security provider that provide firewall based Linux and netfilter... claims the
> entire software is (C) Copyright TOPSEC
> In 2005, the project uncovered evidence that Fortinet had used GPL code in
> its products against the terms of the license, and used cryptographic tools to conceal the violation.
The source code (including their modified kernel) is still available: . This does not exactly match the kernel
that is targetted by the rootkit, but with regard to structure offsets it is closer than
2.4.x stock kernels.
BLATSTING is a toolkit that is to be installed after exploitation, to have a foothold
on a router. It could be installed through a backdoor or exploit, but this is
not part of BLATSTING proper but the stage that preceeds it. BLATSTING, as far as I've
noticed, contains no exploits.
Basically it is a Linux rootkit that loads into the kernel. To what it does
there is no single answer as it can differ based on which modules are loaded. A
few (possibly not all) of these modules are part of the dump. Some of them deal
with network traffic interception or statistics, another one, SECONDDATE can do
MiTM attacks, yet another one TADAQUEOUS can selectively weaken IPsec VPN
encryption. And so on. It can be controlled through the network.
BLATSTING "modular rootkit" implant modules
(not showing implied dependencies, e.g. everything depends on core mod)
│ m00000003 │
│ core │
v v v v v v
┌─────┴─────┐ ┌─────┴──────┐ ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ m01010001 │ │ m01020000 │ │ m0c010001 │ │ m03010000 │ │ m05000003 │ │ m08010001 │
│ crypto │ │ crypto_rsa │ │ bpf │ │ network │ │ install │ │ hash │
└─────┬─────┘ └──────┬─────┘ └─────┬─────┘ └─┬──┬─┬────┘ └─┬───┬──┬──┘ └───────────┘
┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆
└┄┄┄┄┄┄┄┄┄┄┄┄┬┄┘ ┆ ┆ ┆ ┆ ┆ ┆ ┆
┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆
┌┄┄┄┄┄┄┄┄┄┄┄ ┆ ┄┄┄┄┄┄┬┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┴┄ ┆ ┆ ┄┄┄┄┄┄┄┘ ┆ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
┆ ┆ ┆ ┆ ┆ ┆ ┆
┆ ┆ ┆ ┆ └┄┄┄┄┄┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┐ ┆
┆ ┆ ┆ ┆ ┆ ┆
┆ ┆ ┆ ┌┄┄┴┄┄┄┄┄┄┄┄┄┐ ┆ ┆
v ┆ v v v v v
┌─────┴───────────┐┆ ┌─────┴─────┐ ┌───────┴────┐ ┌─────┴─────┐ ┌───────┴───┐ ┌─────┴─────┐
│ m0d000001 │┆ │ m10000001 │ │ m0e000001 │ │ m07000001 │ │ m09000002 │ │ m02000001 │
│ networkProfiler │┆ │ sniffer │ │ seconddate │ │ cnc │ │ tunnel │ │ file │
└─────────────────┘┆ └───────────┘ └────────────┘ └───────────┘ └───────────┘ └─────┬─────┘
┆ ┆
│ m12000000 │
│ tadaqueous │
General notes
- It is quickly apparent that BLATSTING is meant to run inside the Linux kernel. Various
referenced symbol such as `skb_linearize` point in this direction.
- All addresses within modules mentioned in this document are of the form 0x08xxxxxx, where xxxxxx is the
literal offset within the ELF part of the .impmod file. This is the same offset that Radare2 shows.
All interfaces are represented by a function call table (a list of pointers to .text segment,
prefixed with the interface ID and the module ID).
|modid | name | imports (requires) | exports |
|m00000003| core | | i00000003 |
|m01010001| crypto | i00000003 | i01010000 |
|m01020000| crypto_rsa | i00000003 | i01020000 |
|m0c010001| bpf | i00000003 | i0c010000 |
|m03010000| network | i00000003 | i03010001 i11000000 |
|m05000003| install | i00000003 | i05000000 |
|m08010001| hash | i00000003 | i08010000 |
|m0e000001| seconddate | i00000003 i03010001 | |
|m02000001| file | i00000003 i05000000 | i02000000 i04000000 |
|m0d000001| networkProfiler | i00000003 i03010001 i05000000 i0c010000 | i0d000000 |
|m09000002| tunnel | i00000003 i03010001 i05000000 | i09000000 |
|m10000001| sniffer | i00000003 i03010001 i05000000 i0c010000 | i10000000 |
|m07000001| cnc | i00000003 i03010001 | i07000000 |
|m12000000| tadaqueous | i00000003 i01010000 i01020000 i04000000 | |
- `the_interface` is a pointer to the main interface of the modules to the outside world. It is part of the `core`
module, and points to a table of function pointers (and sometimes data fields). Modules register their own
interface(s) using `call *(*the_interface+0x40)`. Other modules (which depend on this interface) can then request this
interface and use it.
A note on interface and module naming
Module and interface IDs, although conceptually in a different namespace, use the same kind of 32-bit "names".
In the module filenames these are represented as 8-byte hexadecimal strings. Internally they are handled in the
following way:
0 1 2 3 byte
│A │B │ C │
A uint8 mod_type
B uint8 intra_mod_type
C uint16 version
The consequence of this is that the last two bytes will appear swapped in memory. E.g. for mod_crypto:
m01010001 Module ID filename
0x01 0x01 0x01 0x00 Appears like this in memory (little endian)
0x00010101 The above interpreted as uint32
To distinguish module IDs and interface IDs separate the convention mXXXXXXXX for module IDs and
iXXXXXXXX for interface IDs is used.
0xff or 0xffff in one or more of the three fields is used as a wildcard when requesting interfaces.
Kernel injection
There is an executable `./Firewall/BLATSTING/BLATSTING_20322/sei/cored`, which is the loader for BLATSTING (although an
older version than the one analyzed here). It is the only file, apart from the `core` module which contains the
mysterious symbol `UYO8_U7c5D`. It also contains the symbol `UWV1S` in obfuscated form, also
referenced in other modules.
╔════════════════╗ ╔════════════════╗
║ kernel ║ ║ cored ║
╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢ ╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢
║ ║ ║ ║
║ Symbol table ───────────> Symbols hash ║
║ ║ ║ table ║
║ ║ ║ ║
║ Syscall table <───────── Hook syscall ║
║ ^ ║ ║ 137 ║
║ │ ║ ║ ║
║ v ║ ║ ║
║ Injected <──────────── .data ║
║ code ║ ║ ║
╚════════════════╝ ╚════════════════╝
The executable `./Firewall/BLATSTING/BLATSTING_20322/sei/cored` performs Linux kernel injection,
and appears to host the other modules.
Some notes on what it does:
- Uses `setrlimit` system call with `RLIMIT_CORE` to prevent dumping core files (avoid leaving evidence). Exit if this fails.
- Swap is disabled later on with the sys_swapoff system call. Possibly for a similar reason.
- Get the kernel version (`/proc/version` as well as `/proc/sys/kernel/version`). Pad up to 256 bytes and compute SHA1 hash
(what is this used for?). Exit if this fails.
- Looks in `/data/.tos_cores/` for `b%03x%03x.%03x` and `bs%03x%03x.%03x` files, where
the %...x is prinf syntax. These appear to be modules and data files respectively.
- First, a configuration file is read, bse226a3.f24. This directs it to open other
modules and load them in to memory.
- If opening the configuration file fails it tries to look inside the executable itself
for information and modules.
- The SHA1 hash computed earier of /proc/version || /proc/sys/kernel/version is compared against
a predefined set of hashes:
Each of these is associated with a two parameter words that are used later in the injection process.
The set of hashes, as well as a 663-byte configuration area is read from the end of the executable.
Likely there exists an off-line configuration utility to prepare the executable for a certain target
kernel and environment.
- See also `BLATSTING_20040/utils/procversionhashmaker`, an utility described as
"Get the hash bpinsmod uses during implant load."
- One of these parameters is the kernel-space base address.
If none of them matches the proces exits (with return code 26).
- It finds `Kernel code` and `Kernel data` in `/proc/iomem`.
- Then mmaps `/dev/mem` directly. It maps the range encompassing kernel code and kernel data.
Note that this trick to gain access to kernel space is no longer possible in kernels newer
than about 2009 (see at least if NONPROMISC_DEVMEM,
nowadays called CONFIG_STRICT_DEVMEM is enabled. All distributions enable this on x86, that I know of.
This points at the age of this software. Newer loaders may exist that use an alternative mechanism.
- Looks for symbol `__tos_kmalloc` in the kernel. This is not a stock kernel symbol. I suspect
it is specific to TopSec/TOS? There are no Google hits on this symbol at all.
- Without finding this symbol, or finding the rest of the symbol table, the program exits with code 4.
- Creates a hash table of kernel symbols.
- Looks for various symbols in the kernel, mostly associated with memory management.
- It seems to hook a syscall interface at some point, and communicate through syscall 137
(`sys_afs_syscall`/`sys_ni_syscall`, a reserved value).
- There is a minimal ELF-loader, which is used to load and relocate the modules. After loading
the modules, along with initialization data, are copied to kernel memory, then
exported symbol `init_bp_module` is called.
Modules on the implant side usually communicate with a respective module on the lp (listening post) side.
Listening post is lingo for a server that runs the control side of the implant.
All control communication with the implant goes through the `cnc` module, which sends and receives packets through
the `network` module.
╔═══════════════════╗ ╔═══════════╗
║ implant ║ ║ lp ║
╟───────────────────╢ UDP ╟───────────╢
║ ┌──────┐ ┌─┐ ┌─┐ ║ network ║ ┌───────┐ ║
║ │impmod│<╌│c│╌│n│<╌╌╌╌╌╌╌╌╌╌╌>│ lpmod │ ║
║ └──────┘ │n│ │e│ ║ ║ └───────┘ ║
║ ┌──────┐ │c│ │t│ ║ ║ ┌───────┐ ║
║ │impmod│<╌│ │╌│ │<╌╌╌╌╌╌╌╌╌╌╌>│ lpmod │ ║
║ └──────┘ └─┘ └─┘ ║ ║ └───────┘ ║
║ ... ║ ║ ... ║
╚═══════════════════╝ ╚═══════════╝
There are two exceptions to this: `seconddate` and `tadaqueous`. These do not interface with `cnc` but with
`network` directly, and have their own protocol for command and control.
| modid | modulename | imp | lp |
| m00000003 | core | ✓ | ✓ |
| m01010000 | crypto | ✕ | ✓ |
| m01010001 | crypto | ✓ | ✕ |
| m01020000 | crypto_rsa | ✓ | ✓ |
| m02000000 | file | ✕ | ✓ |
| m02000001 | file | ✓ | ✕ |
| m03010000 | network | ✓ | ✕ |
| m03010001 | network | ✕ | ✓ |
| m04000000 | process | ✕ | ✓ |
| m05000000 | install | ✕ | ✓ |
| m05000003 | install | ✓ | ✕ |
| m06000000 | beacon | ✕ | ✓ |
| m06000001 | beacon | ✕ | ✕ |
| m07000000 | cnc | ✕ | ✓ |
| m07000001 | cnc | ✓ | ✕ |
| m08010000 | hash | ✕ | ✓ |
| m08010001 | hash | ✓ | ✕ |
| m09000000 | tunnel | ✕ | ✓ |
| m09000002 | tunnel | ✓ | ✕ |
| m0c010000 | bpf | ✕ | ✓ |
| m0c010001 | bpf | ✓ | ✕ |
| m0d000000 | networkProfiler | ✕ | ✓ |
| m0d000001 | networkProfiler | ✓ | ✕ |
| m0e000001 | seconddate | ✓ | ✕ |
| m10000000 | sniffer | ✕ | ✓ |
| m10000001 | sniffer | ✓ | ✕ |
| m11000000 | arp | ✕ | ✓ |
| m12000000 | tadaqueous | ✓ | ✕ |
Each mXXXXXXXX directory contains one of, or both of:
- An `impmod` file which is an ELF file embedded in a special format. To be loaded at
the implant side.
- An `lpmod` file which is an ELF dynamic library loaded by a 'listening post' backend, which is
the command-and-control side of things. These communicate with the associated module
at the implant side.
## IMPlant MODules
- These are loaded into the kernel, but are not Linux kernel modules themselves. A custom loader is used. They lack
the information and symbols normally associated with Linux kernel modules.
- The format describes the module ID, as well as the interfaces exported and imported by the module.
The latter determine the dependency relationships between modules. All modules depend on `core`,
which has module ID `m00000003` and exports the core interface `i00000003`.
- Symbols:
- `the_interface`: The core interface (`i00000003`) - only exported by core module
- `UWV1S`/`UVW1S`: Unknown - exported by `cored`, used by the install module. The
name of these symbols is chosen somewhat clever: designed to not stand out in hexdumps/
strings, as they look like the typical x86 "push ebp..." function prelude. However adding the '1'
character makes it invalid as instructions and unique and easy to grep for.
- `UYO8_U7c5D`: OS information/parameters structure - exported by `cored`
- `init_bp_module`: Initialization function - exported by every module
- `cleanup_bp_module`: Deinitialization function - exported by every module
- `cleanup_core_module`: Deinitialization function - exported by core module
- One module, `tadaqueous`, has two ELF files embedded. The first one
is a module as normal, the other is an executable.
Missing modules?
For the following known modules there is no impmod in the dump:
- m06000001 beacon (FEINTCLOUD)
- m11000000 arp (no separate impmod, but the interface is exported by 'network' module)
- ????????? testing
- m04000000 process (no separate impmod, but the interface is exported by 'file' module)
- ????????? syscall
- ????????? persist
What do the modules do?
m00000003 core
Exposes functionality to interface with the kernel and host process, register
and unregister interfaces, do memory allocation and de-allocation, and hook kernel
- Besides initializing internal data structures it creates a kernel thread on initialization.
- This thread looks through task structures, and find the task structure for process 1 (init).
- Then it reparents to init.
- It does a few modifications in the thread's task_struct, based on that of init.
I suspect this is to hide the rootkit, but lack of the kernel attacked makes it hard to
interpret what is being done.
- The thread then goes into a loop.
- On module cleanup the thread is stopped. This rootkit does attempt to neatly clean up after itself.
m01010001 crypto
Symmetric cryptography functions. This module implements RC6 in Output Feedback (OFB) mode,
with 128-bit blocksize and 20 rounds:
- Various hints in the dump point at this being a favorite of EQGRP
- The encryption and decryption routines are the same.
- The constants 0xb7e15163 and 0x61c88647 are used in the same way as described in chapter 16 of However, this is supposedly false alarm
according to
- I verified the results of encrypting using this module against radare's RC6 implementation, and it matches.
m01020000 crypto_rsa
RSA cryptography functions. See .
m0c010001 bpf
Berkeley Packet Filter functionality. BPFs are programs for a simple
virtual machine that can inspect(among other things) network packets,
and accept or reject them.
Expressions in network sniffers such as pcap are often compiled to this
representation (in fact, pcap is being used as compiler at the lp side).
See also:
It looks like this module implements a dialect of BPF, not the same
BPF as used in the Linux kernel. Instructions are still 8 bytes and have the
same global format, however while trying to decompile the predefined filters
there are 4xxx instructions that are different from normal BPF instructions:
4027 OUTB Write byte to output buffer at offset k
402f OUTH Write half-word to output buffer at offset k
4037 OUTW Write word to output buffer at offset k
Also a BPF_MODE is added
BPF_CNT = 0xc0 # LD/LDX only: Read counter k
These have to do with the goal bpf is used for in `networkProfiler`, which
extracts information from packets instead of filtering them. A quick look at the
function responsible for evaluating bpf programs (0x08000034) shows that there
are more 4xxx and 2xxx extension instructions than these.
m03010000 network
Network functionality. Exposes two interfaces. One is `network` (i03010001), which is used by
other modules to access the network, the other is `arp` (i11000000) which does not offer any functionality
to modules, but can be controlled remotely.
- Hooks kernel function `netif_rx` at initialization to intercept all incoming network traffic,
and unhooks it at cleanup. All network packets dispatched in the Linux kernel go through this function,
so hooking it is the operating system equivalent of a Room 641A within your kernel.
- Tries to request the bpf interface at initialization, but this is not a hard dependency.
m05000003 install
m08010001 hash
Apparent from some of the constants in the code (0x5a827999, 0xca62c1d6) this implements
the SHA1 hashing algorithm. It does, but with a twist that it only gives the correct output
when input size is congruent to 0 mod 4. See below under "Trivia".
This is the only hash algorithm implemented. The equivalent module in BUZZDIRECTION happens to
also implement SHA256.
Note that there are no consumers that require interface i08010000. The cnc module tries to aquire
it but it won't fail if it can't.
m0e000001 seconddate
This is by far the most interesting, also the largest binary.
- SECONDDATE is an exploitation technique that takes advantage of web-based protocols and man-in-the-middle (MitM)
- SECONDDATE influences real-time communications between client and server and can quietly redirect web-browsers to
FOXACID servers for individual client exploitation.
- This allows mass exploitation potential for clients passing through network choke points, but is configurable to
provide surgical target selection as well.
From: (third slide).
See for a
few data structures that are likely used in communication with this module. Like tadaqueous, it does not implement a
normal endpoint for BLATSTING cnc.
A complete regexp-compiling and matching engine is embedded in in this module (apparently PCRE). This is used to look
for the famous string 'ace02468bdf13579' (,
match HTTP in TCP streams '^GET.*(?:/ |\\.(?:htm|asp|php)).*\\r\\n\x00', as well as look for user-defined patterns.
SECONDDATE is not controlled through BLATSTING's C&C mechanism but has it's own command-and-control system. In the
EQGRP-free dump there are separate executables for the LP side. More about SD's C&C protocol can be found here: .
m02000001 file
Exports two interfaces: `file` (i02000000) provides file operations, `process`
(i04000000) provides process control operations.
File operations:
- Hide a file
- Unhide a file
- Read a file from the target
- Write a file to the target
Process operations:
- List hidden process IDs
- Execute a process
m0d000001 networkProfiler
Execute predefined or custom (passive) scans based on BPF rules, collect statistics.
See e.g. `Firewall/BLATSTING/BLATSTING_201381/LP/lpconfig/m0d000000/predefinedScans`. These files contain a description
of the filter, and a compiled BPF program in binary form.
networkProfiler acts like a network sniffer, but instead of storing every packet it creates statistics based on
information extracted from each packet, such as source and destination IP. This is fully programmable.
How this works is that basic BPF opcode set is extended with opcodes to write to an output buffer. Part of this output
buffer is used as key into a hash table, the other part consists of the value, usually counters (counting packets,
bytes, etc). Statistics "records" are thus accumulated per key. This is similar to what e.g. the `iptraf` utility for
Linux does (, except more stealthy.
The LP module allows setting the following command line:
-S/--scantype <scan name> name of predefined scan (enter ? to be provided with a list)
-i/--interface <interface index (as from interface listing)> limit to the specified interface
-t/--traffictypes <traffic queue flags> receive traffic of the specified types only (enter ? to be provided with a list)
-P/--prefilter netmask <netmask length> netmask length for prefilter (0-32, default 0)
-p/--prefilter <pcap filter string> pcap pre-filter definition (enclose this in double quotes)
-s/--duration_seconds <seconds> test duration in seconds
-m/--duration_minutes <minutes> test duration in minutes
-r/--duration_hours <hours> test duration in hours
-y/--duration_days <days> test duration in days
-N/--nperiods <# of scan periods> number of periods to scan (default: 1)
-n/--maxNRecords <# of records> maximum number of records to keep per period
--hashTableSize <# of entries> size of the hash table
-h/--help print this usage message
See also .
m09000002 tunnel
NAT tunneling, packet forwarding and redirection. Likely, this is used to reach
targets behind the router.
The LP module allows setting the following command line:
You will be asked to enter both IP addresses and port numbers for
the outside source and destination and the inside source and destination.
Please enter all parameters as if for a packet which is traveling towards
the inside network.
outside source, dest <-tunnel-> inside source, dest
IP addresses are entered in the form #.#.#.#/<netmask>.
Please enter your tunnel command line (-h for help, CTRL-n to cancel)? -h
-S/--outsidesrc <#.#.#.#/#> outside source IP address
-D/--outsidedst <#.#.#.#/#> outside destination IP address
-s/--insidesrc <#.#.#.#/#> inside source IP address
-d/--insidedst <#.#.#.#/#> inside destination IP address
-P/--outsidesrcport0 <port> outside source port 0
--outsidesrcport1 <port> outside source port 1
--outsidesrcport2 <port> outside source port 2
--outsidesrcport3 <port> outside source port 3
-Q/--outsidedstport0 <port> outside destination port 0
--outsidedstport1 <port> outside destination port 1
--outsidedstport2 <port> outside destination port 2
--outsidedstport3 <port> outside destination port 3
-p/--insidesrcport0 <port> inside source port 0
--insidesrcport1 <port> inside source port 1
--insidesrcport2 <port> inside source port 2
--insidesrcport3 <port> inside source port 3
-q/--insidedstport0 <port> inside destination port 0
--insidedstport1 <port> inside destination port 1
--insidedstport2 <port> inside destination port 2
--insidedstport3 <port> inside destination port 3
-N/--nat this is a NAT tunnel
--hopcount <integer> amount to decrement the hop count by on each pass (default: 2)
-l/--lifetime <seconds> tunnel lifetime (default: tunnel is immortal (0))
-t/--timeout <seconds> active connection timeout (default: 30 seconds)
--nochecksum transport checksum correction off
-y/--priority <priority> priority (default: calculated)
-b/--blackhole blackhole (packet-eating tunnel) [expert only]
-h/--help print this usage message
m10000001 sniffer
Sniff network traffic.
This can capture whole packets or certain segments of them. Uses BPF to pre-filter.
Due to limited space on the device this either uses a ring buffer, which needs
to be periodically polled by the lp to make sure that everything is captured, or
a fixed-size buffer after which the capture will stop.
The LP module allows setting the following command line:
-i/--interface <interface index from interface listing> limit to the specified interface
-t/--traffictypes <traffic queue flags> receive traffic of the specified types only (enter ? to be provided with a list)
-P/--prefilter netmask <netmask length> netmask length for prefilter (0-32, default 0)
-p/--prefilter <pcap filter string> pcap pre-filter definition (enclose this in double quotes)
-c/--capturecap <max no. packets> maximum number of packets to capture
-b/--bufferlen <buffer length> size of buffer for storing captured packets (in bytes)
-s/--snapseg <snapseg> spans of bytes to capture from each packet of the form start-end,start-end up to 8 segments (an end of 0 means to end of packet)
-r/--ring set to use a ring buffer, which will overwrite old captured packets
-R/--noring set to NOT use a ring buffer, capturing will stop when the buffer is full
-H/--printheaders print out the IP and TCP header formats
-h/--help print this usage message
m07000001 cnc
Command-and-control functions. Receives UDPv4 packets from the network module,
if they have the right size and checksum, dispatches them internally.
See for more
Every interface can have a method to process `BF_5i_CALL` RPC requests from the LP.
This is always the function at `ifptr + 0x10`. If not defined it can either be 0
or return an error code. Most interfaces do have some calls to support remote
control, except base utilities such as `bpf`, `crypto` `hash` and modules that have
their own C&C such as `tadaqueous` and `seconddate`.
m12000000 tadaqueous
The non-conventional name seems to apply this is another internal project such as SECONDDATE.
And it is: . My analysis shows that this module
is used for selective IPsec weakening, as well as for disabling the generation of random numbers
within the kernel.
> If you are putting up tadaqueous, there will be lp error due to a missing files, there is no LP for this module.
- quote from Firewall/SCRIPTS/EGBL_AND_BLATSTING.txt (there is, indeed, no lpmod for TADAQUEOUS in the dump)
Different from the other impmods, this still contains the .comment section, which reveals that the module
is compiled with "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)".
Kernel interface
After injection into the kernel a spare syscall, number 137 (0x89), is hooked to provide an
interface from user space to specific kernel functionality.
Register ebx seems to be used to communicate a sub-function, which is one of.
0x9d3d143a kernel_alloc(size,flags)
0x384713aa copy_to_kernel(kaddr,uaddr,size)
0x93b4e2d2 (unk)
0xe53c2e96 (unk)
0xfd13acf3 kernel_free(addr)
Other trivia
- Various strings in the `cored` executable are obfuscated using a simple substitution
cipher. It makes use of multiplication mod 256, which is a clever little trick
I've not seen before for obfuscation. For example: multiply with 29 to decrypt then
multiply with its multiplicative inverse mod 256, 53, to encrypt again.
- The "SHA1" function in `cored` (0x0804ae38) is actually a variant of SHA1. This does cause
the output hashes to be completely different. Not sure if they botched this or this is a subtle
change on purpose:
- Instead of adding 0x80 at the end of the input then padding with zeros, this function
processes the input in 4-byte words, and adds 0x80000000 (little-endian) at the end of the
input, then pads with zeros. This is before the endian-swap at the beginning of the transform
(necessary on little-endian architectures), so for example the buffer for 'test' will end up looking:
74 65 73 74 00 00 00 80 <zeros> 00 00 00 00 20 00 00 00
Whereas it would normally be:
74 65 73 74 80 ...<zeros>... 00 00 00 00 00 00 00 20
- Also note that the endian of the bit count at the end is flipped per 32-bit unit.
- Due to a bug in this padding method, only a multiple of 4 bytes can be processed without
ignoring up to three bytes of input. It looks like the function is only used to hash 256 bytes,
so this bug does not surface in practice.
- However if the `hash` module also implements this variant (it seems that way), and
this module is actually used by anything, things are different.
- The hash module implements an almost-correct SHA1. The buffer itself is built in the same
way as previously, and in the inner function all endian swapping normally required for implementing
SHA-1 on little-endian architectures is left out. But this is handled in an outer function, which
works around the problems: allocates a new buffer (padded to 4 with zeros), copies the input, endian-swapped
intothis new buffer, calls the inner function on this buffer, then frees the buffer, byte-swaps the result
and returns that digest. It's kind of circuitous, but for buffers where the size is a multiple of 4
this returns the same as 'normal' SHA1. For other sizes it return a different output due to the padding.
- BLATSTING's implementers are a big fan of mmap. It seems to be used for all file access, not just
for manipulating kernel memory through `/dev/mem`. Is it done this way to reduce the number
of system calls, to be less conspicious, as well as not reveal what exactly is accessed when
running in `strace`? Or maybe a later stage of the rootkit blocks certain kinds of syscalls
on certain "hidden" files.
- While reverse engineering I haven't found any explicit countermeasures or anti-debugging tricks.
- BLATSTING's implementers took a lot of care not to leak strings that could help with reverse engineering *at the
implant side*. This is true for `cored`, but also for the modules themselves. There are no log messages, no debug
prints, no error messages, nothing.
- The few strings that are absolutely necessary (such as symbol names) are obfuscated.
- The code was compiled with `-fomit-frame-pointers` (or similar), which makes it somewhat harder
to keep track of the stack frame while reading assembly.
- The lp (listening post) side is much more loose: debug printing, spurious symbols (internal functions,
bc no -Bsymbolic used), plenty of error messages and other text.
- The code of `cored` is a strange mix of static and dynamic linking. For example, at one point it uses
a direct `sys_open` syscall to open a file then performs `mmap` through the C library.
In the same function.
- The abbreviation `bp_` in symbols likely stands for BEECHPONY. According to this is
"BEECHPONY A firewall implant that is a predecessor of BANANAGLEE." I haven't looked at
BANANAGLEE much but to me it looks like BUZZDIRECTION is a newer version of this framework.
It wouldn't surprise me if BLATSTING was the oldest of the bunch.
- Another hint that this rootkit is older than BUZZDIRECTION can be found in the hash module:
SHA1 is the only hash algorithm implemented. The equivalent module in BUZZDIRECTION happens to
also implement SHA256.
See also:
- Looking at the core module, it indeed appears that this rootkit is ancient. The kernel thread
spawned by `init_bp_module`, `0x08001384`, relies on the pre-2.6 functionality where the beginning
of the kernel stack was the `task_struct` (nowadays it is `thread_info`, a much smaller structure).
This means the rootkit will only work on Linux 2.4. There is no way that this is a risk to modern kernels,
though some routers in active use may still be based on old kernels such as that.
- The offsets inside the `task_struct` don't match any kernel I could find, though a manually compiled
2.4.25 kernel came closer than debug symbols I found for an RHEL3 2.4.21 kernel. It looks like
this rootkit is specific to an extrememly narrow range of kernel versions.
- This does NOT have to mean that the rootkit is ancient: just that the devices it targets are. Third-world
countries usually won't have the newest equipment.
- The code is written in as platform-independent way as possible. It implements its own ELF loader, its
own BPF packet filter (even though Linux has it built-in), uses big-endian in input formats, the network
module handles its own ARP, and so on. Like a state within a state this implements an OS within an OS.
This has been continued even more strongly with BUZZDIRECTION, which has separate platform and core modules.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment