rapid7 / metasploit-framework

Metasploit Framework
https://www.metasploit.com/
Other
32.92k stars 13.72k forks source link

Note when SMBv1 is supported to the user #19131

Open nrathaus opened 3 weeks ago

nrathaus commented 3 weeks ago

This improves the feedback listed here: https://github.com/rapid7/metasploit-framework/issues/17402

Verification

List the steps needed to make sure this thing works

docker-compose with SMBv1:

version: "3"

services:
  sambav1:
    image: dperson/samba:latest
    container_name: samba
    restart: unless-stopped
    command: '-g "ntlm auth = yes" -g "server min protocol = NT1" -S -s "Files;/mnt/files;yes;yes"'
    ports:
      - 139:139
      - 445:445
    environment:
      - TZ=PST8PDT
    volumes:
      - files:/mnt/files

volumes:
  files:

docker-compose without SMBv1:

version: "3"

services:
  sambav1:
    image: dperson/samba:latest
    container_name: samba
    restart: unless-stopped
    command: '-s "Files;/mnt/files;yes;yes"'
    ports:
      - 139:139
      - 445:445
    environment:
      - TZ=PST8PDT
    volumes:
      - files:/mnt/files

volumes:
  files:
nrathaus commented 3 weeks ago

This is based on an issue raised here https://github.com/rapid7/metasploit-framework/issues/17402

If this is it needed (I agree btw that it’s shown twice) then ignore this PR and close the issue

On Wed, 24 Apr 2024 at 16:12, Spencer McIntyre @.***> wrote:

@.**** commented on this pull request.

In modules/auxiliary/scanner/smb/smb_version.rb https://github.com/rapid7/metasploit-framework/pull/19131#discussion_r1577858105 :

     desc = "SMB Detected (versions:#{info[:versions].join(', ')}) (preferred dialect:#{info[:preferred_dialect]})"
  • if info[:versions].include?(1)
  • desc << ' (SMBv1: true)'
  • end

Wouldn't this be covered on the previous line where (version: includes 1? This seems redundant. I would expect a server that supports SMBv1 to show (versions:1) or (versions:1,2), etc.

— Reply to this email directly, view it on GitHub https://github.com/rapid7/metasploit-framework/pull/19131#pullrequestreview-2019817678, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPQE3SLCODQL455S3EDYWTY66VTJAVCNFSM6AAAAABGWVHNA6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDAMJZHAYTONRXHA . You are receiving this because you authored the thread.Message ID: @.***>

smcintyre-r7 commented 3 weeks ago

I think that issue was to say that the host operating system information isn't extracted from the NTLM challenge/response when SMBv1 isn't in use. I think we could address it, though it may require an update to RubySMB if the NTLM challenge/response, isn't readily accessible.

I could probably help if you were interested in working on that.

adfoster-r7 commented 3 weeks ago

I think that issue was to say that the host operating system information isn't extracted from the NTLM challenge/response when SMBv1 isn't in use.

Yip; it looks like from the original ticket I was hoping that the host information was extracted from the NTLMSSP_CHALLENGE response:

I would have expected the Windows 10.0 Build 14393 metadata to be present I think the information should be extractable from the STATUS_MORE_PROCESSING_REQUIRED, NTLMSSP_CHALLENGE response

Sorry for the confusion in the original ticket

nrathaus commented 3 weeks ago

Can you clarify what are the requirements for completing the task? I will try to work on it

On Wed, 24 Apr 2024 at 16:49, adfoster-r7 @.***> wrote:

I think that issue was to say that the host operating system information isn't extracted from the NTLM challenge/response when SMBv1 isn't in use.

Yip; it looks like from the original ticket I was hoping that the host information was extracted from the NTLMSSP_CHALLENGE response:

I would have expected the Windows 10.0 Build 14393 metadata to be present I think the information should be extractable from the STATUS_MORE_PROCESSING_REQUIRED, NTLMSSP_CHALLENGE response

Sorry for the confusion in the original ticket

— Reply to this email directly, view it on GitHub https://github.com/rapid7/metasploit-framework/pull/19131#issuecomment-2074997707, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPQE3URTLJWWV7ERT6Z4V3Y66Z6HAVCNFSM6AAAAABGWVHNA6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANZUHE4TONZQG4 . You are receiving this because you authored the thread.Message ID: @.***>

