Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Railgun datatype updates #14448

Merged
merged 4 commits into from
Dec 7, 2020
Merged

Conversation

zeroSteiner
Copy link
Contributor

This updates a whole bunch of Railgun stuff. The intention is to correct the PDWORD data type to always be handled as a pointer to an unsigned 32-bit integer, regardless of the host architecture. This fixes #14400. In doing this, a number of definitions needed to be updated from PDWORD to PHANDLE or PSIZE_T where PDWORD was being used previously. In these cases, the functions were reliant on Railgun's misinformed interpretation of the PDWORD datatype. Functions which actually needed a legit PDWORD were broken on 64-bit systems as they'd be treated incorrectly as having a 64-bit width.

Now the PHANDLE and PSIZE_T datatypes are new, and they're both1 actually PULONG_PTR (that is to say PHANDLE == PSIZE_T == PULONG_PTR) which is also a new data type. The new PULONG_PTR data type replaces Railgun's PDWORD and acts as it did when it was broken. You can see in the documentation that it's width is dependant on the host architecture. The PHANDLE and PSIZE_T types use a new type map which allows us to have a closer mapping to the original function definitions/documentation on MSDN. Eventually, I think we should move towards even more explicit definitions such as defining DWORD as uint32_t for example. This would help prevent us from having to update the definitions in the future which would ideally only need to be done when they are inconsistent with what Microsoft has published.

I also consolidated the Meterpreter packet building code for both the single and multi dispatch routines. This reduces code reuse and will make refactoring easier in the future since there are fewer places that need to be updated to add, remove, and change data types.

Verification

  • post/test/railgun should work, all tests should pass
  • post/test/railgun_reverse_lookups should also work with all tests passing
  • The steps to reproduce Railgun uses incorrect size for PDWORD values on x64 systems #14400 should show that the issue has been fixed, check_dir_perms now functions correctly
    • You'll need to use a 64-bit meterpreter session and grant privileges to everyone on a service executable for a true test case showing it works

1 https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#size_t

@zeroSteiner zeroSteiner added the bug label Dec 1, 2020
@zeroSteiner zeroSteiner changed the title Railgun updates Railgun datatype updates Dec 1, 2020
@zeroSteiner zeroSteiner added the code quality Improving code quality label Dec 1, 2020
@bwatters-r7 bwatters-r7 self-assigned this Dec 2, 2020
@bwatters-r7
Copy link
Contributor

Hrm.....

[*] Started reverse TCP handler on 192.168.135.197:4444 
[*] Sending stage (200262 bytes) to 192.168.134.110
[*] Meterpreter session 1 opened (192.168.135.197:4444 -> 192.168.134.110:50330) at 2020-12-03 10:38:55 -0600

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : DESKTOP-D1E425Q
OS              : Windows 10 (10.0 Build 17134).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: DESKTOP-D1E425Q\msfuser
meterpreter > background
[*] Backgrounding session 1...
msf6 payload(windows/x64/meterpreter/reverse_tcp) > loadpath test/modules/
Loaded 36 modules:
    13 auxiliary modules
    13 exploit modules
    10 post modules
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use post/test/railgun
msf6 post(test/railgun) > set session 1
session => 1
msf6 post(test/railgun) > set verbose true
verbose => true
msf6 post(test/railgun) > run

[!] SESSION may not be compatible with this module.
[*] Running against session 1
[*] Session type is meterpreter and platform is windows
[-] FAILED: Should include error information in the results
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support functions with no parameters
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support functions with literal parameters
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support functions with in/out/inout parameter types
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support calling multiple functions at once
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support writing memory
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[-] FAILED: Should support reading memory
[-] Exception: Rex::ArgumentError : An invalid argument was specified. Type unknown: HANDLE. Allowed types: ["VOID",
 "BOOL",
 "BYTE",
 "WORD",
 "DWORD",
 "LPVOID",
 "ULONG_PTR",
 "PDWORD",
 "PULONG_PTR",
 "PWCHAR",
 "PCHAR",
 "PBLOB"]

[*] Testing complete in 0.2089979
[*] Passed: 7; Failed: 0
[*] Post module execution completed
msf6 post(test/railgun) > 

@zeroSteiner
Copy link
Contributor Author

Thanks for testing @bwatters-r7 I was able to reproduce this. I must have made some kinda silly mistake. I'll let you know once I've fixed it.

@bwatters-r7
Copy link
Contributor

[*] Started reverse TCP handler on 192.168.135.197:4444 
[*] Sending stage (200262 bytes) to 192.168.134.110
[*] Meterpreter session 1 opened (192.168.135.197:4444 -> 192.168.134.110:50362) at 2020-12-03 14:21:19 -0600

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : DESKTOP-D1E425Q
OS              : Windows 10 (10.0 Build 17134).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: DESKTOP-D1E425Q\msfuser
meterpreter > background
[*] Backgrounding session 1...
msf6 payload(windows/x64/meterpreter/reverse_tcp) > loadpath test/modules/
Loaded 36 modules:
    13 auxiliary modules
    13 exploit modules
    10 post modules
msf6 payload(windows/x64/meterpreter/reverse_tcp) > use post/test/railgun
msf6 post(test/railgun) > set session 1
session => 1
msf6 post(test/railgun) > run

[!] SESSION may not be compatible with this module.
[*] Running against session 1
[*] Session type is meterpreter and platform is windows
[+] Should include error information in the results
[+] Should support functions with no parameters
[+] Should support functions with literal parameters
[+] Should support functions with in/out/inout parameter types
[+] Should support calling multiple functions at once
[+] Should support writing memory
[+] Should support reading memory
[*] Passed: 7; Failed: 0
[*] Post module execution completed
msf6 post(test/railgun) > use post/test/railgun
use post/test/railgun                  use post/test/railgun_reverse_lookups  
msf6 post(test/railgun) > use post/test/railgun_reverse_lookups 
msf6 post(test/railgun_reverse_lookups) > set session 1
session => 1
msf6 post(test/railgun_reverse_lookups) > run

[!] SESSION may not be compatible with this module.
[*] Running against session 1
[*] Session type is meterpreter and platform is windows
[+] should return a constant name given a const and a filter
[+] should return an error string given an error code
[*] Passed: 2; Failed: 0
[*] Post module execution completed
msf6 post(test/railgun_reverse_lookups) > 

@bwatters-r7
Copy link
Contributor

Running with railgun and railgun_reverse_lookups:
image

@bwatters-r7
Copy link
Contributor

I'll wait for Travis to finish and land this then.

@bwatters-r7 bwatters-r7 merged commit d6095fe into rapid7:master Dec 7, 2020
@bwatters-r7
Copy link
Contributor

bwatters-r7 commented Dec 7, 2020

Release Notes

Fixed a bug where Railgun datatypes were not entirely accurate.

@timwr
Copy link
Contributor

timwr commented Dec 11, 2020

I think this is breaking the file_version (https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/post/windows/file_info.rb#L21) function for me on Windows 7 x64.
Leave it with me.

@zeroSteiner
Copy link
Contributor Author

@timwr That's a confusing one, railgun has the definition correctly using the PDWORD type which is consistent with the MSDN documentation. However, the parameter being called "lpdwHandle" makes me wonder if it should actually be a PHANDLE 🤔 . Let me know if you need a hand with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug code quality Improving code quality rn-fix release notes fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Railgun uses incorrect size for PDWORD values on x64 systems
4 participants