
Прокси для WCF-трафика на основе net.tcp.
Вы можете либо скомпилировать инструмент один раз и затем использовать полученный бинарный файл, либо запускать его «как скрипт» (цепочка инструментов Go скомпилирует его на лету).
Для разработки удобен последний вариант.
Для продуктивного использования рекомендуется скомпилировать его один раз (из директории cli) и использовать полученный исполняемый файл.
Благодаря компилятору Go вы можете собирать как из Linux, так и для Linux или Windows.
Для сборки требуется версия Go не ниже 1.18 (протестировано с Go 1.23).
Чтобы собрать из Linux для Windows или Linux, просто установите GOOS соответствующим образом (выполните из директории cli):```
GOOS=windows GOARCH=amd64 go build -o wcfproxy.exe
.```
GOOS=linux GOARCH=amd64 go build -o wcfproxy
Для сборки из Windows выполните эквивалентные команды, например, из PowerShell:``` $env:GOOS='windows'; $env:GOARCH='amd64'; go build -o wcfproxy.exe
> Пожалуйста, ознакомьтесь с нашими руководствами по [Kernels](https://github.com/syss-research/wcfproxy/blob/HEAD/docs/source/install/kernels.md),
> [Drivers](https://github.com/syss-research/wcfproxy/blob/HEAD/docs/source/install/drivers.md) или
> [Installation](https://github.com/syss-research/wcfproxy/blob/HEAD/docs/source/install/README.md) для получения более подробной информации.
Примечание: если вы используете Windows, этот шаг можно пропустить. Поддержка Syzkaller для
Windows была нарушена некоторое время назад, и не всё может работать корректно.```
$env:GOOS='linux'; $env:GOARCH='amd64'; go build -o wcfproxy
Конфигурация для wcfproxy предоставляется через JSON-файл.
По умолчанию используется файл конфигурации config.json, но путь к файлу конфигурации можно указать с помощью параметра -config.
Файл конфигурации предназначен для хранения произвольного количества именованных конфигураций, например:```json
{
"my-config": {
" ... ": " ... "
}
}
Значение именованных объектов конфигурации должно соответствовать структуре `Config` (см. [Config structure](#config-structure)).
Этот исходный файл с включенными комментариями также служит наиболее точной документацией для опций конфигурации `wcfproxy`.
Из всей предоставленной конфигурации используемая определяется по имени с помощью опции командной строки `-enable`:```
wcfproxy.exe -config config.json -enable my-config
Структура верхнего уровня каждого объекта конфигурации следующая:```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": { " ... ": " ... " } }
Обратите внимание, что конфигурация TLS (`tls-server` и/или `tls-client`) не может быть указана, если присутствует конфигурация NTLM.
### Параметры конфигурации
+ `listen` - TCP-endpoint, на котором *wcfproxy* должен прослушивать, например `127.0.0.1:8000` или `[::1]:8000`
+ `connect` - TCP-endpoint вышестоящего WCF-сервера, например `127.0.0.1:9000` или `[::1]:9000`
+ `retarget` - исходная спецификация целевого адреса (и запасной вариант для `retarget-map`); за объяснениями обратитесь к [Перезапись целевого адреса](#target-rewriting)
+ `retarget-map` - обобщение `retarget`; позволяет выполнять перезапись целевого адреса для нескольких endpoints (полезно только при работе с несколькими WCF-сервисами на одном порту)
+ если один из ключей в `retarget-map` совпадает с текущим целевым адресом, URI цели будет заменен на указанное значение для связи с вышестоящим сервером
+ если ни один ключ `retarget-map` не совпадает с текущим целевым адресом, вместо него будет использован `retarget`
+ `log-level` - уровень логирования; доступные значения: `debug`, `info` (по умолчанию), `warn`, `error`
+ `log-file` - путь к файлу журнала; если путь не указан, журнал выводится в `stdout`
+ `tls-server` - экземпляр `TlsServerConfig` (см. [Конфигурация TLS-сервера](#tls-server-configuration)); требуется только если необходимо поддерживать обновление TLS
+ `tls-client` - экземпляр `TlsClientConfig` (см. [Конфигурация TLS-клиента](#tls-client-configuration)); актуально только если необходимо поддерживать обновление TLS
+ `ntlm` - экземпляр `NtlmConfig` (см. [Конфигурация NTLM](#ntlm-configuration)); требуется только если необходимо поддерживать обновление NTLM (напрямую или через SPNEGO)
+ `interceptor` - экземпляр `InterceptorConfig` (см. [Конфигурация перехватчика](#interceptor-configuration)); обязательно
+ `ctrl` - экземпляр `ControlServerConfig` (см. [Конфигурация сервера управления](#control-server-configuration)), который может предоставлять HTTP-сервер эхо-ответов по умолчанию (полезен вместе с HTTP-перехватчиком), а также небольшой API для управления потоком сообщений (в разработке)
### Конфигурация TLS-сервера
Конфигурация на стороне TLS-сервера предоставляет контроль над наиболее типичными настройками TLS-сервера.
Она имеет следующую структуру:```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"
}
cert-pem - путь к сертификату X.509 (в формате PEM)cert-key - путь к соответствующему ключу для сертификатаmax-version - максимальная допустимая версия TLS; одна из: 1.0, 1.1, 1.2, 1.3 (по умолчанию)min-version - минимальная допустимая версия TLS; одна из: 1.0 (по умолчанию), 1.1, 1.2, 1.3client-roots - список путей к допустимым корневым сертификатам (PEM) для аутентификации клиента, разделённый запятыми; опциональноclient-auth - политика аутентификации клиента; наиболее полезные значения: (по умолчанию), Конфигурация на стороне TLS-клиента предоставляет контроль над наиболее типичными настройками TLS-клиента. Она имеет следующую структуру:```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 }
#### Параметры конфигурации TLS-клиента
+ аналогичны [параметрам конфигурации TLS-сервера](#tls-server-configuration-options)
+ `roots` - путь к разделённому запятыми списку путей к корневым центрам сертификации (PEM); опционально с `skip-verify`
+ `server-name` - имя сервера (SNI); опционально
+ `skip-verify` - логическое значение; следует ли клиенту отказаться от проверки сертификата сервера (по умолчанию: `false`)
### Конфигурация NTLM
Конфигурация NTLM указывает домен, имя сервера, а также учётные данные пользователя.
Для каждого пользователя, который должен иметь возможность аутентифицироваться через прокси, необходимо указать действительные учётные данные.```json
{
"domain": "test.local",
"server": "server.local",
"credentials": [
{
" ... ": " ... "
}
]
}
domain - домен для аутентификации, например test.local; если оставить пустым, будет использовано имя сервераserver - имя сервера для аутентификации; если оставить пустым, будет использовано имя хоста текущей системыcredentials - массив объектов NtlmCredential (см. ниже)Учетные данные NTLM передаются в виде массива объектов NtlmCredential, которые имеют следующую структуру:```json
{
"name": "wcflab",
"password": "Sup3rS3cr3t",
"nt-hash": "a8fc07dede90b0ec10bc1ef355f99292",
"lm-hash": "3e9cb63e11a812cbc467021088dc706f"
}
+ `name` - имя пользователя
+ `password` - пароль пользователя; из него будут получены хеши; переопределяет заданные хеши для пользователя
+ `nt-hash` - NT-хеш (hex) пароля пользователя; альтернатива паролю
+ `lm-hash` - LM-хеш (hex) пароля пользователя; альтернатива паролю; в большинстве случаев не требуется
Если указан пароль, LM-хеш (возможен не для всех паролей) и NT-хеш вычисляются из него.
Любые заданные значения хешей для этого пользователя будут перезаписаны вычисленными хешами.
Также возможно указать только хеш(и) пользователя.
LM-хеш не должен требоваться в большинстве сценариев.
### Конфигурация перехватчика
Конфигурация перехватчика указывает перехватчик (по имени), который должен использоваться, и, опционально, специфичные для перехватчика аргументы.
Объяснение перехватчиков см. в [Перехватчики](#interceptors).
#### Логирующий перехватчик
Для использования логирующего перехватчика просто используйте следующую конфигурацию перехватчика.
Вывод записывается в основное расположение журнала, которым может быть файл или `stdout`, в зависимости от конфигурации `log-file`.```json
{
"name": "log"
}
Для использования HTTP-перехватчика используйте следующую конфигурацию перехватчика с подходящими параметрами для server-url и 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 к вашей конечной точке перехвата HTTP-сервера (например, простая эхо-точка); подробнее о работе HTTP-перехватчика см. [HTTP Interceptor](#http-interceptor-1)
+ `args.proxy-url` - URL HTTP-прокси; опционально
### Конфигурация сервера управления
*wcfproxy* поставляется со встроенным веб-сервером, который выполняет две функции.
Во-первых, он может предоставлять HTTP-конечную точку, которая просто отражает весь отправляемый ей контент.
Это полезно в сочетании с [HTTP-перехватчиком](#http-interceptor-1).```json
{
"ctrl": {
"listen": "127.0.0.1:9999",
"enable-control": false,
"enable-echo": true
}
}
[!WARNING]
Любой, кто имеет доступ к API, может пройти аутентификацию, используя предоставленные учетные данные (NTLM или TLS-сертификаты клиента). На общих системах это может быть актуально, даже если API доступен только локально.
listen - TCP-конечная точка, на которой управляющий сервер должен прослушиватьenable-contorl - включает функции управления, такие как внедрение сообщений или установление соединений (см. Внедрение сообщений)enable-echo - включает простой HTTP-эхо-сервер по адресу http://{listen}/echoСледующие разделы содержат дополнительную информацию, которая может помочь лучше понять WCF и некоторые параметры конфигурации.
Предполагаемая конечная точка WCF кодируется в преамбуле net.tcp, а также в заголовке To передаваемых SOAP-конвертов.
Серверы могут проверять, соответствует ли эта спецификация конечной точки ожидаемой.
Когда клиент манипулируется для подключения к прокси вместо исходного сервера, эта спецификация конечной точки, скорее всего, изменится, и сервер может отклонить связь.
Поэтому обычно имеет смысл корректировать спецификацию конечной точки в исходящем трафике к серверу.
Для этого укажите оригинальную спецификацию конечной точки (например, полученную из конфигурации клиента) в опции retarget в файле конфигурации.
Спецификация конечной точки обычно выглядит так: net.tcp://some/endpoint.
При одновременной работе с несколькими конечными точками WCF может потребоваться выполнить перезапись целевого адреса для всех них.
Для этой цели существует опция retarget-map, которая определяет сопоставление между целевыми URI.
Если совпадение в retarget-map не найдено, целевой URI будет изменён на значение, указанное в retarget.
Двоичный XML, как указано в MC-NBFX, кодирует базовую информацию о типах в двоичном формате (типы записей).
Не вся эта информация легко восстанавливается из (текстового) XML-представления двоичного XML-документа.
По этой причине wcfproxy вставляет подсказки типов в токены символьных данных XML (и некоторые атрибуты).
Эти подсказки типов имеют вид <h>:, где <h> — это короткая строка, кодирующая некоторый тип (например, i для целого числа, ch для символов).
Полный список подсказок типов можно найти в typehint.go.
Не рекомендуется вмешиваться в подсказки типов.
Перехватчики определяют, как обрабатывается полученный трафик, и задаются через конфигурацию перехватчиков. Они обрабатывают трафик, отправляемый в обоих направлениях (клиент -> сервер и сервер -> клиент). В настоящее время существует два перехватчика: log и http.
Перехватчик log преобразует двоично-закодированные SOAP-конверты в их читаемые человеком аналоги, закодированные с использованием обычного текстового XML.
Активного манипулирования (кроме перезаписи спецификации цели) не производится.
Вывод отправляется в указанное место для журнала (по умолчанию stdout).
Убедитесь, что уровень журнала установлен на info (или debug), иначе соответствующий вывод будет подавлен.
Перехватчик http преобразует двоичные SOAP-конверты в их текстовые аналоги и отправляет их на HTTP-конечную точку, указанную в -http-url.
Декодированные SOAP-сообщения отправляются в теле запроса.
HTTP-сервер должен вернуть действительный SOAP-конверт в том же формате, что и входящие сообщения.
Эти сообщения затем преобразуются обратно в исходный двоичный формат и отправляются на вышестоящий сервер.
Простое отражение исходного сообщения всегда является допустимым вариантом для HTTP-сервера. Однако программное манипулирование сообщениями также может быть достигнуто путём предоставления пользовательского HTTP-сервера, который выполняет нужные замены. Следует соблюдать осторожность, чтобы не нарушить структуру SOAP-сообщений. Рекомендуется не вмешиваться в формат сообщений, если вы не знаете, что делаете. Кроме того, не следует воздействовать на подсказки типов, вставленные wcfproxy, так как это может нарушить преобразование текстовых SOAP-сообщений обратно в двоичный формат или разбор сообщений на легитимной конечной точке (клиент или сервер).
wcfproxy поставляется с тривиальным HTTP-сервером, который просто отражает тело полученных HTTP-запросов.
Этот сервер будет запущен, когда предоставлена конфигурация управляющего сервера и опция enable-echo установлена в true.
URL желаемого HTTP-сервера указывается через опцию server-url в конфигурации HTTP-перехватчика.
Чтобы разрешить интерактивное манипулирование, можно указать HTTP-прокси (например, BurpSuite) через опцию proxy-url.
Сообщения затем будут отправляться на HTTP-сервер через указанный HTTP-прокси.
Обратите внимание, что для каждого WCF-сообщения (например, клиент -> сервер) создаётся пара HTTP-запрос-ответ.
Для корреляции сообщений с net.tcp-соединением, из которого они поступили, в запросы, сгенерированные перехватчиком http, вставляется заголовок X-Wcpf-Conn-Id.
Следующее изображение иллюстрирует поток данных с перехватчиком http.
WCF (через net.tcp) может использовать TLS для транспортной безопасности. wcfproxy поддерживает перехват TLS-соединений (только TLS 1.0 – 1.3, без SSL). Настройки TLS со стороны сервера и клиента можно управлять с помощью соответствующей конфигурации TLS (см. Конфигурацию TLS сервера или Конфигурацию TLS клиента).
wcfproxy поддерживает аутентификацию NTLM.
В настоящее время поддерживается прямая аутентификация NTLM или согласование через SPNEGO.
Необходимо предоставить учётные данные пользователя(ей), которые будут проходить аутентификацию.
Эти учётные данные предоставляются в формате JSON, см. Конфигурацию NTLM.
Передача хешей поддерживается путём указания хешей через свойство nt-hash.
Когда управляющий сервер включён, предоставляется небольшой HTTP API, который можно использовать для установки или завершения соединений и внедрения сообщений в существующие соединения. Доступны следующие конечные точки.
/connectionСписок текущих активных соединений.
Для соединений только с сервером (созданных через POST /connection/new) клиент будет отображаться как wcfproxy.
/connection/newСоздать новое соединение.
Тело должно быть JSON-объектом, указывающим предполагаемое обновление (TLS или Negotiate (NTLM)), если таковое имеется.
URI конечной точки указывается через свойство target-uri.
Если обновление не требуется, свойство upgrade можно опустить.```json
{
"target-uri":"net.tcp://127.0.0.1:9510/example/notes-nettcp"
}
#### Пример: обновление TLS
Чтобы инициировать обновление TLS, укажите механизм обновления `tls`.```json
{
"target-uri":"net.tcp://wcf-notes.local:9511/example/notes-nettcp-tls",
"upgrade": {
"mechanism":"tls"
}
}
Объект upgrade должен указать ntlm в качестве механизма и пользователя для аутентификации.
Учётные данные пользователя должны быть предоставлены в конфигурации ntlm.```json
{
"target-uri":"net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcp-winauth",
"upgrade": {
"mechanism": "ntlm",
"ntlmuser": "wcflab"
}
}
### POST `/connection/{id}/kill`
Уничтожить соединение, идентифицированное `{id}`.
### POST `/connection/{id}/inject`
Внедрить сообщение, переданное в теле этого запроса, в соединение, идентифицированное `{id}`.
Тело должно быть в том же формате, который используется для пересылки WCF-сообщений HTTP-перехватчикам.
Поэтому лучше всего скопировать наблюдаемое сообщение, изменить его по мере необходимости, а затем внедрить его через эту конечную точку.
По умолчанию ответы на внедренные сообщения не отображаются.
Однако если перехватчик активен, ответы должны появляться там.
Для удобства, когда параметр запроса `retrieve=true` предоставлен, `wcfproxy` ожидает ответ на внедренное сообщение и отображает его.
## Ограничение количества соединений
Применяется искусственное верхнее ограничение на количество одновременно активных соединений.
В настоящее время этот лимит установлен на 20.
Это сделано для предотвращения случайного исчерпания ресурсов при (неправильном) использовании управляющего API (см. [Внедрение сообщений и установка соединения](#message-injection-and-connection-establishment)).
Это редко должно создавать проблемы для законных WCF-клиентов.
Однако могут быть случаи использования, требующие большего количества одновременных соединений.
В этом случае измените константу `maxConnections` в файле [proxy.go](https://github.com/syss-research/wcfproxy/blob/HEAD/proxy/proxy.go) по мере необходимости.
# Примеры
Следующие примеры показывают базовое использование *wcfproxy*.
Точный вывод может быть изменен, но основная идея должна быть понятна.
## Использование перехватчика журнала
Этот пример демонстрирует использование *wcfproxy* в тестовой среде WCF для обычной WCF-связи по net.tcp с использованием перехватчика **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"
}
}
}
С указанной выше конфигурацией (помещённой в config.json) мы можем использовать её, как показано ниже.
Трафик через прокси должен выводиться в консоль (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>
i:1234 i:37 </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> i:1271 </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
## Использование http-перехватчика
Следующая конфигурация использует **http-перехватчик** в сочетании с 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"
}
}
}
}
При такой конфигурации журнал не показывает ничего интересного.```
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
Однако трафик WCF преобразуется в (почти) обычные SOAP-конверты, отправляемые через HTTP.

## Настройка перехвата (m)TLS
*wcfproxy* можно настроить для перехвата трафика WCF, защищённого mTLS, при наличии подходящих серверных и клиентских сертификатов.
Конфигурация для TLS без аутентификации клиента аналогична; клиентские сертификаты в этом случае не требуются.
Следующая конфигурация предоставляет пример для этого случая использования:```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
}
}
Обратите внимание, что клиенты должны доверять сертификату сервера (server.pem).
Кроме того, сервер должен доверять сертификату, предоставленному клиентской частью 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>
i:1234 i:37 </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> i:1271 </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
## Настройка аутентификации NTLM
Если предположить, что служба WCF использует NTLM для аутентификации (напрямую или через SPNEGO), то для перехвата трафика можно использовать следующую конфигурацию:```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>"
}
]
}
}
}
Обратите внимание, что в настоящее время более надёжно указывать имя хоста через поле server или domain, чем полагаться на автоматическую настройку.
Кроме того, аутентификация в контексте домена AD не тестировалась и поэтому, скорее всего, на данный момент не работает.
При использовании SPNEGO в настоящее время механизм NTLM должен быть предпочтительным, иначе согласование не удастся.```
.\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>
i:1234 i:37 </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> i:1271 </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
nonerequire-and-verifykeylog - файл для записи секретов TLS в формате NNS