7 minute read

CISA released a joint advisory on APT Cyber Tools Targeting ICS/SCADA Devices. This particular malware is said to have capabilities which can specifically target ICS/SCADA devices and cause major damage on target. The malware is modular in architecture and targets below mentioned products through use of ICS protocols.

  • Schneider Electric MODICON and MODICON Nano PLCs, including (but may not be limited to) TM251, TM241, M258, M238, LMC058, and LMC078
  • OMRON Sysmac NJ and NX PLCs, including (but may not be limited to) NEX NX1P2, NXSL3300, NX-ECC203, NJ501-1300, S8VK, and R88D-1SN10F-ECT
  • OPC Unified Architecture (OPC UA) servers.

The malware uses Modbus protocol to communicate with the PLC. The attack surface is not only limited to above mentioned devices. It can interact with a wide variety of ICS devices from various vendors. Below are detailed analysis write-ups from Dragos & Mandiant.

  • https://hub.dragos.com/hubfs/116-Whitepapers/Dragos_ChernoviteWP_v2b.pdf
  • https://www.mandiant.com/resources/incontroller-state-sponsored-ics-tool

As, the sample was available I tried to perform static analysis of INCONTROLLER/PIPEDREAM malware. For the analysis I used a very nice distro called REMnux. It is loaded with lots of malware analysis tools by default. Let’s dive into the analysis part.

Static Analysis

We will start with the most basic utility to identify the type of file we are looking at. We can use file command for it.

$ file incontroller 

File Command

As we see it is PE32+ Windows executable based on x86_64 arch. Now we can try another basic command strings to view all the ASCII strings in the sample.

$ strings incontroller

Strings command

We can see some API calls from Bcrypt library which might be used for encryption purpose somewhere in the malware. Now I used a tool called signsrch to search for any cryptographic signatures in the sample.

$ signsrch incontroller

Signsrch

As we can see it found three signatures, one is anti-debug where malware check if debugger is present then it will try not to run which can slow down analysis of malware. Second was Windows CryptDecrypt and SSH RSA. It didn’t detected Bcrypt at all.

Next, I tried running ClamAV to find any known malicious signature based detection.

$ clamscan incontroller
💡 Update ClamAV definitions before running above command 💡

ClamAV

ClamAV had no detections. Next, I tried running Yara Rules to find any malicious behaviour in the sample.

$ yara-rules incontroller 

Yara Rules

It came back with many useful matches like, the sample has Anti-Debug mechanisms in place. It writes to Windows Registry. It contains some Debug data and other useful information. Again, this is static analysis so there can be False Positives as well.

Next, I used PE-Tree a very nice GUI tool to check PE headers in the sample.

$ pe-tree incontroller

PE Tree

We can see the PDB path inside the headers.

"C:\Users\User1\Desktop\dev projects\SignSploit1\x64\Release\AsrDrv_exploit.pdb"

As found by Mandiant and Dragos team as well. The AsRock Motherboard exploit is being used by APT to gain access and inject code in Windows kernel for further lateral movement. The specific exploit used is CVE-2020-15368

Next, I used a tool called FLOSS by Mandiant which finds obfuscated strings from the binary.

$ floss --no-static-strings incontroller

Copyright (C) 2012 ASRock Incorporation
OriginalFilename
AsrDrv.sys
ProductName
ASRock IO Driver
ProductVersion
1.00.00.0000
VarFileInfo
Translation
<<<Obsolete>>
CrossC

WARNING:envi:i386RegOper needs to implement getOperAddr!
WARNING:vivisect.base:_cb_opcode(0x140002f6b): LOCATION ALREADY EXISTS: loc: 'cccccccccc'
WARNING:vivisect.base:_cb_opcode(0x1400026ab): LOCATION ALREADY EXISTS: loc: 'cccccccccc'
WARNING:vivisect.base:_cb_opcode(0x14002c850): LOCATION ALREADY EXISTS: loc: 'BYTE: 0 (0x0)'

FLOSS decoded 2 strings
SystemRoot
#WVA

FLOSS extracted 3 stackstrings
C110DD4FE9434147B92A5A1E3FDBF29A
SystemRoot
PATH

We can see many interesting strings like AsrDrv.sys and SystemRoot etc.

Next I used a tool called Capa which is from Mandiant. This tool helps in identification of capabilities of the binary.

capa -vv incontroller

check for time delay via GetTickCount
namespace  anti-analysis/anti-debugging/debugger-detection
author     michael.hunhoff@fireeye.com
scope      function
mbc        Anti-Behavioral Analysis::Debugger Detection::Timing/Delay Check GetTickCount [B0001.032]
examples   Practical Malware Analysis Lab 16-03.exe_:0x4013d0
function @ 0x140002140
  and:
    count(api(kernel32.GetTickCount)): 2 or more @ 0x1400021B6, 0x1400023E7

