Class: TDSSSLProxy
- Inherits:
-
Object
- Object
- TDSSSLProxy
- Defined in:
- lib/metasploit/framework/mssql/tdssslproxy.rb
Overview
TDSSSLProxy:
SQL Server uses the TDS protocol to transmit data between clients and servers. Of course this sits on top of TCP.
By default, the TDS payload is not encrypted. However, if “force encryption” is set under the SQL Server protocol properties, it will use SSL/TLS to encrypt the TDS data. Oddly, the entire TCP stream is not encrypted (as is say for HTTPS), but instead a TDS header is put on the front of the TLS packet. As a result, the full TLS/SSL setup is done within a series of TDS payloads.
This “proxy” basically creates a fake SSL endpoint (s2) from which it can add/remove the TDS header as required. This is implemented as a socket pair (think, a bidirectional pipe), where the other end is s1:
sslsock <-> s1 <-> s2 <-> tdssock <-> target SQL Server.
(tdssock is the reference to the “sock” from the scanner module)
TO DO:
This enables brute force of a SQL Server which requires encryption. However, future updates will permit any read/write using mssql_send_recv() to use crypto if required and transparently to other MSF developers.
Cheers, JH
Constant Summary collapse
- TYPE_TDS7_LOGIN =
16
- TYPE_PRE_LOGIN_MESSAGE =
18
- STATUS_END_OF_MESSAGE =
0x01
Instance Method Summary collapse
- #cleanup ⇒ Object
-
#initialize(sock, sslkeylogfile: nil) ⇒ TDSSSLProxy
constructor
A new instance of TDSSSLProxy.
- #send_recv(pkt) ⇒ Object
- #setup_ssl ⇒ Object
- #ssl_setup_thread ⇒ Object
- #write_to_keylog_file(ctx, sslkeylogfile) ⇒ Object
Constructor Details
#initialize(sock, sslkeylogfile: nil) ⇒ TDSSSLProxy
Returns a new instance of TDSSSLProxy.
41 42 43 44 45 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 41 def initialize(sock, sslkeylogfile: nil) @tdssock = sock @sslkeylogfile = sslkeylogfile @s1, @s2 = Rex::Socket.tcp_socket_pair end |
Instance Method Details
#cleanup ⇒ Object
47 48 49 50 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 47 def cleanup @running = false @t1.join end |
#send_recv(pkt) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 78 def send_recv(pkt) @ssl_socket.write(pkt) done = false resp = "" while (not done) head = @ssl_socket.read(8) if !(head and head.length == 8) return false end # Is this the last buffer? if (head[1, 1] == "\x01" or not check_status) done = true end # Grab this block's length rlen = head[2, 2].unpack('n')[0] - 8 while (rlen > 0) buff = @ssl_socket.read(rlen) return if not buff resp << buff rlen -= buff.length end end resp end |
#setup_ssl ⇒ Object
68 69 70 71 72 73 74 75 76 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 68 def setup_ssl @running = true @t1 = Thread.start { ssl_setup_thread } ctx = OpenSSL::SSL::SSLContext.new(:SSLv23) write_to_keylog_file(ctx, @sslkeylogfile) ctx.ciphers = "ALL:!ADH:!EXPORT:!SSLv2:!SSLv3:+HIGH:+MEDIUM" @ssl_socket = OpenSSL::SSL::SSLSocket.new(@s1, ctx) @ssl_socket.connect end |
#ssl_setup_thread ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 108 def ssl_setup_thread while @running do res = select([@tdssock, @s2], nil, nil, 0.1) if res res[0].each do |r| # response from SQL Server for client if r == @tdssock resp = @tdssock.recv(4096) if @ssl_socket.state[0, 5] == "SSLOK" @s2.send(resp, 0) else @s2.send(resp[8..-1], 0) end end # request from client for SQL Server if r == @s2 resp = @s2.recv(4096) # SSL negotiation completed - just send it on if @ssl_socket.state[0, 5] == "SSLOK" @tdssock.send(resp, 0) # Still doing SSL else tds_pkt_len = 8 + resp.length pkt_hdr = '' pkt_hdr << [TYPE_PRE_LOGIN_MESSAGE, STATUS_END_OF_MESSAGE, tds_pkt_len, 0x0000, 0x00, 0x00].pack('CCnnCC') pkt = pkt_hdr << resp @tdssock.send(pkt, 0) end end end end end @s1.close @s2.close end |
#write_to_keylog_file(ctx, sslkeylogfile) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/metasploit/framework/mssql/tdssslproxy.rb', line 52 def write_to_keylog_file(ctx, sslkeylogfile) # writing to the sslkeylogfile is required, it adds support for network capture decryption which is useful to # decrypt TLS traffic in wireshark if sslkeylogfile unless ctx.respond_to?(:keylog_cb) raise 'Unable to create sslkeylogfile - Ruby 3.2 or above required for this functionality' end ctx.keylog_cb = proc do |_sock, line| File.open(sslkeylogfile, 'ab') do |file| file.write("#{line}\n") end end end end |