rapid7 / metasploit-payloads

Unified repository for different Metasploit Framework payloads
Other
1.75k stars 673 forks source link

x86 MinGW Windows Meterpreter Crashing on Windows XP #632

Open zeroSteiner opened 1 year ago

zeroSteiner commented 1 year ago

I noticed this while testing #631 and it appears to be unrelated to #630. It also seems to be related to the Meterpreter core and not any of the extensions as I can reproduce it with AutoLoadStdapi disabled (to avoid #630).

msf6 exploit(windows/smb/ms08_067_netapi) > set AutoLoadStdapi false
AutoLoadStdapi => false
msf6 exploit(windows/smb/ms08_067_netapi) > set MeterpreterDebugBuild false
MeterpreterDebugBuild => false
msf6 exploit(windows/smb/ms08_067_netapi) > check
[+] 192.168.159.16:445 - The target is vulnerable.
msf6 exploit(windows/smb/ms08_067_netapi) > run

[*] Started reverse TCP handler on 192.168.159.128:4444 
[*] 192.168.159.16:445 - Automatically detecting the target...
[*] 192.168.159.16:445 - Fingerprint: Windows XP - Service Pack 2 - lang:English
[*] 192.168.159.16:445 - Selected Target: Windows XP SP2 English (AlwaysOn NX)
[*] 192.168.159.16:445 - Attempting to trigger the vulnerability...
WARNING: Local file /home/smcintyre/.msf4/payloads/meterpreter/metsrv.x86.dll is being used
WARNING: Local files may be incompatible with the Metasploit Framework
[*] Sending stage (488696 bytes) to 192.168.159.16
[*] 192.168.159.16 - Meterpreter session 1 closed.  Reason: Died
[-] Meterpreter session 1 is not valid and will be closed
cdelafuente-r7 commented 10 months ago

I noticed that Windows Server 2008 x64 (WoW64) and Windows Vista x86 have the same issue.

wolfcod commented 3 months ago

Loading metsrv.x86.dll on Windows XP SP3 the entry point GetThreadId could not be located in the dynamic link library KERNEL32.dll

Windows XP SP3 version: 5.1.2600

According to the documentation this API is available from Windows Vista for Desktop Edition, and Windows Server 2003. The API is static imported because it's used by create_remote_thread in remote_thread.c

I guess other api could be not available in Windows Xp.

zeroSteiner commented 3 months ago

That sounds unrelated to this issue. If we're trying to import GetThreadId, that'd likely fail regardless of if the build is from MinGW or MSVC. @wolfcod are you experiencing this issue with the MinGW build? We don't ship it so you'd had have to have built it yourself or obtained it from somewhere else.

wolfcod commented 3 months ago

I read reflective loader source code and there are no checks if any api is available or not. I will build with mingw and try again.. thanks

wolfcod commented 3 months ago

@zeroSteiner I built metsrv.x86.dll with mingw on Linux, and the issue is somehow same of GetThreadId.

