Knock Knock Knocking ...

Running a honeypot, it is good to see it gets attacked and does something, but more important than attacks you see, are attacks you do not see. You can miss attacks for many reasons, the most common:

  1. the attack is does not complete due to software bugs or incomplete emulation
  2. the software does not detect the attack
  3. you don't expect an attack on a given port and therefore do not provide a service

1) bugs & incomplete emulation

Nepenthes is a good example for incomplete emulation, it does not provide the required parts of the protocol, so Conficker scans fail on a Nepenthes honeypot.
Of course Conficker wants to exploit the honeypot, but it fails.
Dionaea currently fails for some very special attacks(?) on the smb services too, attackers call DCE-RPCs dionaea does not provide, so these attacks fail.

attacks dcerpc_uuid service_name op dcerpc_op vuln
9777 12345778-1234- abcd-ef00- 0123456789ac samr 62 Connect4
7852 3919286a-b10c- 11d0-9ba8- 00c04fd92ef5 DSSETUP 9 DsRolerUpgradeDownlevelServer MS04-11
955 000001a0-0000- 0000-c000- 000000000046 ISystemActivator 4 RemoteCreateInstance MS04-12
808 367abb81-9844- 35f1-ad32- 98f038001003 SVCCTL 27 SvcOpenSCManagerA
502 4d9f4ab8-7d1c- 11cf-861e- 0020af6e7c57 DCOM 0 RemoteActivation MS03-26
205 4b324fc8-1670- 01d3-1278- 5a47bf6ee188 SRVSVC 31 NetPathCanonicalize MS08-67
62 8d9f4e40-a03d- 11ce-8f69- 08003e30051b PNP 54 PNP_QueryResConfList MS05-39
47 12345778-1234- abcd-ef00- 0123456789ac samr 64 Connect5
2 000001a0-0000- 0000-c000- 000000000046 ISystemActivator 0 QueryInterfaceIRemoteSCMActivator

The services addressed: samr Connect4 and Connect5 and SVCCTL OpenSCManagerA. I think the attacker wants to create setup a session to upload a file, and schedule a task to execute his new file.
So, it is not an exploit with shellcode and stuff, it uses a real feature of the Windows Operating System, where you can upload a file and execute it on the remotehost afterwards.
I already had a look, and it is awful to emulate this, but as it is a real challenge and makes a majority of the attacks, I'm looking forward to do it someday …

2) the software does not detect the attack

Attacker sends his payload, if we can't detect it, we can't act upon it.
Pattern based shellcode detection is likely to fail, if you don't provide a matching pattern, you fail. Using libemu improves this detection rate, but dionaea revealed some (already fixed) libemu bugs too.

3) no service listening

Even worse, if we do not provide service on the port which gets attacked, as we won't see *anything* in the logfiles, not even an incoming connection.
Tillmann's honeytrap deals with such situation by opening the port on demand, and proxying the attackers traffic to a system which is likely to have the attacked vulnerability - the attacking host himself.
This so called mirror mode in honeytrap does a good job as it works for every service, and besides all automated attacks, it is real fun to see human attackers exploiting their own host.
But, it is at least a little unethical, and technically I would not want to deploy this technology in my own network, slightly to aggressive.

For today, I decided to stick with dealing with attacks on port we do not serve. Technology used is rather easy:

tcpdump -i "tcp[tcpflags] & tcp-rst != 0 and tcp[4:4] = 0  and ( src host ismyself )"

will provide all rejected connections, identified by the tcp-rst flag and the sequence number of 0. Honeytrap uses the same, as does Nepenthes in module-honeytrap (yep, I copied the idea already before).

So we just setup an pcap device, set the bpf filter to look for tcp-rst packets with sequence number 0 originating from ourselves, and log each incoming rejected connection. This way we see attackers knocking on closed ports.

It works!

I added the required to code to log rejected connections to the logsql database, here is an example query:

SELECT 
	COUNT(local_port),
	local_port
FROM 
	connections 
WHERE 
	connection_type = 'reject' 
GROUP BY 
	local_port 
HAVING 
	COUNT(local_port) > 8 
ORDER BY
	COUNT(local_port)
	DESC;
count(local_port) local_port
411 139
183 8080
145 22
80 1433
63 2967
28 5900
12 3128
11 64436
9 1080

Too easy!

Actually, there is a small problem … which is unlikely to affect your dionaea deployment, but may affect other deployments.

Some hints for the curious

  • interesting vars
    • 0x800 matches for IPv4 (from ethernet header)
    • 0x806 matches for ARP (from ethernet header)
    • 0x8035 matches for RARP (from ethernet header)
    • 0x86dd matches for IPv6 (from ethernet header)

libpcap IPv6 fails

The problem is libpcap/bpf shortcoming when dealing with IPv6:

sudo tcpdump -i any -dtxv "tcp[tcpflags] & tcp-rst != 0 and ( src host 127.0.0.1 )"
(000) ldh      [14]
(001) jeq      #0x800           jt 2	jf 12
(002) ldb      [25]
(003) jeq      #0x6             jt 4	jf 12
(004) ldh      [22]
(005) jset     #0x1fff          jt 12	jf 6
(006) ldxb     4*([16]&0xf)
(007) ldb      [x + 29]
(008) jset     #0x4             jt 9	jf 12
(009) ld       [28]
(010) jeq      #0x7f000001      jt 11	jf 12
(011) ret      #96
(012) ret      #0

