Adding process_open_ports and listening_sockets virtual tables to Windows (#2760)

This commit is contained in:
Nick Anderson 2016-12-06 14:25:08 -08:00 committed by GitHub
parent 601ace89fa
commit 7f5345ec7e
6 changed files with 326 additions and 0 deletions

View File

@ -36,6 +36,8 @@ else()
endif()
if(WINDOWS)
ADD_OSQUERY_LINK_CORE("ws2_32.lib")
ADD_OSQUERY_LINK_CORE("iphlpapi.lib")
ADD_OSQUERY_LINK_CORE("netapi32.lib")
ADD_OSQUERY_LINK_CORE("rpcrt4.lib")
ADD_OSQUERY_LINK_CORE("shlwapi.lib")

View File

@ -0,0 +1,270 @@
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include <osquery/core.h>
#include <osquery/core/conversions.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
#include "win_sockets.h"
namespace osquery {
namespace tables {
WinSockets::WinSockets() {
auto pSockTable = allocateSocketTable(IPPROTO_TCP, AF_INET);
if (status_.ok()) {
tcpTable_ = static_cast<MIB_TCPTABLE_OWNER_PID*>(pSockTable);
} else {
TLOG << "Error allocating the TCP IPv4 socket table";
return;
}
pSockTable = allocateSocketTable(IPPROTO_TCP, AF_INET6);
if (status_.ok()) {
tcp6Table_ = static_cast<MIB_TCP6TABLE_OWNER_PID*>(pSockTable);
} else {
TLOG << "Error allocating the TCP IPv6 socket table";
return;
}
pSockTable = allocateSocketTable(IPPROTO_UDP, AF_INET);
if (status_.ok()) {
udpTable_ = static_cast<MIB_UDPTABLE_OWNER_PID*>(pSockTable);
} else {
TLOG << "Error allocating the UDP IPv4 socket table";
return;
}
pSockTable = allocateSocketTable(IPPROTO_UDP, AF_INET6);
if (status_.ok()) {
udp6Table_ = static_cast<MIB_UDP6TABLE_OWNER_PID*>(pSockTable);
} else {
TLOG << "Error allocating the UDP IPv6 socket table";
return;
}
}
WinSockets::~WinSockets() {
if (tcpTable_ != nullptr) {
free(tcpTable_);
tcpTable_ = nullptr;
}
if (tcp6Table_ != nullptr) {
free(tcp6Table_);
tcp6Table_ = nullptr;
}
if (udpTable_ != nullptr) {
free(udpTable_);
udpTable_ = nullptr;
}
if (udp6Table_ != nullptr) {
free(udp6Table_);
udp6Table_ = nullptr;
}
}
void WinSockets::parseSocketTable(WinSockTableType sockType,
QueryData& results) {
unsigned int numEntries;
switch (sockType) {
case WinSockTableType::tcp:
numEntries = tcpTable_->dwNumEntries;
break;
case WinSockTableType::tcp6:
numEntries = tcp6Table_->dwNumEntries;
break;
case WinSockTableType::udp:
numEntries = udpTable_->dwNumEntries;
break;
case WinSockTableType::udp6:
numEntries = udp6Table_->dwNumEntries;
break;
default:
numEntries = 0;
break;
}
for (size_t i = 0; i < numEntries; i++) {
Row r;
std::vector<char> localAddr(128, 0x0);
std::vector<char> remoteAddr(128, 0x0);
auto proto = static_cast<unsigned int>(sockType);
r["protocol"] = INTEGER(proto);
switch (sockType) {
case WinSockTableType::tcp: {
auto tcpLocalAddr = tcpTable_->table[i].dwLocalAddr;
auto retVal =
InetNtopA(AF_INET, &tcpLocalAddr, localAddr.data(), localAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network local address to string: "
<< WSAGetLastError();
}
r["local_port"] =
INTEGER(ntohs(static_cast<u_short>(tcpTable_->table[i].dwLocalPort)));
auto tcpRemoteAddr = tcpTable_->table[i].dwRemoteAddr;
retVal = InetNtopA(
AF_INET, &tcpRemoteAddr, remoteAddr.data(), remoteAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network remote address to string: "
<< WSAGetLastError();
}
r["remote_address"] = remoteAddr.data();
r["remote_port"] = INTEGER(
ntohs(static_cast<u_short>(tcpTable_->table[i].dwRemotePort)));
r["pid"] = INTEGER(tcpTable_->table[i].dwOwningPid);
r["family"] = INTEGER(AF_INET);
break;
}
case WinSockTableType::tcp6: {
auto tcp6LocalAddr = tcp6Table_->table[i].ucLocalAddr;
auto retVal = InetNtopA(
AF_INET6, tcp6LocalAddr, localAddr.data(), localAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network local address to string: "
<< WSAGetLastError();
}
r["local_port"] = INTEGER(
ntohs(static_cast<u_short>(tcp6Table_->table[i].dwLocalPort)));
auto tcp6RemoteAddr = tcp6Table_->table[i].ucRemoteAddr;
retVal = InetNtopA(
AF_INET6, tcp6RemoteAddr, remoteAddr.data(), remoteAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network remote address to string: "
<< WSAGetLastError();
}
r["remote_address"] = remoteAddr.data();
r["remote_port"] = INTEGER(
ntohs(static_cast<u_short>(tcp6Table_->table[i].dwRemotePort)));
r["pid"] = INTEGER(tcp6Table_->table[i].dwOwningPid);
r["family"] = INTEGER(AF_INET6);
break;
}
case WinSockTableType::udp: {
auto udpLocalAddr = udpTable_->table[i].dwLocalAddr;
auto retVal =
InetNtopA(AF_INET, &udpLocalAddr, localAddr.data(), localAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network local address to string: "
<< WSAGetLastError();
}
r["local_port"] =
INTEGER(ntohs(static_cast<u_short>(udpTable_->table[i].dwLocalPort)));
r["remote_address"] = "0";
r["remote_port"] = INTEGER(0);
r["pid"] = INTEGER(udpTable_->table[i].dwOwningPid);
r["family"] = INTEGER(AF_INET);
break;
}
case WinSockTableType::udp6: {
auto udp6LocalAddr = udp6Table_->table[i].ucLocalAddr;
auto retVal = InetNtopA(
AF_INET6, udp6LocalAddr, localAddr.data(), localAddr.size());
if (retVal == nullptr) {
TLOG << "Error converting network local address to string: "
<< WSAGetLastError();
}
r["local_port"] = INTEGER(
ntohs(static_cast<u_short>(udp6Table_->table[i].dwLocalPort)));
r["remote_address"] = "0";
r["remote_port"] = INTEGER(0);
r["pid"] = INTEGER(udp6Table_->table[i].dwOwningPid);
r["family"] = INTEGER(AF_INET6);
break;
}
default:
break;
}
r["local_address"] = localAddr.data();
results.push_back(r);
}
}
void* WinSockets::allocateSocketTable(unsigned long protocol,
unsigned long family) {
unsigned long ret = 0;
unsigned long buffsize = 0;
void* pSockTable = nullptr;
/// Allocate the TCP Socket Tables
if (protocol == IPPROTO_TCP) {
ret = GetExtendedTcpTable(
pSockTable, &buffsize, true, family, TCP_TABLE_OWNER_PID_ALL, 0);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
pSockTable = static_cast<void*>(malloc(buffsize));
if (pSockTable == nullptr) {
status_ = Status(
1, "Unable to allocate sufficient memory for the TCP socket table");
}
}
ret = GetExtendedTcpTable(pSockTable,
reinterpret_cast<PULONG>(&buffsize),
true,
family,
TCP_TABLE_OWNER_PID_ALL,
0);
if (ret != NO_ERROR) {
status_ = Status(1,
"Error retrieving the socket table: ( " +
std::to_string(GetLastError()) + " )");
}
}
/// Allocate the UDP Socket Tables
else {
ret = GetExtendedUdpTable(pSockTable,
reinterpret_cast<PULONG>(&buffsize),
true,
family,
UDP_TABLE_OWNER_PID,
0);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
pSockTable = static_cast<void*>(malloc(buffsize));
if (pSockTable == nullptr) {
status_ = Status(
1, "Unable to allocate sufficient memory for the UDP socket table");
}
}
ret = GetExtendedUdpTable(pSockTable,
reinterpret_cast<PULONG>(&buffsize),
true,
family,
UDP_TABLE_OWNER_PID,
0);
if (ret != NO_ERROR) {
status_ = Status(1,
"Error retrieving the socket table: ( " +
std::to_string(GetLastError()) + " )");
}
}
return pSockTable;
}
QueryData genOpenSockets(QueryContext& context) {
QueryData results;
WinSockets sockTable;
sockTable.parseSocketTable(WinSockTableType::tcp, results);
sockTable.parseSocketTable(WinSockTableType::tcp6, results);
sockTable.parseSocketTable(WinSockTableType::udp, results);
sockTable.parseSocketTable(WinSockTableType::udp6, results);
return results;
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <ws2tcpip.h>
#define WIN32_LEAN_AND_MEAN
#include <Iphlpapi.h>
#include <windows.h>
#include <winsock2.h>
#include <boost/noncopyable.hpp>
namespace osquery {
namespace tables {
enum class WinSockTableType { tcp, tcp6, udp, udp6 };
class WinSockets : private boost::noncopyable {
public:
/// Retreives all of the socket table structures from the Windows API
WinSockets();
/// Ensures that all Socket tables have been deallocated
~WinSockets();
/// Parses all of the socket entries and populates the results QueryData
void parseSocketTable(WinSockTableType sockType, QueryData& results);
/// Returns the status of the Sockets Table
Status getStatus() const {
return status_;
};
private:
Status status_;
MIB_TCPTABLE_OWNER_PID* tcpTable_ = nullptr;
MIB_TCP6TABLE_OWNER_PID* tcp6Table_ = nullptr;
MIB_UDPTABLE_OWNER_PID* udpTable_ = nullptr;
MIB_UDP6TABLE_OWNER_PID* udp6Table_ = nullptr;
/// Helper function to allocate a table based off of family and protocol
void* WinSockets::allocateSocketTable(unsigned long protocol,
unsigned long family);
};
}
}