Shell Monitoring:Using A Modified Script UtilityRCBarnett@Hushmail.com |
During live incident response engagements, this implementation could be used to "wiretap" individual system accounts who have been identified as malicious. This would allow the incident response team to utilize a shell session monitoring mechanism which is both easy to implement and analyze the resulting data quickly.
The scope if this test will be to show how to implement, configure and then test the use of this modified script technique for capturing shell sessions.
Tool
Description:
One of the Honeynet
Project’s biggest obstacles has been developing effective methods of
Data Capture on Honeypot Systems. The following excerpts are
taken from the Honeynet Project’s paper entitled “Know Your Enemy: Honeynets”
located on the Projects website - http://project.honeynet.org/papers/honeynet/
-
| Data
Capture
Data capture is the capturing of all of the blackhat's activities. It is these activities that are then analyzed to learn the tools, tactics, and motives of the blackhat community. The challenge is to capture as much data as possible, without the blackhat knowing their every action is captured. This is done with as few modifications as possible, if any, to the honeypots. Also, data captured cannot be stored on locally on the honeypot. Information stored locally can potentially be detected by the blackhat, alerting them the system is a Honeynet. The stored data can also be lost or destroyed. Not only do we have to capture the blackhats every move without them knowing, but we have to store the information remotely… --CUT-- A second method to capturing system data is to modify the system to capture keystrokes and screen shots and remotely forward that data. The Honeynet Project is currently testing several tools that have this functionality. The first is a modified version of bash. This shell, developed by Antonomasia, can be used to replace the system binary /bin/bash. The trojaned shell forwards the user's keystrokes to syslogd, which is then forwarded to a remote syslog server. A second option is a modified version of TTY Watcher. This kernel module captures both user keystrokes and screen captures and forward this information over a non-standard TCP connection. There are a variety of other options to this functionality… |
You may be asking yourself, “Why do you need to have host-based session logging if you already have all of these network based monitoring tools?” Relying only on network based monitoring tools does capture the vast majority of keystrokes that are sent to a honeypot, either in the initial scans, probes, exploits and/or during the subsequent illegal sessions. The need for additional monitoring tools and host-based monitoring methods has grown due to changes in the attacker’s transport channels, specifically, the use of encrypted channels to access compromised systems. More and more attacker are including Secure Shell (SSH) servers within their rootkits. These encrypted channels essentially leave the network monitoring mechanisms blinded from clear text that would have been passed along the wire via telnet and ftp. There are some newer possibilities for “snooping in” on encrypted channels such as SSH (I.E.- using sshmitm from the dsniff tools suite), however, it is no piece of cake to implement effectively within a typical Honeynet environment. This technique would only work if the attacker would use your trojaned SSH server to access the honeypot. Playing “Man in the Middle” monitoring tricks is focusing on the transport of the attacker’s session, rather than the goal of the attacker, which is the root shell itself. This leads us to complimenting the existing network based monitoring tools with host based solutions.
The techniques discussed in the Honeynet
paper above are very effective. The only shortcoming of the modified
bash shell is that it only shows the attacker’s keystrokes and nothing
else. It does not show the output from these commands. Here
is an example of a honeypot syslog session while using the modified bash
shell mentioned above –
| Mar 16 08:47:05
asdf1 -bash: HISTORY: PID=4172 UID=0 ls
Mar 16 08:47:45 asdf1 -bash: HISTORY: PID=4172 UID=0 mkdir /var/... Mar 16 08:47:46 asdf1 -bash: HISTORY: PID=4172 UID=0 ls Mar 16 08:48:29 asdf1 -bash: HISTORY: PID=4172 UID=0 cd /var/... Mar 16 08:48:32 asdf1 -bash: HISTORY: PID=4172 UID=0 ftp ftp.home.ro Mar 16 08:54:35 asdf1 -bash: HISTORY: PID=4172 UID=0 tar -zxvf emech-2.8.tar.gz Mar 16 08:54:39 asdf1 -bash: HISTORY: PID=4172 UID=0 cd emech-2.8 Mar 16 08:54:44 asdf1 -bash: HISTORY: PID=4172 UID=0 ./configure Mar 16 08:55:04 asdf1 -bash: HISTORY: PID=4172 UID=0 y Mar 16 08:55:29 asdf1 -bash: HISTORY: PID=4172 UID=0 make |
This is essentially forwarding a bash history file to a remote host via the Syslog daemon. Don’t get me wrong this is tremendously useful information. The only shortcoming is that you cannot see “exactly” what the attacker saw. For example, in the 3rd line from the syslog file above, the attacker had just created a hidden directory within /var called “…” (dot dot dot). He then issued an “ls” to get a directory listing. Wouldn't it be nice if you could see what other files were located within this directory? Also, in line number 5, the attacker used FTP to connect to a remote server. The bash history file does not show any information about this session. What was the username that attacker used on the FTP host? What other files were on this host? That information would be even more valuable to an investigator than just relying on the bash history information.
This brings us to the method that I would like to introduce. This method includes using a modified version of the typical Unix “script” command to capture not only the attacker’s keystrokes, but also all text displayed to their screen including STDIN/OUT/ERR. Instead of seeing only keystrokes, this technique will give the Forensic Investigator an "Over the Shoulder" view of an attacker's shell session.
Script Details
Forensic Investigators have long relied
on the Unix “script” command for use as an audit record of their activities
on a compromised host. The script command essentially captures all
data that is displayed on the terminal screen and saves this record to
a file upon the exit of the script session. The MAN page for the
script command is rather short so I will include it here –
| SCRIPT(1)
System Reference Manual
SCRIPT(1)
NAME script - make typescript of terminal session SYNOPSIS script [-a] [-f] [-q] [-t] [file] DESCRIPTION
Script makes a typescript of everything printed on your terminal.
It is
If the argument file is given, script saves all dialogue in file. If no
Options:
-a Append the output to file or typescript,
retaining the prior con-
-f Flush output after each write. This is
nice for telecooperation:
-q Be quiet.
-t Output timeing data to standard error.
This data contains two
The script ends when the forked shell exits (a control-D to exit the
Certain interactive commands, such as vi(1), create garbage in the
type-
ENVIRONMENT The following environment variable is utilized by script:
SHELL If the variable SHELL exists, the shell forked by script will
be
SEE ALSO csh(1) (for the history mechanism). HISTORY The script command appeared in 3.0BSD. BUGS
Script places everything in the log file, including linefeeds and
Linux July 30, 2000 1 |
The script command has proven to be a very valuable tool for documenting actions taken by Forensic Analysts while investigating compromised systems. It wasn't until I started focusing on different ways to implement keystroke/session logging on honeypots, as opposed to logging forensic sessions, that I came back to this interesting utility.
The complete set of tools and applications for this test is as follows:
Test
Apparatus:
The testing was conducted on a closed
network. The network consisted of one Windows 2000 Workstation, which
was the VMWare Host OS machine. There was one RedHat Linux Guest
OS machines on the Windows 2000 Workstation. There was also two SUN
Microsystems SUNBlade 100 Workstations on the test network. The machines
were connected by a CableTron Systems Multi Port Repeater with LANVIEW-
MR9T 802.3 10BaseT. Since this test was conducted on a closed network,
the possibility for outside network interference was minimized. The
test environment used for these tests was:



Environmental
Conditions:
The testing was conducted on a closed
network. The machines were connected by a CableTron Systems Multi
Port Repeater with LANVIEW- MR9T 802.3 10BaseT. Since this test was
conducted on a closed network, the possibility for outside network interference
was minimized.
Test Network
Description
of the procedures --
Testing Phase:
There are two main issues to deal with
in regards to host based keystroke/session monitoring:
Question
1 - How do we force shell sessions into the script command?
An attacker will certainly not choose
to enter a script session, so we must come up with a way to FORCE them
into this session. We would also like this to happen behind the scenes,
so the attacker does not get suspicious. In order to accomplish this
task, I analyzed the normal system login procedure looking for a way to
tripwire a normal user account into using the standard Linux script utility.
Here is an overview, from the Bash MAN page, for the different ways that
a shell can be invoked: (All bolded lines within Pseudo Terminals are
either commands executed or important entries)
| INVOCATION
A login shell is one whose first character of argument zero is a -, or one started with the --login option. An interactive shell is one started without non-option arguments and without the -c option whose standard input and output are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state. The following paragraphs describe how bash executes its startup files. If any of the files exist but cannot be read, bash reports an error. Tildes are expanded in file names as described below under Tilde Expansion in the EXPANSION section. When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior. When a login
shell exits, bash reads and executes commands from the file ~/.bash_logout,
if it exists.
|
This means that if I can add some lines
of text to the user's home .bash_profile, I should be able to rediect them
into my modified script session. I ran an strace on the process of
spawning a login shell and looked for places to tripwire. The strace
log file shows that when root executes the following command "# /bin/sh
-login", the Bash Shell will try and emulate the Bourne Shell as much as
possible and it will eventually read the user's ~/.profile. This
is a potential place to put our booby-trap.
| [root@saphe3
rbarnett]# strace -o test1 /bin/sh -login
bash# exit [root@saphe3 rbarnett]# less test1 execve("/bin/sh", ["/bin/sh", "-login"], [/* 24 vars */]) = 0 brk(0) = 0x80994a0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000 open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 4 -- CUT -- rt_sigprocmask(SIG_BLOCK,
[CHLD], [], 8) = 0
|
On our Linux systems we have symbolically linked the normal Bourne Shell (/bin/sh) to point to the Bash Shell. This means that, for this scenario, we need to consider what shell our potential attacker might use. Since the vast majority of scripted attacks use the most common /bin/sh shell, we will need to focus on thisshell as well as Bash.
Note - All data that is updated within the ~/.bash_profile file, in the following examples, should be copied and renamed to the ~/.profile name so that it will catch all access attempts for the Bourne Shell.
During this analysis, I decided that the
user's home ~/.bash_profile would be the best place to conduct some testing.
I updated the appropriate login files (.profile, etc…) within the home
directories of all system users. I added the following lines to their
~/.bash_profile –
| [root@saphe3
rbarnett]# cat ./.bash_profile
# .bash_profile # Get the aliases
and functions
# User specific
environment and startup programs
export USERNAME BASH_ENV PATH exec /usr/bin/script
/tmp/shell_log.` date +'%Y-%m-%d:%H:%M:%S' `.$$
|
This configuration allowed for the normal login procedures of the system -> telnet -> login -> /etc/profile -> ~/.profile. At this point in the login process, the user has already authenticated, the system wide profiles have been applied and the user’s .profile has been applied all the way until the 2nd to last line in the file “/usr/bin/script /tmp/shell_log.` date +'%Y-%m-%d:%H:%M:%S' `.$$. The user is never actually dropped into their normal shell. The normal .profile process is suspended and they are instead put into a script session, with the session log being saved in the shell_log.date... file in the /tmp/ directory. It is important to designate a directory where the user has WRITE access, otherwise, the script session will error out.
A nice additional feature of this implementation is that even if the user spawned a different sub-shell (I.E. issued “$/bin/csh” to go to the C Shell) while within the script session, script would appropriately fork and log that sub-shell as well. Whatever the end user sees, is what is logged. When the user typed either “exit” or “Ctrl+D” to exit, they were then placed back into the suspended .profile process, which then logs them off the system. It is very important that the script command be executed with "exec", otherwise, the user would then be dropped into a normal shell and thus all of the script logging would stop. This process worked great during my testing phase to log all of the normal system user sessions. In addition to the text of the session, the beginning and end of the file included the normal date stamps of the session.
There was one drawback however. This
new session logging mechanism was not hidden from the user and they knew
that something suspicious was going on. When they logged in, the
were dutifully greeted with the normal Linux script session output (Bolded)
–
| Script started,
file is /tmp/shell_log.2002-08-15:14:05:13.18752
$ls file1 file2 file3 $exit Script done, file is /tmp/shell_log.2002-08-15:14:05:13.18752 |
This banner information announced to the user that they were in fact in the script session instead of a normal shell. If this method of keystroke/session monitoring was to be utilized on a live honeypot, these announcement messages from the script utility needed to be removed or altered. This is in accordance with Rule #1 of honeypot keystroke/session monitoring - Hide the monitoring from the attacker.
Modifying
the Script C Code:
In order to suppress the normal script
status messages, I needed to edit the source code of the script command.
I searched on the Web for the source code for this program and found it
within the utils-linux-2.11n.tar.gz file. I edited the file script.c
and made the following changes (diff changes are piped through ediff
for better readability ) to remove the Banner Messages –
| # diff script.c.orig
script.c | ediff
-------- 1 line
changed at 178 from:
-------- 1 line
changed at 333 from:
-------- 1 line added at 396: |
When compiling this new version of the
script command, I edited the default Makefile and added in the "-static"
flag for compiling. Here is an excerpt from the new Makefile entry
with the new "-static" flag bolded:
| # For script
only
LIBPTY= ifeq "$(HAVE_OPENPTY)" "yes" LIBPTY:=$(LIBPTY) -lutil -static endif |
We then run make to create the new binary.
The resulting compiled script binary was then statically linked, and therefore,
would not need to access and system shared libraries.
| [root@saphe3
misc-utils]# pwd
/mnt/util-linux-2.11n/misc-utils [root@saphe3 misc-utils]# make cc -s script.o -o script -lutil -static [root@saphe3 misc-utils]# file ./script ./script: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, stripped [root@saphe3 misc-utils]# cp ./script /usr/bin/bash_check |
I then renamed this file to the less conspicuous
name "bash_check" and placed it in the /usr/bin directory. Next,
I updated the ~/.bash_profile file to execute the new bash_check file instead
of the real script command. I have moved the execution of the script
further up into the normal ~/.bash_profile settings. This is used
for camouflaging the script execution. Note: Script will read the
environment setting of “SHELL” to execute during the script session.
Therefore, if you want the script sessions to log to bash (since this might
log commands in the ~/.bash_history file), you should specify it within
the “SHELL=” settings in the ~/.bash_profile and make sure that it comes
before the script command. I then tested it and it worked perfectly.
If I logged into the system as a normal user, the ~/.bash_profile executed
and it dumped me into the new /usr/bin/bash_check shell without any messages
displayed to the screen. I then executed the "ls -l" command and
when I exited the session, I was logged off the system without any exit
messages form the script session.
| [root@saphe3
rbarnett]# pwd
/home/rbarnett [root@saphe3 rbarnett]# cat ./.bash_profile # .bash_profile # Get the aliases
and functions
# User specific
environment and startup programs
export USERNAME BASH_ENV PATH [root@saphe3
rbarnett]# su - rbarnett
|
So, we have successfully removed the normal script banner messages displayed to the client. The next issue has to do with hiding the location of the default logfile that is generated by script upon logout. From the man page above, if no output file is designated, then script will simply dump all of its output in to a file called "typescript" within the local directory. This will not be adequate, since creating a new file in the target user's home directory would most certainly raise a flag. We could specify a different output file, such as the one that we showed in our initial test - /tmp/shell_log.date..., however showing this within the ~/.bash_profile would identify our logfile to the attacker. The best solution is to go back into the script.c source code and update the entry for the default output file.
We then edit the script.c file and changed
the default file's name and location. We are changing if from the
name "typescript" within the local directory to the name ".Xconfig.old"
within the /tmp directory.
| # diff script.c.orig
script.c | ediff
-------- 1 line changed at 164 from: fname = "typescript"; -------- to: fname = "/tmp/.Xconfig.old"; /*This is our new temp output file. This file will be deleted upon exiting the program. This is where you can specify another output file if you wish. You should create it in /tmp however so that normal user accounts can create the file.*/ |
I then ran a test with the newly compiled script utility to make sure that the new output file was created successfully. When you look at this next script test session, here are some things to notice:
| [root@saphe3
misc-utils]# ls -la /tmp
total 3156 drwxrwxrwt 9 root root 4096 Jun 13 14:00 . drwxr-xr-x 17 root root 4096 May 29 03:26 .. drwxrwxrwt 2 root root 4096 Jun 3 10:16 .ICE-unix -r--r--r-- 1 root root 11 Jun 3 10:16 .X0-lock drwxrwxrwt 2 root root 4096 Jun 3 10:16 .X11-unix drwxrwxrwt 2 xfs xfs 4096 Jun 3 10:09 .font-unix drwx------ 3 root root 4096 May 29 03:41 .gnome drwx------ 2 root root 4096 May 29 03:41 .gnome_private drwx------ 2 root root 4096 Jun 13 13:18 orbit-root drwxrwxr-x 4 201 201 4096 Nov 1 2001 vmware-linux-tools -r--r--r-- 1 root root 3184640 May 29 08:07 vmware-linux-tools.tar [root@saphe3 misc-utils]# su - rbarnett [rbarnett@saphe3 rbarnett]$ ls -la total 32 drwx------ 3 rbarnett rbarnett 4096 Jun 13 14:00 . drwxr-xr-x 3 root root 4096 May 29 03:55 .. -rw------- 1 rbarnett rbarnett 7 Jun 13 13:33 .bash_history -rw-r--r-- 1 rbarnett rbarnett 24 May 29 03:55 .bash_logout -rw-r--r-- 1 rbarnett rbarnett 256 Jun 13 13:31 .bash_profile -rw-r--r-- 1 rbarnett rbarnett 124 May 29 03:55 .bashrc -rw-r--r-- 1 rbarnett rbarnett 3394 May 29 03:55 .screenrc drwx------ 2 rbarnett root 4096 Jun 13 13:33 .xauth [rbarnett@saphe3 rbarnett]$ ls -la /tmp total 3156 drwxrwxrwt 9 root root 4096 Jun 13 14:02 . drwxr-xr-x 17 root root 4096 May 29 03:26 .. drwxrwxrwt 2 root root 4096 Jun 3 10:16 .ICE-unix -r--r--r-- 1 root root 11 Jun 3 10:16 .X0-lock drwxrwxrwt 2 root root 4096 Jun 3 10:16 .X11-unix -rw-rw-r-- 1 rbarnett rbarnett 0 Jun 13 14:02 .Xconfig.old drwxrwxrwt 2 xfs xfs 4096 Jun 3 10:09 .font-unix drwx------ 3 root root 4096 May 29 03:41 .gnome drwx------ 2 root root 4096 May 29 03:41 .gnome_private drwx------ 2 root root 4096 Jun 13 13:18 orbit-root drwxrwxr-x 4 201 201 4096 Nov 1 2001 vmware-linux-tools -r--r--r-- 1 root root 3184640 May 29 08:07 vmware-linux-tools.tar [rbarnett@saphe3 rbarnett]$ exit exit [root@saphe3 misc-utils]# ls -la /tmp total 3160 drwxrwxrwt 9 root root 4096 Jun 13 14:02 . drwxr-xr-x 17 root root 4096 May 29 03:26 .. drwxrwxrwt 2 root root 4096 Jun 3 10:16 .ICE-unix -r--r--r-- 1 root root 11 Jun 3 10:16 .X0-lock drwxrwxrwt 2 root root 4096 Jun 3 10:16 .X11-unix -rw-rw-r-- 1 rbarnett rbarnett 1930 Jun 13 14:02 .Xconfig.old drwxrwxrwt 2 xfs xfs 4096 Jun 3 10:09 .font-unix drwx------ 3 root root 4096 May 29 03:41 .gnome drwx------ 2 root root 4096 May 29 03:41 .gnome_private drwx------ 2 root root 4096 Jun 13 13:18 orbit-root drwxrwxr-x 4 201 201 4096 Nov 1 2001 vmware-linux-tools -r--r--r-- 1 root root 3184640 May 29 08:07 vmware-linux-tools.tar [root@saphe3 misc-utils]# cat /tmp/.Xconfig.old Script started on Thu Jun 13 14:02:13 2002 [rbarnett@saphe3 rbarnett]$ ls -la total 32 drwx------ 3 rbarnett rbarnett 4096 Jun 13 14:00 . drwxr-xr-x 3 root root 4096 May 29 03:55 .. -rw------- 1 rbarnett rbarnett 7 Jun 13 13:33 .bash_history -rw-r--r-- 1 rbarnett rbarnett 24 May 29 03:55 .bash_logout -rw-r--r-- 1 rbarnett rbarnett 256 Jun 13 13:31 .bash_profile -rw-r--r-- 1 rbarnett rbarnett 124 May 29 03:55 .bashrc -rw-r--r-- 1 rbarnett rbarnett 3394 May 29 03:55 .screenrc drwx------ 2 rbarnett root 4096 Jun 13 13:33 .xauth [rbarnett@saphe3 rbarnett]$ ls -la /tmp total 3156 drwxrwxrwt 9 root root 4096 Jun 13 14:02 . drwxr-xr-x 17 root root 4096 May 29 03:26 .. drwxrwxrwt 2 root root 4096 Jun 3 10:16 .ICE-unix -r--r--r-- 1 root root 11 Jun 3 10:16 .X0-lock drwxrwxrwt 2 root root 4096 Jun 3 10:16 .X11-unix -rw-rw-r-- 1 rbarnett rbarnett 0 Jun 13 14:02 .Xconfig.old drwxrwxrwt 2 xfs xfs 4096 Jun 3 10:09 .font-unix drwx------ 3 root root 4096 May 29 03:41 .gnome drwx------ 2 root root 4096 May 29 03:41 .gnome_private drwx------ 2 root root 4096 Jun 13 13:18 orbit-root drwxrwxr-x 4 201 201 4096 Nov 1 2001 vmware-linux-tools -r--r--r-- 1 root root 3184640 May 29 08:07 vmware-linux-tools.tar [rbarnett@saphe3 rbarnett]$ exit exit Script done
on Thu Jun 13 14:02:33 2002
|
We are now moving in the right direction, however, we are still storing the shell session output locally on the system. This does not conform to Rule 2 - Ensuring the integrity of the data, as discussed in the previous Data Capture description by the Honeynet Project. We need to implement a means to transfer the shell session logs to a remote host.
Question
2 - How do we log the shell sessions remotely?
So in addition to removing the text messages
of the script command, we also need to figure out a way to abide by rule
#2 of honeypot keystroke/session monitoring - Ensuring the integrity
of the data that is captured. We needed to come up with a method
of remote logging of these sessions, rather than having the script session
logs lying around on the honeypots.
To accomplish this task, I decided to use
some additional system tools to aid in the process. I used the “logger”
utility (which is included within the TAR archive utils-linux-2.11n.tar.gz
mentioned above) to send the output of the new script sessions to the syslogd
daemon. Logger will basically send data to the syslogd facility for
inclusion into the syslog files. Here is the MAN page for logger
–
| LOGGER(1)
System Reference Manual
LOGGER(1)
NAME logger - make entries in the system log SYNOPSIS logger [-isd] [-f file] [-p pri] [-t tag] [-u socket] [message ...] DESCRIPTION
Logger provides a shell command interface to the syslog(3) system log
Options: -i Log the process id of the logger process with each line. -s Log the message to standard error, as well as the system log. -f file Log the specified file.
-p pri Enter the message with the specified priority.
The priority may
-t tag Mark every line in the log with the specified tag.
-u sock Write to socket as specified with socket instead of builtin
sys-
-d Use a datagram instead of a stream connection to this socket.
-- End the argument list. This is to
allow the message to start
message Write the message to log; if not specified, and the -f flag
is
The logger utility exits 0 on success, and >0 if an error occurs.
Valid facility names are: auth, authpriv (for security information of a
Valid level names are): alert, crit, debug, emerg, err, error (deprecated
EXAMPLES logger System rebooted logger -p local0.notice -t HOSTIDM -f /dev/idmc SEE ALSO syslog(3), syslogd(8) STANDARDS
The logger command is expected to be IEEE Std1003.2 (``POSIX'') compati-
4.3 Berkeley Distribution June 6, 1993 1 |
So, with logger, our goal is to take the
data from the script session output file - /tmp/.Xconfig.old and send them
on to syslogd for processing. This way, we can rely on syslog to
forward the messages via the normal remote syslog logging capabilities.
The first step is to once again edit the script.c source code and add in
additional C code to run the logger command upon exiting the modified script
session. Here is the additional code that I added to script.c:
| # diff script.c.orig
script.c | ediff
-------- 2 lines added at 329: system("/usr/bin/logger -i -f /tmp/.Xconfig.old -p daemon.warn -t SHELL"); system("cat /dev/null > /tmp/.Xconfig.old"); /*This is the added code that will send all output from the script log file through the logger program to syslog and then the temp file is deleted. This will allow for remote logging via syslog as well as clean up after script sessions so that there are no session files lying around.*/ |
In the above code we are accomplishing the following tasks:
| [root@saphe3
misc-utils]# pwd
/mnt/util-linux-2.11n/misc-utils [root@saphe3 misc-utils]# cc -s logger.o -o logger -static [root@saphe3 misc-utils]# file ./logger ./logger: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, stripped [root@saphe3 misc-utils]# mv ./logger /usr/bin/logger |
I then ran a quick test to verify that the logfile output would indeed be sent to the local syslogd by logger. I went into the /var/log directory and ran the tail command on the messages file and then, in another terminal window, I su'ed to the booby-trapped rbarnett account.
TERMINAL 1 - Monitoring the messages file for logger data
| [root@saphe3
log]# pwd
/var/log [root@saphe3 log]# tail -f messages |
TERMINAL 2 - Su to rbarnett user session
| [root@saphe3
/root]# su - rbarnett
[rbarnett@saphe3 rbarnett]$ w 3:26pm up 6:20, 3 users, load average: 0.02, 0.03, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root tty1 - 3Jun 2 6:20m 1:40 0.02s sh /usr/X11R6/b root pts/0 :0 3Jun 2 38.00s 0.69s 0.01s /usr/bin/script root pts/1 :0 2:48pm 0.00s 0.17s 0.01s /usr/bin/script [rbarnett@saphe3 rbarnett]$ exit exit |
TERMINAL 1 - Monitoring the messages file for logger data
| [root@saphe3
log]# tail -f messages
Jun 13 15:26:10 saphe3 PAM_pwdb[6073]: (su) session opened for user rbarnett by (uid=0) Jun 13 15:26:15 saphe3 SHELL[6109]: Script started on Thu Jun 13 15:26:10 2002 Jun 13 15:26:15 saphe3 SHELL[6109]: [rbarnett@saphe3 rbarnett]$ w^M Jun 13 15:26:15 saphe3 SHELL[6109]: 3:26pm up 6:20, 3 users, load average: 0.02, 0.03, 0.00^M Jun 13 15:26:15 saphe3 SHELL[6109]: USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT^M Jun 13 15:26:15 saphe3 SHELL[6109]: root tty1 - 3Jun 2 6:20m 1:40 0.02s sh /usr/X11R6/b^M Jun 13 15:26:15 saphe3 SHELL[6109]: root pts/0 :0 3Jun 2 38.00s 0.69s 0.01s /usr/bin/script^M Jun 13 15:26:15 saphe3 SHELL[6109]: root pts/1 :0 2:48pm 0.00s 0.17s 0.01s /usr/bin/script^M Jun 13 15:26:15 saphe3 SHELL[6109]: [rbarnett@saphe3 rbarnett]$ exit^M Jun 13 15:26:15 saphe3 SHELL[6109]: exit^M Jun 13 15:26:15 saphe3 SHELL[6109]: Script done on Thu Jun 13 15:26:15 2002 Jun 13 15:26:15 saphe3 PAM_pwdb[6073]: (su) session closed for user rbarnett |
As you can see in the second TERMINAL 1
screen, the logger code worked! Once the user exited the script session,
the data from the /tmp/.Xconfig.old file was sent through syslogd.
Now that we have confirmed that the modified script utility will send that
log data through syslogd, we need to modify the /etc/syslog.conf file to
send this information to a remote syslog host. This step will ensure
the integrity of the data by not keeping it stored locally on the compromised
system. I then updated the local /etc/syslog.conf file and added
in the appropriate lines for remote logging. I then needed to send
a hang-up signal to the syslog daemon process so that it would read the
new configuration:
| [root@saphe3
/etc]# diff syslog.conf.orig syslog.conf | ediff
-------- 2 lines
added at 14:
[root@saphe3
log]# ps -ef | grep syslogd
|
On the remote logging host (IP address
of 10.XXX.XXX.60) I then used tail to watch the messages file for any new
script sessions sent from this host.
| # hostname
saphe2 # uname -a SunOS saphe2 5.8 Generic_108528-06 sun4u sparc SUNW,Sun-Blade-100 # pwd /var/adm # tail -f messages |
I then su'ed to the rbarnett user on the
linux host and issued the "last -5" command and exited.
| [root@saphe3
log]# su - rbarnett
[rbarnett@saphe3 rbarnett]$ last -5 root pts/0 :0 Thu Jun 13 16:20 still logged in root pts/1 :0 Thu Jun 13 14:48 still logged in root pts/0 :0 Mon Jun 3 10:16 - 16:20 (10+06:04) root tty1 Mon Jun 3 10:16 still logged in reboot system boot 2.2.14-5.0 Mon Jun 3 10:09 (10+06:18) wtmp begins Mon
Jun 3 10:09:15 2002
|
Back on the remote logging host, this is
what I received:
| # hostname
saphe2 # uname -a SunOS saphe2 5.8 Generic_108528-06 sun4u sparc SUNW,Sun-Blade-100 # pwd /var/adm # tail -f messages Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: Script started on Thu Jun 13 16:27:33 2002 Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: [rbarnett@saphe3 rbarnett]$ last -5^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: root pts/0 :0 Thu Jun 13 16:20 still logged in ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: root pts/1 :0 Thu Jun 13 14:48 still logged in ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: root pts/0 :0 Mon Jun 3 10:16 - 16:20 (10+06:04) ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: root tty1 Mon Jun 3 10:16 still logged in ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: reboot system boot 2.2.14-5.0 Mon Jun 3 10:09 (10+06:18) ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: ^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: wtmp begins Mon Jun 3 10:09:15 2002^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: [rbarnett@saphe3 rbarnett]$ exit^M Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: Script done on Thu Jun 13 16:27:40 2002 Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: Jun 13 16:54:15 [10.XXX.XXX.51.2.2] SHELL[6256]: exit^M |
It worked! The entire script shell session log was successfully sent to the remote syslog host 10.XXX.XXX.60. While this implementation did work, I realized that this current configuration still did not satisfy both of our determined Rules.
| # snoop -v
10.XXX.XXX.51 udp and port 514 > snoop_test
Using device /dev/eri (promiscuous mode) # grep SYSLOG snoop_test |more UDP: Destination port = 514 (SYSLOG) SYSLOG: ----- SYSLOG: ----- SYSLOG: SYSLOG: "<28>SHELL[7129]: Script started on Fri Jun 14 13:53:52 2002" SYSLOG: UDP: Destination port = 514 (SYSLOG) SYSLOG: ----- SYSLOG: ----- SYSLOG: SYSLOG: "<28>SHELL[7129]: SHELL[7129]: [root@saphe3 rbarnett]# cat /etc/shadow^M" SYSLOG: UDP: Destination port = 514 (SYSLOG) SYSLOG: ----- SYSLOG: ----- SYSLOG: SYSLOG: "<28>SHELL[7129]: root:$1$NbInhLiT$5Mu0qCI.cyPbKSAmarBdg.:118" SYSLOG: UDP: Destination port = 514 (SYSLOG) SYSLOG: ----- SYSLOG: ----- SYSLOG: SYSLOG: "<28>SHELL[7129]: bin:*:11836:0:99999:7:::^M\n" SYSLOG: --CUT-- SYSLOG:
|
Not only could this network traffic tip off the attacker as to what/how we are logging, but we must also consider the sensitivity of the data that is being transferred. In the example shown above, the intruder viewed the contents of the /etc/shadow file. This sent the encrypted password for all system accounts (including root) across the wire in clear text. This is not a very good scenario. I needed to come up with a way to transfer the data to the remote host in a more secure manner.
Question
4 - How can I transfer the files securely?
This is where the use of Cryptcat comes
into play. Cryptcat is essentially Netcat, except that it uses encryption.
If you are unfamiliar with Netcat, here is a quick blurb from the Netcat
README file -
| Netcat 1.10
=========== /\_/\ / 0 0 \ Netcat is a simple Unix utility which reads and writes data ====v==== across network connections, using TCP or UDP protocol. \ W / It is designed to be a reliable "back-end" tool that can | | _ be used directly or easily driven by other programs and / ___ \ / scripts. At the same time, it is a feature-rich network / / \ \ | debugging and exploration tool, since it can create almost (((-----)))-' any kind of connection you would need and has several / interesting built-in capabilities. Netcat, or "nc" as the ( ___ actual program is named, should have been supplied long ago \__.=|___E as another one of those cryptic but standard Unix tools. / |
Here is a some information about Cryptcat
from the README.cryptcat file:
| cryptcat = netcat + encryption
Cryptcat is the standard netcat enhanced with twofish encryption. Twofish is courtesy of counterpane,
and cryptix. We started with the
How do you use it? Machine A: cryptcat -l -p 1234
< testfile
This is identical to the normal netcat
options for doing exactly the
|
So, Cryptcat will allow us to send arbitrary
data across the network through an encrypted channel! This sounds
like the exact type of utility we need to use to complete our script session
data. The first step in implementing Cryptcat is to actually build
the application from the source code. In the session below, I show
how I configured Cryptcat for use on the Linux VMWare host system.
| [root@saphe3
/mnt]# tar -xvf cryptcat_linux2.tar
cryptcat/ cryptcat/Changelog cryptcat/cryptcat cryptcat/farm9crypt.cc cryptcat/farm9crypt.h cryptcat/generic.h cryptcat/Makefile cryptcat/netcat.blurb cryptcat/netcat.c cryptcat/README cryptcat/README.cryptcat cryptcat/twofish2.cc cryptcat/twofish2.h [root@saphe3 /mnt]# cd cryptcat [root@saphe3 cryptcat]# ls Changelog README.cryptcat farm9crypt.h netcat.c Makefile cryptcat generic.h twofish2.cc README farm9crypt.cc netcat.blurb twofish2.h [root@saphe3 cryptcat]# grep metallica netcat.c char * crypt_key_f9 = "metallica"; [root@saphe3 cryptcat]# cp netcat.c netcat.c.orig [root@saphe3 cryptcat]# vi netcat.c [root@saphe3 cryptcat]# diff netcat.c.orig netcat.c 1333c1333 < char * crypt_key_f9 = "metallica"; --- > char * crypt_key_f9 = "honeypot"; [root@saphe3
cryptcat]# make linux
|
Some steps to notice from the session above:
| [root@saphe3
misc-utils]# diff script.c.orig script.c | ediff
-------- 3 lines added at 329: system("cat /tmp/.Xconfig.old | /usr/bin/dns_helper -w 2 10.XXX.XXX.53 53"); system("cat /dev/null > /tmp/.Xconfig.old"); |
This updated code will send the data in the script output file through an encrypted TCP channel to the remote host on port 53. Obviously, the remote host would have to have cryptcat listening on TCP port 53 to receive the data. UDP was considered as the protocol, since attackers do not normally sniff UDP traffic. After testing the UDP cryptcat sessions, it was found that when large amounts of UDP data was sent, there was a tendency for some of the data to become lost. Additionally, TCP port 53 was selected due to DNS' normal chatty nature. This data could be seen as possible DNS traffic if an attacker has installed a sniffer and doesn't look closely enough at the data. Notice the use of the “-w” flag. This is needed to prevent the sessions from hanging and so that it allows enough time for the full script log file to be sent to the remote log host. Next, we recompile the script.c file and place it back in the /usr/bin directory with the filename - bash_check. We then startup up a cryptcat session on the remote logging server:
Remote Logging Host
| [root@saphe4
cryptcat]# ./cryptcat -vv -l -p 53
listening on [any] 53 ... |
Honeypot System
| [root@saphe3
misc-utils]# su - rbarnett
[rbarnett@saphe3 rbarnett]$ who root tty1 Jun 3 10:16 root pts/0 Jun 14 17:01 root pts/1 Jun 13 14:48 [rbarnett@saphe3 rbarnett]$ exit exit |
Remote Logging Host
| [root@saphe4
cryptcat]# ./cryptcat -vv -l -p 53
listening on [any] 53 ... 10.XXX.XXX.51: inverse host lookup failed: Unknown host connect to [10.XXX.XXX.53] from (UNKNOWN) [10.XXX.XXX.51] 1028 Script started on Mon Jun 17 11:06:45 2002 [rbarnett@saphe3 rbarnett]$ who root tty1 Jun 3 10:16 root pts/0 Jun 14 17:01 root pts/1 Jun 13 14:48 [rbarnett@saphe3 rbarnett]$ exit exit Script done
on Mon Jun 17 11:06:49 2002
|
It worked! The remote cryptcat session on SAPHE4 received the script session data. The last test for this transport mechanism is to confirm that this data is indeed sent across the wire in an encrypted form. I then ran the exact same test from above, except I ran a SNOOP session on a Solaris host. Here is an example of the data that it received:
The bolded lines show the Twofish encrypted payloads:
| # snoop -v
10.XXX.XXX.51 tcp and port 53 > /tmp/snoop_test
Using device /dev/eri (promiscuous mode) # grep DNS /tmp/snoop_test |less TCP: Destination port = 53 (DNS) DNS: ----- DNS: ----- DNS: DNS: "Esu\36K\350\235\347t\323^\30u\26Ri-\27\303U\303WrF/\215\373\355<ou&\201\355\17\306b \347\360\373^#\340d\324<|I\332;&t\215\273\367yn\274k\326" DNS: TCP: Destination port = 53 (DNS) DNS: ----- DNS: ----- DNS: DNS: "\257Z\222Z\214\263\3278cqM;?^?\t" DNS: TCP: Destination port = 53 (DNS) DNS: ----- DNS: ----- DNS: DNS: "" DNS: TCP: Destination port = 53 (DNS) DNS: ----- DNS: ----- DNS: DNS: "<\32mK\bT\202\27070ws\375\276 U" DNS: TCP: Destination port = 53 (DNS) DNS: ----- DNS: ----- DNS: DNS: "\327\321l&\204/\0L'[3k!\345\255\211" DNS: |
We have done it! We now have our encrypted transport channel.
Question
5 - How can we verify the integrity of the data?
Since cryptcat will be using TCP as the
transport protocol, there is some degree of reliability from the network
perspective. TCP has a built-in capability to verify if the data
sent out actually made it to the destination host. Using TCP as the
transport protocol is desired from a Forensic Examiner's perspective.
Even with the protocol's built-in verification, we need to be able to forensically
verify that the data received by our logging host was identical to the
data capture on the honeypot. This is where we implement the use
of the MD5 utility.
MD5 will take a file as input and generate
a unique 128 bit hash signature. This signature is considered mathematically
unique so that no two different files should ever have the same MD5 checksum.
MD5 is often used by security professionals to validate their tools, etc...
We therefore need to install a statically compiled version of MD5 on our
honeypot system.
| [root@saphe3
/mnt]# tar -xvf md5-6142000.tar
md5/Makefile md5/README md5/global.h md5/md5-announcement.txt md5/md5.1 md5/md5.1.ps md5/md5.1.txt md5/md5.h md5/md5c.c md5/mddriver.c md5/rfc1321.txt md5/test.rfc [root@saphe3 /mnt]# cd md5 [root@saphe3 md5]# vi Makefile [root@saphe3 md5]# grep static Makefile gcc -o md5 md5c.o mddriver.o -static [root@saphe3 md5]# make gcc -c -O -DMD=5 md5c.c gcc -c -O -DMD=5 mddriver.c gcc -o md5 md5c.o mddriver.o -static [root@saphe3 md5]# file md5 md5: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, not stripped [root@saphe3 md5]# cp md5 /usr/bin/ |
In order to provide a data integrity check
into our modified script scenario, we will need to update the script source
code once again.
| [root@saphe3
misc-utils]# diff script.c.orig script.c | ediff
-------- 4 lines
added at 329:
|
This line of additional code will create an MD5 checksum of the /tmp/.Xconfig.old file and append this data to the end of the file. The next steps are the same as before. After recompiling the script source and renaming it to over-write our previous version of /usr/bin/bash_check, we are ready for another test. We once again startup a cryptcat session on our remote logging host, however, this time we redirect the output received into a file called test1.
Remote Logging Host
| [root@saphe4
cryptcat]# ./cryptcat -vv -l -p 53 > test1
listening on [any] 53 ... |
Honeypot Host
| [ |