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

Linux reverse_tcp should read known # of bytes #12271

Merged

Conversation

@sempervictus
Copy link
Contributor

commented Sep 3, 2019

The linux x64 reverse tcp stager is hardcoded to read 4K off the
socket. When a small intermediate stager is used, this can result
in reading part of the next stage as well, which means that the
intermediate stager will never recv the # of bytes it needs and
hang indefinitely.

Break out the mettle piece to use separate methods for assembly and
binary payload generation as well as actually putting the product
on the existing session socket.

Change the first part of the stage to check for the intermediate
stager generation method, and use the size of the produced stager
in the recvfrom call or fall back to the prior 4K read size.

Testing:
None yet

Ping @bcook-r7, @acammack-r7, @OJ, @zeroSteiner

@sempervictus sempervictus force-pushed the sempervictus:bug/linux-reverse_tcp-read-size branch from c56fc95 to 1de46ca Sep 3, 2019

@bcook-r7

This comment has been minimized.

Copy link
Contributor

commented Sep 3, 2019

Note, the same problem is in other stagers, e.g. x86 also does a blind read.

RageLtMan
Linux x64 reverse_tcp should read known # of bytes
The linux x64 reverse tcp stager is hardcoded to read 4K off the
socket. When a small intermediate stager is used, this can result
in reading part of the next stage as well, which means that the
intermediate stager will never recv the # of bytes it needs and
hang indefinitely.

Break out the mettle piece to use separate methods for assembly and
binary payload generation as well as actually putting the product
on the existing session socket.

Change the first part of the stage to check for the intermediate
stager generation method, and use the size of the produced stager
in the recvfrom call or fall back to the prior 4K read size.

Testing:
  None yet

Ping @bcook-r7, @acammack-r7, @OJ, @zeroSteiner

@sempervictus sempervictus force-pushed the sempervictus:bug/linux-reverse_tcp-read-size branch from 1de46ca to 05944ba Sep 3, 2019

RageLtMan
Linux x86 reverse_tcp should read known # of bytes
See notes for x64.

This part does not appear to be working properly yet - stages
generated with this commit recv 102b on the first call to read(),
but subsequently things seem to go off the rails after the
intermediate stage is loaded.

Needs testing and fixup at present for x86 (no worse than before
in terms of success rate however).
@timwr

This comment has been minimized.

Copy link
Contributor

commented Sep 3, 2019

Surely the payload is now just reading a hardcoded 126 bytes instead of 4096. What if we update the stager in the future so that it's more than 126 bytes? Any previously generated payload will only read 126 bytes and fail. Perhaps it might be better to first read the length and then mmap/read that number of bytes. We do this on aarch64 (and java):

@timwr

This comment has been minimized.

Copy link
Contributor

commented Sep 3, 2019

Is the current behaviour causing issues? There was a bug on OSX that occurred occasionally but it was fixed with a rex.sleep: #11165 potentially we could fix them both at once to use a length (and metasm).

@sempervictus

This comment has been minimized.

Copy link
Contributor Author

commented Sep 3, 2019

Current behavior is broken. The dynamic read size should be a payload option IMO, and your midstager would have to differ for this to break, actual stage doesn't matter.
Also all for dynamic read sizing as an option...

@acammack-r7
Copy link
Contributor

left a comment

I think I prefer this to the timing-based approaches we've used in the past to separate the intermediate stager from the stage on the wire. There are some asm hygiene items to fix, though.

lib/msf/core/payload/linux/reverse_tcp.rb Outdated Show resolved Hide resolved
RageLtMan
Clean up linux/x64/rev_tcp asm per acammack
Address Adam's comments on the PR - remove redundantly pushed
size from mmap section.

@sempervictus sempervictus changed the title Linux x64 reverse_tcp should read known # of bytes Linux reverse_tcp should read known # of bytes Sep 3, 2019

@sempervictus sempervictus force-pushed the sempervictus:bug/linux-reverse_tcp-read-size branch from aaa5b85 to d189bb8 Sep 3, 2019

RageLtMan
Clean up linux/x86/rev_tcp asm per acammack
Push read_size to edx as suggested by Adam, optimize shellcode a
bit by selecting using dx instead of edx for sizes under 64K.

Testing:
  Internal only, creates session on every try instead of every 5th.

@sempervictus sempervictus force-pushed the sempervictus:bug/linux-reverse_tcp-read-size branch from d189bb8 to 04e7500 Sep 4, 2019

@acammack-r7 acammack-r7 self-assigned this Sep 4, 2019

acammack-r7 added 2 commits Sep 4, 2019
@acammack-r7

This comment has been minimized.

Copy link
Contributor

commented Sep 4, 2019

@bwatters-r7 Will also be interested, I think.

Update payload cached size
For real this time?
@sempervictus
Copy link
Contributor Author

left a comment

Thank you. x86 likely as well since we are moving the size param to edx

@acammack-r7

This comment has been minimized.

Copy link
Contributor

commented Sep 4, 2019

Not in the default case. When it's not a meterpreter stager it acts just as it did before, it is just a bit more explicit about what it's doing. Also, when the intermediate stage is short (like it is now), the size fits into a single byte, so the stage still doesn't grow.

@acammack-r7

This comment has been minimized.

Copy link
Contributor

commented Sep 4, 2019

The x64 stager looks to be oscillating in size, I'll dig into it.

Use smallest stager size
Since these stagers can shrink based on the expected size of the next
stage, do our best to anticipate a small size. This makes the cached
payload size consistent for now, though if the x64 mettle stager grows
past 128 bytes I think we'll see the stager start oscillating in size
again. If you run into that and are reading this, sorry :(
acammack-r7 added a commit that referenced this pull request Sep 5, 2019

@acammack-r7 acammack-r7 merged commit 2ee5ec9 into rapid7:master Sep 5, 2019

3 checks passed

Metasploit Automation - Sanity Test Execution Successfully completed all tests.
Details
Metasploit Automation - Test Execution Successfully completed all tests.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
msjenkins-r7 added a commit that referenced this pull request Sep 5, 2019
@acammack-r7

This comment has been minimized.

Copy link
Contributor

commented Sep 5, 2019

Release Notes

Previously on Linux, the x86 and x64 reverse TCP stagers would often read past the end of Meterpreter's intermediate stager and grab the first few bytes of the final Meterpreter payload. Both stagers now only read the expected number of bytes as a hot fix. This makes them more reliable pending reworking them to read the size of the next stage off the wire as done on other platforms.

@tdoan-r7 tdoan-r7 added the rn-fix label Sep 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.