From bill.cummins@cingular.com Fri Jun 22 08:49:28 2001
Date: Wed, 20 Jun 2001 10:33:34 -0500
From: "Cummins, Bill" <bill.cummins@cingular.com>
To: "'project@honeynet.org'" <project@honeynet.org>
Cc: "BOCHONKO, WALLY G (SBMS)" <wally.g.bochonko@cingular.com>,
     "'wrc@pobox.com'" <wrc@pobox.com>
Subject: Scan of the Month -- June (#16)

Too easy.  You gave it away by saying it was a rootkit.  This implies that
it is either trivial (simple repeating-key XOR, crypt() ), or non-trivial
(DES, RC4, etc.).  Since one of the goals is to decrypt it, it must be
trivial.  Here's some short answers to the questions:

1.  Algorithm
XOR, with one byte (0xFF), or bit (1), depending on your point of view.

2.  Determination
A quick frequency check of the supplied data shows that it is text of some
sort.  Ciphertext this short makes a freq analysis iffy, unless it is text
with lots of spaces or newlines.  What luck! 

hexdump -f hexa somefile | sort | uniq -c | sort -nr | head  #(2-byte
combos)
   7 d091
   7 969d
   7 8fd0
   7 8c8f
   7 8c8b
   6 d0ce
   6 cfd0
   6 9bd0
   6 9196
   6 899a

hexdump -f hexb somefile | sort | uniq -c | sort -nr | head #(1-byte)
  48 8c
  45 d0
  34 8f
  30 d3
  29 91
  28 8b
  27 93
  24 9a
  24 96
  18 f5

...Obviously text.  Obviously simple XOR, crypt() would show -some-
randomness in a file this short.

3.  Decryption

---SNIP---
[file]
find=/dev/pts/01/bin/find
du=/dev/pts/01/bin/du
ls=/dev/pts/01/bin/ls
file_filters=01,lblibps.so,sn.l,prom,cleaner,dos,uconf.inv,psbnc,lpacct,USER

[ps]
ps=/dev/pts/01/bin/psr
ps_filters=lpq,lpsched,sh1t,psr,sshd2,lpset,lpacct,bnclp,lpsys
lsof_filters=lp,uconf.inv,psniff,psr,:13000,:25000,:6668,:6667,/dev/pts/01,s
n.l,
prom,lsof,psbnc

[netstat]
netstat=/dev/pts/01/bin/netstat
net_filters=47018,6668

[login]
su_loc=/dev/pts/01/bin/su
ping=/dev/pts/01/bin/ping
passwd=/dev/pts/01/bin/passwd
shell=/bin/sh

su_pass=l33th4x0r
---SNIP---

>From the previous freq analysis, it's obviously XOR, and obviously text.
The key must be short, since the 2-byte pairs have such a high frequency.
At a glance, the key is probably 4 bytes or less to get that much out of 532
bytes of ciphertext, even without looking at the pair offsets to make a
better determination.

Assuming the text is ascii (source code, sniff log, config file), the fact
that every significant bit is '1' implies that the key is -not- ascii, or
ascii rotated so that every msb is fortuitously a '1'.  

I'm lazy.  I snagged xor-analyze-0.1 to automate some keyspace searching and
comparisons.  It took some hacking to actually make it work correctly(ish).
Once it was working, it came up with the key 0xff (even though it figured on
a keylength of 4 bytes, my guess of a max length).  This looked good to me,
so I applied it against the first few bytes of the ciphertext.  Once I got
to the 'e' of [file], I knew it was correct.  I decrypted the rest of the
file w/the key.

4.  Purpose
It's the config file for a rootkit.  It lets the running processes know what
to hide from whom, along with the 'secret password', probably for a
backdoored /bin/su.  It's encrypted/obfuscated to guard against prying eyes.

5.  Lessons
-Crappy code still works, with enough toil.
-It's better to encrypt for real, even if you have to have the key in
memory.
-Never use the defaults in a rootkit.

6.  Time
It took half an hour to finally decrypt the file.  It took an hour to fix
xor-analyze.



-Bill


--
William R. Cummins  **  Cingular GLR Information Security
847-765-5315        **  bill.cummins@cingular.com