netstat and arp commands in win32/posix meterpreter
parent
363c0913ae
commit
c1ca9fea79
|
@ -8,6 +8,14 @@
|
|||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
typedef DWORD __u32;
|
||||
typedef struct ___u128 {
|
||||
__u32 a1;
|
||||
__u32 a2;
|
||||
__u32 a3;
|
||||
__u32 a4;
|
||||
}__u128;
|
||||
#endif
|
||||
#include "openssl/ssl.h"
|
||||
#ifdef _UNIX
|
||||
|
@ -70,16 +78,16 @@ struct ipv4_route_entry {
|
|||
__u32 dest;
|
||||
__u32 netmask;
|
||||
__u32 nexthop;
|
||||
unsigned char interface[IFNAMSIZ+1];
|
||||
__u32 metric;
|
||||
unsigned char interface[IFNAMSIZ+1];
|
||||
__u32 metric;
|
||||
};
|
||||
|
||||
struct ipv6_route_entry {
|
||||
__u128 dest6;
|
||||
__u128 netmask6;
|
||||
__u128 nexthop6;
|
||||
unsigned char interface[IFNAMSIZ+1];
|
||||
__u32 metric;
|
||||
unsigned char interface[IFNAMSIZ+1];
|
||||
__u32 metric;
|
||||
};
|
||||
|
||||
struct ipv4_routing_table {
|
||||
|
@ -93,10 +101,23 @@ struct ipv6_routing_table {
|
|||
};
|
||||
|
||||
struct routing_table {
|
||||
struct ipv4_routing_table ** table_ipv4;
|
||||
struct ipv6_routing_table ** table_ipv6;
|
||||
struct ipv4_routing_table ** table_ipv4;
|
||||
struct ipv6_routing_table ** table_ipv6;
|
||||
};
|
||||
|
||||
struct arp_entry {
|
||||
__u32 ipaddr;
|
||||
unsigned char hwaddr[6];
|
||||
unsigned char name[IFNAMSIZ+1];
|
||||
};
|
||||
|
||||
struct arp_table {
|
||||
int entries;
|
||||
struct arp_entry table[0];
|
||||
};
|
||||
|
||||
|
||||
|
||||
int netlink_get_routing_table(struct ipv4_routing_table **table_ipv4, struct ipv6_routing_table **table_ipv6);
|
||||
int netlink_get_interfaces(struct ifaces_list **iface_list);
|
||||
|
||||
|
@ -108,6 +129,30 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
|
|||
|
||||
#endif
|
||||
|
||||
struct connection_entry {
|
||||
char type; // AF_INET / AF_INET6
|
||||
union {
|
||||
__u32 addr;
|
||||
__u128 addr6;
|
||||
} local_addr;
|
||||
union {
|
||||
__u32 addr;
|
||||
__u128 addr6;
|
||||
} remote_addr;
|
||||
__u32 local_port;
|
||||
__u32 remote_port;
|
||||
unsigned char protocol[5]; // tcp/tcp6/udp/udp6
|
||||
unsigned char state[15]; // established, syn_sent..
|
||||
__u32 uid;
|
||||
__u32 inode;
|
||||
unsigned char program_name[30]; // pid/program_name or "-"
|
||||
};
|
||||
|
||||
struct connection_table {
|
||||
int entries;
|
||||
int max_entries;
|
||||
struct connection_entry table[0];
|
||||
};
|
||||
|
||||
#include "linkage.h"
|
||||
|
||||
|
|
182
external/source/meterpreter/source/extensions/stdapi/server/net/config/arp.c
vendored
Normal file
182
external/source/meterpreter/source/extensions/stdapi/server/net/config/arp.c
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
#include "precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
DWORD windows_get_arp_table(Remote *remote, Packet *response)
|
||||
{
|
||||
PMIB_IPNETTABLE pIpNetTable = NULL;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal;
|
||||
DWORD i;
|
||||
char interface_index[10];
|
||||
|
||||
do {
|
||||
dwRetVal = GetIpNetTable(NULL, &dwSize, 0);
|
||||
|
||||
/* Get the size required by GetIpNetTable() */
|
||||
if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
|
||||
pIpNetTable = (MIB_IPNETTABLE *) malloc (dwSize);
|
||||
}
|
||||
|
||||
else if ((dwRetVal != NO_ERROR) && (dwRetVal != ERROR_NO_DATA)) {
|
||||
result = ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pIpNetTable == NULL) {
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dwRetVal = GetIpNetTable(pIpNetTable, &dwSize, 0)) == NO_ERROR) {
|
||||
dprintf("[ARP] found %d arp entries", pIpNetTable->dwNumEntries);
|
||||
for (i = 0 ; i < pIpNetTable->dwNumEntries ; i++) {
|
||||
// send only dynamic or static entry
|
||||
if ((pIpNetTable->table[i].dwType == MIB_IPNET_TYPE_DYNAMIC) ||
|
||||
(pIpNetTable->table[i].dwType == MIB_IPNET_TYPE_STATIC)) {
|
||||
Tlv arp[3];
|
||||
// can't send interface name as it can be _big_, so send index instead
|
||||
sprintf_s(interface_index, sizeof(interface_index), "%d", pIpNetTable->table[i].dwIndex);
|
||||
|
||||
arp[0].header.type = TLV_TYPE_IP;
|
||||
arp[0].header.length = sizeof(DWORD);
|
||||
arp[0].buffer = (PUCHAR)&pIpNetTable->table[i].dwAddr;
|
||||
|
||||
arp[1].header.type = TLV_TYPE_MAC_ADDR;
|
||||
arp[1].header.length = 6;
|
||||
arp[1].buffer = (PUCHAR)pIpNetTable->table[i].bPhysAddr;
|
||||
|
||||
arp[2].header.type = TLV_TYPE_MAC_NAME;
|
||||
arp[2].header.length = strlen(interface_index) + 1;
|
||||
arp[2].buffer = (PUCHAR)interface_index;
|
||||
|
||||
packet_add_tlv_group(response, TLV_TYPE_ARP_ENTRY, arp, 3);
|
||||
}
|
||||
}
|
||||
free(pIpNetTable);
|
||||
}
|
||||
else { // GetIpNetTable failed
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
|
||||
DWORD linux_proc_get_arp_table(struct arp_table ** table_arp)
|
||||
{
|
||||
unsigned char buffer_ip[40], buffer_mac[40], buffer_int[40];
|
||||
char * end_ptr;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
FILE * fd;
|
||||
__u32 newsize, i;
|
||||
long b;
|
||||
struct arp_table * table_tmp;
|
||||
struct in_addr ip_addr;
|
||||
|
||||
fd = fopen("/proc/net/arp", "r");
|
||||
if (fd == NULL) {
|
||||
result = GetLastError();
|
||||
return result;
|
||||
}
|
||||
|
||||
*table_arp = calloc(sizeof(struct arp_table), 1);
|
||||
|
||||
/*
|
||||
* read first line that we don't need
|
||||
* IP address HW type Flags HW address Mask Device
|
||||
*/
|
||||
while (!feof(fd) && fgetc(fd) != '\n');
|
||||
while (!feof(fd) && (fscanf(fd, " %15[0-9.] %*s %*s %17[A-Fa-f0-9:] %*s %30s", buffer_ip, buffer_mac, buffer_int) == 3)) {
|
||||
|
||||
// allocate size for new entry
|
||||
newsize = sizeof(struct arp_table);
|
||||
newsize += ((*table_arp)->entries + 1) * sizeof(struct arp_entry);
|
||||
table_tmp = realloc(*table_arp, newsize);
|
||||
if (table_tmp == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
memset(&table_tmp->table[table_tmp->entries], 0, sizeof(struct arp_entry));
|
||||
|
||||
// ip address
|
||||
inet_pton(AF_INET, buffer_ip, &ip_addr);
|
||||
table_tmp->table[table_tmp->entries].ipaddr = ip_addr.s_addr;
|
||||
|
||||
// mac address
|
||||
for(i = 0; i < 6 ; i++) {
|
||||
b = strtol(&buffer_mac[3*i], 0, 16);
|
||||
table_tmp->table[table_tmp->entries].hwaddr[i] = (unsigned char)b;
|
||||
}
|
||||
|
||||
// interface name
|
||||
strncpy(table_tmp->table[table_tmp->entries].name, buffer_int, IFNAMSIZ);
|
||||
|
||||
table_tmp->entries++;
|
||||
*table_arp = table_tmp;
|
||||
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD linux_get_arp_table(Remote *remote, Packet *response)
|
||||
{
|
||||
struct arp_table *table_arp = NULL;
|
||||
DWORD result;
|
||||
DWORD index;
|
||||
|
||||
|
||||
dprintf("getting arp table through /proc/net/arp");
|
||||
result = linux_proc_get_arp_table(&table_arp);
|
||||
dprintf("result = %d, table_arp = 0x%p , entries : %d", result, table_arp, table_arp->entries);
|
||||
|
||||
for(index = 0; index < table_arp->entries; index++) {
|
||||
Tlv arp[3];
|
||||
|
||||
arp[0].header.type = TLV_TYPE_IP;
|
||||
arp[0].header.length = sizeof(__u32);
|
||||
arp[0].buffer = (PUCHAR)&table_arp->table[index].ipaddr;
|
||||
|
||||
arp[1].header.type = TLV_TYPE_MAC_ADDR;
|
||||
arp[1].header.length = 6;
|
||||
arp[1].buffer = (PUCHAR)(table_arp->table[index].hwaddr);
|
||||
|
||||
arp[2].header.type = TLV_TYPE_MAC_NAME;
|
||||
arp[2].header.length = strlen(table_arp->table[index].name) + 1;
|
||||
arp[2].buffer = (PUCHAR)(table_arp->table[index].name);
|
||||
|
||||
packet_add_tlv_group(response, TLV_TYPE_ARP_ENTRY, arp, 3);
|
||||
}
|
||||
dprintf("sent %d arp entries", table_arp->entries);
|
||||
|
||||
if (table_arp)
|
||||
free(table_arp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns zero or more arp entries to the requestor from the arp cache
|
||||
*/
|
||||
DWORD request_net_config_get_arp_table(Remote *remote, Packet *packet)
|
||||
{
|
||||
Packet *response = packet_create_response(packet);
|
||||
DWORD result;
|
||||
|
||||
#ifdef _WIN32
|
||||
result = windows_get_arp_table(remote, response);
|
||||
#else
|
||||
result = linux_get_arp_table(remote, response);
|
||||
#endif
|
||||
|
||||
packet_transmit_response(result, remote, response);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
828
external/source/meterpreter/source/extensions/stdapi/server/net/config/netstat.c
vendored
Normal file
828
external/source/meterpreter/source/extensions/stdapi/server/net/config/netstat.c
vendored
Normal file
|
@ -0,0 +1,828 @@
|
|||
#include "precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*
|
||||
* check if there is enough place for another connection entry and allocate some more
|
||||
* memory if necessary
|
||||
*/
|
||||
DWORD check_and_allocate(struct connection_table **table_connection)
|
||||
{
|
||||
DWORD newsize;
|
||||
struct connection_table * tmp_table;
|
||||
|
||||
if ((*table_connection)->entries >= (*table_connection)->max_entries) {
|
||||
newsize = sizeof(struct connection_table);
|
||||
newsize += ((*table_connection)->entries + 10) * sizeof(struct connection_entry);
|
||||
tmp_table = (struct connection_table *)realloc(*table_connection, newsize);
|
||||
if (tmp_table == NULL) {
|
||||
free(*table_connection);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
*table_connection = tmp_table;
|
||||
memset(&(*table_connection)->table[(*table_connection)->entries], 0, 10 * sizeof(struct connection_entry));
|
||||
(*table_connection)->max_entries += 10;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
typedef HANDLE (WINAPI *ptr_CreateToolhelp32Snapshot)(DWORD dwFlags,DWORD th32ProcessID);
|
||||
typedef BOOL (WINAPI *ptr_Process32First)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
|
||||
typedef BOOL (WINAPI *ptr_Process32Next)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
|
||||
|
||||
|
||||
/*
|
||||
* write pid/process_name in buffer
|
||||
*/
|
||||
|
||||
DWORD set_process_name(DWORD pid, char * buffer, DWORD buffer_size)
|
||||
{
|
||||
HANDLE hSnapshot;
|
||||
ptr_CreateToolhelp32Snapshot ct32s = NULL;
|
||||
ptr_Process32First p32f = NULL;
|
||||
ptr_Process32Next p32n = NULL;
|
||||
|
||||
|
||||
ct32s = (ptr_CreateToolhelp32Snapshot)GetProcAddress(GetModuleHandle("kernel32"), "CreateToolhelp32Snapshot");
|
||||
p32f = (ptr_Process32First)GetProcAddress(GetModuleHandle("kernel32"), "Process32First");
|
||||
p32n = (ptr_Process32Next)GetProcAddress(GetModuleHandle("kernel32"), "Process32Next");
|
||||
|
||||
if ((!ct32s) || (!p32f) || (!p32n))
|
||||
return -1;
|
||||
|
||||
hSnapshot = ct32s(TH32CS_SNAPPROCESS,0);
|
||||
if(hSnapshot) {
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
if(p32f(hSnapshot,&pe32)) {
|
||||
do {
|
||||
if (pe32.th32ProcessID == pid) {
|
||||
sprintf_s(buffer, buffer_size, "%d/%s",pid, pe32.szExeFile);
|
||||
break;
|
||||
}
|
||||
} while(p32n(hSnapshot,&pe32));
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
char *tcp_connection_states[] = {
|
||||
"", "CLOSED", "LISTEN", "SYN_SENT", "SYN_RECV", "ESTABLISHED", "FIN_WAIT1", "FIN_WAIT2", "CLOSE_WAIT",
|
||||
"CLOSING", "LAST_ACK", "TIME_WAIT", "DELETE_TCB", "UNKNOWN" };
|
||||
|
||||
typedef struct _MIB_TCP6ROW_OWNER_MODULE {
|
||||
UCHAR ucLocalAddr[16];
|
||||
DWORD dwLocalScopeId;
|
||||
DWORD dwLocalPort;
|
||||
UCHAR ucRemoteAddr[16];
|
||||
DWORD dwRemoteScopeId;
|
||||
DWORD dwRemotePort;
|
||||
DWORD dwState;
|
||||
DWORD dwOwningPid;
|
||||
LARGE_INTEGER liCreateTimestamp;
|
||||
ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];
|
||||
} MIB_TCP6ROW_OWNER_MODULE, *PMIB_TCP6ROW_OWNER_MODULE;
|
||||
|
||||
typedef struct _MIB_UDP6ROW_OWNER_MODULE {
|
||||
UCHAR ucLocalAddr[16];
|
||||
DWORD dwLocalScopeId;
|
||||
DWORD dwLocalPort;
|
||||
DWORD dwOwningPid;
|
||||
LARGE_INTEGER liCreateTimestamp;
|
||||
union {
|
||||
struct {
|
||||
int SpecificPortBind :1;
|
||||
};
|
||||
int dwFlags;
|
||||
};
|
||||
ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];
|
||||
} MIB_UDP6ROW_OWNER_MODULE, *PMIB_UDP6ROW_OWNER_MODULE;
|
||||
|
||||
typedef struct _MIB_TCP6TABLE_OWNER_MODULE {
|
||||
DWORD dwNumEntries;
|
||||
MIB_TCP6ROW_OWNER_MODULE table[ANY_SIZE];
|
||||
} MIB_TCP6TABLE_OWNER_MODULE, *PMIB_TCP6TABLE_OWNER_MODULE;
|
||||
|
||||
typedef struct {
|
||||
DWORD dwNumEntries;
|
||||
MIB_UDP6ROW_OWNER_MODULE table[ANY_SIZE];
|
||||
} MIB_UDP6TABLE_OWNER_MODULE, *PMIB_UDP6TABLE_OWNER_MODULE;
|
||||
|
||||
typedef DWORD (WINAPI * ptr_GetExtendedTcpTable)(PVOID, PDWORD pdwSize, BOOL bOrder, ULONG ulAf,TCP_TABLE_CLASS TableClass,
|
||||
ULONG Reserved);
|
||||
typedef DWORD (WINAPI * ptr_GetExtendedUdpTable)(PVOID, PDWORD pdwSize, BOOL bOrder, ULONG ulAf,TCP_TABLE_CLASS TableClass,
|
||||
ULONG Reserved);
|
||||
|
||||
|
||||
/*
|
||||
* retrieve tcp table for win 2000 and NT4 ?
|
||||
*/
|
||||
DWORD windows_get_tcp_table_win2000_down(struct connection_table **table_connection)
|
||||
{
|
||||
PMIB_TCPTABLE pTcpTable = NULL;
|
||||
struct connection_entry * current_connection;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal = 0;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD i, state;
|
||||
|
||||
do {
|
||||
dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE);
|
||||
dprintf("[NETSTAT TCP] need %d bytes",dwSize);
|
||||
/* Get the size required by GetTcpTable() */
|
||||
if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
|
||||
pTcpTable = (MIB_TCPTABLE *) malloc (dwSize);
|
||||
}
|
||||
else if (dwRetVal != NO_ERROR) {
|
||||
result = ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) == NO_ERROR) {
|
||||
dprintf("[NETSTAT] found %d tcp connections", pTcpTable->dwNumEntries);
|
||||
for (i = 0 ; i < pTcpTable->dwNumEntries ; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(pTcpTable);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET;
|
||||
current_connection->local_addr.addr = pTcpTable->table[i].dwLocalAddr;
|
||||
current_connection->remote_addr.addr = pTcpTable->table[i].dwRemoteAddr;
|
||||
current_connection->local_port = ntohs((u_short)(pTcpTable->table[i].dwLocalPort & 0x0000ffff));
|
||||
// if socket is in LISTEN, remote_port is garbage, force value to 0
|
||||
if (pTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
|
||||
current_connection->remote_port = 0;
|
||||
else
|
||||
current_connection->remote_port = ntohs((u_short)(pTcpTable->table[i].dwRemotePort & 0x0000ffff));
|
||||
|
||||
state = pTcpTable->table[i].dwState;
|
||||
if ((state <= 0) || (state > 12))
|
||||
state = 13; // points to UNKNOWN in the state array
|
||||
strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "tcp", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-"
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
free(pTcpTable);
|
||||
}
|
||||
else { // GetTcpTable failed
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
} while (0) ;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve tcp table for win xp and up
|
||||
*/
|
||||
DWORD windows_get_tcp_table(struct connection_table **table_connection)
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
struct connection_entry * current_connection = NULL;
|
||||
MIB_TCPTABLE_OWNER_MODULE * tablev4 = NULL;
|
||||
MIB_TCP6TABLE_OWNER_MODULE * tablev6 = NULL;
|
||||
MIB_TCPROW_OWNER_MODULE * currentv4 = NULL;
|
||||
MIB_TCP6ROW_OWNER_MODULE * currentv6 = NULL;
|
||||
DWORD i, state, dwSize;
|
||||
|
||||
|
||||
ptr_GetExtendedTcpTable gett = NULL;
|
||||
|
||||
gett = (ptr_GetExtendedTcpTable)GetProcAddress(GetModuleHandle("iphlpapi"), "GetExtendedTcpTable");
|
||||
|
||||
// systems that don't support GetExtendedTcpTable
|
||||
if (gett == NULL) {
|
||||
return windows_get_tcp_table_win2000_down(table_connection);
|
||||
}
|
||||
do {
|
||||
// IPv4 part
|
||||
dwSize = 0;
|
||||
if (gett(NULL,&dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
tablev4 = (MIB_TCPTABLE_OWNER_MODULE *)malloc(dwSize);
|
||||
if (gett(tablev4, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) {
|
||||
for(i=0; i<tablev4->dwNumEntries; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(tablev4);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
currentv4 = &tablev4->table[i];
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET;
|
||||
current_connection->local_addr.addr = currentv4->dwLocalAddr;
|
||||
current_connection->remote_addr.addr = currentv4->dwRemoteAddr;
|
||||
current_connection->local_port = ntohs((u_short)(currentv4->dwLocalPort & 0x0000ffff));
|
||||
// if socket is in LISTEN, remote_port is garbage, force value to 0
|
||||
if (currentv4->dwState == MIB_TCP_STATE_LISTEN)
|
||||
current_connection->remote_port = 0;
|
||||
else
|
||||
current_connection->remote_port = ntohs((u_short)(currentv4->dwRemotePort & 0x0000ffff));
|
||||
|
||||
state = currentv4->dwState;
|
||||
if ((state <= 0) || (state > 12))
|
||||
state = 13; // points to UNKNOWN in the state array
|
||||
strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "tcp", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
}
|
||||
else { // gett failed
|
||||
result = GetLastError();
|
||||
if (tablev4)
|
||||
free(tablev4);
|
||||
break;
|
||||
}
|
||||
if (tablev4)
|
||||
free(tablev4);
|
||||
}
|
||||
// IPv6 part
|
||||
dwSize = 0;
|
||||
if (gett(NULL,&dwSize, TRUE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
tablev6 = (MIB_TCP6TABLE_OWNER_MODULE *)malloc(dwSize);
|
||||
if (gett(tablev6, &dwSize, TRUE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) {
|
||||
for(i=0; i<tablev6->dwNumEntries; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(tablev6);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
currentv6 = &tablev6->table[i];
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET6;
|
||||
memcpy(¤t_connection->local_addr.addr6, currentv6->ucLocalAddr, sizeof(current_connection->local_addr.addr6));
|
||||
memcpy(¤t_connection->remote_addr.addr6, currentv6->ucRemoteAddr, sizeof(current_connection->remote_addr.addr6));
|
||||
current_connection->local_port = ntohs((u_short)(currentv6->dwLocalPort & 0x0000ffff));
|
||||
// if socket is in LISTEN, remote_port is garbage, force value to 0
|
||||
if (currentv6->dwState == MIB_TCP_STATE_LISTEN)
|
||||
current_connection->remote_port = 0;
|
||||
else
|
||||
current_connection->remote_port = ntohs((u_short)(currentv6->dwRemotePort & 0x0000ffff));
|
||||
|
||||
state = currentv6->dwState;
|
||||
if ((state <= 0) || (state > 12))
|
||||
state = 13; // points to UNKNOWN in the state array
|
||||
strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "tcp6", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
}
|
||||
else { // gett failed
|
||||
result = GetLastError();
|
||||
if (tablev6)
|
||||
free(tablev6);
|
||||
break;
|
||||
}
|
||||
if (tablev6)
|
||||
free(tablev6);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve udp table for win 2000 and NT4 ?
|
||||
*/
|
||||
DWORD windows_get_udp_table_win2000_down(struct connection_table **table_connection)
|
||||
{
|
||||
PMIB_UDPTABLE pUdpTable = NULL;
|
||||
struct connection_entry * current_connection;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal = 0;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD i;
|
||||
|
||||
do {
|
||||
dwRetVal = GetUdpTable(pUdpTable, &dwSize, TRUE);
|
||||
dprintf("[NETSTAT UDP] need %d bytes",dwSize);
|
||||
/* Get the size required by GetUdpTable() */
|
||||
if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
|
||||
pUdpTable = (MIB_UDPTABLE *) malloc (dwSize);
|
||||
}
|
||||
else if (dwRetVal != NO_ERROR) {
|
||||
result = ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dwRetVal = GetUdpTable(pUdpTable, &dwSize, TRUE)) == NO_ERROR) {
|
||||
dprintf("[NETSTAT] found %d udp connections", pUdpTable->dwNumEntries);
|
||||
for (i = 0 ; i < pUdpTable->dwNumEntries ; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(pUdpTable);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
// GetUdpTable reports only listening UDP sockets, not "active" ones
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET;
|
||||
current_connection->local_addr.addr = pUdpTable->table[i].dwLocalAddr;
|
||||
current_connection->remote_addr.addr = 0;
|
||||
current_connection->local_port = ntohs((u_short)(pUdpTable->table[i].dwLocalPort & 0x0000ffff));
|
||||
current_connection->remote_port = 0;
|
||||
|
||||
// force state to ""
|
||||
strncpy(current_connection->state, "", sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "udp", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-"
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
free(pUdpTable);
|
||||
}
|
||||
else { // GetUdpTable failed
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
} while (0) ;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* retrieve udp table for win xp and up
|
||||
*/
|
||||
DWORD windows_get_udp_table(struct connection_table **table_connection)
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
struct connection_entry * current_connection = NULL;
|
||||
MIB_UDPTABLE_OWNER_MODULE * tablev4 = NULL;
|
||||
MIB_UDP6TABLE_OWNER_MODULE * tablev6 = NULL;
|
||||
MIB_UDPROW_OWNER_MODULE * currentv4 = NULL;
|
||||
MIB_UDP6ROW_OWNER_MODULE * currentv6 = NULL;
|
||||
DWORD i, dwSize;
|
||||
|
||||
|
||||
ptr_GetExtendedUdpTable geut = NULL;
|
||||
|
||||
geut = (ptr_GetExtendedTcpTable)GetProcAddress(GetModuleHandle("iphlpapi"), "GetExtendedUdpTable");
|
||||
|
||||
// systems that don't support GetExtendedUdpTable
|
||||
if (geut == NULL) {
|
||||
return windows_get_udp_table_win2000_down(table_connection);
|
||||
}
|
||||
do {
|
||||
// IPv4 part
|
||||
dwSize = 0;
|
||||
if (geut(NULL,&dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
tablev4 = (MIB_UDPTABLE_OWNER_MODULE *)malloc(dwSize);
|
||||
if (geut(tablev4, &dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) {
|
||||
for(i=0; i<tablev4->dwNumEntries; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(tablev4);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
// GetExtendedUdpTable reports only listening UDP sockets, not "active" ones
|
||||
currentv4 = &tablev4->table[i];
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET;
|
||||
current_connection->local_addr.addr = currentv4->dwLocalAddr;
|
||||
current_connection->remote_addr.addr = 0;
|
||||
current_connection->local_port = ntohs((u_short)(currentv4->dwLocalPort & 0x0000ffff));
|
||||
current_connection->remote_port = 0;
|
||||
|
||||
strncpy(current_connection->state, "", sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "udp", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
}
|
||||
else { // geut failed
|
||||
result = GetLastError();
|
||||
if (tablev4)
|
||||
free(tablev4);
|
||||
break;
|
||||
}
|
||||
if (tablev4)
|
||||
free(tablev4);
|
||||
}
|
||||
// IPv6 part
|
||||
dwSize = 0;
|
||||
if (geut(NULL,&dwSize, TRUE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
tablev6 = (MIB_UDP6TABLE_OWNER_MODULE *)malloc(dwSize);
|
||||
if (geut(tablev6, &dwSize, TRUE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) {
|
||||
for(i=0; i<tablev6->dwNumEntries; i++) {
|
||||
// check available memory and allocate if necessary
|
||||
if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) {
|
||||
free(tablev6);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
currentv6 = &tablev6->table[i];
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
current_connection->type = AF_INET6;
|
||||
memcpy(¤t_connection->local_addr.addr6, currentv6->ucLocalAddr, sizeof(current_connection->local_addr.addr6));
|
||||
memset(¤t_connection->remote_addr.addr6, 0, sizeof(current_connection->remote_addr.addr6));
|
||||
current_connection->local_port = ntohs((u_short)(currentv6->dwLocalPort & 0x0000ffff));
|
||||
current_connection->remote_port = 0;
|
||||
|
||||
strncpy(current_connection->state, "", sizeof(current_connection->state));
|
||||
strncpy(current_connection->protocol, "udp6", sizeof(current_connection->protocol));
|
||||
|
||||
// force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
}
|
||||
else { // gett failed
|
||||
result = GetLastError();
|
||||
if (tablev6)
|
||||
free(tablev6);
|
||||
break;
|
||||
}
|
||||
if (tablev6)
|
||||
free(tablev6);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
DWORD windows_get_connection_table(Remote *remote, Packet *response)
|
||||
{
|
||||
struct connection_table *table_connection = NULL;
|
||||
struct connection_entry * current_connection;
|
||||
DWORD dwRetVal;
|
||||
int index;
|
||||
DWORD local_port_be, remote_port_be;
|
||||
|
||||
table_connection = (struct connection_table *)calloc(sizeof(struct connection_table) + 10 * sizeof(struct connection_entry), 1);
|
||||
table_connection->max_entries = 10;
|
||||
|
||||
dwRetVal = windows_get_tcp_table(&table_connection);
|
||||
if (dwRetVal == ERROR_NOT_ENOUGH_MEMORY)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dwRetVal = windows_get_udp_table(&table_connection);
|
||||
if (dwRetVal == ERROR_NOT_ENOUGH_MEMORY)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
|
||||
for(index = 0; index < table_connection->entries; index++) {
|
||||
Tlv connection[7];
|
||||
current_connection = &table_connection->table[index];
|
||||
if (current_connection->type == AF_INET) {
|
||||
connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW;
|
||||
connection[0].header.length = sizeof(__u32);
|
||||
connection[0].buffer = (PUCHAR)¤t_connection->local_addr.addr;
|
||||
|
||||
connection[1].header.type = TLV_TYPE_PEER_HOST_RAW;
|
||||
connection[1].header.length = sizeof(__u32);
|
||||
connection[1].buffer = (PUCHAR)¤t_connection->remote_addr.addr;
|
||||
}
|
||||
else {
|
||||
connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW;
|
||||
connection[0].header.length = sizeof(__u128);
|
||||
connection[0].buffer = (PUCHAR)¤t_connection->local_addr.addr6;
|
||||
|
||||
connection[1].header.type = TLV_TYPE_PEER_HOST_RAW;
|
||||
connection[1].header.length = sizeof(__u128);
|
||||
connection[1].buffer = (PUCHAR)¤t_connection->remote_addr.addr6;
|
||||
}
|
||||
|
||||
local_port_be = htonl(current_connection->local_port);
|
||||
connection[2].header.type = TLV_TYPE_LOCAL_PORT;
|
||||
connection[2].header.length = sizeof(__u32);
|
||||
connection[2].buffer = (PUCHAR)&local_port_be;
|
||||
|
||||
remote_port_be = htonl(current_connection->remote_port);
|
||||
connection[3].header.type = TLV_TYPE_PEER_PORT;
|
||||
connection[3].header.length = sizeof(__u32);
|
||||
connection[3].buffer = (PUCHAR)&remote_port_be;
|
||||
|
||||
connection[4].header.type = TLV_TYPE_MAC_NAME;
|
||||
connection[4].header.length = strlen(current_connection->protocol) + 1;
|
||||
connection[4].buffer = (PUCHAR)(current_connection->protocol);
|
||||
|
||||
connection[5].header.type = TLV_TYPE_SUBNET_STRING;
|
||||
connection[5].header.length = strlen(current_connection->state) + 1;
|
||||
connection[5].buffer = (PUCHAR)(current_connection->state);
|
||||
|
||||
connection[6].header.type = TLV_TYPE_PROCESS_NAME;
|
||||
connection[6].header.length = strlen(current_connection->program_name) + 1;
|
||||
connection[6].buffer = (PUCHAR)(current_connection->program_name);
|
||||
|
||||
packet_add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 7);
|
||||
}
|
||||
dprintf("sent %d connections", table_connection->entries);
|
||||
|
||||
if (table_connection)
|
||||
free(table_connection);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
char *tcp_connection_states[] = {
|
||||
"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2", "TIME_WAIT",
|
||||
"CLOSED", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"
|
||||
};
|
||||
char *udp_connection_states[] = {
|
||||
"", "ESTABLISHED", "", "", "", "", "", "", "", "", "", "", "UNKNOWN"
|
||||
};
|
||||
|
||||
|
||||
DWORD linux_parse_proc_net_file(char * filename, struct connection_table ** table_connection, char type, char * protocol, char tableidx )
|
||||
{
|
||||
struct connection_table * tmp_table;
|
||||
struct connection_entry * current_connection;
|
||||
char ** connection_states;
|
||||
FILE * fd;
|
||||
char buffer[300], buffer_junk[100];
|
||||
__u32 local_addr, remote_addr;
|
||||
__u128 local_addr6, remote_addr6;
|
||||
__u32 local_port, remote_port;
|
||||
__u32 state, uid, inode;
|
||||
__u32 newsize;
|
||||
|
||||
fd = fopen(filename, "r");
|
||||
if (fd == NULL)
|
||||
return -1;
|
||||
|
||||
if (tableidx == 0) // TCP states
|
||||
connection_states = tcp_connection_states;
|
||||
else // UDP states
|
||||
connection_states = udp_connection_states;
|
||||
|
||||
/*
|
||||
* read first line that we don't need
|
||||
* sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
||||
*/
|
||||
while (!feof(fd) && fgetc(fd) != '\n');
|
||||
while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) {
|
||||
if ((*table_connection)->entries >= (*table_connection)->max_entries) {
|
||||
newsize = sizeof(struct connection_table);
|
||||
newsize += ((*table_connection)->entries + 10) * sizeof(struct connection_entry);
|
||||
tmp_table = realloc(*table_connection, newsize);
|
||||
*table_connection = tmp_table;
|
||||
memset(&(*table_connection)->table[(*table_connection)->entries], 0, 10 * sizeof(struct connection_entry));
|
||||
(*table_connection)->max_entries += 10;
|
||||
}
|
||||
|
||||
current_connection = &(*table_connection)->table[(*table_connection)->entries];
|
||||
|
||||
if (type == AF_INET) {
|
||||
if (sscanf(buffer, " %*u: %lX:%x %lX:%x %x %*X:%*X %*x:%*X %*x %u %*u %u %[^\n] ", &local_addr, &local_port,
|
||||
&remote_addr, &remote_port, &state, &uid, &inode, buffer_junk) == 8) {
|
||||
|
||||
current_connection->local_addr.addr = local_addr;
|
||||
current_connection->remote_addr.addr = remote_addr;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else { // AF_INET6
|
||||
if (sscanf(buffer, " %*u: %08X%08X%08X%08X:%x %08X%08x%08X%08X:%x %x %*X:%*X %*x:%*X %*x %u %*u %u %[^\n] ", &local_addr6.a1,
|
||||
&local_addr6.a2,&local_addr6.a3, &local_addr6.a4, &local_port, &remote_addr6.a1, &remote_addr6.a2, &remote_addr6.a3,
|
||||
&remote_addr6.a4,&remote_port, &state, &uid, &inode, buffer_junk) == 14) {
|
||||
memcpy(¤t_connection->local_addr.addr6, &local_addr6, sizeof(__u128));
|
||||
memcpy(¤t_connection->remote_addr.addr6, &remote_addr6, sizeof(__u128));
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
current_connection->type = type;
|
||||
current_connection->local_port = local_port;
|
||||
current_connection->remote_port = remote_port;
|
||||
current_connection->uid = uid;
|
||||
current_connection->inode = inode;
|
||||
// protocol such as tcp/tcp6/udp/udp6
|
||||
strncpy(current_connection->protocol, protocol, sizeof(current_connection->protocol));
|
||||
if ((state < 0) && (state > 11))
|
||||
state = 12; // points to UNKNOWN in the table
|
||||
|
||||
// state, number to string : 0x0A --> LISTEN
|
||||
strncpy(current_connection->state, connection_states[state], sizeof(current_connection->state));
|
||||
|
||||
// initialize every program_name to "-", will be changed if we find the good info in /proc
|
||||
strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name));
|
||||
|
||||
(*table_connection)->entries++;
|
||||
}
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD linux_proc_get_program_name(struct connection_entry * connection, unsigned char * pid)
|
||||
{
|
||||
FILE *fd;
|
||||
char buffer[30], buffer_file[50], name[30];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%s/status", pid);
|
||||
|
||||
fd = fopen(buffer, "r");
|
||||
if (fd == NULL)
|
||||
return -1;
|
||||
|
||||
if (fgets(buffer_file, sizeof(buffer_file), fd) == NULL) {
|
||||
fclose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(buffer_file, "Name: %s\n", name) != 1) {
|
||||
fclose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(connection->program_name, sizeof(connection->program_name), "%s/%s",pid,name);
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct connection_entry * find_connection(struct connection_table * table_connection, __u32 inode)
|
||||
{
|
||||
__u32 i;
|
||||
for( i = 0 ; i < table_connection->entries ; i++) {
|
||||
if (table_connection->table[i].inode == inode)
|
||||
return &table_connection->table[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD linux_proc_fill_program_name(struct connection_table * table_connection)
|
||||
{
|
||||
char buffer[60];
|
||||
struct dirent *procent, *fdent;
|
||||
DIR * procfd, * pidfd;
|
||||
struct stat stat_buf;
|
||||
struct connection_entry * connection;
|
||||
|
||||
procfd = opendir("/proc");
|
||||
if (procfd == NULL)
|
||||
return -1;
|
||||
while ((procent = readdir(procfd)) != NULL) {
|
||||
// not a pid directory
|
||||
if (!isdigit(*(procent->d_name)))
|
||||
continue;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%s/fd/", procent->d_name);
|
||||
if ((pidfd = opendir(buffer)) == NULL)
|
||||
continue;
|
||||
|
||||
while((fdent = readdir(pidfd)) != NULL) {
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%s/fd/%s", procent->d_name, fdent->d_name);
|
||||
if (stat(buffer, &stat_buf) < 0)
|
||||
continue;
|
||||
if (!S_ISSOCK(stat_buf.st_mode))
|
||||
continue;
|
||||
// ok, FD is a socket, search if we have it in our list
|
||||
if ((connection = find_connection(table_connection, stat_buf.st_ino)) != NULL)
|
||||
linux_proc_get_program_name(connection, procent->d_name);
|
||||
}
|
||||
closedir(pidfd);
|
||||
}
|
||||
closedir(procfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DWORD linux_proc_get_connection_table(struct connection_table ** table_connection)
|
||||
{
|
||||
*table_connection = calloc(sizeof(struct connection_table) + 10 * sizeof(struct connection_entry), 1);
|
||||
(*table_connection)->max_entries = 10;
|
||||
|
||||
linux_parse_proc_net_file("/proc/net/tcp" , table_connection, AF_INET , "tcp", 0);
|
||||
linux_parse_proc_net_file("/proc/net/tcp6", table_connection, AF_INET6, "tcp6", 0);
|
||||
linux_parse_proc_net_file("/proc/net/udp" , table_connection, AF_INET , "udp", 1);
|
||||
linux_parse_proc_net_file("/proc/net/udp6", table_connection, AF_INET6, "udp6", 1);
|
||||
|
||||
// fill the PID/program_name part
|
||||
linux_proc_fill_program_name(*table_connection);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD linux_get_connection_table(Remote *remote, Packet *response)
|
||||
{
|
||||
struct connection_table *table_connection = NULL;
|
||||
__u32 local_port_be, remote_port_be, uid_be, inode_be;
|
||||
__u32 index;
|
||||
DWORD result;
|
||||
|
||||
dprintf("getting connection list through /proc/net");
|
||||
result = linux_proc_get_connection_table(&table_connection);
|
||||
dprintf("result = %d, table_connection = 0x%p , entries : %d", result, table_connection, table_connection->entries);
|
||||
|
||||
for(index = 0; index < table_connection->entries; index++) {
|
||||
Tlv connection[9];
|
||||
if (table_connection->table[index].type == AF_INET) {
|
||||
connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW;
|
||||
connection[0].header.length = sizeof(__u32);
|
||||
connection[0].buffer = (PUCHAR)&table_connection->table[index].local_addr.addr;
|
||||
|
||||
connection[1].header.type = TLV_TYPE_PEER_HOST_RAW;
|
||||
connection[1].header.length = sizeof(__u32);
|
||||
connection[1].buffer = (PUCHAR)&table_connection->table[index].remote_addr.addr;
|
||||
}
|
||||
else {
|
||||
connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW;
|
||||
connection[0].header.length = sizeof(__u128);
|
||||
connection[0].buffer = (PUCHAR)&table_connection->table[index].local_addr.addr6;
|
||||
|
||||
connection[1].header.type = TLV_TYPE_PEER_HOST_RAW;
|
||||
connection[1].header.length = sizeof(__u128);
|
||||
connection[1].buffer = (PUCHAR)&table_connection->table[index].remote_addr.addr6;
|
||||
}
|
||||
|
||||
local_port_be = htonl(table_connection->table[index].local_port & 0x0000ffff);
|
||||
connection[2].header.type = TLV_TYPE_LOCAL_PORT;
|
||||
connection[2].header.length = sizeof(__u32);
|
||||
connection[2].buffer = (PUCHAR)&local_port_be;
|
||||
|
||||
remote_port_be = htonl(table_connection->table[index].remote_port & 0x0000ffff);
|
||||
connection[3].header.type = TLV_TYPE_PEER_PORT;
|
||||
connection[3].header.length = sizeof(__u32);
|
||||
connection[3].buffer = (PUCHAR)&remote_port_be;
|
||||
|
||||
connection[4].header.type = TLV_TYPE_MAC_NAME;
|
||||
connection[4].header.length = strlen(table_connection->table[index].protocol) + 1;
|
||||
connection[4].buffer = (PUCHAR)(table_connection->table[index].protocol);
|
||||
|
||||
connection[5].header.type = TLV_TYPE_SUBNET_STRING;
|
||||
connection[5].header.length = strlen(table_connection->table[index].state) + 1;
|
||||
connection[5].buffer = (PUCHAR)(table_connection->table[index].state);
|
||||
|
||||
uid_be = htonl(table_connection->table[index].uid);
|
||||
connection[6].header.type = TLV_TYPE_PID;
|
||||
connection[6].header.length = sizeof(__u32);
|
||||
connection[6].buffer = (PUCHAR)&uid_be;
|
||||
|
||||
inode_be = htonl(table_connection->table[index].inode);
|
||||
connection[7].header.type = TLV_TYPE_ROUTE_METRIC;
|
||||
connection[7].header.length = sizeof(__u32);
|
||||
connection[7].buffer = (PUCHAR)&inode_be;
|
||||
|
||||
connection[8].header.type = TLV_TYPE_PROCESS_NAME;
|
||||
connection[8].header.length = strlen(table_connection->table[index].program_name) + 1;
|
||||
connection[8].buffer = (PUCHAR)(table_connection->table[index].program_name);
|
||||
|
||||
packet_add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 9);
|
||||
}
|
||||
dprintf("sent %d connections", table_connection->entries);
|
||||
|
||||
if (table_connection)
|
||||
free(table_connection);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns zero or more connection entries to the requestor from the connection list
|
||||
*/
|
||||
DWORD request_net_config_get_netstat(Remote *remote, Packet *packet)
|
||||
{
|
||||
Packet *response = packet_create_response(packet);
|
||||
DWORD result;
|
||||
|
||||
#ifdef _WIN32
|
||||
result = windows_get_connection_table(remote, response);
|
||||
#else
|
||||
result = linux_get_connection_table(remote, response);
|
||||
#endif
|
||||
|
||||
packet_transmit_response(result, remote, response);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
|
@ -49,6 +49,10 @@ DWORD request_net_config_remove_route(Remote *remote, Packet *packet);
|
|||
|
||||
DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet);
|
||||
|
||||
DWORD request_net_config_get_arp_table(Remote *remote, Packet *packet);
|
||||
|
||||
DWORD request_net_config_get_netstat(Remote *remote, Packet *packet);
|
||||
|
||||
// Socket
|
||||
DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet);
|
||||
|
||||
|
|
|
@ -325,6 +325,14 @@ Command customCommands[] =
|
|||
{ request_net_config_get_interfaces, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
{ "stdapi_net_config_get_arp_table",
|
||||
{ request_net_config_get_arp_table, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
{ "stdapi_net_config_get_netstat",
|
||||
{ request_net_config_get_netstat, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
|
||||
// Socket
|
||||
{ "stdapi_net_socket_tcp_shutdown",
|
||||
|
|
|
@ -360,6 +360,11 @@
|
|||
TLV_META_TYPE_UINT, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1424)
|
||||
#define TLV_TYPE_ARP_ENTRY \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
TLV_META_TYPE_GROUP, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1425)
|
||||
|
||||
#define TLV_TYPE_IP \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
|
@ -434,6 +439,21 @@
|
|||
TLV_META_TYPE_UINT, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1504)
|
||||
#define TLV_TYPE_NETSTAT_ENTRY \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
TLV_META_TYPE_GROUP, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1505)
|
||||
#define TLV_TYPE_PEER_HOST_RAW \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
TLV_META_TYPE_RAW, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1506)
|
||||
#define TLV_TYPE_LOCAL_HOST_RAW \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
TLV_META_TYPE_RAW, \
|
||||
TLV_TYPE_EXTENSION_STDAPI, \
|
||||
1507)
|
||||
|
||||
#define TLV_TYPE_SHUTDOWN_HOW \
|
||||
MAKE_CUSTOM_TLV( \
|
||||
|
|
|
@ -32,6 +32,8 @@ objects = \
|
|||
server/general.o \
|
||||
server/net/config/interface.o \
|
||||
server/net/config/route.o \
|
||||
server/net/config/arp.o \
|
||||
server/net/config/netstat.o \
|
||||
server/net/socket/tcp.o \
|
||||
server/net/socket/tcp_server.o \
|
||||
server/net/socket/udp.o \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env ruby
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'ipaddr'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Extensions
|
||||
module Stdapi
|
||||
module Net
|
||||
|
||||
###
|
||||
#
|
||||
# This class represents an arp entry
|
||||
# on the remote machine.
|
||||
#
|
||||
###
|
||||
class Arp
|
||||
|
||||
##
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Returns an arp entry and initializes it to the supplied
|
||||
# parameters.
|
||||
#
|
||||
def initialize(opts={})
|
||||
self.ip_addr = IPAddr.new_ntoh(opts[:ip_addr]).to_s
|
||||
self.mac_addr = mac_to_string(opts[:mac_addr])
|
||||
self.interface = opts[:interface]
|
||||
end
|
||||
|
||||
def mac_to_string(mac_addr)
|
||||
macocts = []
|
||||
mac_addr.each_byte { |o| macocts << o }
|
||||
macocts += [0] * (6 - macocts.size) if macocts.size < 6
|
||||
return sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
macocts[0], macocts[1], macocts[2],
|
||||
macocts[3], macocts[4], macocts[5])
|
||||
end
|
||||
|
||||
#
|
||||
# The ip address corresponding to the arp address.
|
||||
#
|
||||
attr_accessor :ip_addr
|
||||
#
|
||||
# The physical (MAC) address of the ARP entry
|
||||
#
|
||||
attr_accessor :mac_addr
|
||||
#
|
||||
# The name of the interface.
|
||||
#
|
||||
attr_accessor :interface
|
||||
end
|
||||
|
||||
end; end; end; end; end; end
|
|
@ -2,7 +2,9 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'rex/post/meterpreter/extensions/stdapi/tlv'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/arp'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/route'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/netstat'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/interface'
|
||||
|
||||
module Rex
|
||||
|
@ -101,12 +103,72 @@ class Config
|
|||
|
||||
alias interfaces get_interfaces
|
||||
|
||||
##
|
||||
#
|
||||
# Network connections
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Returns an array of network connection entries with each element being a Netstat.
|
||||
#
|
||||
|
||||
def get_netstat
|
||||
request = Packet.create_request('stdapi_net_config_get_netstat')
|
||||
netstat = []
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
# Build out the array of netstat
|
||||
response.each(TLV_TYPE_NETSTAT_ENTRY) { |connection|
|
||||
netstat << Netstat.new(
|
||||
:local_addr => connection.get_tlv_value(TLV_TYPE_LOCAL_HOST_RAW),
|
||||
:remote_addr => connection.get_tlv_value(TLV_TYPE_PEER_HOST_RAW),
|
||||
:local_port => connection.get_tlv_value(TLV_TYPE_LOCAL_PORT),
|
||||
:remote_port => connection.get_tlv_value(TLV_TYPE_PEER_PORT),
|
||||
:protocol => connection.get_tlv_value(TLV_TYPE_MAC_NAME), # tcp/tcp6/udp/udp6
|
||||
:state => connection.get_tlv_value(TLV_TYPE_SUBNET_STRING),
|
||||
:uid => connection.get_tlv_value(TLV_TYPE_PID),
|
||||
:inode => connection.get_tlv_value(TLV_TYPE_ROUTE_METRIC),
|
||||
:pid_name => connection.get_tlv_value(TLV_TYPE_PROCESS_NAME)
|
||||
)
|
||||
}
|
||||
|
||||
return netstat
|
||||
end
|
||||
|
||||
alias netstat get_netstat
|
||||
|
||||
##
|
||||
#
|
||||
# Routing
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Returns an array of arp entries with each element being an Arp.
|
||||
#
|
||||
|
||||
def get_arp_table
|
||||
request = Packet.create_request('stdapi_net_config_get_arp_table')
|
||||
arps = []
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
# Build out the array of arp
|
||||
response.each(TLV_TYPE_ARP_ENTRY) { |arp|
|
||||
arps << Arp.new(
|
||||
:ip_addr => arp.get_tlv_value(TLV_TYPE_IP),
|
||||
:mac_addr => arp.get_tlv_value(TLV_TYPE_MAC_ADDRESS),
|
||||
:interface => arp.get_tlv_value(TLV_TYPE_MAC_NAME)
|
||||
)
|
||||
}
|
||||
|
||||
return arps
|
||||
end
|
||||
|
||||
alias arp_table get_arp_table
|
||||
|
||||
#
|
||||
# Enumerates each route.
|
||||
#
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
#!/usr/bin/env ruby
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'ipaddr'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Extensions
|
||||
module Stdapi
|
||||
module Net
|
||||
|
||||
###
|
||||
#
|
||||
# This class represents a connection (listening, connected)
|
||||
# on the remote machine.
|
||||
#
|
||||
###
|
||||
class Netstat
|
||||
|
||||
##
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Returns a netstat entry and initializes it to the supplied
|
||||
# parameters.
|
||||
#
|
||||
def initialize(opts={})
|
||||
self.local_addr = IPAddr.new_ntoh(opts[:local_addr]).to_s
|
||||
self.remote_addr = IPAddr.new_ntoh(opts[:remote_addr]).to_s
|
||||
self.local_port = opts[:local_port]
|
||||
self.remote_port = opts[:remote_port]
|
||||
self.protocol = opts[:protocol]
|
||||
self.state = opts[:state]
|
||||
self.uid = opts[:uid] || 0
|
||||
self.inode = opts[:inode] || 0
|
||||
self.pid_name = opts[:pid_name]
|
||||
|
||||
self.local_addr_str = sprintf("%s:%d",self.local_addr, self.local_port)
|
||||
if self.remote_port == 0
|
||||
port = "*"
|
||||
else
|
||||
port = self.remote_port.to_s
|
||||
end
|
||||
self.remote_addr_str = sprintf("%s:%s",self.remote_addr, port)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The local address of the connection
|
||||
#
|
||||
attr_accessor :local_addr
|
||||
#
|
||||
# The remote address (peer) of the connection
|
||||
#
|
||||
attr_accessor :remote_addr
|
||||
#
|
||||
# The local port of the connection.
|
||||
#
|
||||
attr_accessor :local_port
|
||||
#
|
||||
# The remote port of the connection.
|
||||
#
|
||||
attr_accessor :remote_port
|
||||
#
|
||||
# The protocol type (tcp/tcp6/udp/udp6)
|
||||
#
|
||||
attr_accessor :protocol
|
||||
#
|
||||
# The state of the connection (close, listening, syn_sent...)
|
||||
#
|
||||
attr_accessor :state
|
||||
#
|
||||
# The uid of the user who started the process to which the connection belongs to
|
||||
#
|
||||
attr_accessor :uid
|
||||
#
|
||||
# The socket inode
|
||||
#
|
||||
attr_accessor :inode
|
||||
#
|
||||
# The name of the process to which the connection belongs to
|
||||
#
|
||||
attr_accessor :pid_name
|
||||
#
|
||||
# The local address of the connection plus the port
|
||||
#
|
||||
attr_accessor :local_addr_str
|
||||
#
|
||||
# The remote address (peer) of the connection plus the port or *
|
||||
#
|
||||
attr_accessor :remote_addr_str
|
||||
end
|
||||
|
||||
end; end; end; end; end; end
|
|
@ -53,6 +53,7 @@ TLV_TYPE_NETMASK = TLV_META_TYPE_RAW | 1421
|
|||
TLV_TYPE_GATEWAY = TLV_META_TYPE_RAW | 1422
|
||||
TLV_TYPE_NETWORK_ROUTE = TLV_META_TYPE_GROUP | 1423
|
||||
TLV_TYPE_IP_PREFIX = TLV_META_TYPE_UINT | 1424
|
||||
TLV_TYPE_ARP_ENTRY = TLV_META_TYPE_GROUP | 1425
|
||||
|
||||
TLV_TYPE_IP = TLV_META_TYPE_RAW | 1430
|
||||
TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431
|
||||
|
@ -71,6 +72,9 @@ TLV_TYPE_PEER_PORT = TLV_META_TYPE_UINT | 1501
|
|||
TLV_TYPE_LOCAL_HOST = TLV_META_TYPE_STRING | 1502
|
||||
TLV_TYPE_LOCAL_PORT = TLV_META_TYPE_UINT | 1503
|
||||
TLV_TYPE_CONNECT_RETRIES = TLV_META_TYPE_UINT | 1504
|
||||
TLV_TYPE_NETSTAT_ENTRY = TLV_META_TYPE_GROUP | 1505
|
||||
TLV_TYPE_PEER_HOST_RAW = TLV_META_TYPE_RAW | 1506
|
||||
TLV_TYPE_LOCAL_HOST_RAW = TLV_META_TYPE_RAW | 1507
|
||||
|
||||
TLV_TYPE_SHUTDOWN_HOW = TLV_META_TYPE_UINT | 1530
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
"ifconfig" => "Display interfaces",
|
||||
"route" => "View and modify the routing table",
|
||||
"portfwd" => "Forward a local port to a remote service",
|
||||
"arp" => "Display the host ARP cache",
|
||||
"netstat" => "Display the network connections",
|
||||
}
|
||||
reqs = {
|
||||
"ipconfig" => [ "stdapi_net_config_get_interfaces" ],
|
||||
|
@ -74,6 +76,8 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
# Only creates tcp channels, which is something whose availability
|
||||
# we can't check directly at the moment.
|
||||
"portfwd" => [ ],
|
||||
"arp" => [ "stdapi_net_config_get_arp_table" ],
|
||||
"netstat" => [ "stdapi_net_config_get_netstat" ],
|
||||
}
|
||||
|
||||
all.delete_if do |cmd, desc|
|
||||
|
@ -96,6 +100,63 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
def name
|
||||
"Stdapi: Networking"
|
||||
end
|
||||
#
|
||||
# Displays network connections of the remote machine.
|
||||
#
|
||||
def cmd_netstat(*args)
|
||||
connection_table = client.net.config.netstat
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Connection list",
|
||||
'Indent' => 4,
|
||||
'Columns' =>
|
||||
[
|
||||
"Proto",
|
||||
"Local address",
|
||||
"Remote address",
|
||||
"State",
|
||||
"User",
|
||||
"Inode",
|
||||
"PID/Program name"
|
||||
])
|
||||
|
||||
connection_table.each { |connection|
|
||||
tbl << [ connection.protocol, connection.local_addr_str, connection.remote_addr_str,
|
||||
connection.state, connection.uid, connection.inode, connection.pid_name]
|
||||
}
|
||||
|
||||
if tbl.rows.length > 0
|
||||
print("\n" + tbl.to_s + "\n")
|
||||
else
|
||||
print_line("Connection list is empty.")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Displays ARP cache of the remote machine.
|
||||
#
|
||||
def cmd_arp(*args)
|
||||
arp_table = client.net.config.arp_table
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => "ARP cache",
|
||||
'Indent' => 4,
|
||||
'Columns' =>
|
||||
[
|
||||
"IP address",
|
||||
"MAC address",
|
||||
"Interface"
|
||||
])
|
||||
|
||||
arp_table.each { |arp|
|
||||
tbl << [ arp.ip_addr, arp.mac_addr, arp.interface ]
|
||||
}
|
||||
|
||||
if tbl.rows.length > 0
|
||||
print("\n" + tbl.to_s + "\n")
|
||||
else
|
||||
print_line("ARP cache is empty.")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Displays interfaces on the remote machine.
|
||||
|
|
Loading…
Reference in New Issue