Contents

Netstat Post Module for Meterpreter

Contents

Submitted it to MSF via pull request here: https://github.com/rapid7/metasploit-framework/pull/538

Added to trunk: https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/tcpnetstat.rb

I promised this one a while ago, sorry for the delay. This only does TCP, it’d be trivial to do UDP as well but never really found anything interesting and actively going on on the UDP side. It’s real simple, first we’ve gotta add the GetTcpTable function to railgun:

1
2
3
4
5
session.railgun.add_function('iphlpapi', 'GetTcpTable', 'DWORD', [
	['PBLOB', 'pTcpTable', 'out'],
	['PDWORD', 'pdwSize', 'inout'],
	['BOOL', 'bOrder', 'in']
])

Then gauge the size of the table:

1
2
getsize = session.railgun.iphlpapi.GetTcpTable(4,4,true)
buffersize = getsize['pdwSize']

Run the call again with the correct buffer size:

1
tcptable = session.railgun.iphlpapi.GetTcpTable(buffersize,buffersize,true)

Then it’s all just parsing the result. Also pretty straight forward. First we get the number of entries which is held in the first 4 bytes, then just parse the MIB_TCPTABLE one MIB_TCPROW at a time (translating the state to something readable):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def parse_tcptable(buffer)
	entries = buffer[0,4].unpack("V*")[0]
	print_status("Total TCP Entries: #{entries}")
	rtable = Rex::Ui::Text::Table.new(
		'Header' => 'Routing Table',
		'Indent' => 2,
		'Columns' => ['STATE', 'LHOST', 'LPORT', 'RHOST', 'RPORT']
	)
	offset = 4
	(1..entries).each do
		x = {}
		x[:state] = case buffer[(offset + 0), 4].unpack("V*")[0]
		when 1
			'CLOSED'
		when 2
			'LISTEN'
		when 3
			'SYN_SENT'
		when 4
			'SYN_RCVD'
		when 5
			'ESTABLISHED'
		when 6
			'FIN_WAIT1'
		when 7
			'FIN_WAIT2'
		when 8
			'CLOSE_WAIT'
		when 9
			'CLOSING'
		when 10
			'LAST_ACK'
		when 11
			'TIME_WAIT'
		when 12
			'DELETE_TCB'
		else
			'UNDEFINED'
		end
		
		x[:lhost] = Rex::Socket.addr_itoa(buffer[(offset + 4), 4].unpack("N")[0])
		x[:lport] = buffer[(offset + 8), 4].unpack("n")[0]
		x[:rhost] = Rex::Socket.addr_itoa(buffer[(offset + 12), 4].unpack("N")[0])
		if x[:state] == "LISTEN"
			x[:rport] = "_"
		else
			x[:rport] = buffer[(offset + 16), 4].unpack("n")[0]
		end

		offset = offset + 20
		rtable << [x[:state], x[:lhost], x[:lport], x[:rhost], x[:rport]]
	end

	print_status(rtable.to_s)
end