Class: Rex::Proto::Proxy::Socks4a::Client::Packet

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/proto/proxy/socks4a.rb

Overview

A Socks4a packet.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePacket

Returns a new instance of Packet.



41
42
43
44
45
46
47
# File 'lib/rex/proto/proxy/socks4a.rb', line 41

def initialize
  @version   = REQUEST_VERSION
  @command   = 0
  @dest_port = 0
  @dest_ip   = '0.0.0.0'
  @userid    = ''
end

Instance Attribute Details

#commandObject

Returns the value of attribute command.



124
125
126
# File 'lib/rex/proto/proxy/socks4a.rb', line 124

def command
  @command
end

#dest_ipObject

Returns the value of attribute dest_ip.



124
125
126
# File 'lib/rex/proto/proxy/socks4a.rb', line 124

def dest_ip
  @dest_ip
end

#dest_portObject

Returns the value of attribute dest_port.



124
125
126
# File 'lib/rex/proto/proxy/socks4a.rb', line 124

def dest_port
  @dest_port
end

#useridObject

Returns the value of attribute userid.



124
125
126
# File 'lib/rex/proto/proxy/socks4a.rb', line 124

def userid
  @userid
end

#versionObject

Returns the value of attribute version.



124
125
126
# File 'lib/rex/proto/proxy/socks4a.rb', line 124

def version
  @version
end

Class Method Details

.recv(sock, timeout = 30) ⇒ Object

A helper function to recv in a Socks4a packet byte by byte.

sf: we could just call raw = sock.get_once but some clients

seem to need reading this byte by byte instead.


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rex/proto/proxy/socks4a.rb', line 55

def Packet.recv( sock, timeout=30 )
  raw = ''
  # read in the 8 byte header
  while( raw.length < 8 )
    raw << sock.read( 1 )
  end
  # if its a request there will be more data
  if( raw[0..0].unpack( 'C' ).first == REQUEST_VERSION )
    # read in the userid
    while( raw[8..raw.length].index( "\x00" ) == nil )
      raw << sock.read( 1 )
    end
    # if a hostname is going to be present, read it in
    ip = raw[4..7].unpack( 'N' ).first
    if( ( ip & 0xFFFFFF00 ) == 0x00000000 and ( ip & 0x000000FF ) != 0x00 )
      hostname = ''
      while( hostname.index( "\x00" ) == nil )
        hostname += sock.read( 1 )
      end
      raw << hostname
    end
  end
  # create a packet from this raw data...
  packet = Packet.new
  packet.from_r( raw ) ? packet : nil
end

Instance Method Details

#from_r(raw) ⇒ Object

Unpack a raw packet into its components.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rex/proto/proxy/socks4a.rb', line 94

def from_r( raw )
  return false if( raw.length < 8 )
  @version   = raw[0..0].unpack( 'C' ).first
  return false if( @version != REQUEST_VERSION and @version != REPLY_VERSION )
  @command   = raw[1..1].unpack( 'C' ).first
  @dest_port = raw[2..3].unpack( 'n' ).first
  @dest_ip   = Rex::Socket.addr_itoa( raw[4..7].unpack( 'N' ).first )
  if( raw.length > 8 )
    @userid = raw[8..raw.length].unpack( 'Z*' ).first
    # if this is a socks4a request we can resolve the provided hostname
    if( self.is_hostname? )
      hostname = raw[(8+@userid.length+1)..raw.length].unpack( 'Z*' ).first
      @dest_ip = self.resolve( hostname )
      # fail if we couldnt resolve the hostname
      return false if( not @dest_ip )
    end
  else
    @userid  = ''
  end
  return true
end

#is_bind?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/rex/proto/proxy/socks4a.rb', line 120

def is_bind?
  @command == COMMAND_BIND ? true : false
end

#is_connect?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/rex/proto/proxy/socks4a.rb', line 116

def is_connect?
  @command == COMMAND_CONNECT ? true : false
end

#is_hostname?Boolean (protected)

As per the Socks4a spec, check to see if the provided dest_ip is 0.0.0.XX which indicates after the @userid field contains a hostname to resolve.

Returns:

  • (Boolean)


146
147
148
149
150
151
152
# File 'lib/rex/proto/proxy/socks4a.rb', line 146

def is_hostname?
  ip = Rex::Socket.addr_atoi( @dest_ip )
  if( ip & 0xFFFFFF00 == 0x00000000 )
    return true if( ip & 0x000000FF != 0x00 )
  end
  return false
end

#resolve(hostname) ⇒ Object (protected)

Resolve the given hostname into a dotted IP address.



131
132
133
134
135
136
137
138
139
140
# File 'lib/rex/proto/proxy/socks4a.rb', line 131

def resolve( hostname )
  if( not hostname.empty? )
    begin
      return Rex::Socket.getaddress(hostname, false)
    rescue ::SocketError
      return nil
    end
  end
  return nil
end

#to_rObject

Pack a packet into raw bytes for transmitting on the wire.



85
86
87
88
89
# File 'lib/rex/proto/proxy/socks4a.rb', line 85

def to_r
  raw = [ @version, @command, @dest_port, Rex::Socket.addr_atoi( @dest_ip ) ].pack( 'CCnN' )
  return raw if( @userid.empty? )
  return raw + [ @userid ].pack( 'Z*' )
end