RotaJakiro: A long live secret backdoor with 0 VT detection
<!--kg-card-begin: markdown--><h2 id="overview">Overview</h2>
<p>On March 25, 2021,  360 NETLAB's BotMon system flagged a suspiciousELF file (MD5=64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of TLS/SSL. A close look at the sample revealed it to be a <strong>backdoor</strong> targeting Linux X64 systems, a family that has been around for <strong>at least 3 years</strong>.</p>
<p>We named it <strong>RotaJakiro</strong> based on the fact that the family uses rotate encryption and behaves differently for <code>root/non-root accounts</code> when executing.</p>
<p><code>RotaJakiro</code> pays quite some attention to hide its trails,  using multiple of encryption algorithms, including: the use of AES algorithm to encrypt the resource information within the sample; C2 communication using a combination of <code>AES, XOR, ROTATE encryption</code> and <code>ZLIB compression</code>.</p>
<p><code>RotaJakiro</code> supports a total of 12 functions, three of which are related to the execution of specific Plugins. Unfortunately, we have no visibilityto the plugins, and therefore do not know its true purpose. From a broad backdoor perspective, the functions can be grouped into the following four categories.</p>
<ul>
<li>Reporting device information</li>
<li>Stealing sensitive information</li>
<li>File/Plugin management (query, download, delete)</li>
<li>Execution of specific Plugin</li>
</ul>
<h2 id="anymoreoutthere">Any more out there?</h2>
<p>With the sample we have, we discovered the following 4 samples, all of which have 0 detections on VT, and the earliest First Seen time on VT is in 2018.</p>
<table>
<thead>
<tr>
<th>FileName</th>
<th>MD5</th>
<th>Detection</th>
<th>First Seen in VT</th>
</tr>
</thead>
<tbody>
<tr>
<td>systemd-daemon</td>
<td>1d45cd2c1283f927940c099b8fab593b</td>
<td>0/61</td>
<td>2018-05-16 04:22:59</td>
</tr>
<tr>
<td>systemd-daemon</td>
<td>11ad1e9b74b144d564825d65d7fb37d6</td>
<td>0/58</td>
<td>2018-12-25 08:02:05</td>
</tr>
<tr>
<td>systemd-daemon</td>
<td>5c0f375e92f551e8f2321b141c15c48f</td>
<td>0/56</td>
<td>2020-05-08 05:50:06</td>
</tr>
<tr>
<td>gvfsd-helper</td>
<td>64f6cfe44ba08b0babdd3904233c4857</td>
<td>0/61</td>
<td>2021-01-18 13:13:19</td>
</tr>
</tbody>
</table>
<p>These samples all have the following 4 C2s embedded. These 4 C2 domains have very close <code>Crteated,Updated and Expired</code> time, readers will notice that the crated data was in Dec 2015, 6 years ago.</p>
<table>
<thead>
<tr>
<th>Domain</th>
<th>Detection</th>
<th>Created</th>
<th>Last Updated</th>
<th>Expired</th>
</tr>
</thead>
<tbody>
<tr>
<td>news.thaprior.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:13</td>
<td>2020-12-03 07:24:33</td>
<td>2021-12-09 06:24:13</td>
</tr>
<tr>
<td>blog.eduelects.com</td>
<td>0/83</td>
<td>2015-12-10 13:12:52</td>
<td>2020-12-03 07:24:33</td>
<td>2021-12-10 13:12:52</td>
</tr>
<tr>
<td>cdn.mirror-codes.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:19</td>
<td>2020-12-03 07:24:32</td>
<td>2021-12-09 06:24:19</td>
</tr>
<tr>
<td>status.sublineover.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:24</td>
<td>2020-12-03 07:24:32</td>
<td>2021-12-09 06:24:24</td>
</tr>
</tbody>
</table>
<h2 id="reverseanalysis">Reverse Analysis</h2>
<p>The 4 RotaJakiro samples, with time distribution from 2018 to 2021, are very close to their functions, and the 2021 sample is selected for analysis in this blog, which has the following basic information:</p>
<pre><code>MD5:64f6cfe44ba08b0babdd3904233c4857
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped
Packer:No
</code></pre>
<p><code>At the coding level</code>, RotaJakiro uses techniques such as dynamic AES, double-layer encrypted communication protocols to counteract the binary &amp; network traffic analysis.<br>
<code>At the functional level</code>, RotaJakiro first determines whether the user is root or non-root at run time, with different execution policies for different accounts, then decrypts the relevant sensitive resources using AES&amp; ROTATE for subsequent <code>persistence</code>, <code>process guarding</code> and <code>single instance</code> use, and finally establishes communication with C2 and waits for the execution of commands issued by C2.</p>
<p>The following will analyze the specific implementation of RotaJakiro from the above perspective.</p>
<h2 id="0x00tricksusedbythesample">0x00: Tricks used by the sample</h2>
<ul>
<li>Dynamically generate a table of constants required by the AES encryption algorithm to prevent the algorithm from being directly identified<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_dynaes.png" width="860px"  /></li>
<li>Use stack strings obfuscation technique to store encrypted sensitive resource information<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_stack.png" width="860px"  /></li>
<li>Network communication using double layer encryption</li>
</ul>
<h2 id="0x01encryptionalgorithm">0x01: Encryption algorithm</h2>
<p>All sensitive resources in RotaJakiro are encrypted, and in IDA we can see that the decryption method <strong>dec_proc</strong> is called 60 times, which is composed of AES and Rotate.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_dec.png" width="860px"  /><br>
The AES decryption entry is as follows:<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_aes.png" width="860px"  /><br>
Where <code>aes_dec</code> is AES-256, CBC mode, key&amp;iv are hardcoded.</p>
<ul>
<li>KEY</li>
</ul>
<pre><code> 14 BA EE 23 8F 72 1A A6 00 00 00 00 00 00 00 00 
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</code></pre>
<ul>
<li>IV</li>
</ul>
<pre><code>  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</code></pre>
<p>The Rotate decryption entry is shown below:<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_rota.png" width="860px"  /><br>
The so-called Rotate is a cyclic shift, we can see that the number of shifts is determined by the value of <code>plain_len(length of plaintext) &amp;7</code>.</p>
<p>Take the following C2 cipher text as an example.</p>
<pre><code>ff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99 
ac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60
</code></pre>
<p>The various parameters related to decryption are shown below, the length of the ciphertext is 32 bytes and the length of the plaintext is 26 bytes.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_exp.png" width="860px"  /><br>
<strong>First</strong>, decrypting with AES, we get the following &quot;sub-ciphertext&quot;.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_valid.png" width="860px"  /><br>
<strong>Then</strong>, the valid ciphertext is extracted from the  sub-ciphertext, where the valid ciphertext starts from the 8th byte, and the length is the plaintext length minus 8, which is 26-8=18 bytes here.</p>
<pre><code>98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8 
DB 5B
</code></pre>
<p><strong>Finally</strong>, we can calculate 26(the length of plaintext is 26)&amp;7=2, and get the number of shifts, and shift the above valid ciphertext byte by byte by 2 bits to get C2 plaintext.</p>
<pre><code>blog.eduelects.com
</code></pre>
<h2 id="0x02persistence">0x02: Persistence</h2>
<p>RotaJakiro makes a distinction between <code>root/non-root</code> users when implementing persistence features, and different techniques are used for different accounts.</p>
<h3 id="rootaccount">root account</h3>
<ul>
<li>
<p>Depending on the Linux distribution, create the corresponding self-starting script <code>/etc/init/systemd-agent.conf</code> or <code>/lib/systemd/system/sys-temd-agent.service</code>.</p>
<pre><code>Content of systemd-agent.conf
-----------------------------
#system-daemon - configure for system daemon
#This service causes system have an associated
#kernel object to be started on boot.
description &quot;system daemon&quot;
start on filesystem or runlevel [2345]
exec /bin/systemd/systemd-daemon
respawn 
</code></pre>
<pre><code>Content of systemd-agent.service
-----------------------------
[Unit]
Description=System Daemon
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/lib/systemd/systemd-daemon
Restart=always
[Install]
</code></pre>
</li>
<li>
<p>The file name used for the disguise is one of the following twos.</p>
<pre><code>/bin/systemd/systemd-daemon
/usr/lib/systemd/systemd-daemon
</code></pre>
</li>
</ul>
<h3 id="nonrootaccount">non-root account</h3>
<ul>
<li>Create autostart script<code>$HOME/.config/au-tostart/gnomehelper.desktop</code> for <strong>desktop environment</strong><pre><code>[Desktop Entry]
Type=Application
Exec=$HOME/.gvfsd/.profile/gvfsd-helper
</code></pre>
</li>
<li>Modify the <code>.bashrc</code> file to create the autostart script for the <strong>shell environment</strong><pre><code># Add GNOME's helper designed to work with the I/O abstraction of GIO
# this environment variable is set, gvfsd will not start the fuse filesystem
if [ -d ${HOME} ]; then
        ${HOME}/.gvfsd/.profile/gvfsd-helper