adfoster-r7 commented 3 weeks ago

Requirements for completing the task would be extracting extra details from the NTLM negotiation and showing it to the user, i.e the mockup:

- [*] 192.168.123.13:445    - SMB Detected (versions:2, 3) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:required) (uptime:3m 46s) (guid:{3863d7d4-26ca-4913-8ff3-d4e27787e43d}) (authentication domain:ADF3)
+ [*] 192.168.123.13:445    - SMB Detected (versions:2, 3) (Windows 10.0 Build 14393 x64) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:required) (uptime:3m 46s) (guid:{3863d7d4-26ca-4913-8ff3-d4e27787e43d}) (authentication domain:ADF3) 
                                                           ^^^^^^^^^^^ Added ^^^^^^^^^^^^

Running the module against a windows box should provide the details that we can log out for the user, I'm not sure what samba gives you

nrathaus commented 3 weeks ago

I think what you are asking to add already exists:

msf6 auxiliary(scanner/smb/smb_version) > run 172.22.0.2

[*] 172.22.0.2:445        - SMB Detected (versions:1, 2, 3) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:optional) (guid:{63613736-3062-3034-6238-653700000000}) (authentication domain:67ACB040B8E7)
[*] 172.22.0.2:445        -   Host could not be identified: Windows 6.1 (Samba 4.12.2)
[*] 172.22.0.2:           - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

NOTE the part about Windows 6.1 (Samba 4.12.2)

adfoster-r7 commented 3 weeks ago

Running smb_version against a windows target with SMB v1,v2,v3 enabled outputs the target build information ✅

msf6 auxiliary(scanner/smb/smb_version) > rerun rhost=192.168.123.136 username=vagrant password=vagrant
[*] Reloading module...

[*] 192.168.123.136:445   - Force SMB1 since SMB fingerprint needs native_lm/native_os information
[*] 192.168.123.136:445   - SMB Detected (versions:1, 2, 3) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:optional) (uptime:3m 45s) (guid:{eafd6aa4-cdfe-41c7-a1c5-340d151af52a}) (authentication domain:WINDEV)Windows 2016 Standard (build:14393) (name:WINDEV)
[+] 192.168.123.136:445   -   Host is running SMB Detected (versions:1, 2, 3) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:optional) (uptime:3m 45s) (guid:{eafd6aa4-cdfe-41c7-a1c5-340d151af52a}) (authentication domain:WINDEV)Windows 2016 Standard (build:14393) (name:WINDEV)
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[*] 192.168.123.136:      - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Disabling SMB v1 on the windows target:

Set-SmbServerConfiguration -EnableSMB1Protocol $false

Running the same module against the target with SMB v1 disabled no longer shows the target build information ❌

msf6 auxiliary(scanner/smb/smb_version) > rerun rhost=192.168.123.136 username=vagrant password=vagrant 
[*] Reloading module...

[*] 192.168.123.136:445   - Force SMB1 since SMB fingerprint needs native_lm/native_os information
[*] 192.168.123.136:445   - SMB Detected (versions:2, 3) (preferred dialect:SMB 3.1.1) (compression capabilities:) (encryption capabilities:AES-128-GCM) (signatures:optional) (uptime:4m 52s) (guid:{eafd6aa4-cdfe-41c7-a1c5-340d151af52a}) (authentication domain:WINDEV)
[*] 192.168.123.136:445   -   Host could not be identified
[*] 192.168.123.136:      - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

We can see that that build information is missing on the re-scan; but from wireshark it looks like it should be available just fine in the NTLMSSP_CHALLENGE packet:

image

nrathaus commented 3 weeks ago

This information is processed in these two lines of code:

        response = smb2_ntlmssp_negotiate
        challenge_packet = smb2_ntlmssp_challenge_packet(response)
nrathaus commented 3 weeks ago

Specifically, the: packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)

nrathaus commented 3 weeks ago

There seems to be no parsing of the GSS-API Generic Security Service Application Program Interface section of the data

nrathaus commented 3 weeks ago

There seems to be some thought placed into the code to support GSS?

        def set_type2_blob(type1_message)
          gss_blob = RubySMB::Gss.gss_type2(type1_message)
          self.security_buffer_length = gss_blob.length
          self.buffer = gss_blob
        end