encrypt or decrypt data via BCrypt
namespace  data-manipulation/encryption
author     michael.hunhoff@fireeye.com
scope      function
att&ck     Defense Evasion::Obfuscated Files or Information [T1027]
mbc        Cryptography::Decrypt Data [C0031], Cryptography::Encrypt Data [C0027]
function @ 0x140001B40
  and:
    or:
      api: BCryptEncrypt @ 0x140001CE9
    optional:
      api: BCryptOpenAlgorithmProvider @ 0x140001B8C
      api: BCryptCloseAlgorithmProvider @ 0x140001DCD
      api: BCryptGenerateSymmetricKey @ 0x140001C40
      api: BCryptDestroyKey @ 0x140001D7F

debug build
namespace  executable/pe/debug
author     william.ballenthin@fireeye.com
scope      file
or:
  string: "Assertion failed!" @ 0x513C8, 0x51A48

contains PDB path
namespace  executable/pe/pdb
author     moritz.raabe@fireeye.com
scope      file
examples   464EF2CA59782CE697BC329713698CCC
regex: /:\\.*\.pdb/
  - "C:\\Users\\User1\\Desktop\\dev projects\\SignSploit1\\x64\\Release\\AsrDrv_exploit.pdb" @ 0x5C284
  - "c:\\asrock\\work\\asrocksdk_v0.0.69\\asrrw\\src\\driver\\src\\objfre_win7_amd64\\amd64\\AsrDrv103.pdb" @ 0x62C98

contain a resource (.rsrc) section
namespace  executable/pe/section/rsrc
author     moritz.raabe@fireeye.com
scope      file
examples   A933A1A402775CFA94B6BEE0963F4B46:0x41fd25
section: .rsrc @ 0x140071000

contain an embedded PE file
namespace  executable/subfile/pe
author     moritz.raabe@fireeye.com
scope      file
mbc        Execution::Install Additional Program [B0023]
examples   Practical Malware Analysis Lab 01-04.exe_:0x4060
or:
  count(characteristic(embedded pe)): 1 or more @ 0x60010

get file size
namespace  host-interaction/file-system/meta
author     michael.hunhoff@fireeye.com
scope      function
att&ck     Discovery::File and Directory Discovery [T1083]
examples   mimikatz.exe_:0x40630D
function @ 0x140001060
  or:
    api: kernel32.GetFileSize @ 0x140001109

read file
namespace  host-interaction/file-system/read
author     moritz.raabe@fireeye.com
scope      function
mbc        File System::Read File [C0051]
examples   BFB9B5391A13D0AFD787E87AB90F14F5:0x1314567B
function @ 0x140001060
  or:
    and:
      or:
        api: kernel32.ReadFile @ 0x140001135

write file
namespace  host-interaction/file-system/write
author     william.ballenthin@fireeye.com
scope      function
mbc        File System::Writes File [C0052]
examples   Practical Malware Analysis Lab 01-04.exe_:0x4011FC, 563653399B82CD443F120ECEFF836EA3678D4CF11D9B351BB737573C2D856299:0x1400025C4
function @ 0x140001060
  and:
    or:
      api: fwrite @ 0x140001179

print debug messages
namespace  host-interaction/log/debug/write-event
author     michael.hunhoff@fireeye.com
scope      function
examples   493167E85E45363D09495D0841C30648:0x401000
function @ 0x14002B260
  or:
    api: kernel32.OutputDebugString @ 0x14002B271

create or open registry key
namespace  host-interaction/registry
author     michael.hunhoff@fireeye.com
scope      basic block
mbc        Operating System::Registry::Create Registry Key [C0036.004], Operating System::Registry::Open Registry Key [C0036.003]
examples   Practical Malware Analysis Lab 03-02.dll_:0x10004706, Practical Malware Analysis Lab 11-01.exe_:0x401000, 493167E85E45363D09495D0841C30648:0x404D60, B5F85C26D7AA5A1FB4AF5821B6B5AB9B:0x4045F2, B5F85C26D7AA5A1FB4AF5821B6B5AB9B:0x40433E
basic block @ 0x140002730
  or:
    api: advapi32.RegOpenKeyEx @ 0x1400027C0

query or enumerate registry value
namespace  host-interaction/registry
author     william.ballenthin@fireeye.com, michael.hunhoff@fireeye.com
scope      function
att&ck     Discovery::Query Registry [T1012]
mbc        Operating System::Registry::Query Registry Value [C0036.006]
examples   BFB9B5391A13D0AFD787E87AB90F14F5:0x13145B5A, Practical Malware Analysis Lab 03-02.dll_:0x100047AD
function @ 0x140002730
  and:
    optional:
      match: create or open registry key @ 0x140002730
        or:
          api: advapi32.RegOpenKeyEx @ 0x1400027C0
    or:
      api: advapi32.RegQueryValueEx @ 0x14000283C

