-
Notifications
You must be signed in to change notification settings - Fork 4
How to use Railgun for Windows post exploitation
Railgun is a very powerful post exploitation feature exclusive to Windows Meterpreter. It allows you to have complete control of your target machine's Windows API, or you can use whatever DLL you find and do even more creative stuff with it. For example: say you have a meterpreter session on a Windows target. You have your eyes on a particular application that you believe stores the user's password, but it is encrypted and there are no tools out there for decryption. With Railgun, what you can do is you can either tab into the process and grep for any sensitive information found in memory, or you can look for the program's DLL that's responsible for the decryption, call it, and let it decrypt it for you. If you're a penetration tester, obviously post exploitation is an important skill to have, but if you don't know Railgun, you are missing out a lot.
The Windows API is obviously quite large, so by default Railgun only comes with a handful of pre-defined DLLs and functions that are commonly used for building a Windows program. These built-in DLLs are: kernel32, ntdll, user32, ws2_32, iphlpapi, advapi32, shell32, netapi32, crypt32, wlanapi, wldap32, version. The same list of built-in DLLs can also be retrieved by using the known_dll_names
method, via the railgun
object.
All DLL definitions are found in the "def" directory, where they are defined as classes. The following template should demonstrate how a DLL is actually defined:
# -*- coding: binary -*-
module Rex
module Post
module Meterpreter
module Extensions
module Stdapi
module Railgun
module Def
class Def_somedll
def self.create_dll(dll_path = 'somedll')
dll = DLL.new(dll_path, ApiConstants.manager)
# 1st argument = Name of the function
# 2nd argument = Return value's data type
# 3rd argument = An array of parameters
dll.add_function('SomeFunction', 'DWORD',[
["DWORD","hwnd","in"]
])
return dll
end
end
end; end; end; end; end; end; end
In function definitions, Railgun supports these datatypes: VOID, BOOL, DWORD, WORD, BYTE, LPVOID, HANDLE, PDWORD, PWCHAR, PCHAR, PBLOB.
There are four parameter/buffer directions: in, out, inout, and return. When you pass a value to an "in" parameter, Railgun handles the memory management. For example, MessageBoxA
has a "in" parameter named lpText
, and is of type PCHAR. You can simply pass a Ruby string to it, and Railgun handles the rest, it's all pretty straight forward.
An "out" parameter will always be of a pointer datatype. Basically you tell Railgun how many bytes to allocate for the parameter, it allocates memory, provides a pointer to it when calling the function, and then it reads that region of memory that the function wrote, converts that to a Ruby object and adds it to the return hash.
An "inout" parameter serves as an input to the called function, but can be potentially modified by it. You can inspect the return hash for the modified value like an "out" parameter.
A quick way to define a new function on the module's level can be done like the following example:
client.railgun.add_function('user32', 'MessageBoxA', 'DWORD',[
["DWORD","hWnd","in"],
["PCHAR","lpText","in"],
["PCHAR","lpCaption","in"],
["DWORD","uType","in"]
])
However, if this function will most likely be used more than once, or it's part of the Windows API, then you should put it in the library.
The best way to try Railgun is with IRB in a Windows Meterpreter prompt. Here's an example of how to get there:
$ msfconsole -q
msf > use exploit/multi/handler
msf exploit(handler) > run
[*] Started reverse handler on 192.168.1.64:4444
[*] Starting the payload handler...
[*] Sending stage (769536 bytes) to 192.168.1.106
[*] Meterpreter session 1 opened (192.168.1.64:4444 -> 192.168.1.106:55148) at 2014-07-30 19:49:35 -0500
meterpreter > irb
[*] Starting IRB shell
[*] The 'client' variable holds the meterpreter client
>>
Note that when you're running a post module or in irb, you always have a client
or session
object to work with, both point to the session object (Msf::Sessions::Meterpreter_x86_Win
or the 64bit version). This Meterpreter session object gives you API access to the target machine, including the Railgun object Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun
. Here's how you simply access it:
session.railgun
If you run the above in irb, you will see that it returns information about all the DLLs, functions, constants, etc. To call a Windows API function, here's how:
>> session.railgun.user32.MessageBoxA(0, "hello, world", "hello", "MB_OK")
=> {"GetLastError"=>0, "ErrorMessage"=>"The operation completed successfully.", "return"=>1}
As you can see this API call returns a hash. One habit we have seen is that sometimes people don't like to check GetLastError
, ErrorMessage
, and/or the return
value, they kind of just assume it works. This is a bad programming habit, and is not recommended.
https://www.youtube.com/watch?v=AniR-T0AnnI
https://www.defcon.org/images/defcon-20/dc-20-presentations/Maloney/DEFCON-20-Maloney-Railgun.pdf
https://dev.metasploit.com/redmine/projects/framework/wiki/RailgunUsage
- Home Welcome to Metasploit!
- Using Metasploit A collection of useful links for penetration testers.
-
Setting Up a Metasploit Development Environment From
apt-get install
togit push
. - CONTIBUTING.md What should your contributions look like?
- Landing Pull Requests Working with other people's contributions.
- Using Git All about Git and GitHub.
- Contributing to Metasploit Be a part of our open source community.
- Meterpreter All about the Meterpreter payload.