The Honeynet Project: Scan 16
Submitted by: Matthew Fiddler

The Scan for June 2001:
Your challenge is to decrypt and analyze an encrypted file.

1. [Identify the encryption algorithm used to encrypt the file:]

I grabbed the file <somefile.tgz> from The Honeynet Project (http://project.honeynet.org/scans/scna16/somefile.tgz), unpacked and verified the file to begin my analysis.

A "strings" of the file produced no output and a "cat" provided little more than a mix of ASCII characters. I decided to dump a hex output of "somefile" to glean possibly more information:

# hexdump somefile
0000000 99a4 9396 a29a 99f5 9196 c29b 9bd0 899a
0000010 8fd0 8c8b cfd0 d0ce 969d d091 9699 9b91
0000020 9bf5 c28a 9bd0 899a 8fd0 8c8b cfd0 d0ce
0000030 969d d091 8a9b 93f5 c28c 9bd0 899a 8fd0
0000040 8c8b cfd0 d0ce 969d d091 8c93 99f5 9396
0000050 a09a 9699 8b93 8d9a c28c cecf 93d3 939d
0000060 9d96 8c8f 8cd1 d390 918c 93d1 8fd3 908d
0000070 d392 939c 9e9a 9a91 d38d 909b d38c 9c8a
0000080 9190 d199 9196 d389 8c8f 919d d39c 8f93
0000090 9c9e 8b9c aad3 baac f5ad a4f5 8c8f f5a2
00000a0 8c8f d0c2 9a9b d089 8b8f d08c cecf 9dd0
00000b0 9196 8fd0 8d8c 8ff5 a08c 9699 8b93 8d9a
00000c0 c28c 8f93 d38e 8f93 9c8c 9a97 d39b 978c
00000d0 8bce 8fd3 8d8c 8cd3 978c cd9b 93d3 8c8f
00000e0 8b9a 93d3 9e8f 9c9c d38b 919d 939c d38f
00000f0 8f93 868c f58c 8c93 9990 99a0 9396 9a8b
0000100 8c8d 93c2 d38f 9c8a 9190 d199 9196 d389
0000110 8c8f 9691 9999 8fd3 8d8c c5d3 ccce cfcf
0000120 d3cf cdc5 cfca cfcf c5d3 c9c9 c7c9 c5d3
0000130 c9c9 c8c9 d0d3 9a9b d089 8b8f d08c cecf
0000140 8cd3 d191 d393 8d8f 9290 93d3 908c d399
0000150 8c8f 919d f59c a4f5 9a91 8c8b 9e8b a28b
0000160 91f5 8b9a 8b8c 8b9e d0c2 9a9b d089 8b8f
0000170 d08c cecf 9dd0 9196 91d0 8b9a 8b8c 8b9e
0000180 91f5 8b9a 99a0 9396 9a8b 8c8d cbc2 cfc8
0000190 c7ce c9d3 c9c9 f5c7 a4f5 9093 9698 a291
00001a0 8cf5 a08a 9093 c29c 9bd0 899a 8fd0 8c8b
00001b0 cfd0 d0ce 969d d091 8a8c 8ff5 9196 c298
00001c0 9bd0 899a 8fd0 8c8b cfd0 d0ce 969d d091
00001d0 968f 9891 8ff5 8c9e 888c c29b 9bd0 899a
00001e0 8fd0 8c8b cfd0 d0ce 969d d091 9e8f 8c8c
00001f0 9b88 8cf5 9a97 9393 d0c2 969d d091 978c
0000200 f5f5 8a8c 8fa0 8c9e c28c cc93 8bcc cb97
0000210 cf87 f58d

Again, I was at a loss, there was no apparent plain text from the "strings" or "cat" and a hex dump yielded no additional information, or so I thought. With the assumption that the beginning of the file might include a constant from the encryption algorithm, I ran a search of the first four bytes (99a4 9396) against http://www.google.com:

The first hit looked very intriguing!

This was a very detailed SANS analysis of two Redhat boxes compromised on Nov 25, 2000. Included in the analysis was a listing of the files installed by the black hat. My search hit included in the analysis a file named "uconf.inv", detailed here:

< snipped from http://www.sans.org/y2k/the_compromise.htm >
uconf.inv - I believe this file is where Adore keeps the list of items to be hidden. The file is referenced by ls, ps, netstat. The strings command produces no data however the file is DATA (but not ascii) and it contains 652 character (wc -c). Below is the hex dump. There was only one line difference between the hex dump from Victim#1 and Victim#2's file The line line on Victim#2 that is different.

Victim 2 - 0000280 8c8c 91c2 8991 c795 9395 f591
Victim 1 - 0000280 8c8c 8dc2 99c9 cdcf 878b f591

<Start of uconf.inv hexdump from Victim#1>
0000000 99a4 9396 a29a 99f5 9196 c29b 93d0 9d96
0000010 8cd0 9c9a 8d8a 8b96 d086 9cd1 9190 9699
0000020 d098 969d d091 9699 9b91 9bf5 c28a 93d0
0000030 9d96 8cd0 9c9a 8d8a 8b96 d086 9cd1 9190
0000040 9699 d098 969d d091 8a9b 93f5 c28c 93d0
0000050 9d96 8cd0 9c9a 8d8a 8b96 d086 9cd1 9190
0000060 9699 d098 969d d091 8c93 99f5 9396 a09a
0000070 9699 8b93 8d9a c28c 9c8a 9190 d199 9196
0000080 d389 9c8b d18f 9093 d398 9387 9890 9196
0000090 d1d3 909c 9991 9896 d1d3 909c 9991 9896
00000a0 8cd3 978c 9bcd f5f5 8fa4 a28c 8ff5 c28c
00000b0 93d0 9d96 8cd0 9c9a 8d8a 8b96 d086 9cd1
00000c0 9190 9699 d098 969d d091 8c8f f58d 8c8f
00000d0 99a0 9396 9a8b 8c8d 93c2 8e8f 93d3 8c8f
00000e0 979c 9b9a 8cd3 ce97 d38b 8c8f d38d 8c8c
00000f0 cd97 d39b 8f93 9a8c d38b 8f93 9c8c 9a97
0000100 d39b 9387 9890 9196 d0d3 9693 d09d 9a8c
0000110 f59c 8c93 9990 99a0 9396 9a8b 8c8d d0c2
0000120 9693 d09d 9a8c 8a9c 968d 868b d1d0 909c
0000130 9991 9896 8ad3 909c 9991 96d1 8991 8fd3
0000140 918c 9996 d399 8c8f d38d cec5 cfcc cfcf
0000150 c5d3 cacd cfcf d3cf 9bd0 899a 8fd0 8c8b
0000160 cfd0 d3ce 918c 93d1 8fd3 908d d392 8c93
0000170 9990 8bd3 8f9c 93d1 9890 8cd3 978c 9bcd
0000180 93d3 8c8f 979c 9b9a 87d3 9093 9698 d391
0000190 9cd1 9190 9699 f598 a4f5 9a91 8c8b 9e8b
00001a0 a28b 91f5 8b9a 8b8c 8b9e d0c2 9693 d09d
00001b0 9a8c 8a9c 968d 868b d1d0 909c 9991 9896
00001c0 9dd0 9196 91d0 8b9a 8b8c 8b9e 91f5 8b9a
00001d0 99a0 9396 9a8b 8c8d cec2 cfcc cfcf cdd3
00001e0 cfca cfcf c9d3 c9c9 d3c8 cfc7 cfcf c6d3
00001f0 cfcf f5cf a4f5 9093 9698 a291 8cf5 a08a
0000200 9093 c29c 93d0 9d96 8cd0 9c9a 8d8a 8b96
0000210 d086 9cd1 9190 9699 d098 969d d091 8a8c
0000220 8ff5 9196 c298 93d0 9d96 8cd0 9c9a 8d8a
0000230 8b96 d086 9cd1 9190 9699 d098 969d d091
0000240 968f 9891 8ff5 8c9e 888c c29b 93d0 9d96
0000250 8cd0 9c9a 8d8a 8b96 d086 9cd1 9190 9699
0000260 d098 969d d091 9e8f 8c8c 9b88 8cf5 9a97
0000270 9393 d0c2 969d d091 978c 8cf5 a08a 9e8f
0000280 8c8c 8dc2 99c9 cdcf 878b f591
< /end snip >

While a diff of my "somefile" and "uconf.inv" had too many inconsistent bytes, the fact that the two files were similar in size (wc -c somefile=532chars, wc -c uconf.inv=652chars), and that the first few bytes were consistent, brought me back to the SANS review:

< snipped from http://www.sans.org/y2k/the_compromise.htm >
Rootkit Directory
The rootkit is installed in a newly created directory named /lib/security/.config .

drwx------ root/lp 0 2000-11-25 14:46:14 ./.config/
drwx------ root/lp 0 2000-11-25 14:46:07 ./.config/backup/
-rwx------ root/lp 19464 2000-11-25 14:46:06 ./.config/backup/login
-rwx------ root/lp 5228 2000-11-25 14:46:07 ./.config/backup/network
-rwx------ root/lp 37884 2000-11-25 14:46:07 ./.config/backup/in.telnetd
drwx------ root/lp 0 2000-11-25 14:46:06 ./.config/bin/
-rws------ root/lp 14184 2000-11-25 14:46:06 ./.config/bin/su
-rws------ root/lp 20604 2000-11-25 14:46:06 ./.config/bin/ping
-rwx------ root/lp 25116 2000-11-25 14:46:06 ./.config/bin/du
-r-s------ root/lp 13536 2000-11-25 14:46:06 ./.config/bin/passwd
-rwx------ root/lp 74236 2000-11-25 14:46:06 ./.config/bin/find
-rwx------ root/lp 43740 2000-11-25 14:46:06 ./.config/bin/ls
-rwx------ root/lp 78012 2000-11-25 14:46:06 ./.config/bin/netstat
-rwx------ root/lp 83868 2000-11-25 14:46:06 ./.config/bin/lsof
-r-x------ root/lp 65148 2000-11-25 14:46:06 ./.config/bin/psr
-rw------- root/lp 652 2000-11-25 14:46:06 ./.config/uconf.inv
-rwx------ root/lp 205288 2000-11-25 14:46:07 ./.config/sshd
drwx------ root/lp 0 2000-11-25 14:46:07 ./.config/ssh/
-rw------- root/lp 525 2000-11-25 14:46:07 ./.config/ssh/ssh_host_key
-rw------- root/lp 329 2000-11-25 14:46:07 ./.config/ssh/ssh_host_key.pub
-rw------- root/lp 512 2000-11-29 18:46:12 ./.config/ssh/ssh_random_seed
-rw------- root/lp 461 2000-11-25 14:46:07 ./.config/ssh/sshd_config
-rwx------ root/lp 5064 2000-11-25 14:46:14 ./.config/ava
-rwx------ root/lp 4032 2000-11-25 14:46:14 ./.config/cleaner
-rwx------ root/lp 1596 2000-11-25 14:46:14 ./.config/sz
-rwx------ root/lp 960 2000-11-25 14:46:14 ./.config/patcher
-rwx------ root/lp 11970 2000-11-25 14:46:14 ./.config/pg
-rwx------ root/lp 3648 2000-11-25 14:46:14 ./.config/crypt
-rwx------ root/lp 3052 2000-11-25 14:46:14 ./.config/utime
-rwx------ root/lp 7028 2000-11-25 14:46:14 ./.config/lpsched
-rw------- root/lp 47238 2000-11-29 18:45:10 ./.config/mfs
< /end snip >

The majority of the files were consistent with standard root-kits, however I was not familiar with "uconf.inv" and I was curious to see "crypt" included. Could "somefile" be a standard Unix crypt'd file?

For the next several hours of analysis I attempted to un-encrypt "somefile" using crypt. I grabbed all the wordlists I could, and ran a script that would run crypt with each of the words as keys from my wordlists:

for $KEY in 'cat wordlist';
    crypt $KEY<somefile>somefile.$KEY

Chewing up significant disk space and much of my time analyzing the pages and pages of "somefile.$keys" I was beginning to get frustrated. Did Lance really expect this challenge to come down to brute force? Hardly.

I needed to take a break, step back, and re-evaluate my approach to this challenge. Breaking out my favorite Hex editor, BIEW (http://biew.sourceforge.net), I loaded up "somefile" to look at it from another angle. BIEW has some unique features like the ability to convert text from vi mode into 17 different code pages, and the ability to do simple cryptography (Bitwise NOT, OR, AND and XOR operations).

2. [How did you determine the encryption method?]

Analyzing various code-pages didn't enlighten me so I turned to running "somefile" against the Bitwise operations. BINGO!, "somefile" is encrypted using Bitwise NOT operations. Bitwise Not, is a simple method of reversing all bits, as seen below:

Take the following ASCII character "A":

 a            61H     01100001

Using Bitwise NOT, the binary is inverted to produce:

 .             9EH     10011110

3. [Decrypt the file, be sure to explain how you decrypted the file.]

I completed the Bitwise NOT conversion in BIEW, and wrote out my new unencrypted file as "somefile.unenc"

< somefile.unenc>






4. [Once decrypted, explain the purpose / function of the file and why it was encrypted.]

"somefile.unenc" is clearly a configuration file from a root-kit detailing the location of trojan binaries, processes / files to filter from viewing, ports to block from admins snooping with "netstat", and a su password for the black-hat "l33th4x0r". Corollary to the SANS compromise analysis, we now can assume the original name of "somefile" is uconf.inv .

Detailed Analysis of <somefile>:

'Location of trojaned find utility'

'Location of trojaned du utility'

'Location of trojaned ls utility'

file_filters=01,lblibps.so,sn.l,prom,cleaner,dos,uconf.inv,psb nc,lpacct,USER
'Detailed listing of files to be  sanitized from viewing from the above mentioned utilities, (find, du and ls)'

'Location of trojaned ps utility'

'Trojaned proceses to be removed from the output of a standard "ps" listing'

'Files to be removed from the output of List Open Files, included here is our configuration file, uconf.inv,and other trojaned binares (sniffers, sniffer logs, IRC and other trojaned ports,)

'Location of trojaned netstat program'

'Ports to filter from netstat output, 6668 is typically used for IRC, whil 47018 is most probably the entry port for our black hat.'

'Default login location to perform su to root'

'Location of trojaned ping utility'

'Location of trojaned passwd program'

'Default shell for our black hat'

'Access password with root privelidges for our black hat'

5. [What lesson did you learn from this challenge?]

The biggest lesson learned from this challenge was to examine all challenges from multiple angles. Had I continued to approach this challenge assuming "somefile" was encrypted with "crypt", I would have become extremely frustrated. Stepping away from the challenge for a while and rethinking my attack and approach gave me the clarity to see through the obscurity.

6. [How long did this challenge take you?]

Total analysis and documentation of this challenge took me approximately 10 hours.

Bonus Question:
[This encryption method and file are part of a security tool kit. Can you identify this tool kit?]

After completing the decrypt, and doing a silent little jig, (it was a pretty good feeling), I began my research into what security tool kit actually includes a file named "uconf.inv", what I believe to be the original name of "somefile". This proved a daunting task, harder than the decrypt itself. Although I have yet to identify the "actual" tool kit used in this attack, I have found some detailed information on a root kit that uses an encrypt method that was used to obfuscate "somefile". The Universal Root Kit by K2 (http://www.ktwo.ca/security.html) includes a C program to do the Bitwise NOT operation (inv.c) and a configuration file similar to <somefile>, named (urk.conf) that becomes (conf.inv) upon root kit compile and install. While this root kit, (K2 URK), appears to be be a foundation for the tool kit, I believe there is an updated version floating around in the ether that is being used to target Solaris boxes, specifically using the SnmpxDmid exploit. I base this analysis on the followingCERT advisory: http://www.cert.org/advisories/CA-2001-05.html.

CA-2001-05 lists the following trojan binaries found on exploited systems, which matches the unencrypted "somefile" contents:
System binaries replaced by a rootkit installed in /dev/pts/01/ and /dev/pts/01/bin
(the versions of 'ls' and 'find' installed by the rootkit do not show these directories)
The contents of /dev/pts/01 may include

The contents of /dev/pts/01/bin may include

While CA-2001-05 does not explicitly mention uconf.inv or conf.inv, there exists a system binary, urklogin, that leads me to belive this advisory is the result of a new root-kit in the wild bred from K2's URK.

< Code and configuration file snippets from K2's Universal Root Kit >

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char **argv)
   int c;
   FILE *file1,*file2;

   /* simple error checking */
   if(argc <= 1) {
      printf("Inverses the bit's in a file to make it unreadable.\n");
      printf("inv [file1] [file2]\n");
      return -1;

   /* read and write a file in binary mode, if error then exit */
   if (( file1 = fopen(argv[1],"rb")) == NULL ) {
      fprintf(stderr, "Cannot open input file: \"%s\".\n", argv[1]);
      return -2;


   /* while there is still input */
   while((c = getc(file1)) != EOF) {
   printf("File processed...\n");
   /* close */
   return 0;





/*  Change this to where you would like to store your config file
 MUST BE WORLD READABLE!!!  /tmp is not a good place

char *conf_file="/tmp/conf.inv";

 Default location and default filter's, these are used if the urk.conf
 cannot be found!!!

#define ls_loc_def "/usr/bin/ls"
#define du_loc_def "/usr/bin/du"
#define ps_loc_def "/usr/bin/ps"
#define su_loc_def "/usr/bin/su"
#define find_loc_def "/usr/bin/find"
#define net_loc_def "/usr/bin/netstat"
#define passwd_loc_def "/usr/bin/passwd"
#define ping_loc_def "/usr/sbin/ping"
#define shell_loc_def "/usr/local/bin/bash"

#define file_fil_def "xxxxx,yyyyy"
#define ps_fil_def "crack,xxxxxx.ps,psniff,ps.gnu"
#define net_fil_def "666,van,a1a89441"

#define su_default "h4x0r"

 You should not have to modify any of these

#define MAXLEN 1024

char *file_section="[file]";
char *ls_location="ls";
char *find_location="find";
char *du_location="du";
char *file_filters="file_filters";

char *ps_section="[ps]";
char *ps_location="ps";
char *ps_filters="ps_filters";

char *netstat_section="[netstat]";
char *netstat_location="netstat";
char *netstat_filters="net_filters";

char *login_section="[login]";
char *login_pass="su_pass";
char *su_location="su_loc";
char *ping_location="ping";
char *passwd_location="passwd";
char *exec_shell="shell";

char *f_ptr[256];

char *file(char *,char *,char *);
int count_filter(char *);
FILE *popen_r(char* name_to_use, char** argv, pid_t* return_pid)