fi
</code></pre>
</li>
<li>The file name used for the disguise, both of which exist at the same time<pre><code>$HOME/.dbus/sessions/session-dbus
$HOME/.gvfsd/.profile/gvfsd-helper
</code></pre>
</li>
</ul>
<h2 id="0x03processguarding">0x03:Process guarding</h2>
<p>RotaJakiro implements process guarding to protect its own operation, and like persistence, there are different implementations for <code>root/non-root</code> users.</p>
<h3 id="rootaccount">root account</h3>
<p>When running under the root account, depending on the Linux distribution, a new process is automatically created when the service process is terminated by writing <code>Restart=always or respawn</code> to the service's configuration file.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_rootcfg.png" width="860px"  /><br>
The actual result is shown in the figure below, where you can see that a new process is created immediately after the systemd-daemon process is terminated.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_rootprot.png" width="860px"  /></p>
<h3 id="nonrootaccount">non-root account</h3>
<p>When running under a non-root account, RotaJakiro generates two processes, <code>session-dbus</code> and <code>gvfsd-helper</code>, which monitor each other's survival and restore them when one of them is terminated, which is very typical of dual-process protection.</p>
<p>How is RotaJakiro's dual-process protection implemented?</p>
<p><strong>First</strong>, it creates a piece of shared memory with the <code>shmget API</code>, and session-dbus and gvfsd-helper communicate with each other through this shared memory, telling each other their PIDs.<br>
<strong>Then</strong>, dynamically fetching the process survival through the <code>/proc/[PID]</code> directory. When the other process is found dead, the process is created by <strong>execvp</strong> API to help the dead process &quot;resurrect&quot;, as shown in the following diagram.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_monitor.png" width="860px"  /><br>
The actual effect is shown in the figure below, you can see that after session-dbus and gvfsd-helper are ended by kill -9, new processes are created right away.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_nonrprot.png" width="860px"  /></p>
<h2 id="0x04singleinstance">0x04: Single instance</h2>
<p>RotaJakiro implements a single instance by file locking, as shown below.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_single.png" width="860px"  /><br>
The lockfile used in this differs under the root/non-root account.</p>
<ul>
<li>The lockfile under root, one will be created.<pre><code>/usr/lib32/.X11/X0-lock
/bin/lib32/.X11/X0-lock
</code></pre>
</li>
<li>The lockfile under non-root, both will be created.<pre><code>$HOME/.X11/X0-lock
$HOME/.X11/.X11-lock
</code></pre>
</li>
</ul>
<p>In the actual non-root account, for example, the processes and file locks can be matched by <code>/proc/locks</code>, and then the corresponding RotaJakiro sample is executed.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_instance.png" width="860px"  /></p>
<h2 id="0x05networkcommunication">0x05: Network communication</h2>
<p>RotaJakiro establishes communication with C2 through the following code snippet, pending the execution of subsequent commands.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_stage.png" width="860px"  /><br>
This process can be divided into 2 stages</p>
<ul>
<li>Stage 1, initialization phase<br>
Decrypt the C2 list, establish a connection with C2, send the online information, receive and decrypt the information returned by C2.</li>
<li>Stage 2, wait for C2 calls<br>
Verify the information returned by C2, if it passes the verification, execute the subsequent instructions sent by C2.</li>
</ul>
<h3 id="stage1initialization">Stage 1: Initialization</h3>
<p>The C2 list is decrypted by the decryption algorithm described in the previous section, and the following four C2s are built into the sample at present.</p>
<pre><code>news.thaprior.net
blog.eduelects.com
cdn.mirror-codes.net
status.sublineover.net
</code></pre>
<p>RotaJakiro will first try to establish a connection with them, and then construct the golive message by the following code snippet.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_cons.png" width="860px"  /><br>
Then it encrypts the golive information and sends it to the C2s<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_xor.png" width="860px"  /><br>
Finally, it receives the packet back from the C2, decrypts it and checks its legitimacy, and if it passes the check, it goes to Stage 2.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_recvreg.png" width="860px"  /></p>
<h3 id="stage2specificoperations">Stage 2: Specific operations</h3>
<p>Receive and execute the command from C2 through the following codesnippet.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_stage2.png" width="860px"  /><br>
At present, RotaJakiro supports a total of 12 instructions, and the correspondence between the instruction code and the function is shown in the following table.</p>
<table>
<thead>
<tr>
<th>CmdId</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x138E3E6</td>
<td>Exit</td>
</tr>
<tr>
<td>0x208307A</td>
<td>Test</td>
</tr>
<tr>
<td>0x5CCA727</td>
<td>Heartbeat</td>
</tr>
<tr>
<td>0x17B1CC4</td>
<td>Set C2 timeout time</td>
</tr>
<tr>
<td>0x25360EA</td>
<td>Steal Senstive Info</td>
</tr>
<tr>
<td>0x18320e0</td>
<td>Upload Device Info</td>
</tr>
<tr>
<td>0x2E25992</td>
<td>Deliver File/Plugin</td>
</tr>
<tr>
<td>0x2CD9070</td>
<td>Query File/Plugin Status</td>
</tr>
<tr>
<td>0x12B3629</td>
<td>Delete File/Plugin Or Dir</td>
</tr>
<tr>
<td>0x1B25503</td>
<td>Run Plugin_0x39C93E</td>
</tr>
<tr>
<td>0x1532E65</td>
<td>Run Plugin_0x75A7A2</td>
</tr>
<tr>
<td>0x25D5082</td>
<td>Run Plugin_0x536D01</td>
</tr>
<tr>
<td>The <strong>Run Plugin</strong> function reuses the same code and implements the function call through the following logic.</td>
<td></td>
</tr>
<tr>
<td><img src="__GHOST_URL__/content/images/2021/04/jak_plugin.png" width="860px"  /></td>
<td></td>
</tr>
<tr>
<td>We are currently not capturing such payloads, so we use the <code>Plugin_&quot;parameter&quot;</code> form to represent different tasks.</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="0x06packetanalysis">0x06 Packet analysis</h2>
<p>The network communication packet of RotaJakiro consists of three parts: <code>Head, Key, Payload</code>.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_packet.png" width="860px"  /><br>
<code>Head</code> is mandatory and 82 bytes long, and the <code>Key &amp; Payload</code> parts are optional.<br>
<code>Head &amp; Key</code>are encrypted with XOR &amp; Rotate, and <code>Payload</code> is encrypted with AES &amp; ZLIB Compression.<br>
In the following, we will illustrate the composition of network traffic <code>head&amp;key&amp;payload</code> and the decryption process through a round of interaction between Bot and C2.</p>
<h3 id="c2bot">C2 -&gt; Bot</h3>
<img src="__GHOST_URL__/content/images/2021/04/jak_cmd.png" width="860px"  />
<p>The first 0x52 bytes are the content of the Head. How to decrypt the head? Very simple, <code>shift 3 bits left byte by byte, and then XOR with 0x1b</code>. After decryption, we can get the following content.</p>
<pre><code>00000000  16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0  |...¹.±.û. .....à|
00000010  20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00  | ..Â d .â....Â..|
00000020  00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44  |..2B69334F841D0D|
00000030  39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44  |9FA0658EC3E29FAD|
00000040  34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9  |49ÈSæ.HÄ.w$....Ù|
00000050  81 28
------------filed parse------------------
offset 0x09, 4 bytes---&gt;payload length
offset 0x0d, 2 bytes---&gt;body length
offset ox0f, 4 bytes---&gt;cmdid
</code></pre>
<p>Through the field parsing, we can know that the length of key is 0x8 bytes, the length of payload is 0x20 bytes, and the instruction code to be executed is 0x18320e0, that is, the <code>report device information</code>.Reading 8 bytes from offset 0x52 gives the <strong>Key</strong><code>ea 9a 1a 18 18 44 26 a0</code>, and using the same decryption method as head, we get <code>4c cf cb dbdb 39 2a 1e</code>, which is used as the AES key to decrypt the Payload.</p>
<p>Reading 32 bytes from offset 0x5a gives us the following <strong>Payload</strong>.</p>
<pre><code>54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b 
b2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d
</code></pre>
<p>Using the decrypted key as the AES-256 key, decrypt the above data in CBC mode to get the following content.</p>
<pre><code>3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28
</code></pre>
<p>The 8th byte onwards is ZLIB compressed data, decompressed to get the following content.</p>
<pre><code>08 00 00 00 bf 89 88 08 cd 2d fd 50
------------filed parse------------------
offset 0, 4 bytes---&gt;length
</code></pre>
<p>What is the use of the decompressed Payload(<code>bf 89 88 08 cd 2d fd 50</code>)? It is used as <strong>a new AES key to decrypt some sensitive resource information</strong>.</p>
<p>For example, when Bot collects device information, one of the information is the current OS distribution, which is implemented by the <code>cat /etc/*release | uniq</code> command.</p>
<pre><code>root@debian:~# cat /etc/*release | uniq
PRETTY_NAME=&quot;Debian GNU/Linux 9 (stretch)&quot;
NAME=&quot;Debian GNU/Linux&quot;
VERSION_ID=&quot;9&quot;
VERSION=&quot;9 (stretch)&quot;
ID=debian
HOME_URL=&quot;https://www.debian.org/&quot;
SUPPORT_URL=&quot;https://www.debian.org/support&quot;
BUG_REPORT_URL=&quot;https://bugs.debian.org/&quot;
</code></pre>
<p>The<code> cat /etc/*release | uniq</code> command  is the result of the following cipher text</p>
<pre><code>&quot;cat /etc/*release | uniq&quot; cmd_ciphertxt
---------------------------
74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81 
6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a 
6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca
</code></pre>
<p>decrypted with the <code>new AES key and the parameters</code> in the following figure.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_paykey.png" width="860px"  /></p>
<h3 id="botc2">Bot -&gt; C2</h3>
<p>When BOT receives C2's &quot;report device information&quot; command, it will send the following data to C2, and you can see that the value of the key part is still <code>ea 9a 1a 18 18 44 26 a0</code>.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_payload.png" width="860px"  /><br>
The decrypted key value is <code>4c cf cb db db 39 2a 1e</code>. After decrypting and decompressing the payload sent by Bot to C2, we get the following data, which is the various information of the device, including the information obtained by <code>cat /etc/*release | uniq </code>mentioned before, which verifies that our analysis is correct.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_device-1.png" width="860px"  /></p>
<h2 id="relationshipwiththetoriibotnet">Relationship with the Torii Botnet</h2>
<p>The <a href="https://blog.avast.com/new-torii-botnet-threat-research">Torii botnet</a> was exposed by Avast on September 20, 2018, and we noticed that there are some the similarities between the twos,for example:</p>
<h4 id="1stringsimilarity">1: String similarity</h4>
<p>After decrypting the sensitive resources of RotaJakiro &amp; Torii, we found that they reuse a lot of the same commands.</p>
<pre><code>1：semanage fcontext -a -t bin_t '%s' &amp;&amp; restorecon '%s'
2：which semanage
3：cat /etc/*release 
4：cat /etc/issue
5：systemctl enable
6：initctl start
...
</code></pre>
<h4 id="2trafficsimilarity">2: Traffic similarity</h4>
<p>In the process of constructing the flow, a large number of constants are used and the construction methods are very close.<br>
<img src="__GHOST_URL__/content/images/2021/04/jak_compare.png" width="860px"  /></p>
<h4 id="3functionalsimilarity">3: Functional similarity</h4>
<p>From the perspective of reverse engineering, RotaJakiro &amp; Torii share similar styles: the use of encryption algorithms to hide sensitive resources, the implementation of a rather old-school style of persistence,structured network traffic, etc.</p>
<p>We don’t exactly know the answer, but it seems that RotaJakiro and Torii have some connections.</p>
<h2 id="thetipoftheiceberg">The tip of the iceberg</h2>
<p>While this concludes our analysis of RotaJakiro, the real work is far from over, and many questions remain unanswered: &quot;How did RotaJakiro spread, and what was its purpose?&quot; , &quot;Does RotaJakiro have a specific target?”, We would love to know if the community has relevant leads.</p>
<h2 id="contactus">Contact us</h2>
<p>Readers are always welcomed to reach us on <a href="https://twitter.com/360Netlab"><strong>twitter</strong></a>, or email to <strong>netlabat[at]360.cn</strong>.</p>
<h2 id="ioc">IOC</h2>
<p>Sample MD5</p>
<pre><code>1d45cd2c1283f927940c099b8fab593b
11ad1e9b74b144d564825d65d7fb37d6
5c0f375e92f551e8f2321b141c15c48f
64f6cfe44ba08b0babdd3904233c4857
</code></pre>
<p>C2</p>
<pre><code>news.thaprior.net:443
blog.eduelects.com:443
cdn.mirror-codes.net:443
status.sublineover.net:443
</code></pre>
<p>IP</p>
<pre><code>176.107.176.16 Ukraine|Kiev|Unknown 42331|PE_Freehost
</code></pre>
<!--kg-card-end: markdown-->
Overview


On March 25, 2021, 360 NETLAB's BotMon system flagged a suspiciousELF file (MD5=64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of TLS/SSL. A close look at the sample revealed it to be a backdoor targeting Linux X64 systems, a family that has been around for at least 3 years.


We named it RotaJakiro based on the fact that the family uses rotate encryption and behaves differently for root/non-root accounts when executing.


RotaJakiro pays quite some attention to hide its trails, using multiple of encryption algorithms, including: the use of AES algorithm to encrypt the resource information within the sample; C2 communication using a combination of AES, XOR, ROTATE encryption and ZLIB compression.


RotaJakiro supports a total of 12 functions, three of which are related to the execution of specific Plugins. Unfortunately, we have no visibilityto the plugins, and therefore do not know its true purpose. From a broad backdoor perspective, the functions can be grouped into the following four categories.


 * Reporting device information
 * Stealing sensitive information
 * File/Plugin management (query, download, delete)
 * Execution of specific Plugin



Any more out there?


With the sample we have, we discovered the following 4 samples, all of which have 0 detections on VT, and the earliest First Seen time on VT is in 2018.





FileName
MD5
Detection
First Seen in VT




systemd-daemon
1d45cd2c1283f927940c099b8fab593b
0/61
2018-05-16 04:22:59


systemd-daemon
11ad1e9b74b144d564825d65d7fb37d6
0/58
2018-12-25 08:02:05


systemd-daemon
5c0f375e92f551e8f2321b141c15c48f
0/56
2020-05-08 05:50:06


gvfsd-helper
64f6cfe44ba08b0babdd3904233c4857
0/61
2021-01-18 13:13:19





These samples all have the following 4 C2s embedded. These 4 C2 domains have very close Crteated,Updated and Expired time, readers will notice that the crated data was in Dec 2015, 6 years ago.





Domain
Detection
Created
Last Updated
Expired




news.thaprior.net
0/83
2015-12-09 06:24:13
2020-12-03 07:24:33
2021-12-09 06:24:13


blog.eduelects.com
0/83
2015-12-10 13:12:52
2020-12-03 07:24:33
2021-12-10 13:12:52


cdn.mirror-codes.net
0/83
2015-12-09 06:24:19
2020-12-03 07:24:32
2021-12-09 06:24:19


status.sublineover.net
0/83
2015-12-09 06:24:24
2020-12-03 07:24:32
2021-12-09 06:24:24






Reverse Analysis


The 4 RotaJakiro samples, with time distribution from 2018 to 2021, are very close to their functions, and the 2021 sample is selected for analysis in this blog, which has the following basic information:


MD5:64f6cfe44ba08b0babdd3904233c4857
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped
Packer:No



At the coding level, RotaJakiro uses techniques such as dynamic AES, double-layer encrypted communication protocols to counteract the binary & network traffic analysis.

At the functional level, RotaJakiro first determines whether the user is root or non-root at run time, with different execution policies for different accounts, then decrypts the relevant sensitive resources using AES& ROTATE for subsequent persistence, process guarding and single instance use, and finally establishes communication with C2 and waits for the execution of commands issued by C2.


The following will analyze the specific implementation of RotaJakiro from the above perspective.



0x00: Tricks used by the sample


 * Dynamically generate a table of constants required by the AES encryption algorithm to prevent the algorithm from being directly identified
   
   
 * Use stack strings obfuscation technique to store encrypted sensitive resource information
   
   
 * Network communication using double layer encryption



0x01: Encryption algorithm


All sensitive resources in RotaJakiro are encrypted, and in IDA we can see that the decryption method dec_proc is called 60 times, which is composed of AES and Rotate.



The AES decryption entry is as follows:



Where aes_dec is AES-256, CBC mode, key&iv are hardcoded.


 * KEY


 14 BA EE 23 8F 72 1A A6 00 00 00 00 00 00 00 00 
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



 * IV


  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



The Rotate decryption entry is shown below:



The so-called Rotate is a cyclic shift, we can see that the number of shifts is determined by the value of plain_len(length of plaintext) &7.


Take the following C2 cipher text as an example.


ff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99 
ac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60



The various parameters related to decryption are shown below, the length of the ciphertext is 32 bytes and the length of the plaintext is 26 bytes.



First, decrypting with AES, we get the following "sub-ciphertext".



Then, the valid ciphertext is extracted from the sub-ciphertext, where the valid ciphertext starts from the 8th byte, and the length is the plaintext length minus 8, which is 26-8=18 bytes here.


98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8 
DB 5B



Finally, we can calculate 26(the length of plaintext is 26)&7=2, and get the number of shifts, and shift the above valid ciphertext byte by byte by 2 bits to get C2 plaintext.


blog.eduelects.com




0x02: Persistence


RotaJakiro makes a distinction between root/non-root users when implementing persistence features, and different techniques are used for different accounts.



root account


 * 
   
   
   Depending on the Linux distribution, create the corresponding self-starting script /etc/init/systemd-agent.conf or /lib/systemd/system/sys-temd-agent.service.
   
   
   Content of systemd-agent.conf
   -----------------------------
   #system-daemon - configure for system daemon
   #This service causes system have an associated
   #kernel object to be started on boot.
   description "system daemon"
   start on filesystem or runlevel [2345]
   exec /bin/systemd/systemd-daemon
   respawn 
   
   
   
   Content of systemd-agent.service
   -----------------------------
   [Unit]
   Description=System Daemon
   Wants=network-online.target
   After=network-online.target
   [Service]
   ExecStart=/usr/lib/systemd/systemd-daemon
   Restart=always
   [Install]
   
   

 * 
   
   
   The file name used for the disguise is one of the following twos.
   
   
   /bin/systemd/systemd-daemon
   /usr/lib/systemd/systemd-daemon
   
   



non-root account


 * Create autostart script$HOME/.config/au-tostart/gnomehelper.desktop for desktop environment
   
   [Desktop Entry]
   Type=Application
   Exec=$HOME/.gvfsd/.profile/gvfsd-helper
   
   

 * Modify the .bashrc file to create the autostart script for the shell environment
   
   # Add GNOME's helper designed to work with the I/O abstraction of GIO
   # this environment variable is set, gvfsd will not start the fuse filesystem
   if [ -d ${HOME} ]; then
           ${HOME}/.gvfsd/.profile/gvfsd-helper
   fi
   
   

 * The file name used for the disguise, both of which exist at the same time
   
   $HOME/.dbus/sessions/session-dbus
   $HOME/.gvfsd/.profile/gvfsd-helper
   
   



0x03:Process guarding


RotaJakiro implements process guarding to protect its own operation, and like persistence, there are different implementations for root/non-root users.



root account


When running under the root account, depending on the Linux distribution, a new process is automatically created when the service process is terminated by writing Restart=always or respawn to the service's configuration file.



The actual result is shown in the figure below, where you can see that a new process is created immediately after the systemd-daemon process is terminated.





non-root account


When running under a non-root account, RotaJakiro generates two processes, session-dbus and gvfsd-helper, which monitor each other's survival and restore them when one of them is terminated, which is very typical of dual-process protection.


How is RotaJakiro's dual-process protection implemented?


First, it creates a piece of shared memory with the shmget API, and session-dbus and gvfsd-helper communicate with each other through this shared memory, telling each other their PIDs.

Then, dynamically fetching the process survival through the /proc/[PID] directory. When the other process is found dead, the process is created by execvp API to help the dead process "resurrect", as shown in the following diagram.



The actual effect is shown in the figure below, you can see that after session-dbus and gvfsd-helper are ended by kill -9, new processes are created right away.





0x04: Single instance


RotaJakiro implements a single instance by file locking, as shown below.



The lockfile used in this differs under the root/non-root account.


 * The lockfile under root, one will be created.
   
   /usr/lib32/.X11/X0-lock
   /bin/lib32/.X11/X0-lock
   
   

 * The lockfile under non-root, both will be created.
   
   $HOME/.X11/X0-lock
   $HOME/.X11/.X11-lock
   
   


In the actual non-root account, for example, the processes and file locks can be matched by /proc/locks, and then the corresponding RotaJakiro sample is executed.





0x05: Network communication


RotaJakiro establishes communication with C2 through the following code snippet, pending the execution of subsequent commands.



This process can be divided into 2 stages


 * Stage 1, initialization phase
   
   Decrypt the C2 list, establish a connection with C2, send the online information, receive and decrypt the information returned by C2.
 * Stage 2, wait for C2 calls
   
   Verify the information returned by C2, if it passes the verification, execute the subsequent instructions sent by C2.



Stage 1: Initialization


The C2 list is decrypted by the decryption algorithm described in the previous section, and the following four C2s are built into the sample at present.


news.thaprior.net
blog.eduelects.com
cdn.mirror-codes.net
status.sublineover.net



RotaJakiro will first try to establish a connection with them, and then construct the golive message by the following code snippet.



Then it encrypts the golive information and sends it to the C2s



Finally, it receives the packet back from the C2, decrypts it and checks its legitimacy, and if it passes the check, it goes to Stage 2.





Stage 2: Specific operations


Receive and execute the command from C2 through the following codesnippet.



At present, RotaJakiro supports a total of 12 instructions, and the correspondence between the instruction code and the function is shown in the following table.





CmdId
Function




0x138E3E6
Exit


0x208307A
Test


0x5CCA727
Heartbeat


0x17B1CC4
Set C2 timeout time


0x25360EA
Steal Senstive Info


0x18320e0
Upload Device Info


0x2E25992
Deliver File/Plugin


0x2CD9070
Query File/Plugin Status


0x12B3629
Delete File/Plugin Or Dir


0x1B25503
Run Plugin_0x39C93E


0x1532E65
Run Plugin_0x75A7A2


0x25D5082
Run Plugin_0x536D01


The Run Plugin function reuses the same code and implements the function call through the following logic.







We are currently not capturing such payloads, so we use the Plugin_"parameter" form to represent different tasks.







0x06 Packet analysis


The network communication packet of RotaJakiro consists of three parts: Head, Key, Payload.



Head is mandatory and 82 bytes long, and the Key & Payload parts are optional.

Head & Keyare encrypted with XOR & Rotate, and Payload is encrypted with AES & ZLIB Compression.

In the following, we will illustrate the composition of network traffic head&key&payload and the decryption process through a round of interaction between Bot and C2.



C2 -> Bot



The first 0x52 bytes are the content of the Head. How to decrypt the head? Very simple, shift 3 bits left byte by byte, and then XOR with 0x1b. After decryption, we can get the following content.


00000000  16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0  |...¹.±.û. .....à|
00000010  20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00  | ..Â d .â....Â..|
00000020  00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44  |..2B69334F841D0D|
00000030  39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44  |9FA0658EC3E29FAD|
00000040  34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9  |49ÈSæ.HÄ.w$....Ù|
00000050  81 28
------------filed parse------------------
offset 0x09, 4 bytes--->payload length
offset 0x0d, 2 bytes--->body length
offset ox0f, 4 bytes--->cmdid



Through the field parsing, we can know that the length of key is 0x8 bytes, the length of payload is 0x20 bytes, and the instruction code to be executed is 0x18320e0, that is, the report device information.Reading 8 bytes from offset 0x52 gives the Keyea 9a 1a 18 18 44 26 a0, and using the same decryption method as head, we get 4c cf cb dbdb 39 2a 1e, which is used as the AES key to decrypt the Payload.


Reading 32 bytes from offset 0x5a gives us the following Payload.


54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b 
b2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d



Using the decrypted key as the AES-256 key, decrypt the above data in CBC mode to get the following content.


3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28



The 8th byte onwards is ZLIB compressed data, decompressed to get the following content.


08 00 00 00 bf 89 88 08 cd 2d fd 50
------------filed parse------------------
offset 0, 4 bytes--->length



What is the use of the decompressed Payload(bf 89 88 08 cd 2d fd 50)? It is used as a new AES key to decrypt some sensitive resource information.


For example, when Bot collects device information, one of the information is the current OS distribution, which is implemented by the cat /etc/*release | uniq command.


root@debian:~# cat /etc/*release | uniq
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"



The cat /etc/*release | uniq command is the result of the following cipher text


"cat /etc/*release | uniq" cmd_ciphertxt
---------------------------
74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81 
6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a 
6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca



decrypted with the new AES key and the parameters in the following figure.





Bot -> C2


When BOT receives C2's "report device information" command, it will send the following data to C2, and you can see that the value of the key part is still ea 9a 1a 18 18 44 26 a0.



The decrypted key value is 4c cf cb db db 39 2a 1e. After decrypting and decompressing the payload sent by Bot to C2, we get the following data, which is the various information of the device, including the information obtained by cat /etc/*release | uniq mentioned before, which verifies that our analysis is correct.





Relationship with the Torii Botnet


The Torii botnet was exposed by Avast on September 20, 2018, and we noticed that there are some the similarities between the twos,for example:


1: String similarity


After decrypting the sensitive resources of RotaJakiro & Torii, we found that they reuse a lot of the same commands.


1：semanage fcontext -a -t bin_t '%s' && restorecon '%s'
2：which semanage
3：cat /etc/*release 
4：cat /etc/issue
5：systemctl enable
6：initctl start
...



2: Traffic similarity


In the process of constructing the flow, a large number of constants are used and the construction methods are very close.




3: Functional similarity


From the perspective of reverse engineering, RotaJakiro & Torii share similar styles: the use of encryption algorithms to hide sensitive resources, the implementation of a rather old-school style of persistence,structured network traffic, etc.


We don’t exactly know the answer, but it seems that RotaJakiro and Torii have some connections.



The tip of the iceberg


While this concludes our analysis of RotaJakiro, the real work is far from over, and many questions remain unanswered: "How did RotaJakiro spread, and what was its purpose?" , "Does RotaJakiro have a specific target?”, We would love to know if the community has relevant leads.



Contact us


Readers are always welcomed to reach us on twitter, or email to netlabat[at]360.cn.



IOC


Sample MD5


1d45cd2c1283f927940c099b8fab593b
11ad1e9b74b144d564825d65d7fb37d6
5c0f375e92f551e8f2321b141c15c48f
64f6cfe44ba08b0babdd3904233c4857



C2


news.thaprior.net:443
blog.eduelects.com:443
cdn.mirror-codes.net:443
status.sublineover.net:443



IP


176.107.176.16 Ukraine|Kiev|Unknown 42331|PE_Freehost


{"version":"0.3.1","atoms":[],"cards":[["markdown",{"markdown":"## Overview\nOn March 25, 2021,  360 NETLAB's BotMon system flagged a suspiciousELF file (MD5=64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of TLS/SSL. A close look at the sample revealed it to be a **backdoor** targeting Linux X64 systems, a family that has been around for **at least 3 years**. \n\nWe named it **RotaJakiro** based on the fact that the family uses rotate encryption and behaves differently for ```root/non-root accounts``` when executing.\n\n```RotaJakiro``` pays quite some attention to hide its trails,  using multiple of encryption algorithms, including: the use of AES algorithm to encrypt the resource information within the sample; C2 communication using a combination of ```AES, XOR, ROTATE encryption``` and ```ZLIB compression```.\n\n```RotaJakiro``` supports a total of 12 functions, three of which are related to the execution of specific Plugins. Unfortunately, we have no visibilityto the plugins, and therefore do not know its true purpose. From a broad backdoor perspective, the functions can be grouped into the following four categories.\n* Reporting device information\n* Stealing sensitive information\n* File/Plugin management (query, download, delete)\n* Execution of specific Plugin\n## Any more out there?\nWith the sample we have, we discovered the following 4 samples, all of which have 0 detections on VT, and the earliest First Seen time on VT is in 2018.\n| FileName       | MD5                              | Detection | First Seen in VT    |\n| -------------- | -------------------------------- | --------- | ------------------- |\n| systemd-daemon | 1d45cd2c1283f927940c099b8fab593b | 0/61      | 2018-05-16 04:22:59 |\n| systemd-daemon | 11ad1e9b74b144d564825d65d7fb37d6 | 0/58      | 2018-12-25 08:02:05 |\n| systemd-daemon | 5c0f375e92f551e8f2321b141c15c48f | 0/56      | 2020-05-08 05:50:06 |\n| gvfsd-helper   | 64f6cfe44ba08b0babdd3904233c4857 | 0/61      | 2021-01-18 13:13:19 |\n\nThese samples all have the following 4 C2s embedded. These 4 C2 domains have very close ```Crteated,Updated and Expired``` time, readers will notice that the crated data was in Dec 2015, 6 years ago.\n| Domain                 | Detection | Created             | Last Updated        | Expired             |\n| ---------------------- | --------- | ------------------- | ------------------- | ------------------- |\n| news.thaprior.net      | 0/83      | 2015-12-09 06:24:13 | 2020-12-03 07:24:33 | 2021-12-09 06:24:13 |\n| blog.eduelects.com     | 0/83      | 2015-12-10 13:12:52 | 2020-12-03 07:24:33 | 2021-12-10 13:12:52 |\n| cdn.mirror-codes.net   | 0/83      | 2015-12-09 06:24:19 | 2020-12-03 07:24:32 | 2021-12-09 06:24:19 |\n| status.sublineover.net | 0/83      | 2015-12-09 06:24:24 | 2020-12-03 07:24:32 | 2021-12-09 06:24:24 |\n\n\n## Reverse Analysis\nThe 4 RotaJakiro samples, with time distribution from 2018 to 2021, are very close to their functions, and the 2021 sample is selected for analysis in this blog, which has the following basic information:\n```\nMD5:64f6cfe44ba08b0babdd3904233c4857\nELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped\nPacker:No\n```\n```At the coding level```, RotaJakiro uses techniques such as dynamic AES, double-layer encrypted communication protocols to counteract the binary & network traffic analysis.\n```At the functional level```, RotaJakiro first determines whether the user is root or non-root at run time, with different execution policies for different accounts, then decrypts the relevant sensitive resources using AES& ROTATE for subsequent ```persistence```, ```process guarding``` and ```single instance``` use, and finally establishes communication with C2 and waits for the execution of commands issued by C2.\n\nThe following will analyze the specific implementation of RotaJakiro from the above perspective.\n## 0x00: Tricks used by the sample\n* Dynamically generate a table of constants required by the AES encryption algorithm to prevent the algorithm from being directly identified\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_dynaes.png\" width=\"860px\"  />\n* Use stack strings obfuscation technique to store encrypted sensitive resource information\n <img src=\"__GHOST_URL__/content/images/2021/04/jak_stack.png\" width=\"860px\"  />\n* Network communication using double layer encryption\n## 0x01: Encryption algorithm\n\n All sensitive resources in RotaJakiro are encrypted, and in IDA we can see that the decryption method **dec_proc** is called 60 times, which is composed of AES and Rotate.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_dec.png\" width=\"860px\"  />\nThe AES decryption entry is as follows:\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_aes.png\" width=\"860px\"  />\nWhere ```aes_dec``` is AES-256, CBC mode, key&iv are hardcoded.\n* KEY\n```\n 14 BA EE 23 8F 72 1A A6 00 00 00 00 00 00 00 00 \n 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n```\n* IV\n```\n  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n```\nThe Rotate decryption entry is shown below:\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_rota.png\" width=\"860px\"  />\nThe so-called Rotate is a cyclic shift, we can see that the number of shifts is determined by the value of ```plain_len(length of plaintext) &7```.\n\nTake the following C2 cipher text as an example.\n```\nff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99 \nac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60\n```\nThe various parameters related to decryption are shown below, the length of the ciphertext is 32 bytes and the length of the plaintext is 26 bytes.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_exp.png\" width=\"860px\"  />\n**First**, decrypting with AES, we get the following \"sub-ciphertext\".\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_valid.png\" width=\"860px\"  />\n**Then**, the valid ciphertext is extracted from the  sub-ciphertext, where the valid ciphertext starts from the 8th byte, and the length is the plaintext length minus 8, which is 26-8=18 bytes here.\n```\n98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8 \nDB 5B\n```\n**Finally**, we can calculate 26(the length of plaintext is 26)&7=2, and get the number of shifts, and shift the above valid ciphertext byte by byte by 2 bits to get C2 plaintext.\n```\nblog.eduelects.com\n```\n## 0x02: Persistence\nRotaJakiro makes a distinction between ```root/non-root``` users when implementing persistence features, and different techniques are used for different accounts.\n### root account\n* Depending on the Linux distribution, create the corresponding self-starting script ```/etc/init/systemd-agent.conf``` or ```/lib/systemd/system/sys-temd-agent.service```.\n  ```\n  Content of systemd-agent.conf\n  -----------------------------\n  #system-daemon - configure for system daemon\n  #This service causes system have an associated\n  #kernel object to be started on boot.\n  description \"system daemon\"\n  start on filesystem or runlevel [2345]\n  exec /bin/systemd/systemd-daemon\n  respawn \n  ```\n\n\n  ```\n  Content of systemd-agent.service\n  -----------------------------\n  [Unit]\n  Description=System Daemon\n  Wants=network-online.target\n  After=network-online.target\n  [Service]\n  ExecStart=/usr/lib/systemd/systemd-daemon\n  Restart=always\n  [Install]\n  ```\n* The file name used for the disguise is one of the following twos.\n\n  ```\n  /bin/systemd/systemd-daemon\n  /usr/lib/systemd/systemd-daemon\n  ```\n### non-root account\n* Create autostart script```$HOME/.config/au-tostart/gnomehelper.desktop``` for **desktop environment** \n  ```\n  [Desktop Entry]\n  Type=Application\n  Exec=$HOME/.gvfsd/.profile/gvfsd-helper\n  ```\n* Modify the ```.bashrc``` file to create the autostart script for the **shell environment**\n  ```\n  # Add GNOME's helper designed to work with the I/O abstraction of GIO\n  # this environment variable is set, gvfsd will not start the fuse filesystem\n  if [ -d ${HOME} ]; then\n          ${HOME}/.gvfsd/.profile/gvfsd-helper\n  fi\n  ```\n* The file name used for the disguise, both of which exist at the same time\n  ```\n  $HOME/.dbus/sessions/session-dbus\n  $HOME/.gvfsd/.profile/gvfsd-helper\n  ```\n  \n  \n## 0x03:Process guarding\nRotaJakiro implements process guarding to protect its own operation, and like persistence, there are different implementations for ```root/non-root``` users.\n### root account\nWhen running under the root account, depending on the Linux distribution, a new process is automatically created when the service process is terminated by writing ```Restart=always or respawn``` to the service's configuration file.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_rootcfg.png\" width=\"860px\"  />\nThe actual result is shown in the figure below, where you can see that a new process is created immediately after the systemd-daemon process is terminated.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_rootprot.png\" width=\"860px\"  />\n### non-root account\nWhen running under a non-root account, RotaJakiro generates two processes, ```session-dbus``` and ```gvfsd-helper```, which monitor each other's survival and restore them when one of them is terminated, which is very typical of dual-process protection.\n\nHow is RotaJakiro's dual-process protection implemented?\n\n**First**, it creates a piece of shared memory with the ```shmget API```, and session-dbus and gvfsd-helper communicate with each other through this shared memory, telling each other their PIDs.\n**Then**, dynamically fetching the process survival through the ```/proc/[PID]``` directory. When the other process is found dead, the process is created by **execvp** API to help the dead process \"resurrect\", as shown in the following diagram.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_monitor.png\" width=\"860px\"  />\nThe actual effect is shown in the figure below, you can see that after session-dbus and gvfsd-helper are ended by kill -9, new processes are created right away.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_nonrprot.png\" width=\"860px\"  />\n\n## 0x04: Single instance\nRotaJakiro implements a single instance by file locking, as shown below.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_single.png\" width=\"860px\"  />\nThe lockfile used in this differs under the root/non-root account.\n* The lockfile under root, one will be created.\n  ```\n  /usr/lib32/.X11/X0-lock\n  /bin/lib32/.X11/X0-lock\n  ```\n* The lockfile under non-root, both will be created.\n  ```\n  $HOME/.X11/X0-lock\n  $HOME/.X11/.X11-lock\n  ```\nIn the actual non-root account, for example, the processes and file locks can be matched by ```/proc/locks```, and then the corresponding RotaJakiro sample is executed.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_instance.png\" width=\"860px\"  />\n## 0x05: Network communication\nRotaJakiro establishes communication with C2 through the following code snippet, pending the execution of subsequent commands.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_stage.png\" width=\"860px\"  />\nThis process can be divided into 2 stages\n* Stage 1, initialization phase\nDecrypt the C2 list, establish a connection with C2, send the online information, receive and decrypt the information returned by C2.\n * Stage 2, wait for C2 calls\nVerify the information returned by C2, if it passes the verification, execute the subsequent instructions sent by C2.\n### Stage 1: Initialization\nThe C2 list is decrypted by the decryption algorithm described in the previous section, and the following four C2s are built into the sample at present.\n```\nnews.thaprior.net\nblog.eduelects.com\ncdn.mirror-codes.net\nstatus.sublineover.net\n```\nRotaJakiro will first try to establish a connection with them, and then construct the golive message by the following code snippet.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_cons.png\" width=\"860px\"  />\nThen it encrypts the golive information and sends it to the C2s\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_xor.png\" width=\"860px\"  />\nFinally, it receives the packet back from the C2, decrypts it and checks its legitimacy, and if it passes the check, it goes to Stage 2.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_recvreg.png\" width=\"860px\"  />\n### Stage 2: Specific operations\nReceive and execute the command from C2 through the following codesnippet.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_stage2.png\" width=\"860px\"  />\nAt present, RotaJakiro supports a total of 12 instructions, and the correspondence between the instruction code and the function is shown in the following table.\n| CmdId     | Function                  |\n| --------- | ------------------------- |\n| 0x138E3E6 | Exit                      |\n| 0x208307A | Test                      |\n| 0x5CCA727 | Heartbeat                 |\n| 0x17B1CC4 | Set C2 timeout time       |\n| 0x25360EA | Steal Senstive Info      |\n| 0x18320e0 | Upload Device Info        |\n| 0x2E25992 | Deliver File/Plugin       |\n| 0x2CD9070 | Query File/Plugin Status  |\n| 0x12B3629 | Delete File/Plugin Or Dir |\n| 0x1B25503 | Run Plugin_0x39C93E       |\n| 0x1532E65 | Run Plugin_0x75A7A2       |\n| 0x25D5082 | Run Plugin_0x536D01       |\nThe **Run Plugin** function reuses the same code and implements the function call through the following logic.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_plugin.png\" width=\"860px\"  />\nWe are currently not capturing such payloads, so we use the ```Plugin_\"parameter\"``` form to represent different tasks.\n\n## 0x06 Packet analysis\nThe network communication packet of RotaJakiro consists of three parts: ```Head, Key, Payload```.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_packet.png\" width=\"860px\"  />\n```Head``` is mandatory and 82 bytes long, and the ```Key & Payload``` parts are optional. \n```Head & Key```are encrypted with XOR & Rotate, and ```Payload``` is encrypted with AES & ZLIB Compression.\nIn the following, we will illustrate the composition of network traffic ```head&key&payload``` and the decryption process through a round of interaction between Bot and C2.\n\n### C2 -> Bot\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_cmd.png\" width=\"860px\"  />\n\nThe first 0x52 bytes are the content of the Head. How to decrypt the head? Very simple, ```shift 3 bits left byte by byte, and then XOR with 0x1b```. After decryption, we can get the following content.\n```\n00000000  16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0  |...¹.±.û. .....à|\n00000010  20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00  | ..Â d .â....Â..|\n00000020  00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44  |..2B69334F841D0D|\n00000030  39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44  |9FA0658EC3E29FAD|\n00000040  34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9  |49ÈSæ.HÄ.w$....Ù|\n00000050  81 28\n------------filed parse------------------\noffset 0x09, 4 bytes--->payload length\noffset 0x0d, 2 bytes--->body length\noffset ox0f, 4 bytes--->cmdid\n```\nThrough the field parsing, we can know that the length of key is 0x8 bytes, the length of payload is 0x20 bytes, and the instruction code to be executed is 0x18320e0, that is, the ```report device information```.Reading 8 bytes from offset 0x52 gives the **Key**```ea 9a 1a 18 18 44 26 a0```, and using the same decryption method as head, we get ```4c cf cb dbdb 39 2a 1e```, which is used as the AES key to decrypt the Payload.\n\nReading 32 bytes from offset 0x5a gives us the following **Payload**.\n```\n54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b \nb2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d\n```\nUsing the decrypted key as the AES-256 key, decrypt the above data in CBC mode to get the following content.\n```\n3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28\n```\nThe 8th byte onwards is ZLIB compressed data, decompressed to get the following content.\n```\n08 00 00 00 bf 89 88 08 cd 2d fd 50\n------------filed parse------------------\noffset 0, 4 bytes--->length\n```\nWhat is the use of the decompressed Payload(```bf 89 88 08 cd 2d fd 50```)? It is used as **a new AES key to decrypt some sensitive resource information**.\n\nFor example, when Bot collects device information, one of the information is the current OS distribution, which is implemented by the ```cat /etc/*release | uniq``` command.\n```\nroot@debian:~# cat /etc/*release | uniq\nPRETTY_NAME=\"Debian GNU/Linux 9 (stretch)\"\nNAME=\"Debian GNU/Linux\"\nVERSION_ID=\"9\"\nVERSION=\"9 (stretch)\"\nID=debian\nHOME_URL=\"https://www.debian.org/\"\nSUPPORT_URL=\"https://www.debian.org/support\"\nBUG_REPORT_URL=\"https://bugs.debian.org/\"\n```\nThe``` cat /etc/*release | uniq``` command  is the result of the following cipher text \n```\n\"cat /etc/*release | uniq\" cmd_ciphertxt\n---------------------------\n74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81 \n6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a \n6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca\n```\ndecrypted with the ```new AES key and the parameters``` in the following figure.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_paykey.png\" width=\"860px\"  />\n\n### Bot -> C2\nWhen BOT receives C2's \"report device information\" command, it will send the following data to C2, and you can see that the value of the key part is still ```ea 9a 1a 18 18 44 26 a0```.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_payload.png\" width=\"860px\"  />\nThe decrypted key value is ```4c cf cb db db 39 2a 1e```. After decrypting and decompressing the payload sent by Bot to C2, we get the following data, which is the various information of the device, including the information obtained by ```cat /etc/*release | uniq ```mentioned before, which verifies that our analysis is correct.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_device-1.png\" width=\"860px\"  />\n## Relationship with the Torii Botnet \nThe [Torii botnet](https://blog.avast.com/new-torii-botnet-threat-research) was exposed by Avast on September 20, 2018, and we noticed that there are some the similarities between the twos,for example:\n#### 1: String similarity\nAfter decrypting the sensitive resources of RotaJakiro & Torii, we found that they reuse a lot of the same commands.\n```\n1：semanage fcontext -a -t bin_t '%s' && restorecon '%s'\n2：which semanage\n3：cat /etc/*release \n4：cat /etc/issue\n5：systemctl enable\n6：initctl start\n...\n```\n\n#### 2: Traffic similarity\nIn the process of constructing the flow, a large number of constants are used and the construction methods are very close.\n<img src=\"__GHOST_URL__/content/images/2021/04/jak_compare.png\" width=\"860px\"  />\n#### 3: Functional similarity\nFrom the perspective of reverse engineering, RotaJakiro & Torii share similar styles: the use of encryption algorithms to hide sensitive resources, the implementation of a rather old-school style of persistence,structured network traffic, etc.\n\nWe don’t exactly know the answer, but it seems that RotaJakiro and Torii have some connections.\n## The tip of the iceberg\nWhile this concludes our analysis of RotaJakiro, the real work is far from over, and many questions remain unanswered: \"How did RotaJakiro spread, and what was its purpose?\" , \"Does RotaJakiro have a specific target?”, We would love to know if the community has relevant leads.\n## Contact us\nReaders are always welcomed to reach us on [**twitter**](https://twitter.com/360Netlab), or email to **netlabat[at]360.cn**.\n## IOC \n\nSample MD5\n\n```\n1d45cd2c1283f927940c099b8fab593b\n11ad1e9b74b144d564825d65d7fb37d6\n5c0f375e92f551e8f2321b141c15c48f\n64f6cfe44ba08b0babdd3904233c4857\n```\n\nC2\n\n```\nnews.thaprior.net:443\nblog.eduelects.com:443\ncdn.mirror-codes.net:443\nstatus.sublineover.net:443\n```\n\nIP\n```\n176.107.176.16 Ukraine|Kiev|Unknown 42331|PE_Freehost\n```"}]],"markups":[],"sections":[[10,0],[1,"p",[]]],"ghostVersion":"3.0"}