Mirai_ptea Botnet is Exploiting Undisclosed KGUARD DVR Vulnerability
Overview
On 2021-06-22 we detected a sample of a mirai variant that we named mirai_ptea
propagating through a new vulnerability targeting KGUARD DVR. Coincidently, a day later, on June 23, we received an inquiry from the security community asking if we had seen a new DDoS botnet, cross-referencing some data, it was exactly this botnet that we had just discovered.
Timeline
- 2021-03-22 Our historical data indicates the first probe against this vulnerability
- 2021-06-22 We observed the
mirai_ptea
sample exploiting this vulnerability to spread - 2021-06-23 We got a tip from the security community that this botnet was being used for ongoing DDoS attacks.
- 2021-06-25
mirai_aurora
, another mirai variant, starts to use this vulnerability to propagate
Vulnerability analysis
Given that we have not found public information on this vulnerability, we will hide some of the key information here to prevent the vulnerability from being further abused.
One program on the KGUARD DVR firmware listens on port *****
at 0.0.0.0
to remotely execute system commands without authentication. The firmware released after 2017 seems to have this fixed by modifying the listening address to 127.0.0.1
. Some of the exploited payloads are as follows.
Analysis of affected devices
We have discovered at least 3,000 or so online devices still have the vulnerability. The affected devices are as follows:
DeviceType | ProductType | HardVersion | DefDeviceName |
---|---|---|---|
D1004NR | DVR4-1600 | DM-268A | DVR4-1600 |
D1004NR | HY-DVR | DM-268 | 720P-HY04N |
D1004NR | HY-DVR | DM-268A | 720P-HY04N |
D1004NR | HY-DVR | DM-274 | 720P-HY04N |
D1004NR | HY-DVR | DM-274B | 720P-HY04N |
D1004NR | NHDR | DM-274 | NHDR-3204AHD |
D1004NR | RL-AHD4n | DM-268 | 720P-HY04N |
D1008NR | 1093/508N-DVRBM08H | DM-292 | 720P-HY08N |
D1008NR | DVR8-1600 | DM-298 | DVR8-1600 |
D1008NR | DVR8-HDA10L | DM-292 | DVR8-HDA10L |
D1008NR | HD881 | DM-292 | HD881 |
D1008NR | HY-DVR | DM-292 | 720P-HY08N |
D1008NR | HY-DVR | DM-298 | 720P-HY08N |
D1008NR | NHDR | DM-298 | NHDR-3208AHD |
D1008NR | RL-AHD8n | DM-292 | 720P-HY08N |
D1016NR | DVR16-HDA10L | DM-303 | DVR16-HDA10L |
D1016NR | HD1681 | DM-303 | HD1681 |
D1016NR | HY-DVR | DM-303A | 720P-HY16N |
D1016NR | HY-DVR | DM-310 | 720P-HY16N |
D1016NR | HY-DVR | DM-310A | 720P-HY16N |
D1016NR | NHDR | DM-310 | NHDR-3216AHD |
D1016NR | RL-MHD16n(21A) | DM-310A | 720P-HY16N |
D1104 | HY-DVR | DM-290A | 1080P-HY04 |
D1104 | NHDR | DM-307 | NHDR-5304AHD |
D1104NR | HD1T4 | DM-291A | 1080P-04 |
D1104NR | HD481 | DM-291 | HD481 |
D1104NR | HRD-E430L | DM-291A | HRD-E430L |
D1104NR | HY-DVR | DM-284 | 1080P-HY04N |
D1104NR | HY-DVR | DM-291 | "Panda |
D1104NR | HY-DVR | DM-291 | 1080P-HY04N |
D1104NR | HY-DVR | DM-291A | 1080P-HY04N |
D1104NR | HY-DVR | DM-291C | LRA3040N |
D1104NR | NHDR | DM-307 | NHDR-5104AHD |
D1104NR | SDR-B73303 | DM-291A | SDR-B73303 |
D1104NR | SVR9204H | DM-291A | 1080P-HY04N |
D1108NR | 1093/538P | DM-290 | 1080P-HY08N |
D1108NR | DVR8-4575 | DM-290 | DVR8-4575 |
D1108NR | DVR8-HDA10P | DM-290 | DVR8-HDA10P |
D1108NR | HRD-E830L | DM-290A | HRD-E830L |
D1108NR | HY-DVR | DM-290 | 1080P-HY08N |
D1108NR | HY-DVR | DM-290A | 1080P-HY08N |
D1108NR | HY-DVR | DM-290A | LRA3080N |
D1108NR | NHDR | DM-307 | NHDR-5108AHD |
D1108NR | RL-AHD8p | DM-290 | 1080P-HY08N |
D1108NR | SDR-B74301 | DM-290A | SDR-B74301 |
D1108NR | SDR-B74303 | DM-290A | SDR-B74303 |
D1116 | HY-DVR | DM-300 | EHR-5164 |
D1116NR | HRD-E1630L | DM-295 | HRD-E1630L |
D1116NR | HY-DVR | DM-295 | 1080P-HY16N |
D1116NR | HY-DVR | DM-295 | LRA3160N |
D1116NR | HY-DVR | DM-299 | 1080P-HY16N |
D1116NR | SDR-B75303 | DM-295 | SDR-B75303 |
D1132NR | HY-DVR | DM-300 | 1080P-HY32 |
D2116NR | SDR-B85300 | DM-300 | SDR-B85300 |
D973215U | F9-DVR32 | DM-195 | F9-DVR32 |
D9804AHD | DVR | DM-210 | 391115 |
D9804NAHD | AHD7-DVR4 | DM-239 | AHD7-DVR4 |
D9804NAHD | DVR | DM-239 | 720P-DVR04ND |
D9804NAHD | NHDR | DM-239 | NHDR-3104AHD-II |
D9808NRAHD | AHD7-DVR8 | DM-228 | AHD7-DVR8 |
D9808NRAHD | DVR | DM-228 | |
D9808NRAHD | DVR | DM-228 | 391116 |
D9808NRAHD | NHDR | DM-228 | NHDR-3108AHD-II |
D9808NRAHD | NHDR | DM-228 | NHDR3108AHDII |
D9816NAHD | DVR | DM-233 | 720P-DVR016N |
D9816NAHD | NHDR | DM-233 | NHDR3116AHDII |
D9816NRAHD | AHD7-DVR16 | DM-229 | AHD7-DVR16 |
D9816NRAHD | DVR | DM-229 | 720P-DVR016NB |
D9904 | D9904 | DM-237 | 1080P-DVR04 |
D9904 | DVR | DM-237 | 1080P-DVR04 |
D9904 | NHDR | DM-237 | NHDR-5204AHD |
D9904NR | DVR | DM-244 | 1080P-DVR04N |
D9904NR | DVR | DM-244 | BCS-VAVR0401M |
D9904NR | HY-DVR | DM-244 | CVD-AF04S |
D9904NR | N420 | DM-244 | 1080P-DVR04N |
D9904NR | NHDR | DM-244 | NHDR-5004AHD-II |
D9904NR | NHDR | DM-244 | NHDR5004AHDII |
D9908 | DVR | DM-245 | BCS-VAVR0802Q |
D9908 | NHDR | DM-245 | NHDR-5208AHD |
D9908AHD | DVR | DM-246 | 1080P-DVR08A |
D9908NR | AHD10-DVR8 | DM-237 | AHD10-DVR8 |
D9908NR | DVR | DM-237 | 1080P-DVR08N |
D9908NR | DVR | DM-237 | SVR9008ATHD/C |
D9908NR | HY-DVR | DM-237 | CVD-AF08S |
D9908NR | N820 | DM-237 | 1080P-DVR08N |
D9908NR | NHDR | DM-237 | NHDR-5008AHD-II |
D9916NR | DVR | DM-245 | 1080P-DVR016NAT;UI |
D9916NR | DVR | DM-245 | HR-31-211620;UI |
D9916NR | HY-DVR | DM-245 | CVD-AF16S |
D9916NR | NHDR | DM-245 | NHDR-5016AHD-II |
D9916NRAHD | DVR | DM-246 | 1080P-DVR016NA |
D9916NRAHD | N1620 | DM-246 | 1080P-DVR016NA |
H1104W | SNR-73200W | DM-339 | SNR-73200W |
H1106W | LHB806 | DM-291B | LHB806 |
H1106W | LHB906 | DM-291B | LHB906 |
Bot scale analysis
We are able to see a portion of the infected bots, the following is a daily active trend:
The geographic distribution of Bot source IPs is as follows, mainly concentrated in the United States, Korea and Brazi:
Sample Analysis
Let’s take a look a the the following samples
Verdict:mirai_ptea
MD5:c6ef442bc804fc5290d3617056492d4b
ELF 32-bit LSB executable, ARM, version 1, statically linked, stripped
Packer:No
Lib:uclibc
c6ef442bc804fc5290d3617056492d4b
is a variant of Mirai, which we call Mirai_ptea
based on its use of Tor Proxy to communicate with C2 and the TEA algorithm (Tiny Encryption Algorithm) to hide sensitive resource information. When ptea runs, it prints out in the Console: come at me krebs rimasuta go BRRT
.
This sample is very similar to Mirai at the host behavior level, so we will not cover it here; At the network traffic level, Tor proxy is used, with a large number of proxy nodes embedded in the sample, and Tor-C2 is encrypted. In the following section we will focus on the encryption method and communication protocol.
Encryption algorithm
Mirai_ptea
encrypts all sensitive resource information and stores it in a certain order. The string information seen when the sample is opened in IDA is shown below, with almost no readable information.
The following code snippet is from the decryption-related functions in the sample, which can be determined to use the TEA algorithm by the constants 0xC6EF3720 & 0X61C88647
.
The key is:
0xC26F6A52 0x24AA0006 0x8E1BF2C5 0x4BA51F8C
We wrote a decryption script(see appendix), through which we can obtain all the decrypted sensitive resources and their table entry information, part of the resource information is shown below.
Mirai_ptea has two ways of operation when using encrypted resources
- The traditional Mirai way: Decrypt an encrypted item, take the value, re-encrypt the decrypted item, i.e.
var_unlock-->var_get-->var_lock
. For example, the console information is taken by this method.
The value of table entry 0x11 is exactly: come at me krebs rimasuta go BRRT
.
- Mirai_ptea’s way: Decrypt multiple encrypted items, taking the value, and re-encrypt the decrypted items, i.e.
rangeVar_unlock-->var_get-->rangeVar_lock
. For example, this method is used when getting the disguised process name.
The values of the table entries 0x2c to 0x2c+10 shown below are the exact 11 pseudo-process names that can be chosen.
index 0x2c, value = /bin/sh
index 0x2d, value = telnetd
index 0x2e, value = upnpc-static
index 0x2f, value = wsdd
index 0x30, value = proftpd
index 0x31, value = mini_httpd
index 0x32, value = udevd
index 0x33, value = /sbin/udhcpc
index 0x34, value = boa
index 0x35, value = /usr/sbin/inetd
index 0x36, value = dnsmasq
Communication Protocol
An overview of the network traffic in Mirai_ptea is provided below.
The whole process can be divided into 3 steps as follows.
1: Establishing a connection with the proxy node
2: Establishing a connection with Tor C2
3: Communicate with C2 via ptea's custom protocol to receive attack commands from C2.
0x1.Establishing a connection with the proxy
The Mirai_ptea sample has two sets of proxies built into it, with table entries 0x2a and 0x2b
in the encrypted resource. When the Bot sample runs, one of the two sets of proxies is selected at random, and then one proxy node of the selected sets is connected by the following code snippet.
There are 38 proxy nodes in 0x2a
in the format of ip:port
And there are 334 proxy nodes in 0x2b
, in the format of ip
, and the port of this group of proxies is fixed at 9050
.
See the appendix for a detailed list of proxies.
0x2. Connecting to C2 via the Tor-Proxy protocol
You can see that C2 has the table entry 0xD
in the encrypted resource, and after decrypting it, get the following string.
rkz2f5u57cvs3kdt6amdku2uhly2esj7m2336dttvcygloivcgsmxjjnuickasbuatxajrovi4lvd2zjuejivzrb3vobuoezbc6z3gtu6b3r5tce.onion
Excluding the .onion
at the end of the above string and splitting it by length 16, then splicing it with the .onion
string at the end, we get the following 7 C2s.
rkz2f5u57cvs3kdt.onion
6amdku2uhly2esj7.onion
m2336dttvcygloiv.onion
cgsmxjjnuickasbu.onion
atxajrovi4lvd2zj.onion
uejivzrb3vobuoez.onion
bc6z3gtu6b3r5tce.onion
0x3. Communicate with the C2s via custom protocols for registration, heartbeat, and attack as follows
- Registration
msg parsing
----------------------------------------------------------------
3e c7 e3 1e 37 47 61 20 ----->hardcoded msg from Bot
b1 2f de ce cb 89 e1 a0 ----->cmd from C2,ask Bot to upload info
3a 31 34 b5 02 00 ----->hardcoded 6 bytes msg from Bot
b4 a3 e1 16 ----->ip of infected device
04 ----->group string length
74 65 73 74 ----->group string
79 ----->padding
- Heartbeat
msg parsing
----------------------------------------------------------------
2a 23 -----> random 2 bytes msg from Bot
2a 23 -----> random 2 bytes msg from C2
- Attack command The first 4 bytes of the attack command,
AD AF FE 7F
are fixed phantom numbers, and the rest of the attack command is similar to mirai's attack command format
00000000: AD AF FE 7F 1E 00 00 00 00 01 B9 98 42 65 20 00 ............Be .
00000010: 42 65 20 00
DDoS attack activity
This botnet has been busy launching DDoS attacks, the following figure shows some DDoS attack instructions of the botnet that we observed.
Contact us
Readers are always welcomed to reach us on twitter , or email to netlabat[at]360.cn
.
IoC
Tor-C2
bc6z3gtu6b3r5tce.onion:3742
cgsmxjjnuickasbu.onion:992
uejivzrb3vobuoez.onion:5353
rkz2f5u57cvs3kdt.onion:280
atxajrovi4lvd2zj.onion:110
6amdku2uhly2esj7.onion:513
m2336dttvcygloiv.onion:666
Sample MD5
c6ef442bc804fc5290d3617056492d4b
f849fdd79d433e2828473f258ffddaab
Downloader URL
http://193[.177.182.221/boot
Scanner IP
205.185.117.21 AS53667|FranTech_Solutions United_States|Nevada|Las_Vegas
205.185.114.55 AS53667|FranTech_Solutions United_States|Nevada|Las_Vegas
68.183.109.6 AS14061|DigitalOcean,_LLC United_States|New_York|New_York_City
67.205.163.141 AS14061|DigitalOcean,_LLC United_States|New_York|New_York_City
165.227.88.215 AS14061|DigitalOcean,_LLC United_States|New_York|New_York_City
Proxys
---------proxys at index 0x2a,count=38---------
149.202.9.7:9898
91.134.216.103:16358
84.32.188.34:1157
51.178.185.237:32
65.21.16.80:23560
149.202.9.14:19765
146.59.11.109:5089
195.189.96.61:29582
84.32.188.37:1454
51.195.209.80:26848
5.199.174.242:27931
95.179.158.147:22413
146.59.11.103:1701
185.150.117.10:29086
149.56.154.210:24709
135.148.11.151:3563
51.195.152.255:25107
45.79.193.124:7158
135.148.11.150:5560
185.150.117.41:20790
135.125.250.120:14498
172.106.70.135:692
195.189.96.60:9700
172.106.70.134:25054
149.56.154.211:21299
108.61.218.205:29240
51.178.185.236:21685
51.81.139.251:6255
51.255.237.164:963
51.81.139.249:32380
139.162.45.218:5165
65.21.16.94:28056
207.148.74.163:32389
172.104.100.78:1039
45.32.8.100:19759
141.164.46.133:2205
172.105.36.167:10843
172.105.180.239:19531
---------proxys at index 0x2b,count=334,port=9050---------
Too many, not list here, you can get them via the IDA script
Appendix(IDA Decrypt script)
# IDAPYTHON SCRIPT for md5 c6ef442bc804fc5290d3617056492d4b only.
# Tested at ida 7.0
from ctypes import *
import struct
print "-------------------decryption start------------------------"
key=[0xC26F6A52,0x24AA0006,0x8E1BF2C5,0x4BA51F8C]
def tea_dec(buf,key):
rbuf=""
fmt = '>' + str(len(buf)/4) + 'I'
tbuf= struct.unpack_from(fmt,buf)
j=0
for i in range(0,len(tbuf)/2):
v1=c_uint32(tbuf[i+j])
v2=c_uint32(tbuf[i+1+j])
sum=c_uint32(0xC6EF3720)
while(sum.value):
v2.value -= ((v1.value>>5)+key[3]) ^(v1.value+sum.value)^ ((v1.value<<4)+key[2])
v1.value -= ((v2.value>>5)+key[1]) ^(v2.value+sum.value)^ ((v2.value<<4)+key[0])
sum.value+=0x61C88647
rbuf +=struct.pack(">I",v1.value)+struct.pack(">I",v2.value)
j+=1
return rbuf
def getbuff(addr):
buf = ""
while idc.get_bytes(addr, 2) != "\x00\x00":
buf += idc.get_bytes(addr, 1)
addr += 1
return buf
# pay attention to function at 0x0000D074
a=getbuff(idc.get_wide_dword(0x00019C9C))
buf=[]
#0x19c9c-0x199f0 --> 684
for i in range(0,684,12):
offset=idc.get_wide_word(0x000199F4+i)
length=idc.get_wide_word(0x000199F4+i+2)
buf.append(a[offset:offset+length])
c2=[]
#684/12 --> 57
for i in range(57):
decbuf=tea_dec(buf[i],key)
if(".onion" in decbuf):
c2.append(decbuf)
print "index %x, value = %s" %(i,decbuf)
print "-------------------decryption end---------------"
proxya=tea_dec(buf[0x2a],key)
pacnt=struct.unpack("<H",proxya[2:4])
proxy=[]
port=[]
tmp=proxya[4:4+6*(pacnt[0])]
print "------------proxys at index 0x2A, count= %d------------" %(pacnt[0])
for i in range(0,len(tmp),6):
proxy.append(struct.unpack(">I",tmp[i:i+4])[0])
port.append(struct.unpack("<H",tmp[i+4:i+6])[0])
for i in range(pacnt[0]):
a=struct.pack(">I",proxy[i])
ip=""
for j in range(4):
ip+=str(ord(a[j]))
if j!=3:
ip+="."
print"%s:%d" %(ip,port[i])
proxyb=tea_dec(buf[0x2b],key)
pbcnt=struct.unpack("<H",proxyb[2:4])
fmt = '>' + str(pbcnt[0]) + 'I'
tmp=proxyb[4:4*(pbcnt[0]+1)]
print "------------proxys at index 0x2B, count= %d------------" %(pbcnt[0])
xxxxx=struct.unpack(fmt,tmp)
for i in xxxxx:
a=struct.pack(">I",i)
ip=""
for i in range(4):
ip+=str(ord(a[i]))
if i!=3:
ip+="."
print ip
print "-------------------------onion info--------------"
if len(c2)!=0:
for i in c2:
pos=i.find(".onion")
for j in range(0,pos,16):
print i[j:16+j]+".onion"
else:
print "Don't find the onion c2"