“tcp[tcpflags] & tcp-rst != 0 and ( src host 127.0.0.1 )”

This is a human readable version of the filter, matching packets sent from 127.0.0.1 with tcp-rst set and sequence number 0.
As I have a slightly different understanding from human readable, I hacked some python script to parse the bpf filter and create a graph using graphviz's dot.

"tcp[tcpflags] & tcp-rst != 0 and ( src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)" graph

No, lets include an IPv6 host in the filter, it is the same:

sudo tcpdump -i any -dtxv "tcp[tcpflags] & tcp-rst != 0 and ( src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)"
(000) ldh      [14]
(001) jeq      #0x800           jt 2	jf 12
(002) ldb      [25]
(003) jeq      #0x6             jt 4	jf 12
(004) ldh      [22]
(005) jset     #0x1fff          jt 12	jf 6
(006) ldxb     4*([16]&0xf)
(007) ldb      [x + 29]
(008) jset     #0x4             jt 9	jf 12
(009) ld       [28]
(010) jeq      #0x7f000001      jt 11	jf 12
(011) ret      #96
(012) ret      #0

“tcp[tcpflags] & tcp-rst != 0 and ( src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)”

Obviously we are missing the IPv6 host match in the pattern.

But it works when matching only hosts:

sudo tcpdump -i any -dtxv "src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
(000) ldh      [14]
(001) jeq      #0x800           jt 2	jf 4
(002) ld       [28]
(003) jeq      #0x7f000001      jt 17	jf 18
(004) jeq      #0x806           jt 6	jf 5
(005) jeq      #0x8035          jt 6	jf 8
(006) ld       [30]
(007) jeq      #0x7f000001      jt 17	jf 18
(008) jeq      #0x86dd          jt 9	jf 18
(009) ld       [24]
(010) jeq      #0x2001ffff      jt 11	jf 18
(011) ld       [28]
(012) jeq      #0xffffffff      jt 13	jf 18
(013) ld       [32]
(014) jeq      #0xffffffff      jt 15	jf 18
(015) ld       [36]
(016) jeq      #0xffffffff      jt 17	jf 18
(017) ret      #96
(018) ret      #0

“src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff”

Visualization:
"src host 127.0.0.1 or src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff" graph

Matching for tcp-rst for a single IPv6 host only gives

sudo tcpdump -i any -dtxv "tcp[tcpflags] & tcp-rst != 0 and ( src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)"
tcpdump: expression rejects all packets

“tcp[tcpflags] & tcp-rst != 0 and ( src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)”

Turning of optimization provides more information whats going wrong:

sudo tcpdump -i any -Odtxv "tcp[tcpflags] & tcp-rst != 0 and ( src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)"
(000) ldh      [14]
(001) jeq      #0x800           jt 2	jf 43
(002) ldh      [14]
(003) jeq      #0x86dd          jt 4	jf 6 
(004) ldb      [22]
(005) jeq      #0x6             jt 10	jf 6
(006) ldh      [14]
(007) jeq      #0x800           jt 8	jf 43
(008) ldb      [25]
(009) jeq      #0x6             jt 10	jf 43
(010) ldh      [22]
(011) jset     #0x1fff          jt 43	jf 12
(012) ld       #0xd
(013) st       M[0]
(014) ldxb     4*([16]&0xf)
(015) ld       M[0]
(016) add      x
(017) tax      
(018) ldb      [x + 16]
(019) st       M[1]
(020) ld       #0x4
(021) st       M[2]
(022) ldx      M[2]
(023) ld       M[1]
(024) and      x
(025) st       M[2]
(026) ld       #0x0
(027) st       M[3]
(028) ldx      M[3]
(029) ld       M[2]
(030) sub      x
(031) jeq      #0x0             jt 43	jf 32
(032) ldh      [14]
(033) jeq      #0x86dd          jt 34	jf 43
(034) ld       [24]
(035) jeq      #0x2001ffff      jt 36	jf 43
(036) ld       [28]
(037) jeq      #0xffffffff      jt 38	jf 43
(038) ld       [32]
(039) jeq      #0xffffffff      jt 40	jf 43
(040) ld       [36]
(041) jeq      #0xffffffff      jt 42	jf 43
(042) ret      #96
(043) ret      #0

“tcp[tcpflags] & tcp-rst != 0 and ( src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)”

Visualization:
 "tcp[tcpflags] & tcp-rst != 0 and ( src host 2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff)" graph

The problem is the generated instructions are bad, the packet is expected to be of type IPv4 and IPv6, the bpf optimizer detects this unsatisfiable condition and optimizes the filter to be 'negative for any input'.

consequences

You can't match IPv6 traffic by host including a tcp filter, the generated code path is unsatisfiable and gets optimized away. Therefore you can't see IPv6 knocks to closed ports in dionaea.

old news

This is not news, it is default behavior since 2000.

BUGS
  Arithmetic expression against transport layer headers, like tcp[0], does not work against IPv6 packets.  
  It only looks at IPv4 packets.

man tcpdump

But as I missed it and did not expect it to work that way, I decided to make new news of it.

Comments



2009/11/17/knock_knock_knocking.txt · Last modified: 2010/06/15 11:54 by common
chimeric.de = chi`s home Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0