But no one is calling this function

nrathaus commented 3 weeks ago

Parsing this data while coding it in Ruby is at the moment beyond my technical skills

nrathaus commented 3 weeks ago

BTW It seems to be in fact (the security blob) ASN.1 encoded content: https://gchq.github.io/CyberChef/#recipe=Parse_ASN.1_hex_string(0,32)&input=ICAgYTEgODEgZDYgMzAgODEgZDMgYTAgMDMgMGEgMDEgMDEgYTEgMGMgMDYgMGEgMmIKICAgMDYgMDEgMDQgMDEgODIgMzcgMDIgMDIgMGEgYTIgODEgYmQgMDQgODEgYmEgNGUKICAgNTQgNGMgNGQgNTMgNTMgNTAgMDAgMDIgMDAgMDAgMDAgMTggMDAgMTggMDAgMzgKICAgMDAgMDAgMDAgMzUgODIgOGEgZTIgY2IgOGMgOWQgNTkgMjkgNTcgNzYgNTkgMDAKICAgMDAgMDAgMDAgMDAgMDAgMDAgMDAgNmEgMDAgNmEgMDAgNTAgMDAgMDAgMDAgMDYKICAgMDEgMDAgMDAgMDAgMDAgMDAgMGYgMzYgMDAgMzMgMDAgMzQgMDAgNDUgMDAgMzIKICAgMDAgNDQgMDAgNDQgMDAgMzkgMDAgNDYgMDAgMzggMDAgMzMgMDAgMzAgMDAgMDIKICAgMDAgMTggMDAgMzYgMDAgMzMgMDAgMzQgMDAgNDUgMDAgMzIgMDAgNDQgMDAgNDQKICAgMDAgMzkgMDAgNDYgMDAgMzggMDAgMzMgMDAgMzAgMDAgMDEgMDAgMTggMDAgMzYKICAgMDAgMzMgMDAgMzQgMDAgNDUgMDAgMzIgMDAgNDQgMDAgNDQgMDAgMzkgMDAgNDYKICAgMDAgMzggMDAgMzMgMDAgMzAgMDAgMDQgMDAgMDIgMDAgMDAgMDAgMDMgMDAgMTgKICAgMDAgMzYgMDAgMzMgMDAgMzQgMDAgNjUgMDAgMzIgMDAgNjQgMDAgNjQgMDAgMzkKICAgMDAgNjYgMDAgMzggMDAgMzMgMDAgMzAgMDAgMDcgMDAgMDggMDAgZTggNGQgMGEKICAgNzAgZmEgOTYgZGEgMDEgMDAgMDAgMDAgMDAK

smcintyre-r7 commented 3 weeks ago

You should be able to parse it using RubyNTLM / Net::NTLM. It's possible the entire message isn't available outside of RubySMB and RubySMB would need to be updated to parse the message when it's available, extract and save the necessary fields.

adfoster-r7 commented 3 weeks ago

iirc there's also all of the required parsers over in the ruby_smb library for that octet string/buffer, i.e. these methods:

https://github.com/rapid7/ruby_smb/blob/681f67763491639365acd6c18b3d3ce4f70388ce/lib/ruby_smb/peer_info.rb

And the binary model:

https://github.com/rapid7/ruby_smb/blob/681f67763491639365acd6c18b3d3ce4f70388ce/lib/ruby_smb/ntlm.rb#L48

But if RubyNTLM is easier to reach for in this context, that sounds good to me 💯

nrathaus commented 2 weeks ago

Is RubyNTLM being shipped/used by metasploit atm? or do I need to copy-paste the code there into the smb.rb that comes with Metasploit?

smcintyre-r7 commented 2 weeks ago

It's already included with Metasploit https://github.com/rapid7/metasploit-framework/blob/master/metasploit-framework.gemspec#L84

It's worth noting though, that for the actual authentication workflow we use our own client from RubySMB because it includes some changes we haven't been able to get merged into the upstream library. Most notably, it supports anonymous authentication which is required in certain contexts by Metasploit such as exploiting zerologon.

For what's going on here though, you just need to use the parsing code. I only point this out to provide context that for the actual processing we have to use our version.