mirror of
https://github.com/rapid7/metasploit-payloads
synced 2024-11-20 14:39:22 +01:00
Land #599, Bind to the specified LocalHost
This commit is contained in:
commit
ca639d4756
@ -19,6 +19,52 @@
|
||||
extern IN6_ADDR in6addr_any;
|
||||
#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.
|
||||
* @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 };
|
||||
USHORT localPort = 0;
|
||||
BOOL v4Fallback = FALSE;
|
||||
int ai_family = AF_UNSPEC;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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
|
||||
// so instead, we'll just revert back to v4 and listen on that one address instead.
|
||||
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 };
|
||||
DWORD sockAddrSize = 0;
|
||||
|
||||
if (v4Fallback)
|
||||
if (ai_family == AF_INET)
|
||||
{
|
||||
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_port = htons(localPort);
|
||||
sockAddrSize = sizeof(struct sockaddr_in);
|
||||
}
|
||||
else
|
||||
else if (ai_family == AF_INET6)
|
||||
{
|
||||
// TODO: add IPv6 address binding support
|
||||
sockAddr.sin6_addr = in6addr_any;
|
||||
if (localHost) {
|
||||
inet_pton(AF_INET6, localHost, &sockAddr.sin6_addr);
|
||||
}
|
||||
else {
|
||||
sockAddr.sin6_addr = in6addr_any;
|
||||
}
|
||||
sockAddr.sin6_family = AF_INET6;
|
||||
sockAddr.sin6_port = htons(localPort);
|
||||
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)
|
||||
{
|
||||
@ -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");
|
||||
}
|
||||
|
||||
ctx->ipv6 = !v4Fallback;
|
||||
ctx->ipv6 = ai_family == AF_INET6;
|
||||
|
||||
memset(&chops, 0, sizeof(StreamChannelOps));
|
||||
chops.native.context = ctx;
|
||||
|
Loading…
Reference in New Issue
Block a user