Sunday, April 20, 2008

Automated Shellcode Analysis

Working with Lenny Zeltser in his SANS Malware Analysis course, I was able to cobble together a script to automate shellcode analysis preparation. The analysis involves wrapping the shellcode in a shell function, then compiling it into a small program. There are several ways to do this, including using an empty C main function (Lenny) and injecting the shellcode into a husk executable (iDefense). I didn't want to use the injection method since it falls prey to two problems. 1) The husk is always the same size, only the shellcode changes (might be good for diff comparisons). I wanted something smaller. 2) The shellcode must fit into the blank space in the husk, which opens it up to possible overflow attack or, at least, shellcode size limitation. Compiling yourself avoids this problem.

Here's the script I hacked together. With a little work, I plan to put it to a CGI frontend with a return of the disassembled output.

Shellcode Analysis Script

bt shellcodetest # cat shellcode_analyzer.sh
#!/bin/sh
# a little script to clean up shellcode, parse it, convert to
little-endian, and compile into the smallest wrapper possible.
# based on instruction provided by Lenny Zelster.

# hacked together by
# Andrew Hunt
# 4/19/08
# Copyright 2008 Creative Commons Share-Alike
# http://creativecommons.org/licenses/by-sa/3.0/us/

# this script is very alpha, assuming you will call with a text file
argument. text file should have the unicode pasted in it,
# like `./shellcode_analyzer.sh shellcode.unicodeorhex.strings.file`.
# it comes without any warranties or promises.
#
# user needs to replace the script path and script for unescaping
unicode/hex/other with the path to their own script or an unescaping
routine.
# some replacement suggestions if you don't have a script...
#
# perl -pe 's/\\x(..)/chr(hex($1))/ge'
# perl -pe 's/[\%\\]u(..)(..)/chr(hex($2$1))/ge'

cat $1 | perl -pe "s/\'\+\'//g" | perl -pe 's/\"\+\"//g' | perl -pe
's/\"//g' | perl -pe "s/\'//g" | perl /mnt/sda1/scripts/unescape.pl >
/tmp/test5.bin

cat /tmp/test5.bin | hexdump | awk '{print $2 $3 $4 $5 $6 $7 $8 $9}' |
perl -pe 's/(..)(..)/print("\"\\x".$2."\\x".$1."\"\n")/ge' | grep -P
'^\"'>/tmp/test6.hex


echo "unsigned char shellcode[]="> /tmp/test7.c
cat /tmp/test6.hex >> /tmp/test7.c
echo ";" >> /tmp/test7.c
echo "int main(){}" >> /tmp/test7.c

gcc -c -o shellcode-compiled /tmp/test7.c
objdump -D shellcode-compiled > shellcode.disasm
rm -f /tmp/test*

# optional
less shellcode.disasm