Building with MSVC using v141xp toolchain is working (with or without a patch for GetThreadId, because the ReflectiveLoader doesn't check the return value of GetProcAddress).

Building with MingW doesn't work, in other words, when you're trying to load metsrv.x86.dll in a process via reflective loader or using a simple LoadLibrary there is an error due a symbol not resolved rightly.

The function server_setup in c/meterpreter/source/metsrv/server_setup.c uses OpenThreadToken, an API available on Windows XP according to MSDN.

OpenThreadToken in MSVC build is imported from ADVAPI32.dll (the documentation says ADVAPI32.lib/ADVAPI32.dll) but in MingW build this API is imported from KERNEL32.dll, so when the server is initialized, there is an access violation when the function is called, because not resolved in the reflectiveloader, and the return value of GetProcAddress is NULL.

I guess somehow you should use an old release of MingW to build for Windows XP, or to resolve dynamically OpenThreadToken from ADVAPI32, which will be solved as symbol forward KERNEL32.OpenThreadToken in new OS and ADAVAPI32.OpenThreadToken on Windows XP.

I can submit a patch ASAP, but how I can apply the new build to metasploit-framework to use it? Is there any way to apply a different build to GEM files?

dledda-r7 commented 3 months ago

@zeroSteiner I built metsrv.x86.dll with mingw on Linux, and the issue is somehow same of GetThreadId.

Building with MSVC using v141xp toolchain is working (with or without a patch for GetThreadId, because the ReflectiveLoader doesn't check the return value of GetProcAddress).

Building with MingW doesn't work, in other words, when you're trying to load metsrv.x86.dll in a process via reflective loader or using a simple LoadLibrary there is an error due a symbol not resolved rightly.

The function server_setup in c/meterpreter/source/metsrv/server_setup.c uses OpenThreadToken, an API available on Windows XP according to MSDN.

OpenThreadToken in MSVC build is imported from ADVAPI32.dll (the documentation says ADVAPI32.lib/ADVAPI32.dll) but in MingW build this API is imported from KERNEL32.dll, so when the server is initialized, there is an access violation when the function is called, because not resolved in the reflectiveloader, and the return value of GetProcAddress is NULL.

I guess somehow you should use an old release of MingW to build for Windows XP, or to resolve dynamically OpenThreadToken from ADVAPI32, which will be solved as symbol forward KERNEL32.OpenThreadToken in new OS and ADAVAPI32.OpenThreadToken on Windows XP.

I can submit a patch ASAP, but how I can apply the new build to metasploit-framework to use it? Is there any way to apply a different build to GEM files?

Hello @wolfcod, did you inspect the PE to determinate the import of OpenThreadToken is expected from kernel32.dll? By reading the mingw-w64 source, I would expect it loaded from advapi32.dll anyway. Check this out

And specifically this

wolfcod commented 3 months ago

Hi @dledda-r7, yes I did. I inspected metsrv.x86.dll built using mingw on ubuntu 22.

The symbol OpenThreadToken is present on both dll (kernel32 and advapi32) for x86 target, but is missing from kernel32 in x86_64 library.

The problem came from CMakeLists.txt. The symbol LINK_LIBS override the default order used by gcc/ld to link libraries with object files.

In the standard build, the sequence is: kernel32, user32... advapi32 (the order is stored into linklibs.rsp generated by cmake during the build in ~/c/meterpreter/workspace/build/mingw-x86/${project}/CMakeFiles/${project}.dir/linklibs.rsp, and the symbol (in x86 build) is present in kernel32 before inspecting advapi32.

Adding advapi32 in set(LINK_LIBS, advapi32, .....) in CMakeLists for metsrv and extensions forces CMake to generate a linklibs.rsp where advapi32 is duplicated (I guess is present by default in CMAKE) but also present before kernel32 in gcc parameters for ld, generating a metsrv.x86.dll where OpenThreadToken is present but imported directly from ADVAPI32.dll instead of KERNEL32.dll

dledda-r7 commented 3 months ago

Hi @dledda-r7, yes I did. I inspected metsrv.x86.dll built using mingw on ubuntu 22.

The symbol OpenThreadToken is present on both dll (kernel32 and advapi32) for x86 target, but is missing from kernel32 in x86_64 library.

The problem came from CMakeLists.txt. The symbol LINK_LIBS override the default order used by gcc/ld to link libraries with object files.

In the standard build, the sequence is: kernel32, user32... advapi32 (the order is stored into linklibs.rsp generated by cmake during the build in ~/c/meterpreter/workspace/build/mingw-x86/${project}/CMakeFiles/${project}.dir/linklibs.rsp, and the symbol (in x86 build) is present in kernel32 before inspecting advapi32.

Adding advapi32 in set(LINK_LIBS, advapi32, .....) in CMakeLists for metsrv and extensions forces CMake to generate a linklibs.rsp where advapi32 is duplicated (I guess is present by default in CMAKE) but also present before kernel32 in gcc parameters for ld, generating a metsrv.x86.dll where OpenThreadToken is present but imported directly from ADVAPI32.dll instead of KERNEL32.dll

Thanks a lot for the analysis! probably the best way is, as you said, to modify the linking order instead of modify metsrv + extensions to resolve the function dynamically.

wolfcod commented 3 months ago

Hi @dledda-r7, yes I did. I inspected metsrv.x86.dll built using mingw on ubuntu 22. The symbol OpenThreadToken is present on both dll (kernel32 and advapi32) for x86 target, but is missing from kernel32 in x86_64 library. The problem came from CMakeLists.txt. The symbol LINK_LIBS override the default order used by gcc/ld to link libraries with object files. In the standard build, the sequence is: kernel32, user32... advapi32 (the order is stored into linklibs.rsp generated by cmake during the build in ~/c/meterpreter/workspace/build/mingw-x86/${project}/CMakeFiles/${project}.dir/linklibs.rsp, and the symbol (in x86 build) is present in kernel32 before inspecting advapi32. Adding advapi32 in set(LINK_LIBS, advapi32, .....) in CMakeLists for metsrv and extensions forces CMake to generate a linklibs.rsp where advapi32 is duplicated (I guess is present by default in CMAKE) but also present before kernel32 in gcc parameters for ld, generating a metsrv.x86.dll where OpenThreadToken is present but imported directly from ADVAPI32.dll instead of KERNEL32.dll

Thanks a lot for the analysis! probably the best way is, as you said, to modify the linking order instead of modify metsrv + extensions to resolve the function dynamically.

Both issue (GetThreadId and OpenThreadToken) fixed in https://github.com/rapid7/metasploit-payloads/pull/712