1
mirror of https://github.com/rapid7/metasploit-payloads synced 2024-11-26 17:41:08 +01:00

Land #599, Bind to the specified LocalHost

This commit is contained in:
Grant Willcox 2023-01-19 17:49:34 -06:00
commit ca639d4756
No known key found for this signature in database
GPG Key ID: D35E05C0F2B81E83

View File

@ -19,6 +19,52 @@
extern IN6_ADDR in6addr_any; extern IN6_ADDR in6addr_any;
#endif #endif
static int get_ai_family(const char* address) {
struct addrinfo* resolved_host = NULL;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_flags = AI_NUMERICHOST
};
int ai_family = AF_UNSPEC;
if (getaddrinfo(address, NULL, &hints, &resolved_host) == 0) {
ai_family = resolved_host->ai_family;
freeaddrinfo(resolved_host);
}
return ai_family;
}
// The inet_pton function is not available prior to Windows 8.1 so
// use getaddrinfo.
static int inet_pton(int af, const char* src, void* dst) {
struct addrinfo* resolved_host = NULL;
struct addrinfo hints = {
.ai_family = af,
.ai_flags = AI_NUMERICHOST
};
if ((af != AF_INET) && (af != AF_INET6)) {
return -1;
}
int ai_family = AF_UNSPEC;
if (getaddrinfo(src, NULL, &hints, &resolved_host)) {
return 0;
}
if (resolved_host->ai_family != af) { // verify the returned address is of the expected family
freeaddrinfo(resolved_host);
return 0;
}
if (af == AF_INET) {
memcpy(dst, &((struct sockaddr_in*)resolved_host->ai_addr)->sin_addr, sizeof(struct in_addr));
} else if (af == AF_INET6) {
memcpy(dst, &((struct sockaddr_in6*)resolved_host->ai_addr)->sin6_addr, sizeof(struct in_addr6));
}
freeaddrinfo(resolved_host);
return 1;
}
/*! /*!
* @brief Deallocates and cleans up the attributes of a tcp server socket context. * @brief Deallocates and cleans up the attributes of a tcp server socket context.
* @param ctx Pointer to the context to free. * @param ctx Pointer to the context to free.
@ -283,6 +329,7 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet)
StreamChannelOps chops = { 0 }; StreamChannelOps chops = { 0 };
USHORT localPort = 0; USHORT localPort = 0;
BOOL v4Fallback = FALSE; BOOL v4Fallback = FALSE;
int ai_family = AF_UNSPEC;
do do
{ {
@ -305,12 +352,28 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet)
localPort = (USHORT)(met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF); localPort = (USHORT)(met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF);
localHost = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST); localHost = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST);
ctx->fd = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); if ((localHost) && (strlen(localHost) == 0)) {
// normalize empty host strings
localHost = NULL;
}
if (localHost) {
ai_family = get_ai_family(localHost);
}
else {
ai_family = AF_INET6;
}
ctx->fd = WSASocket(ai_family, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
if (ctx->fd == INVALID_SOCKET) if (ctx->fd == INVALID_SOCKET)
{ {
v4Fallback = TRUE; if ((ai_family == AF_INET6) && (!localHost)) {
// if the socket that failed to be created was IPv6 but it was only selected because not
// address was specified, fail back to IPv4
ai_family = AF_INET;
ctx->fd = WSASocket(ai_family, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
}
} }
else else if (ai_family == AF_INET6)
{ {
int no = 0; int no = 0;
if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) == SOCKET_ERROR) if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) == SOCKET_ERROR)
@ -319,29 +382,46 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet)
// support IPv4 and IPv6 we'd need to create two separate sockets. IPv6 on XP isn't that common // support IPv4 and IPv6 we'd need to create two separate sockets. IPv6 on XP isn't that common
// so instead, we'll just revert back to v4 and listen on that one address instead. // so instead, we'll just revert back to v4 and listen on that one address instead.
closesocket(ctx->fd); closesocket(ctx->fd);
v4Fallback = TRUE; ai_family = AF_INET;
ctx->fd = WSASocket(ai_family, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
} }
} }
if (ctx->fd == INVALID_SOCKET) {
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSASocket failed");
}
struct sockaddr_in6 sockAddr = { 0 }; struct sockaddr_in6 sockAddr = { 0 };
DWORD sockAddrSize = 0; DWORD sockAddrSize = 0;
if (v4Fallback) if (ai_family == AF_INET)
{ {
struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr; struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr;
v4Addr->sin_addr.s_addr = localHost == NULL ? htons(INADDR_ANY) : inet_addr(localHost); if (localHost) {
inet_pton(AF_INET, localHost, &v4Addr->sin_addr);
}
else {
v4Addr->sin_addr.s_addr = INADDR_ANY;
}
v4Addr->sin_family = AF_INET; v4Addr->sin_family = AF_INET;
v4Addr->sin_port = htons(localPort); v4Addr->sin_port = htons(localPort);
sockAddrSize = sizeof(struct sockaddr_in); sockAddrSize = sizeof(struct sockaddr_in);
} }
else else if (ai_family == AF_INET6)
{ {
// TODO: add IPv6 address binding support if (localHost) {
sockAddr.sin6_addr = in6addr_any; inet_pton(AF_INET6, localHost, &sockAddr.sin6_addr);
}
else {
sockAddr.sin6_addr = in6addr_any;
}
sockAddr.sin6_family = AF_INET6; sockAddr.sin6_family = AF_INET6;
sockAddr.sin6_port = htons(localPort); sockAddr.sin6_port = htons(localPort);
sockAddrSize = sizeof(struct sockaddr_in6); sockAddrSize = sizeof(struct sockaddr_in6);
} }
else {
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed, invalid address", ERROR_INVALID_PARAMETER);
}
if (bind(ctx->fd, (SOCKADDR *)&sockAddr, sockAddrSize) == SOCKET_ERROR) if (bind(ctx->fd, (SOCKADDR *)&sockAddr, sockAddrSize) == SOCKET_ERROR)
{ {
@ -364,7 +444,7 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet)
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed"); BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed");
} }
ctx->ipv6 = !v4Fallback; ctx->ipv6 = ai_family == AF_INET6;
memset(&chops, 0, sizeof(StreamChannelOps)); memset(&chops, 0, sizeof(StreamChannelOps));
chops.native.context = ctx; chops.native.context = ctx;