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

Use upstream ruby-mysql in Remote::MYSQL #18296

Conversation

rorymckinley
Copy link
Contributor

@rorymckinley rorymckinley commented Aug 17, 2023

Continuation of #18278
Relates to #18297

This is the next iteration of replacing the local RbMysql with the upstream ruby-mysql gem. It replaces RbMysql in Msf::Exploit::Remote::MYSQL.

There are two manual tests to confirm that this functionality works:

  • modules/auxiliary/scanner/mysql/mysql_file_enum.rb (it seems to use most of the core functionality provided by Msf::Exploit::Remote::MYSQL)
  • modules/auxiliary/scanner/mysql/mysql_authbypass_hashdump.rb (it not only uses Msf::Exploit::Remote::MYSQL but it also uses RbMysql independently. ~~I cannot fully test this as I could not find a mysql container that is old enough to have the vulnerability, so it is a very high-level test, but enough to confirm that the code can connect to the MySQL instance (hopefully). ~~ Resolved by: Fix broken mysql_authbypass_hashdump module #18297

Verification

Part 1 (mysql_file_enum.rb)

  • docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=foo123 -d mysql:5.7.42 --secure-file-priv=/etc
  • echo '/etc/my.cnf' > test.txt
  • Start msfconsole
  • use auxiliary/scanner/mysql/mysql_file_enum
  • set RHOSTS 127.0.0.1
  • set USERNAME root
  • set PASSWORD foo123
  • [] set FILE_LIST test.txt
  • [] run

You should see output as per the below:

image

Part 2 (mysql_authbypass_hashdump)

  • `docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=foo123 -d mysql:5.7.42
  • Start msfconsole
  • use auxiliary/scanner/mysql/mysql_authbypass_hashdump
  • set RHOSTS 127.0.0.1
  • run

You should see output as per the below:

image

part 3 - mysql_authbypass_hashdump - vulnerable

docker run -it --rm -p 3306:3306 vulhub/mysql:5.5.23

Expected results from #18297 :

msf6 auxiliary(scanner/mysql/mysql_authbypass_hashdump) > run rhosts=127.0.0.1

[+] 127.0.0.1:3306        - 127.0.0.1:3306 The server allows logins, proceeding with bypass test
[*] 127.0.0.1:3306        - 127.0.0.1:3306 Authentication bypass is 10% complete
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Successfully bypassed authentication after 138 attempts. URI: mysql://root:[email protected]:3306
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Successfully exploited the authentication bypass flaw, dumping hashes...
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Saving HashString as Loot: root:*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Saving HashString as Loot: root:*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Saving HashString as Loot: root:*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Saving HashString as Loot: root:*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Saving HashString as Loot: root:*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
[+] 127.0.0.1:3306        - 127.0.0.1:3306 Hash Table has been saved: /Users/user/.msf4/loot/20231012170829_default_127.0.0.1_mysql.hashes_222750.txt
[*] 127.0.0.1:3306        - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

@adfoster-r7
Copy link
Contributor

Thanks for championing this! 💯

There are two manual tests to confirm that this functionality works:

  • ...
  • modules/auxiliary/scanner/mysql/mysql_authbypass_hashdump.rb

I also tried verifying this module using a prebuilt vulnerable 5.5.23 image from https://github.com/vulhub/vulhub - specifically the versions from dockerhub https://hub.docker.com/r/vulhub/mysql/tags and saw similar output as yourself

Another community member was recently hitting issues with this module which made probe a bit deeper - and I've had to create a PR to patch both the module and MySQL library code a bit - #18297

It looks like we might want to send a feature request/pull request to add socket-reuse to the RbMysql library, as well as fixing the nil charset exception when the server immediately responds with an error - rather than initially attempting to negotiate a charset. I can attempt to contribute those code changes plus extra tests as a contribution upstream, or I'm happy for you to try and contribute a patch upstream/raise an issue

Let me know whatever works best for yourself 👍

@rorymckinley
Copy link
Contributor Author

Let me know whatever works best for yourself 👍

Ha! TIL about vulhub, thank you!

I haven't fully grokked #18297 but happy to take a stab at converting that into a PR on upstream.

lib/msf/core/exploit/remote/mysql.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/mysql.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/mysql.rb Outdated Show resolved Hide resolved
modules/exploits/windows/mysql/mysql_mof.rb Outdated Show resolved Hide resolved
modules/exploits/windows/mysql/mysql_mof.rb Outdated Show resolved Hide resolved
modules/exploits/windows/mysql/mysql_mof.rb Outdated Show resolved Hide resolved
@@ -72,7 +72,7 @@ def query(q)
res.each_hash do |row|
rows << row
end
rescue RbMysql::ParseError
rescue Mysql::ParseError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rescue Mysql::ParseError
rescue ::Mysql::ParseError

@@ -104,7 +104,7 @@ def exploit
print_status("Attempting to login as '#{datastore['USERNAME']}:#{datastore['PASSWORD']}'")
begin
m = mysql_login(datastore['USERNAME'], datastore['PASSWORD'])
rescue RbMysql::AccessDeniedError
rescue Mysql::AccessDeniedError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rescue Mysql::AccessDeniedError
rescue ::Mysql::AccessDeniedError

@@ -116,7 +116,7 @@ def exploit

begin
drive = get_drive_letter
rescue RbMysql::ParseError
rescue Mysql::ParseError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rescue Mysql::ParseError
rescue ::Mysql::ParseError

@@ -129,7 +129,7 @@ def exploit
print_status("Uploading to '#{dest}'")
begin
upload_file(exe, dest)
rescue RbMysql::AccessDeniedError
rescue Mysql::AccessDeniedError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rescue Mysql::AccessDeniedError
rescue ::Mysql::AccessDeniedError

@adfoster-r7 adfoster-r7 self-assigned this Aug 21, 2023
@rorymckinley
Copy link
Contributor Author

@adfoster-r7 Apologies for the slow response on this, my week took an unexpected turn to the left. If it is ok with you, I am happy to keep this open until I have gotten the RbMySQL changes merged upstream and we can continue to replace the use of RbMYSQL.

I am hoping to get some work done on branch for upstream over the weekend (unfortunately, I am primarily restricted to after-hours and weekends for this stuff).

@adfoster-r7
Copy link
Contributor

No worries! Feel free to ping me if you need anything 👍

@rorymckinley
Copy link
Contributor Author

@adfoster-r7 Upstream ruby-mysql now has a fix for one of the issues fixed locally by #18297 (https://github.com/rapid7/metasploit-framework/pull/18297/files#r1297845124). The second issue (https://github.com/rapid7/metasploit-framework/pull/18297/files#r1297825664) is already fixed by a change in upstream that was absent from the local ruby-mysql (I tested against the vulnerable mysql container to confirm).

As a result, I think this PR is ready to be resuscitated. The one catch is that I am not sure when an updated version of the gem will be released. Would you have any objections to the gem being sourced from the project's gitlab repo rather than from rubygems?

@adfoster-r7
Copy link
Contributor

Thanks for handling those PRs! (https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/4 + https://gitlab.com/tmtms/ruby-mysql/-/merge_requests/2)

If you're good with rebasing, pointing to the latest Github SHA on GitLab, we could start testing this on our side. If everything's well, we can see if there's new version available on RubyGems https://rubygems.org/gems/ruby-mysql by then and decide what to do next 😄

I'd definitely preference the source code being available in RubyGems as it has the benefit of being cacheable by artifactory / nexus in CI envs, and I know it wouldn't impact downstream build systems like Kali/Arch etc; but happy to re-evaluate after testing things! 👍

@rorymckinley
Copy link
Contributor Author

I'd definitely preference the source code being available in RubyGems as it has the benefit of being cacheable by artifactory / nexus in CI envs, and I know it wouldn't impact downstream build systems like Kali/Arch etc; but happy to re-evaluate after testing things! 👍

Makes sense - let me rebase and re-test based on the Gitlab HEAD and then we can always park this until an updated version of the gem is released.

@rorymckinley rorymckinley force-pushed the use_upstream_ruby_mysql_in_mysql_exploit branch from 37b8f00 to 0b6e60f Compare September 26, 2023 14:01
@@ -37,21 +37,21 @@ def mysql_login(user='root', pass='', db=nil)
connect

begin
@mysql_handle = ::RbMysql.connect(rhost, user, pass, db, rport, sock)
@mysql_handle = ::Mysql.connect(rhost, user, pass, db, rport, io: sock)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@rorymckinley
Copy link
Contributor Author

@adfoster-r7 I have manually tested this per the examples at the top of this PR. All seems fine - I have tried recreating the 'blocked because of many connection errors' issue (to confirm that the gem and my manual change of earlier have produced the same result) but I have been unable to.

At any rate, some googling and a cursory inspection of the docs around add_runtime_dependency seems to indicate that there is no clean way to have the gemspec build the gem from a repo URL - therefore we will need to put this PR on ice pending a new gem release.

@adfoster-r7
Copy link
Contributor

Thanks for the awesome work! Will keep an eye on the release page for the gem to be available 🤞

@adfoster-r7 adfoster-r7 added the blocked Blocked by one or more additional tasks label Sep 27, 2023
@rorymckinley
Copy link
Contributor Author

@adfoster-r7 I see that version 4.1.0 of ruby-mysql was released - I will update this PR accordingly (hopefully on Thursday or Friday).

@rorymckinley rorymckinley force-pushed the use_upstream_ruby_mysql_in_mysql_exploit branch from 0b6e60f to 1b17276 Compare October 12, 2023 11:10
@rorymckinley
Copy link
Contributor Author

@adfoster-r7 I think this is ready to go - I see there is one check failing, but I can't see why.

@adfoster-r7
Copy link
Contributor

@msjenkins-r7 retest this please

@adfoster-r7
Copy link
Contributor

Thanks! I'll try and run through things today 🎉

@adfoster-r7
Copy link
Contributor

Updated the steps to include the happy path of #18297 now too, and everything looks good - thanks! 👍

@adfoster-r7 adfoster-r7 merged commit 80d2fa7 into rapid7:master Oct 12, 2023
55 checks passed
@adfoster-r7
Copy link
Contributor

Release Notes

Updates multiple MySQL modules to support authenticating with newer versions of MySQL.

@adfoster-r7 adfoster-r7 added rn-enhancement release notes enhancement and removed blocked Blocked by one or more additional tasks labels Oct 12, 2023
@adfoster-r7
Copy link
Contributor

Added a call out for the updated support in the Metasploit release notes, thanks! 👍

https://www.rapid7.com/blog/post/2023/10/13/metasploit-weekly-wrap-up-31/

@rorymckinley
Copy link
Contributor Author

Added a call out for the updated support in the Metasploit release notes, thanks! 👍
Thank you! :)

I am hoping to get rid of the last few RbMysql remnants this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rn-enhancement release notes enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants