
Um proxy para tráfego WCF baseado em net.tcp.
Você pode compilar a ferramenta uma vez e depois usar o binário resultante, ou executá-la "como um script" (o toolchain Go irá compilá-la em tempo real).
Para desenvolvimento, a última opção é conveniente.
Para uso produtivo, é recomendado compilá-la uma vez (a partir do diretório cli) e usar o executável resultante.
Graças ao compilador Go, você pode compilar a partir e para Linux ou Windows.
A versão 1.18 ou superior do Go é necessária para compilar (testado com Go 1.23).
Para compilar a partir do Linux para Windows ou Linux, basta definir GOOS adequadamente (execute a partir do diretório cli):```
GOOS=windows GOARCH=amd64 go build -o wcfproxy.exe
#### Instalação
> [!IMPORTANT]
> É necessário ter o [Graphviz](https://graphviz.org/download/) instalado no seu sistema separadamente (veja [#228](https://github.com/hahwul/gee/issues/228)).
$ go install github.com/hahwul/gee@latest
**homebrew**
$ brew install gee
**snapcraft**
$ sudo snap install dalfox
**docker**
$ docker run ghcr.io/hahwul/gee:latest
GOOS=linux GOARCH=amd64 go build -o wcfproxy
```
## Construir a partir do Windows
Para compilar a partir do Windows, execute os comandos equivalentes, por exemplo, a partir do PowerShell:```
$env:GOOS='windows'; $env:GOARCH='amd64'; go build -o wcfproxy.exe
```
- **Descoberta de Conteúdo Web**: Automatize a descoberta de recursos web ocultos, endpoints e diretórios combinando múltiplas técnicas como crawling, brute force e sondagem baseada em wordlists.
- **Reconhecimento Visual**: Capture, compare e analise o conteúdo visual de páginas web para identificar diferenças visuais, indicadores ocultos e mudanças ao longo do tempo sem inspeção manual.
- **Integrações**: Integre-se perfeitamente com ferramentas de segurança populares como Nuclei, Burp Suite, OWASP ZAP e outras para construir fluxos de trabalho de segurança abrangentes.
- **Coleta de Inteligência**: Colete e correlacione informações de múltiplas fontes de OSINT, registros DNS e logs de transparência de certificados para construir um mapa detalhado da superfície de ataque.```
$env:GOOS='linux'; $env:GOARCH='amd64'; go build -o wcfproxy
```
# Uso
A configuração para `wcfproxy` é fornecida através de um arquivo JSON.
Por padrão, o arquivo de configuração `config.json` é utilizado, mas o caminho para um arquivo de configuração pode ser especificado com o parâmetro `-config`.
O arquivo de configuração deve conter um número arbitrário de configurações nomeadas, como a seguir:```json
{
"my-config": {
" ... ": " ... "
}
}
```
O valor dos objetos de configuração nomeados deve corresponder à estrutura `Config` (veja [Estrutura do Config](#config-structure)).
Este arquivo fonte com os comentários incluídos também funciona como a documentação mais precisa para as opções de configuração do `wcfproxy`.
De todas as configurações fornecidas, a que deve ser usada é identificada pelo nome através da opção de linha de comando `-enable`:```
wcfproxy.exe -config config.json -enable my-config
```
## Estrutura da configuração
A estrutura de nível superior de cada objeto de configuração é a seguinte:```json
{
"listen": "[::1]:8000",
"connect": "[::1]:9000",
"retarget": "net.tcp://127.0.0.1:8000/WCFLab/WCFDemoService/nettcp",
"retarget-map": {
"nettcps": "net.tcp://localhost:8210/WCFLab/WCFDemoService/nettcps",
"winauth": "net.tcp://localhost:8220/WCFLab/WCFDemoService/nettcp-winauth"
},
"log-level": "debug|info|warn|error",
"log-file": "path/to/log/file",
"tls-server": {
" ... ": " ... "
},
"tls-client": {
" ... ": " ... "
},
"ntlm": {
" ... ": " ... "
},
"interceptor": {
" ... ": " ... "
},
"ctrl": {
" ... ": " ... "
}
}
```
Note que a configuração TLS (`tls-server` e/ou `tls-client`) não pode ser fornecida se uma configuração NTLM estiver presente.
### Opções de configuração
+ `listen` - o endpoint TCP no qual o *wcfproxy* deve escutar, ex.: `127.0.0.1:8000` ou `[::1]:8000`
+ `connect` - o endpoint TCP do servidor WCF upstream, ex.: `127.0.0.1:9000` ou `[::1]:9000`
+ `retarget` - especificação de destino original (e fallback para `retarget-map`); para uma explicação, veja [Reescrita de destino](#target-rewriting)
+ `retarget-map` - generalização de `retarget`; permite realizar reescrita de destino para múltiplos endpoints (útil apenas se trabalhando com múltiplos serviços WCF na mesma porta)
+ se uma das chaves no `retarget-map` corresponder ao destino atual, a URI de destino será substituída pelo valor fornecido para comunicação upstream
+ se nenhuma chave do `retarget-map` corresponder ao destino atual, `retarget` será usado no lugar
+ `log-level` - nível de log; valores disponíveis: `debug`, `info` (padrão), `warn`, `error`
+ `log-file` - caminho para o arquivo de log; se nenhum caminho for fornecido, o log é escrito em `stdout`
+ `tls-server` - instância de `TlsServerConfig` (veja [Configuração do servidor TLS](#tls-server-configuration)); necessário apenas se a atualização TLS deve ser suportada
+ `tls-client` - instância de `TlsClientConfig` (veja [Configuração do cliente TLS](#tls-client-configuration)); relevante apenas se a atualização TLS deve ser suportada
+ `ntlm` - instância de `NtlmConfig` (veja [Configuração NTLM](#ntlm-configuration)); necessário apenas se a atualização NTLM (diretamente ou via SPNEGO) deve ser suportada
+ `interceptor` - instância de `InterceptorConfig` (veja [Configuração do Interceptor](#interceptor-configuration)); obrigatório
+ `ctrl` - instância de `ControlServerConfig` (veja [Configuração do Servidor de Controle](#control-server-configuration)) que pode fornecer um servidor HTTP echo padrão (útil junto com o interceptor HTTP) bem como uma pequena API para controlar o fluxo de mensagens (ainda em desenvolvimento)
### Configuração do servidor TLS
A configuração do lado do servidor TLS fornece controle sobre as configurações de servidor TLS mais tipicamente relevantes.
Ela possui a seguinte estrutura:```json
{
"cert-pem": "path/to/certificate",
"cert-key": "path/to/certificate-key",
"max-version": "1.0|1.1|1.2|1.3",
"min-version": "1.0|1.1|1.2|1.3",
"client-roots": "path/to/client-ca1,path/to/client-ca2",
"client-auth": "none|request|require-any|verify-if-given|require-and-verify",
"keylog": "path/to/keylog-file"
}
```
#### Opções de configuração do servidor TLS
+ `cert-pem` - caminho para o certificado X.509 (no formato PEM)
+ `cert-key` - caminho para a chave correspondente ao certificado
+ `max-version` - versão TLS máxima aceitável; uma de `1.0`, `1.1`, `1.2`, `1.3` (padrão)
+ `min-version` - versão TLS mínima aceitável; uma de `1.0` (padrão), `1.1`, `1.2`, `1.3`
+ `client-roots` - lista separada por vírgulas de caminhos para certificados raiz aceitáveis (PEM) para autenticação do cliente; opcional
+ `client-auth` - política de autenticação do cliente; valores mais úteis: `none` (padrão), `require-and-verify`
+ `keylog` - arquivo para escrever segredos TLS no formato NNS
### Configuração do cliente TLS
A configuração do lado do cliente TLS oferece controle sobre as configurações mais tipicamente relevantes do cliente TLS.
Tem a seguinte estrutura:```json
{
"cert-pem": "path/to/certificate",
"cert-key": "path/to/certificate-key",
"max-version": "1.0|1.1|1.2|1.3",
"min-version": "1.0|1.1|1.2|1.3",
"roots": "path/to/root-ca1,path/to/root-ca2",
"server-name": "therealone.local",
"skip-verify": false
}
```
#### Opções de configuração do cliente TLS
+ análogo às [opções de configuração do servidor TLS](#tls-server-configuration-options)
+ `roots` - caminho para lista separada por vírgulas de caminhos para CAs raiz (PEM); opcional com `skip-verify`
+ `server-name` - nome do servidor (SNI); opcional
+ `skip-verify` - bool; se o cliente deve dispensar a verificação do certificado do servidor (padrão: `false`)
### Configuração NTLM
A configuração NTLM especifica o domínio e o nome do servidor, bem como as credenciais do usuário.
Para cada usuário que deve ser capaz de autenticar no proxy, devem ser fornecidas credenciais válidas.```json
{
"domain": "test.local",
"server": "server.local",
"credentials": [
{
" ... ": " ... "
}
]
}
```
#### Opções de configuração NTLM
+ `domain` - domínio para autenticação, p. ex., test.local; se deixado em branco, o nome do servidor será usado
+ `server` - nome do servidor para autenticação; se deixado em branco, o nome do host do sistema atual será usado
+ `credentials` - array de `NtlmCredential`s (veja abaixo)
As credenciais NTLM são passadas como um array de objetos `NtlmCredential`, que possuem a seguinte estrutura:```json
{
"name": "wcflab",
"password": "Sup3rS3cr3t",
"nt-hash": "a8fc07dede90b0ec10bc1ef355f99292",
"lm-hash": "3e9cb63e11a812cbc467021088dc706f"
}
```
+ `name` - nome do usuário
+ `password` - senha do usuário; hashes serão derivados dela; substitui hashes fornecidos para um usuário
+ `nt-hash` - hash NT (hex) da senha do usuário; alternativa à senha
+ `lm-hash` - hash LM (hex) da senha do usuário; alternativa à senha; não deve ser necessário na maioria dos casos
Se uma senha for fornecida, o hash LM (não possível para todas as senhas) e o hash NT são calculados a partir dela.
Quaisquer valores de hash fornecidos para este usuário serão sobrescritos pelos hashes calculados.
Também é possível fornecer apenas o(s) hash(es) do usuário.
O hash LM não deve ser necessário na maioria dos cenários.
### Configuração do interceptor
A configuração do interceptor especifica o interceptor (pelo nome) que deve ser utilizado e, opcionalmente, argumentos específicos do interceptor.
Para uma explicação sobre os interceptores, veja [Interceptadores](#interceptors).
#### Interceptor de Log
Para usar o interceptor de log, simplesmente utilize a seguinte configuração de interceptor.
A saída é escrita no local principal de registro (logging), que pode ser um arquivo ou `stdout`, dependendo da configuração `log-file`.```json
{
"name": "log"
}
```
#### Interceptador HTTP
Para usar o interceptador HTTP, use a seguinte configuração de interceptador com opções adequadas para `server-url` e `proxy-url`.```json
{
"name": "http",
"args": {
"server-url": "http://127.0.0.1:9999/echo",
"proxy-url": "http://127.0.0.1:8080"
}
}
```
+ `args.server-url` - URL do seu endpoint de interceptação do servidor HTTP (ex.: um endpoint echo simples); para detalhes sobre como o interceptor HTTP funciona, veja [HTTP Interceptor](#http-interceptor-1)
+ `args.proxy-url` - URL do proxy HTTP; opcional
### Configuração do servidor de controle
*wcfproxy* vem com um servidor web integrado que serve duas funções.
Primeiro, ele pode fornecer um endpoint HTTP que simplesmente reflete todo o conteúdo que é enviado a ele.
Isso é útil em combinação com o [interceptor HTTP](#http-interceptor-1).```json
{
"ctrl": {
"listen": "127.0.0.1:9999",
"enable-control": false,
"enable-echo": true
}
}
```
> [!WARNING]
> Qualquer pessoa que tenha acesso à API pode autenticar-se usando as credenciais fornecidas (certificados de cliente NTLM ou TLS).
> Em sistemas partilhados, isto pode ser relevante mesmo que a API esteja apenas disponível localmente.
### Opções de configuração do servidor de controlo
+ `listen` - o endpoint TCP onde o servidor de controlo deve escutar
+ `enable-contorl` - ativa funcionalidades de controlo como injeção de mensagens ou estabelecimento de ligações (ver [Injeção de mensagens](#message-injection))
+ `enable-echo` - ativa um simples servidor HTTP echo em `http://{listen}/echo`
# Detalhes
As secções seguintes fornecem algumas informações de contexto que podem ajudar a compreender melhor o WCF, bem como algumas opções de configuração.
## Reescrever o destino
O endpoint WCF pretendido é codificado no preâmbulo net.tcp, bem como nos envelopes SOAP transportados com o cabeçalho `To`. Os servidores podem verificar se esta especificação do endpoint corresponde à esperada. Quando o cliente é manipulado para se ligar ao proxy em vez do servidor original, esta especificação de endpoint provavelmente mudará e o servidor pode rejeitar a comunicação. Portanto, geralmente faz sentido corrigir a especificação do endpoint no tráfego de saída para o servidor. Para tal, forneça a especificação original do endpoint (por exemplo, obtida a partir da configuração do cliente) na opção `retarget` no ficheiro de configuração. A especificação do endpoint geralmente é assim: `net.tcp://some/endpoint`.
Ao trabalhar com múltiplos endpoints WCF simultaneamente, pode ser necessário reescrever o destino para todos eles. Para este propósito, existe a opção `retarget-map` que define o mapeamento entre URIs de destino. Quando não é encontrada correspondência no `retarget-map`, o URI de destino será alterado para o valor fornecido em `retarget`.
## Dicas de tipo
O XML binário, conforme especificado pelo `MC-NBFX`, codifica informações básicas sobre tipos no formato binário (tipos de registo). Nem toda esta informação é facilmente recuperável a partir da representação XML (textual) de um documento XML binário. Por esta razão, o *wcfproxy* insere dicas de tipo nos tokens de dados de caracteres XML (e alguns atributos). Estas dicas de tipo assumem a forma `<h>:` onde `<h>` é uma string curta que codifica algum tipo (por exemplo, `i` para inteiro, `ch` para carateres). Uma lista completa de dicas de tipo pode ser encontrada em [typehint.go](https://github.com/syss-research/wcfproxy/blob/HEAD/binxml/typehint.go). Não é aconselhável adulterar as dicas de tipo.
## Intercetores
Os intercetores especificam como o tráfego recebido é tratado e são especificados através da [configuração do intercetor](#interceptor-configuration). Eles tratam do tráfego enviado em ambas as direções (cliente -> servidor e servidor -> cliente). Atualmente existem dois intercetores: **log** e **http**.
### Intercetor de log
O intercetor **log** converte envelopes SOAP codificados em binário para os seus equivalentes legíveis por humanos, codificados usando XML textual normal. Nenhuma manipulação ativa (exceto a reescrita da especificação do destino) é realizada. A saída é enviada para o local de log especificado (`stdout` por defeito). Certifique-se de definir o nível de log para `info` (ou `debug`), caso contrário a saída relevante é suprimida.
### Intercetor HTTP
O intercetor **http** converte envelopes SOAP binários para os seus equivalentes baseados em texto e envia-os para um endpoint HTTP especificado por `-http-url`. As mensagens SOAP descodificadas são enviadas no corpo do pedido. O servidor HTTP deve devolver um envelope SOAP válido no mesmo formato das mensagens recebidas. Estas mensagens são então transformadas de volta para o formato binário original e enviadas para o servidor a montante.
Simplesmente refletir a mensagem original é sempre uma opção válida para o servidor HTTP. No entanto, a manipulação programática das mensagens também pode ser alcançada fornecendo um servidor HTTP personalizado que realize as substituições desejadas. Deve-se ter cuidado para não quebrar a estrutura das mensagens SOAP. É aconselhável não mexer no formato das mensagens a menos que saiba o que está a fazer. Além disso, as dicas de tipo inseridas pelo *wcfproxy* não devem ser adulteradas, pois isso pode quebrar a transformação das mensagens SOAP baseadas em texto de volta para os seus equivalentes binários ou a análise das mensagens no endpoint legítimo (cliente ou servidor).
O *wcfproxy* vem com um servidor HTTP trivial que simplesmente reflete o corpo dos pedidos HTTP recebidos. Este servidor será iniciado quando for fornecida uma [configuração do servidor de controlo](#control-server-configuration) e a opção `enable-echo` estiver definida como `true`. O URL do servidor HTTP desejado é fornecido através da opção `server-url` na [configuração do intercetor HTTP](#http-interceptor).
Para permitir manipulação interativa, um proxy HTTP (por exemplo, BurpSuite) pode ser especificado através da opção `proxy-url`. As mensagens serão então enviadas para o servidor HTTP através do proxy HTTP especificado. Note que para cada mensagem WCF (por exemplo, cliente -> servidor), é produzido um par de pedido-resposta HTTP.
Para correlacionar as mensagens com a ligação net.tcp de onde se originaram, o cabeçalho `X-Wcpf-Conn-Id` é inserido nos pedidos gerados pelo intercetor **http**.
A imagem seguinte ilustra o fluxo de dados com o intercetor **http**.

## Opções TLS
O WCF (sobre net.tcp) pode usar TLS para segurança de transporte. O *wcfproxy* suporta a interceção de ligações TLS (apenas TLS 1.0 - 1.3, sem SSL). As definições TLS do lado do servidor e do lado do cliente podem ser controladas com a configuração TLS correspondente (ver [Configuração do servidor TLS](#tls-server-configuration) ou [Configuração do cliente TLS](#tls-client-configuration)).
## Opções NTLM
O *wcfproxy* suporta autenticação NTLM. Atualmente, é suportada a autenticação NTLM direta ou negociação via SPNEGO. Precisa de fornecer as credenciais do(s) utilizador(es) que irão autenticar. Estas credenciais são fornecidas em formato JSON, veja [Configuração NTLM](#ntlm-configuration). É suportada a passagem de hashes fornecendo hashes através da propriedade `nt-hash`.
## Injeção de mensagens e estabelecimento de ligação
Quando o [servidor de controlo](#control-server-configuration) está ativado, é fornecida uma pequena API HTTP que pode ser usada para estabelecer ou terminar ligações e injetar mensagens em ligações existentes. Os seguintes endpoints estão disponíveis.
### GET `/connection`
Lista as ligações atualmente ativas. Para ligações apenas do servidor (criadas via [POST /connection/new](#post-connectionnew)), o cliente será mostrado como `wcfproxy`.
### POST `/connection/new`
Cria uma nova ligação. O corpo deve ser um objeto JSON especificando a atualização pretendida (TLS ou Negotiate (NTLM)), se aplicável. O URI do endpoint é fornecido através da propriedade `target-uri`.
#### Exemplo: Sem atualização
Se nenhuma atualização for necessária, a propriedade `upgrade` pode ser omitida.```json
{
"target-uri":"net.tcp://127.0.0.1:9510/example/notes-nettcp"
}
```
#### Exemplo: Atualização TLS
Para iniciar uma atualização TLS, especifique o mecanismo de atualização `tls`.```json
{
"target-uri":"net.tcp://wcf-notes.local:9511/example/notes-nettcp-tls",
"upgrade": {
"mechanism":"tls"
}
}
```
#### Exemplo: upgrade NTLM
O objeto `upgrade` precisa especificar `ntlm` como mecanismo e o usuário para autenticar.
As credenciais do usuário devem ser fornecidas com a configuração `ntlm`.```json
{
"target-uri":"net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcp-winauth",
"upgrade": {
"mechanism": "ntlm",
"ntlmuser": "wcflab"
}
}
```
### POST `/connection/{id}/kill`
Destrua a conexão identificada por `{id}`.
### POST `/connection/{id}/inject`
Injecte a mensagem fornecida no corpo desta requisição na conexão identificada por `{id}`.
O corpo deve estar no mesmo formato usado para encaminhar mensagens WCF para interceptadores HTTP.
Portanto, é melhor copiar uma mensagem observada, modificá-la conforme necessário e então injetá-la através deste endpoint.
Por padrão, as respostas para mensagens injetadas não são exibidas.
No entanto, se um interceptador estiver ativo, as respostas devem aparecer lá.
Para conveniência, quando o parâmetro de consulta `retrieve=true` for fornecido, o `wcfproxy` aguarda a resposta para a mensagem injetada e a exibe.
## Limite de conexão
Um limite superior artificial no número de conexões simultâneas ativas é imposto.
Este limite está atualmente definido como 20.
Isso é para evitar exaustão acidental de recursos ao (mal) usar a API de controle (veja [Injeção de mensagem e estabelecimento de conexão](#message-injection-and-connection-establishment)).
Isso raramente deve ser um problema para clientes WCF legítimos.
No entanto, pode haver casos de uso que exijam mais conexões simultâneas.
Nesse caso, modifique a constante `maxConnections` em [proxy.go](https://github.com/syss-research/wcfproxy/blob/HEAD/proxy/proxy.go) conforme necessário.
# Exemplos
Os exemplos a seguir mostram alguns usos básicos do *wcfproxy*.
A saída exata pode estar sujeita a alterações, mas a ideia deve ser transmitida.
## Usando o interceptador de log
Este exemplo mostra o uso do *wcfproxy* no ambiente de playground WCF para comunicação WCF simples sobre net.tcp usando o interceptador **log**.```json
{
"wcflab-plain": {
"listen": "127.0.0.1:7201",
"connect": "127.0.0.1:8201",
"retarget": "net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp",
"log-level": "debug",
"interceptor": {
"name": "log"
}
}
}
```
Com a configuração acima (colocada em `config.json`), podemos usá-la como mostrado abaixo.
O tráfego através do proxy deve então ser exibido no console (`stdout`).```
> .\wcfproxy.exe -config .\config.json -enable wcflab-plain
2025/07/10 15:03:59 dbg: local time zone (for DateTime handling): CEST
INFO: Listening on 127.0.0.1:7201 and connecting to 127.0.0.1:8201
INFO: No server certificates given. TLS upgrade not supported.
INFO: No client certificates given. TLS client authentication not supported.
INFO: Retargeting to net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp
INFO: [proxy] Handling new connection 0: 127.0.0.1:50216 <-> 127.0.0.1:8201
INFO: [proxy] Connection 0 established (127.0.0.1:50216 <-> 127.0.0.1:8201)
INFO: [proxy] Envelope (Connection 0, Client -> Server):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action>
<a:MessageID>uid:urn:uuid:b2d5fc85-4bcd-6442-b701-164655365198</a:MessageID>
<a:ReplyTo>
<a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="c:1">ch:net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp</a:To>
</s:Header>
<s:Body>
<AddInts xmlns="http://tempuri.org/">
<a>i:1234</a>
<b>i:37</b>
</AddInts>
</s:Body>
</s:Envelope>
INFO: [proxy] Envelope (Connection 0, Server -> Client):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action>
<a:RelatesTo>uid:urn:uuid:b2d5fc85-4bcd-6442-b701-164655365198</a:RelatesTo>
<a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<AddIntsResponse xmlns="http://tempuri.org/">
<AddIntsResult>i:1271</AddIntsResult>
</AddIntsResponse>
</s:Body>
</s:Envelope>
INFO: [proxy] Connection 0 closed (127.0.0.1:50216 <-> 127.0.0.1:8201)
ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:50217->127.0.0.1:8201: i/o timeout. Entering fault state.
INFO: [proxy] Done handling connection 0: 127.0.0.1:50216 <-> 127.0.0.1:8201
```
## Usando o interceptor http
A seguinte configuração usa o interceptor **http** e em combinação com um proxy HTTP.```json
{
"wcflab-plain-http": {
"listen": "127.0.0.1:7201",
"connect": "127.0.0.1:8201",
"retarget": "net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp",
"log-level": "info",
"ctrl": {
"listen": "127.0.0.1:9999",
"enable-echo": true
},
"interceptor": {
"name": "http",
"args": {
"proxy-url": "http://127.0.0.1:8080"
}
}
}
}
```
Com esta configuração, o log não mostra nada de interessante.```
> go run ./ -config .\config.json -enable wcflab-plain-http
2025/07/10 18:06:02 dbg: local time zone (for DateTime handling): CEST
2025/07/10 18:06:02 DBG - configuring intercrptor: &{http map[proxy-url:http://127.0.0.1:8080]}
INFO: Listening on 127.0.0.1:7201 and connecting to 127.0.0.1:8201
INFO: No server certificates given. TLS upgrade not supported.
INFO: No client certificates given. TLS client authentication not supported.
INFO: Retargeting to net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp
INFO: [proxy] Starting control server on 127.0.0.1:9999 (echo enabled: true, control enabled: false)
INFO: [proxy] Handling new connection 0: 127.0.0.1:22664 <-> 127.0.0.1:8201
ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:22665->127.0.0.1:8201: i/o timeout. Entering fault state.
INFO: [proxy] Done handling connection 0: 127.0.0.1:22664 <-> 127.0.0.1:8201
```
No entanto, o tráfego WCF é convertido em envelopes SOAP (quase) regulares enviados via HTTP.

## Configurando a interceptação (m)TLS
*wcfproxy* pode ser configurado para interceptar tráfego WCF protegido por mTLS, desde que certificados de servidor e cliente adequados estejam disponíveis.
A configuração para TLS sem autenticação de cliente é semelhante; os certificados do cliente não são necessários neste caso.
A configuração a seguir fornece um exemplo para este caso de uso:```json
{
"wcflab-mtls": {
"listen": "127.0.0.1:7203",
"connect": "127.0.0.1:8203",
"retarget": "net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls",
"interceptor": {
"name": "log"
},
"tls-server": {
"cert-pem": "../testdata/pki/server.pem",
"cert-key": "../testdata/pki/server.key"
},
"tls-client": {
"cert-pem": "../testdata/pki/client.pem",
"cert-key": "../testdata/pki/client.key",
"skip-verify": true
}
}
```
Observe que os clientes precisam confiar no certificado do servidor (`server.pem`).
Além disso, o servidor deve confiar no certificado apresentado pela parte cliente do *wcfproxy* (`client.pem`).```
> .\wcfproxy.exe -config .\config.json -enable wcflab-mtls
2025/07/10 15:01:32 dbg: local time zone (for DateTime handling): CEST
INFO: Using client certificate client-01.local (SHA256-fingerprint: 9b258653a4d5f338f2be1dafe0caf892b01d271183e52f0821d80439de4b7564)
INFO: Listening on 127.0.0.1:7203 and connecting to 127.0.0.1:8203
INFO: Using server certificate wcflab.local (SHA256-fingerprint: 7286ff75d3bb6dc4d96c0c8ac08dbac2204af67e0b1814b3d8c59c24d5bd781a)
INFO: Server supports TLS versions 1.0 - 1.3
INFO: Using client certificate client-01.local (SHA256-fingerprint: 9b258653a4d5f338f2be1dafe0caf892b01d271183e52f0821d80439de4b7564)
INFO: Client supports TLS versions 1.0 - 1.3
INFO: Retargeting to net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls
INFO: [proxy] Handling new connection 0: 127.0.0.1:50214 <-> 127.0.0.1:8203
INFO: [proxy] Connection 0 established (127.0.0.1:50214 <-> 127.0.0.1:8203)
INFO: [proxy] Initiating TLS upgrade
INFO: [proxy] 127.0.0.1:50214 <-> 127.0.0.1:7203: negotiated TLS 1.2 (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
INFO: [proxy] 127.0.0.1:50215 <-> 127.0.0.1:8203: negotiated TLS 1.2 (TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
INFO: [proxy] Upgrade done
INFO: [proxy] Envelope (Connection 0, Client -> Server):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action>
<a:MessageID>uid:urn:uuid:d36e17be-2cc2-a94f-83a7-cd2442dba24e</a:MessageID>
<a:ReplyTo>
<a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="c:1">ch:net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls</a:To>
</s:Header>
<s:Body>
<AddInts xmlns="http://tempuri.org/">
<a>i:1234</a>
<b>i:37</b>
</AddInts>
</s:Body>
</s:Envelope>
INFO: [proxy] Envelope (Connection 0, Server -> Client):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action>
<a:RelatesTo>uid:urn:uuid:d36e17be-2cc2-a94f-83a7-cd2442dba24e</a:RelatesTo>
<a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<AddIntsResponse xmlns="http://tempuri.org/">
<AddIntsResult>i:1271</AddIntsResult>
</AddIntsResponse>
</s:Body>
</s:Envelope>
INFO: [proxy] Connection 0 closed (127.0.0.1:50214 <-> 127.0.0.1:8203)
ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:50215->127.0.0.1:8203: i/o timeout. Entering fault state.
INFO: [proxy] Done handling connection 0: 127.0.0.1:50214 <-> 127.0.0.1:8203
```
## Configurando autenticação NTLM
Supondo que o serviço WCF dependa de NTLM para autenticação (diretamente ou via SPNEGO) a seguinte configuração pode ser usada para interceptar o tráfego:```json
{
"wcflab-ntlm": {
"listen": "[::1]:7204",
"connect": "[::1]:8204",
"retarget": "net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth",
"interceptor": {
"name": "log"
},
"ntlm": {
"domain": "DESKTOP-65ITJF5",
"credentials": [
{
"name": "<user>",
"password": "<password>"
}
]
}
}
}
```
Note que atualmente é mais robusto fornecer o nome do host através do campo `server` ou `domain` do que depender da configuração automática.
Além disso, a autenticação em um contexto de domínio AD não foi testada e, portanto, provavelmente está quebrada no momento.
Quando SPNEGO é usado, atualmente o mecanismo NTLM deve ser o preferido, caso contrário a negociação falhará.```
> .\wcfproxy.exe -config .\config.json -enable wcflab-ntlm
2025/07/10 15:15:15 dbg: local time zone (for DateTime handling): CEST
INFO: Listening on [::1]:7204 and connecting to [::1]:8204
INFO: No server certificates given. TLS upgrade not supported.
INFO: No client certificates given. TLS client authentication not supported.
INFO: Retargeting to net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth
INFO: [proxy] Handling new connection 0: [::1]:50247 <-> [::1]:8204
INFO: [proxy] Connection 0 established ([::1]:50247 <-> [::1]:8204)
INFO: [proxy] Initiating Negotiate upgrade
INFO: [NTLM server] User wcflab authenticated successfully
INFO: [proxy] [::1]:50247 <-> [::1]:7204: negotiated NTLM
INFO: [proxy] [::1]:50248 <-> [::1]:8204: negotiated NTLM
INFO: [proxy] Upgrade done
INFO: [proxy] Envelope (Connection 0, Client -> Server):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action>
<a:MessageID>uid:urn:uuid:f9cc5af3-3930-9242-be3c-d36d2a0cb09e</a:MessageID>
<a:ReplyTo>
<a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="c:1">ch:net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth</a:To>
</s:Header>
<s:Body>
<AddInts xmlns="http://tempuri.org/">
<a>i:1234</a>
<b>i:37</b>
</AddInts>
</s:Body>
</s:Envelope>
INFO: [proxy] Envelope (Connection 0, Server -> Client):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action>
<a:RelatesTo>uid:urn:uuid:f9cc5af3-3930-9242-be3c-d36d2a0cb09e</a:RelatesTo>
<a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<AddIntsResponse xmlns="http://tempuri.org/">
<AddIntsResult>i:1271</AddIntsResult>
</AddIntsResponse>
</s:Body>
</s:Envelope>
INFO: [proxy] Connection 0 closed ([::1]:50247 <-> [::1]:8204)
ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp [::1]:50248->[::1]:8204: i/o timeout. Entering fault state.
INFO: [proxy] Done handling connection 0: [::1]:50247 <-> [::1]:8204
```