rapid7/metasploit-framework

View on GitHub
documentation/modules/auxiliary/server/capture/smtp.md

Summary

Maintainability
Test Coverage
## Vulnerable Application

This module creates a mock SMTP server which accepts credentials or unauthenticated email
before throwing a `503` error.

## Verification Steps

  1. Start msfconsole
  2. Do: ```use auxiliary/server/capture/smtp```
  3. Do: ```run```

## Options

### AUTHPROMPT

If the client should be prompted for credentials or not.  When set to `false` credentials can still be
accepted, but the client isn't prompted outright to give them. Some systems will only provide crednetials
if prompted. Defaults to `false`

## Scenarios

### Testing Script

The following script should test the following:

1. Auth Plain
2. Auth Login
3. Auth CRAM-MD5
4. Sending an email w/o auth
5. RSET is implemented (https://github.com/rapid7/metasploit-framework/issues/11980)

    ```
    require 'net/smtp'
    require 'socket'

    puts 'Testing: plain'
    begin
      Net::SMTP.start('127.0.0.1', 25, 'localhost', 'username_plain', 'password_plain', :plain)
    rescue => e
      puts "Error: #{e}"
    end
    
    puts 'Testing: login'
    begin
      Net::SMTP.start('127.0.0.1', 25, 'localhost', 'username_login', 'password_login', :login)
    rescue => e
      puts "Error: #{e}"
    end
    
    puts 'Testing: cram md5'
    begin
      Net::SMTP.start('127.0.0.1', 25, 'localhost', 'username_cram', 'password_cram', :cram_md5)
    rescue => e
      puts "Error: #{e}"
    end
    
    puts 'Testing: DATA'
    begin
      Net::SMTP.start('127.0.0.1') do |smtp|
        smtp.send_message 'test', 'from@test.com', 'to@test.com'
      end
    rescue => e
      puts "Error: #{e}"
    end
    
    
    # test for https://github.com/rapid7/metasploit-framework/issues/11980
    puts 'Testing: RSET during DATA'
    begin
      t = TCPSocket.open('127.0.0.1', 25)
      t.gets
      t.print("EHLO localhost \r\n")
      t.gets
      t.print("MAIL FROM:<from@test.com>\r\n")
      t.gets
      t.print("MAIL TO:<to@test.com>\r\n")
      t.gets
      t.print("DATA\r\n")
      t.gets
      t.print("RSET\r\n")
      puts "  Response: #{t.gets.chop}"
    rescue => e
      puts "Error: #{e}"
    end

    puts 'Testing: RSET during middle of DATA'
    begin
      t = TCPSocket.open('127.0.0.1', 25)
      t.gets
      t.print("EHLO localhost \r\n")
      t.gets
      t.print("MAIL FROM:<from@test.com>\r\n")
      t.gets
      t.print("MAIL TO:<to@test.com>\r\n")
      t.gets
      t.print("DATA\r\n")
      t.gets
      t.print("testing a message which gets cancelled\r\n")
      t.print("RSET\r\n")
      puts "  Response: #{t.gets.chop}"
    rescue => e
      puts "Error: #{e}"
    end
    ```

### Output from testing script

When this script is run from the Metasploit console, it intermingles with the commands, which is great!

```
$ sudo ./msfconsole -qx 'use auxiliary/server/capture/smtp; set srvhost 127.0.0.1;run;ruby tools/dev/test_capture_smtp.rb'
srvhost => 127.0.0.1
[*] Auxiliary module running as background job 0.
[*] exec: ruby tools/dev/test_capture_smtp.rb

[*] Started service listener on 127.0.0.1:25 
[*] Server started.
Testing: plain
[*] SMTP: 127.0.0.1:46212 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46212 Command: AUTH PLAIN AHVzZXJuYW1lX3BsYWluAHBhc3N3b3JkX3BsYWlu
[+] SMTP LOGIN 127.0.0.1:46212 username_plain / password_plain
Testing: login
[*] SMTP: 127.0.0.1:46214 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46214 Command: AUTH LOGIN
[*] SMTP: 127.0.0.1:46214 Command: dXNlcm5hbWVfbG9naW4=
[*] SMTP: 127.0.0.1:46214 Command: cGFzc3dvcmRfbG9naW4=
[+] SMTP LOGIN 127.0.0.1:46214 username_login / password_login
Testing: cram md5
[*] SMTP: 127.0.0.1:46216 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46216 Command: AUTH CRAM-MD5
[*] SMTP: 127.0.0.1:46216 Command: dXNlcm5hbWVfY3JhbSA3YjA2NzUyMjVhM2FjMmI5MjMxYzJlOTM5OTg2Y2U0Mg==
Testing: DATA
[+] SMTP LOGIN 127.0.0.1:46216 username_cram / <12345@127.0.0.1>#7b0675225a3ac2b9231c2e939986ce42
[*] SMTP: 127.0.0.1:46218 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46218 Command: MAIL FROM:<from@test.com>
[*] SMTP: 127.0.0.1:46218 Command: RCPT TO:<to@test.com>
[*] SMTP: 127.0.0.1:46218 Command: DATA
[*] SMTP: 127.0.0.1:46218 Command: test
.
[*] SMTP: 127.0.0.1:46218 EMAIL: test
[*] SMTP: 127.0.0.1:46218 Command: QUIT
Testing: RSET during DATA
[*] SMTP: 127.0.0.1:46220 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46220 Command: MAIL FROM:<from@test.com>
[*] SMTP: 127.0.0.1:46220 Command: MAIL TO:<to@test.com>
[*] SMTP: 127.0.0.1:46220 Command: DATA
[*] SMTP: 127.0.0.1:46220 Command: RSET
  Response: 250 OK
Testing: RSET during middle of DATA
[*] SMTP: 127.0.0.1:46222 Command: EHLO localhost
[*] SMTP: 127.0.0.1:46222 Command: MAIL FROM:<from@test.com>
[*] SMTP: 127.0.0.1:46222 Command: MAIL TO:<to@test.com>
[*] SMTP: 127.0.0.1:46222 Command: DATA
[*] SMTP: 127.0.0.1:46222 Command: testing a message which gets cancelled
RSET
[*] SMTP: 127.0.0.1:46222 EMAIL: testing a message which gets cancelled
  Response: 250 OK
msf5 auxiliary(server/capture/smtp) > creds
Credentials
===========

host       origin     service        public          private                                             realm  private_type        JtR Format
----       ------     -------        ------          -------                                             -----  ------------        ----------
127.0.0.1  127.0.0.1  25/tcp (smtp)  username_cram   <12345@127.0.0.1>#7b0675225a3ac2b9231c2e939986ce42         Nonreplayable hash  hmac-md5
127.0.0.1  127.0.0.1  25/tcp (smtp)  username_login  password_login                                             Password            
127.0.0.1  127.0.0.1  25/tcp (smtp)  username_plain  password_plain                                             Password            

msf5 auxiliary(server/capture/smtp) > notes

Notes
=====

 Time                     Host       Service  Port  Protocol  Type          Data
 ----                     ----       -------  ----  --------  ----          ----
 2020-04-17 15:11:24 UTC  127.0.0.1                           smtp_message  "testing a message which gets cancelled\r\n"


```

### Cracking Cram-md5 (hmac-md5)

Metasploit currently doesn't have a cracker for `hmac-md5`, however the output is pre-formatted to JTR standards,
and `creds -o /tmp/file.jtr` will export it correctly for John.  It is also possible to export to hashcat format
with `creds -o /tmp/file.hcat` and mode `10200`.

```
user@kali:~/metasploit-framework$ sudo cat /tmp/cram
username_cram:<12345@127.0.0.1>#7b0675225a3ac2b9231c2e939986ce42
user@kali:~/metasploit-framework$ sudo cat /tmp/wordlist 
password_cram
user@kali:~/metasploit-framework$ sudo john --wordlist=/tmp/wordlist --format=hmac-md5 /tmp/cram
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-MD5 [password is key, MD5 256/256 AVX2 8x3])
Warning: poor OpenMP scalability for this hash type, consider --fork=8
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 1 candidate left, minimum 192 needed for performance.
password_cram    (username_cram)
1g 0:00:00:00 DONE (2020-04-17 11:32) 50.00g/s 50.00p/s 50.00c/s 50.00C/s password_cram
Use the "--show --format=HMAC-MD5" options to display all of the cracked passwords reliably
Session completed
```