← Back to all posts
Internal Network Security Research5 min read

Internal Network Proxy Traffic: SOCKS5 Protocol Analysis and Programming

In routine penetration testing exercises, proxies are indispensable. Common choices include Cobalt Strike’s built-in SOCKS4 proxy and the SOCKS5 protocol used by proxy tools. Traffic detection evasion must also be considered, making it necessary to examine the underlying protocol in detail and analyze and modify traffic characteristics.

#Security Development#Security#Web Security
Read in Chinese→

0x00 Background

Proxies are indispensable in routine penetration testing exercises. We generally use Cobalt Strike’s built-in SOCKS4 proxy or the SOCKS5 protocol supported by proxy tools. At the same time, we also need to consider traffic detection evasion during this process. Therefore, it is still necessary to examine the underlying protocol in detail, then analyze and modify the characteristics found in the traffic.

0x01 Introduction and Workflow

The following is excerpted from Wikipedia:

SOCKS is a network transport protocol primarily used to relay communications between clients and external servers. SOCKS is an abbreviation of “SOCKetS”[Note 1]. When a client behind a firewall wants to access an external server, it connects to a SOCKS proxy server. The proxy server controls whether the client is authorized to access the external network. If access is allowed, it forwards the client’s request to the external server. The protocol was originally developed by David Koblas and was later extended to SOCKS4 by Ying-Da Lee of NEC. The latest version is SOCKS5, which adds support for UDP, authentication, and IPv6 compared with the previous version. According to the OSI model, SOCKS is a session-layer protocol located between the presentation layer and the transport layer. The SOCKS protocol does not provide encryption.

A small fact: SOCKS5 extends version 4 by adding support for the UDP protocol.

The SOCKS5 protocol is primarily divided into three stages:

  • (1) Protocol version and authentication method
  • (2) Perform the corresponding authentication based on the selected method
  • (3) Request information

The following sections analyze these processes in detail, with a little Go pseudocode included for readability.

0x02 Socks5Auth Authorization and Authentication

The client must first initiate a request specifying the protocol version and authentication methods.

This is the request format sent by the client to the server:

VER Protocol version number for this request; SOCKS5 uses the fixed value 0x05
NMETHODS Number of authentication methods supported by the client; valid values range from 1~255
METHODS List of available authentication methods

The server must then select an authentication method and inform the client:

VER VER specifies the SOCKS version, which is 0x05
METHOD Selected authentication method; 0x00 means no authentication is required, 0x02 means username/password authentication, ……

METHOD generally supports two commonly used authentication methods:

  • 0x00 (no authentication required)
  • 0x20 (username/password authentication)

For example, since this is SOCKS5, the accepted version must be 0x05. If we configure it so that no authentication is required, the method is 0x00.```javascript //无需认证 直接返回 0x05 0x00 就好了 n, err = client.Write([]byte{0x05, 0x00})


# 0x03 Establishing a Connection in the SOCKS5 Protocol

After the SOCKS5 client and server successfully complete mutual authorization and authentication, they begin establishing a connection. The connection is initiated by the client, which tells the SOCKS server which remote server it needs to access. This includes the remote server’s address and port. The address may be IPv4, IPv6, or a domain name.

| VER | VER specifies the SOCKS version, which is 0x05 |
| --- | --- |
| REP | Status code: 0x00=success, 0x01=unknown error, …… |
| RSV | Still a useless RESERVED field |
| ATYP | Address type |
| BND.ADDR | Address used by the server to establish a connection with DST |
| BND.PORT | Port used by the server to establish a connection with DST |

- VER represents the SOCKS protocol version. SOCKS5 uses 0x05 by default, and the field is 1 byte long.

- CMD represents the type of client request. This field is also 1 byte long and has three possible values:

  - CONNECT 0x01
  - BIND 0x02
  - UDP ASSOCIATE 0x03’

- RSV is a reserved field with a length of 1 byte.

- ATYP represents the address type of the requested remote server. This field is 1 byte long, and there are three commonly used types.

- ```javascript
  1:表示是一个IPV4地址(IP V4 address);
  3:表示是一个域名(DOMAINNAME);
  4:表示是一个IPV6地址(IP V6 address);
  • DST.ADDR represents the address of the remote server. It is parsed according to ATYP and has a variable length.

  • DST.PORT represents the remote server port—that is, the port to be accessed. This field is 2 bytes long.

When the server responds to the client that the connection was successful, it returns the following data:

resp := []byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

This is also a relatively interesting aspect when working on traffic detection evasion.

0x03 Data Forwarding After Establishing the Connection

After the connection has finally been established, data must be forwarded. This works the same way as writing port forwarding: use io.Copy() to forward traffic between the two ports.

Because Golang provides io.Copy, it is very simple to use.

forward := func(src, dest net.Conn) {
    defer src.Close()
    defer dest.Close()
    io.Copy(src, dest)
  }

go forward(client, target)
go forward(target, client)

0x04 Traffic Detection Issues

Only SkyEye was tested here. This authentication process can be identified easily because the matching rule becomes immediately apparent after analysis. This is the rule for the server responding to the client that the connection was successful, so SkyEye detects it as a successful attack rule.

{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

SkyEye’s detection PAYLOAD:

0x05 Traffic Detection Evasion

Once the rule is known, evading detection becomes much easier. Since this is part of the SOCKS authentication process, although the server can be modified, all of our tools use the standard SOCKS5 protocol, which means the client would also need to be modified. Therefore, modifying the authentication process is not particularly convenient. The simplest implementation is to add a tunnel in the middle.

image-20211027203826936

This can indeed evade traffic detection, but I did not notice when writing it that it used a forward connection. For real-world use, it should instead be written so that the client actively establishes the outbound connection. As it stands, it is not very useful, so I will have to revise it again…