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:
the attack is does not complete due to software bugs or incomplete emulation
the software does not detect the attack
you don't expect an attack on a given port and therefore do not provide a service
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 …
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.
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.
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 |
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)
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.
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:
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:
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'.
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.
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.