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

SOCKS5 updates for BIND requests parsing specs and refactoring #10102

Merged
merged 10 commits into from
May 30, 2018

Conversation

zeroSteiner
Copy link
Contributor

@zeroSteiner zeroSteiner commented May 27, 2018

This makes some changes to the new SOCKS5 server code base, most notably:

  1. Adds support for BIND requests
  2. Refactors request parsing to use bindata
  3. Adds spec tests for request packets
  4. Refactors the code base into submodules
  5. UDP associate requests will be responded to with a "command not supported"
    error

The bind implementation is able to accept reverse connections over sessions. The
implemenation is a bit liberal in the sense that it does not deny connections
from hosts other than the one specified in the request. This is necessary to
make it functional when the user doesn't know where the connection will
originate from.

Verification

  • Review the new test units and make sure they seem sensible
  • Ensure the new test units all pass (travis should handle this but they can
    be run manually using rspec spec/lib/rex/proto/proxy
  • Start msfconsole
  • use auxiliary/server/socks5
  • Test the bind functionality (implementations are hard to come by, see
    this tcl implementation for the one)

Bind Testing

Socks clients and libraries supporting bind are hard to come by. For example,
Filezilla forces passive mode when a SOCKS proxy is in use and proxychains-ng
and tsocks simply don't support it. For testing with the tcl implementation
referenced above, the following script (a slight modification from the libraries
example) can be used.

# allow the socks5 package to be in the same directory
pkg_mkIndex -verbose [pwd] socks5.tcl
lappend auto_path [pwd]
package require socks5

proc handle_connect {result arg} {
   if {$result eq "ok"} {
      puts "connection established via channel $arg"
   } elseif {$result eq "timeout"} {
      puts "timeout expired while waiting for connection"
   } elseif {$result eq "error"} {
      puts "error from proxy while waiting for connection: $arg"
   }
}

socks5::configure -proxy localhost -proxyport 1080 -bindtimeout 2000

# accept a connection form 192.168.0.10
socks5::bind 192.168.0.10 21 handle_connect

cc: @asoto-r7

@asoto-r7
Copy link
Contributor

Test units all pass:

asoto@AUS-MBP-4155:~/git/r7/metasploit-framework (pr/10102)$ rspec spec/lib/rex/proto/proxy
WARN: Unresolved specs during Gem::Specification.reset:
      minitest (~> 5.1)
      crass (~> 1.0.2)
      rake (>= 0.8.7)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

Randomized with seed 64774
Rex::Proto::Proxy::Socks5::Packet ............
Rex::Proto::Proxy::Socks5::Server .

Top 10 slowest examples (0.09125 seconds, 93.1% of total time):
  Rex::Proto::Proxy::Socks5::Packet#address= should set an IPv6 address
    0.08114 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:35
  Rex::Proto::Proxy::Socks5::Packet#address= should set a domain name
    0.00191 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:42
  Rex::Proto::Proxy::Socks5::Packet#address= should set an IPv4 address
    0.0014 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:28
  Rex::Proto::Proxy::Socks5::Packet#command should parse a bind command
    0.00109 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:56
  Rex::Proto::Proxy::Socks5::Packet#version should have the SOCKS5 version set by default
    0.00102 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:86
  Rex::Proto::Proxy::Socks5::Packet#to_binary_s should pack the data to a binary string
    0.00101 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:79
  Rex::Proto::Proxy::Socks5::Packet#command should parse a connect command
    0.00093 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:51
  Rex::Proto::Proxy::Socks5::Packet#address should parse a domain name
    0.00093 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:20
  Rex::Proto::Proxy::Socks5::Packet#address should parse an IPv6 address
    0.00091 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:14
  Rex::Proto::Proxy::Socks5::Packet#read should parse all fields
    0.00089 seconds ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:68

Top 2 slowest example groups:
  Rex::Proto::Proxy::Socks5::Packet
    0.00795 seconds average (0.09536 seconds / 12 examples) ./spec/lib/rex/proto/proxy/socks5/packet_spec.rb:4
  Rex::Proto::Proxy::Socks5::Server
    0.00086 seconds average (0.00086 seconds / 1 example) ./spec/lib/rex/proto/proxy/socks5/server_spec.rb:4

Finished in 0.09798 seconds (files took 11.31 seconds to load)
13 examples, 0 failures

Randomized with seed 64774
Coverage report generated for RSpec to /Users/asoto/git/r7/metasploit-framework/coverage. 764 / 5472 LOC (13.96%) covered.

@asoto-r7
Copy link
Contributor

asoto-r7 commented May 30, 2018

@zeroSteiner provided a TCL script that was helpful for testing BIND, because every other implementation sucks. 😄

TCL client

msf_socks5.tcl
#!/bin/sh
# This line continues for Tcl, but is a single line for 'sh' \
exec tclsh "$0" ${1+"$@"}
# test_client.tcl --
#
#   Implements a simple TCP client program utilizing the SOCKS 5 library
#
# Copyright (c) 2011 Blair Kitchen
#
# See the file "license.terms" for information on usage and
# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
set proxyIP "localhost"
set proxyPort "1080"
set serverHost "ubuntu.target.com"
set serverIP "192.168.108.227"
set serverPort "8000"
set root [file join [file dirname [info script]] ..]
source [file join $root socks5.tcl]
set data ""
proc handleConnect {result arg} {
    if {$result != "ok"} {
        puts "SOCKS error accepting incoming connection: $arg"
        return
    }
    set ::data $arg
}
::socks5::configure -proxy $proxyIP -proxyport $proxyPort -username foo -password bar -bindtimeout 30000
foreach server [list $serverHost $serverIP] {
    puts "Attempting CNTRL connection to $server:$serverPort using proxy $proxyIP:$proxyPort"
    set cntrl [::socks5::connect $server $serverPort]
    puts "CNTRL connection established"
    puts "Attempting to create SOCKS5 binding for DATA connection"
    set bindInfo [::socks5::bind $server $serverPort handleConnect]
    lassign $bindInfo host port
    puts "SOCKS server listening for DATA connection on $host:$port"
    puts "Sending details via CNTRL connection"
    puts $cntrl $host
    puts $cntrl $port
    flush $cntrl
    puts "Waiting for DATA connection"
    vwait data
    puts "DATA connection established"
    puts $cntrl "Hello World (via CNTRL)"
    flush $cntrl
    puts [gets $data]
    puts $data "Hello World (via DATA)"
    flush $data
    puts [gets $cntrl]
    close $data
    close $cntrl
    puts "---------------"
}

Save the above as msf_socks5.tcl.

Sample runthrough:

Step 0: Setup a DNS entry in /etc/hosts and run msfconsole to start the SOCKS5 server:

client$ echo "192.168.108.227 ubuntu.target.com" >> /etc/hosts
client$ ./msfconsole -qx 'use auxiliary/server/socks5; set SRVHOST 127.0.0.1; run'

Step 1: Setup a listener on an "external" server:

server$ nc -vnl 8000
Listening on [0.0.0.0] (family 0, port 8000)

Step 2: Run the TCL script to generate the BIND request. You should see a CNTRL connection:

client$ tclsh msf_socks5.tcl
Attempting CNTRL connection to ubuntu.target.com:8000 using proxy localhost:1080
CNTRL connection established
Attempting to create SOCKS5 binding for DATA connection
SOCKS server listening for DATA connection on 0.0.0.0:54011
Sending details via CNTRL connection
Waiting for DATA connection
DATA connection established

Step 3: Back on the server, you'll get a port for the external server to connect back to the proxy:

server$ nc -vnl 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from [192.168.108.1] port 8000 [tcp/*] accepted (family 2, sport 54008)
0.0.0.0
54011
Hello World (via CNTRL)

Step 4: Connect back to the proxy server on that port, from another window on the external server. You can send strings back to the client via the proxy, and you should see a "Hello World (via DATA)".

server$ nc -vn 192.168.108.1 54011
Connection to 192.168.108.1 54011 port [tcp/*] succeeded!
HELLO
Hello World (via DATA)

asoto-r7 added a commit to asoto-r7/metasploit-framework that referenced this pull request May 30, 2018
@asoto-r7 asoto-r7 merged commit da26665 into rapid7:master May 30, 2018
@asoto-r7
Copy link
Contributor

Many thanks to @zeroSteiner for significant refactoring, assistance with testing, and unit tests! 👍

@asoto-r7
Copy link
Contributor

Release Notes

auxiliary/server/socks5 now supports BIND requests and gracefully declines UDP associate requests.

@asoto-r7 asoto-r7 added this to Done in PR queue Jun 5, 2018
@tdoan-r7 tdoan-r7 added the rn-enhancement release notes enhancement label Jun 20, 2018
@zeroSteiner zeroSteiner deleted the feat/socks5 branch February 23, 2021 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
PR queue
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

3 participants