create service
namespace  host-interaction/service/create
author     moritz.raabe@fireeye.com
scope      function
att&ck     Persistence::Create or Modify System Process::Windows Service [T1543.003], Execution::System Services::Service Execution [T1569.002]
examples   Practical Malware Analysis Lab 03-02.dll_:0x10004706
function @ 0x140001060
  and:
    api: advapi32.CreateService @ 0x1400011ED
    optional:
      api: advapi32.OpenSCManager @ 0x14000118E

start service
namespace  host-interaction/service/start
author     moritz.raabe@fireeye.com
scope      function
att&ck     Persistence::Create or Modify System Process::Windows Service [T1543.003]
examples   E544A4D616B60147D9774B48C2B65EF2:0x401FA0
function @ 0x140001060
  and:
    optional:
      match: get service handle @ 0x140001060
        or:
          api: advapi32.CreateService @ 0x1400011ED
          api: advapi32.OpenService @ 0x14000120B
    api: advapi32.StartService @ 0x140001244

link function at runtime
namespace  linking/runtime-linking
author     moritz.raabe@fireeye.com
scope      function
att&ck     Execution::Shared Modules [T1129]
examples   9324D1A8AE37A36AE560C37448C9705A:0x404130, Practical Malware Analysis Lab 01-04.exe_:0x401350
function @ 0x140001000
  and:
    or:
      api: kernel32.GetModuleHandle @ 0x14000100B
    or:
      api: kernel32.GetProcAddress @ 0x14000101B

We can see the malware is using GetTicketCount() to measure the time delay from CPU to find if any debugger is attached for analysis. It is one of the standard anti-analysis techniques.

Next, I used a tool called RetDec from Avast which is a decompiler that support PE and ELF file formats. It is available in the form of docker image in REMnux.

$ docker run -it --rm -v <files_directory>:/tmp/files remnux/retdec bash 

Once the sample file in available inside the container the decompiler command is like.

$ retdec-decomplier.py incontroller

The output will contain incontroller.c file which can be analysed further manually. The C file is little human readable code.

 if (v7 == 0) {
        goto lab_0x14000151a;
    } else {
        int64_t * hFile = (int64_t *)(int64_t)v7; // 0x140001109
        uint32_t v15 = GetFileSize(hFile, NULL); // 0x140001109
        function_140001630(&v3, (int64_t)v15);
        int32_t lpNumberOfBytesRead = 0; // bp-1360, 0x14000111b
        ReadFile(hFile, NULL, 0, &lpNumberOfBytesRead, NULL);
        CloseHandle(hFile);
        int64_t file = function_140017870((int64_t)"C:\\AsRockDrv.sys", "wb"); // 0x140001155
        v8 = (int64_t)"wb";
        v9 = 0;
        v13 = &lpNumberOfBytesRead;
        v10 = (int64_t)"cant drop and load exploatable driver ! \n";
        if (file == 0) {
            goto lab_0x14000151a;
        } else {
            // 0x140001166
            function_140018290(&g77, 0x8708, 1, file);
            fclose((struct _IO_FILE *)file);
            hSCManager = OpenSCManagerW(NULL, NULL, 2);
            v8 = 0;
            v9 = 2;
            v13 = file;
            v10 = (int64_t)"cant drop and load exploatable driver ! \n";
            if (hSCManager == NULL) {
                goto lab_0x14000151a;
            } else {
                int64_t * v16 = CreateServiceA(hSCManager, "AsRockDrv", "AsRockDrv", 0xf01ff, 1, 2, 1, "C:\\AsRockDrv.sys", NULL, NULL, NULL, NULL, NULL); // 0x1400011ed
                hService = v16;
                v12 = (int64_t)"AsRockDrv";
                if (v16 != NULL) {
                    goto lab_0x14000122e;
                } else {
                    // 0x1400011fb
                    hService = OpenServiceA(hSCManager, "AsRockDrv", 0xf01ff);
                    hSCObject = hSCManager;
                    v14 = (int64_t)"AsRockDrv";
                    v11 = 0xf01ff;
                    v12 = 0xf01ff;
                    if (hService != NULL) {
                        goto lab_0x14000122e;
                    } else {
                        goto lab_0x14000121c;
                    }
                }
            }
        }
    }
  

Above is a snippet from the C file. We can read and understand the code where the malware tries to drop the AsRock exploit.

Final Notes

This was my quick static analysis for INCONTROLLER malware. The malware is modular in nature and targets OT environment specifically. It uses ICS protocols such as Modbus, OPC UA servers to implant the packets on the equipment which can persist on them for a long time and can cause major outage in operations. The APT group has made it modular so that it could have more modules in future for other protocols/OEM’s It is best of interest for anyone using this equipments to apply the countermeasures suggested by CISA in their report. Also, for detecting activity from this malware the Yara Rule shared in Mandiant’s blog can be useful.

Below are some other analysis reports I referred while writing this blogpost. Thanks, until next time Happy Hacking 🙂 🏭

Other Analysis Reports

Leave a comment