
When a hacker tries to reach you from a distance and attacks your services on the outer perimeter, you and that person are separated by dozens of hops, Tor, Proxy, VPN, etc., which makes the attacker absolutely elusive. The hacker can easily change the IP address, jump to any continent (or, quite the opposite, select an exit point close to the target). And you have no choice but to endure such attacks again and again. However, if everything is OK on your perimeter, then you have nothing to be worried about.
But what if the hacker has already got close to you and somehow managed to penetrate into your internal network? Is it possible to detect the attacker at this point? After all, in such a situation, the intruder poses a real threat to your infrastructure.
This is where the SOC (also known as Blue Team) comes into play. But not every company has its own ‘cyberpatrol’. In many organizations, security measures are slowed down by the wheels of bureaucracy or interfere with the business process: after all, security often contradicts convenience and comfort. Therefore, it might be difficult to implement sophisticated and expensive security tools. If your company doesn’t have its own ‘cyberpolice’, it’s critical to know simple cyber self-defense techniques.
My experience shows that many IT security specialists aren’t aware of relatively simple techniques making it possible to track down intruders during an attack. Being a seasoned hacker penetration tester, I can clearly see multiple places where attackers can be caught – provided that you know what to check.
This series of publications discusses simple but effective computer self-defense techniques that will help you to detect hackers who have already penetrated into your local network (or are preparing to do this while hanging around your perimeter and examining your Wi-Fi networks).
You will learn to pay attention not only to ‘noisy’ locations, but also to events believed to be quiet enough by most hackers – but still having distinctive features. You will catch hackers in a hacker way: by running special scripts. Your self-defense kung-fu will be aimed at most common (and, therefore, most likely) attacks.
And since this is self-defense, any user can master it: all protection techniques described below don’t require admin rights. They can be implemented from any workstation, without extended access to server logs or network equipment – nothing unavailable to an ordinary user. This means that any employee will be able to detect an intruder and everyone can protect the entire company!
Your main goal is to see the invisible. The network level is the initial stage of hacker’s advancement through the internal infrastructure. At this stage, the intruder neither has an account in Active Directory nor knows anything about your network yet. Therefore, hacker’s actions can be quite spontaneous and noisy.
This is the first round in your confrontation with the hacker. It’s highly desirable to detect the intruder at this stage and as early as possible, while attacker’s capabilities are limited and actions leave traces. Remember: the further a hacker advances, the more elusive they become; when the attacker finds the first domain account, this round will end. Accordingly, this article presents defense techniques in the order of increasing hacker capabilities (as the attacker advances through the infrastructure).
Network sniffer
The presence of a sniffer on the network isn’t considered a network attack per se, but it’s a good reason to search for intruders. A bona fide user won’t start a sniffer unless this is an admin… or a hacker.
At early stages of any attack, the hacker who has just gained access to the network often starts a sniffer to collect at least some information about your network. By default, some sniffers try to display the host name instead of its IP address. This means that they resolve each new IP address of the intercepted packet. For instance, the popular tcpdump sniffer behaves this way if started without due precautions.

This can help to detect an inquisitive hacker because the attacker’s computer starts sending predictable DNS requests. But how do you know that a DNS request was sent? After all, not every user can read DNS server logs. The answer is simple: you just use a nonrecursive DNS request or a request to DNS server’s cache.
Corporate networks usually have their own DNS servers, and these servers are common to all hosts. If you request a name from the DNS server and set the norecurse
flag, the DNS server will provide a name to you based on its cache. If no one except you had resolved this IP address, then you’ll get an ’empty’ response.

But if this address was recently resolved by someone on the network, you’ll see the following picture.

A repeated DNS request to the cache makes this clear, and you see a different picture.

A similar operation can be performed to resolve an IP address into a DNS name. If you broadcast a packet or send a targeted query to other subnets between DNS requests sent to the entire subnet on behalf of some unpopular IP address that has a DNS name, then the sniffer started by an intruder will betray itself by sending a DNS request whose result will be subsequently saved in the cache of the corporate DNS server.

In the above example, immediately after receiving a packet with the address 176.
(any external IP with an existing DNS name), node 10.
(hacker) resolves its IP into a DNS name. And this operation is performed upon receiving a single network packet. Importantly, this ICMP packet isn’t intended for any application: it’s processed at the OS level, and, under normal circumstances, no one would respond to such a packet with a DNS request. Therefore, with a high degree of probability, you can conclude that a network sniffer is running on this node.
To automate the above-described check, the following script can be used:
defence/sniffer.py#!/usr/bin/python3from scapy.all import *from netaddr import IPNetworkfrom time import sleepfrom sys import argvfrom os import systemIPS_WITH_PTR = IPNetwork("176.34.0.0/24")targets = []dns_servers = []conf.verb = 0alerts = []def alert(ip): if ip in alerts: return print("[!] sniffer detected %s" % ip) system("zenity --warning --title='sniffer detected' --text='sniffer detected: %s' &" % ip) #system("echo 'sniffer detected' | festival --tts --language english") alerts.append(ip)n = 1def get_source(): global n while True: ip = str(IPS_WITH_PTR[n]) if not dns_no_recurse(ip): return ip n += 1def dns_no_recurse(ip): def rev(ip): ip = ip.split(".") ip.reverse() return ".".join(ip) for dns_server in dns_servers: try: answer = sr1(IP(dst=dns_server)/UDP(dport=53)/DNS(rd=0, qd=DNSQR(qname=rev(ip)+".in-addr.arpa", qtype='PTR'))) if answer[DNS].ancount > 0: return True except: print(f"[-] {dns_server} has no answer")def probe(src, dst): send(IP(src=src, dst=dst)/ICMP())with open(argv[1]) as f: for line in f: targets.append( line.split("\n")[0] )with open(argv[2]) as f: for line in f: dns_servers.append( line.split("\n")[0] )src = get_source()while True: for dst in targets: probe(src, dst) sleep(1) if dns_no_recurse(src): alert(dst) src = get_source() sleep(60)
Using this script, you can check any IP address for the presence of a sniffer – even those from other subnets: you just methodically send packets to them and check if some host has resolved this address.

Someone else (not you!) had requested this name, and only a sniffer could find it out.
Port scanning
After penetrating the network perimeter, the hacker starts looking around by scanning network ports to find out whether any hosts are located nearby. After discovering such hosts, the intruder can attack them, advance further, and gain a stronger foothold on the network.
Scanning network ports is the first and, in most cases, mandatory element of any network attack. Therefore, it would be great to detect a hacker at this early stage.
Most people scan ports with Nmap
, and very few of them adjust the performance of this tool (especially downwards). By default, Nmap
is quite noisy: it sends exactly 100 TCP SYN packets per second to a target and checks some 1000 network ports. Under normal conditions, not a single legitimate program generates such network activity. In addition, Nmap
has a distinctive feature: it knocks on each port exactly twice. This is its default behavior.
In some situations, Nmap
is used to scan a small number of ports on a wide range of hosts. Such scans maker it possible to identify ‘live’ hosts on a network or find so-called ‘low-hanging fruits’ (easy targets).
It doesn’t really matter what program is used to scan your resources: Nmap
, Masscan
, or something else. Even more specialized tools (e.g. NBTscan
, CrackMapExec
, and BloodHound
) create outgoing connections that can be detected.
If the hacker performs a scan, then, most likely, your computer would be scanned, too. Accordingly, all you need to do is monitor incoming connections:
defence/tcp.py#!/usr/bin/python3import logginglogging.getLogger("scapy.runtime").setLevel(logging.ERROR)from scapy.all import *from os import systemfrom sys import argvMAX_PORTS_ALLOWED = 2clients = {}alerts = []def alert(src_ip): if src_ip in alerts: return print("[!] port scanning %s" % src_ip) system("zenity --warning --title='port scanning detected' --text='port scanning detected' &") #system("echo 'port scanning detected' | festival --tts --language english") alerts.append(src_ip)def parse(p): if IP in p and TCP in p: src_ip = p[IP].src src_port = p[TCP].sport dst_port = p[TCP].dport print("[+] %s:%d -> %s:%d" % (src_ip, src_port, ip, dst_port)) if not src_ip in clients: clients[src_ip] = set() clients[src_ip].add(dst_port) if len(clients[src_ip]) > MAX_PORTS_ALLOWED: alert(src_ip)conf.iface = argv[1]ip = conf.iface.ipsniff(iface=conf.iface, prn=parse, filter='tcp[tcpflags] == tcp-syn and dst host %s'%ip)
Even if the hacker is quieter than MAX_PORTS_ALLOWED
, you will still see an incoming connection attempt in the script log.

In the screenshot below, the hacker exceeded MAX_PORTS_ALLOWED
and was caught after scanning just three ports.

Under normal circumstances, client operating systems won’t connect to each other (at least, through no more than one or two ports). So, if you run this script on an ordinary workstation, it will detect the attacker with a high degree of probability.
The above-described check is probably the most effective one.
Detecting traffic interception
Traffic interception attacks can be detected in two ways:
- by detecting previous attacks on respective protocols (ARP, DHCP, CDP, HSRP, etc.); or
- by detecting the very fact of routing changes.
Attacks on the same ARP can be detected in different ways, and the attacker can always find a way to evade a specific check. Therefore, the second method is more reliable, because every intervention ultimately results in routing changes, one way or another.
There is one simple but reliable technique making it possible to understand that your traffic is being intercepted. As you know, every time your traffic passes a node, its IP.
value decreases by one. However, initial IP.
values are standard: 255,
. This allows you to see the length of a network route leading to a certain node.
Traffic interception attacks are often implemented within a network segment, and the attacker stands between you and the gateway. For you, the gateway is the closest network device that forwards your traffic further. Therefore, you can check whether your traffic is intercepted by pinging the gateway.

In Cisco network devices, the initial IP.
often equals 255
, and you can see that it doesn’t change, which means that no one stands between you and the gateway. But if a hacker hiding nearby starts misbehaving, the picture would change.

You can immediately see this because IP.
decreases.

The traceroute
command makes it possible to identify the location of the intruder who stands between you and the gateway.

As you remember, in Windows, ttl = 128; while in Linux, ttl = 64. The ping
output indicates that someone using Linux (maybe even Kali) appeared among office computers running Windows.

Importantly, this entire investigation was performed using only the trivial ping
command.
In a similar way, you can detect traffic interception attacks in other subnets. After all, you can ping
any node and monitor how its IP.
changes.

In addition, you can determine the trace route.

This way, you can easily monitor the entire network (as far as your packets reach). To detect MiTM attacks (including those delivered in other network segments), all you have to do is ping
important IPs in each subnet on a regular basis, create an IP.ttl database, and analyze changes in TTL. The script below automates this process:
defence/mitm.py#!/usr/bin/python3from scapy.all import *from time import sleepfrom sys import argvfrom os import systemtargets = []conf.verb = 0TIMEOUT = 1alerts = []def alert(ip, distance_old, distance_new): if ip in alerts: return traceroute = probe_traceroute(ip) print("[!] MiTM detected %s: change distance: %s -> %s (%s)" % (ip, str(distance_old), str(distance_new), traceroute)) system("zenity --warning --title='MiTM detected' --text='MiTM detected: victim %s' &" % ip) #system("echo 'MiTM detected' | festival --tts --language english") alerts.append(ip)def probe_ttl(ip): answer = sr1(IP(dst=ip)/ICMP(), timeout=TIMEOUT) if answer: return answer[IP].ttldef probe_traceroute(ip): trace = [] for hop in traceroute(ip, l4=ICMP(), timeout=TIMEOUT)[0]: req,res = hop trace.append(res[IP].src) return "->".join(trace)with open(argv[1]) as f: for line in f: targets.append( line.split("\n")[0] )distances = {}while True: for target in targets: distance = probe_ttl(target) #distance = probe_traceroute(target) if distance: if not distances.get(target): distances[target] = distance if distances[target] != distance: alert(target, distances[target], distance) sleep(1) sleep(30)

Under certain circumstances, instead of standing in the middle (i.e. in addition to the existing nodes), the attacker can substitute some network device (i.e. stand instead of it). Therefore, it’s more efficient to check for traffic interception based not on the route length, but on the route itself (i.e. use tracing). This technique makes it possible to detect even the most cunning attackers who have fixated their TTL prior to traffic interception.
However, tracing is a lengthy procedure; therefore, this detection method is commented out in the script.
Detecting malicious DHCP/DHCPv6/SLAAC servers
In addition to MiTM, other attacks involving partial traffic interception can be delivered in local networks. DHCP, DHCPv6, and SLAAC protocols automatically issue IPv4 or IPv6 addresses to newly-connected clients, clients whose address leases have expired, or unconfigured clients.
If ARP spoofing fails, hackers can try to intercept traffic using DHCP. In addition, they can use DHCPv6/SLAAC if your network doesn’t have a developed IPv6 infrastructure, but this protocol is active on workstations: this way, attackers can partially intercept traffic (e.g. DNS traffic).
Such attack can be easily detected since the DHCP and DHCPv6 protocols involve a request that forces servers to respond:
defence/dhcp.py#!/usr/bin/python3from scapy.all import *from threading import Threadfrom time import sleepfrom sys import argvfrom os import systemconf.iface = argv[1]conf.verb = 0def parse(p): global dhcp_servers if DHCP in p: for option in p[DHCP].options: if 'message-type' in option and 2 in option: dhcp_servers.add(p[IP].src) elif DHCP6_Advertise in p: dhcp_servers.add(p[IPv6].src) try: domains = ','.join(p[DHCP6OptDNSDomains].dnsdomains) print(domains) except: passalerts = []def alert(new_dhcp_servers): if not new_dhcp_servers - set(alerts): return dhcp_servers = ", ".join(map(str, new_dhcp_servers)) print("[!] DHCP roque: " + dhcp_servers) system("zenity --warning --title='DHCP roque server' --text='DHCP roque: %s' &" % dhcp_servers) #system("echo 'DHCP roque server detected' | festival --tts --language english &") alerts.extend(new_dhcp_servers)def dhcp_discover(): dhcp_discover = Ether(dst='ff:ff:ff:ff:ff:ff', src=Ether().src, type=0x0800) / IP(src='0.0.0.0', dst='255.255.255.255')/UDP(dport=67,sport=68)/BOOTP(op=1, chaddr=Ether().src, xid=RandInt())/DHCP(options=[('message-type','discover'), ('hostname','localhost'), ('param_req_list',[1,3,6]), ('end')]) sendp(dhcp_discover) dhcp_discover6 = Ether(dst="33:33:00:01:00:02", src=Ether().src)/IPv6(dst="ff02::1:2")/UDP(sport=546, dport=547)/DHCP6_Solicit(trid=RandInt())/DHCP6OptClientId(duid=DUID_LLT(lladdr=Ether().src,timeval=int(time.time())))/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptRapidCommit()/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=[23,24]) sendp(dhcp_discover6)dhcp_servers_legal = set()while True: dhcp_servers = set() thr = Thread(target=lambda:sniff(timeout=5, prn=parse)) thr.start() dhcp_discover() thr.join() if not dhcp_servers_legal: dhcp_servers_legal = dhcp_servers.copy() or set([""]) print("[*] DHCP legal: " + ", ".join(map(str,dhcp_servers_legal))) if dhcp_servers - dhcp_servers_legal: alert(dhcp_servers - dhcp_servers_legal) sleep(10)
Let’s say the hacker tries to deliver a DHCP traffic interception attack.

Hacker’s software starts responding to your discover requests; while you, in turn, to attacker’s offer packets.

Voila!. The hacker has been identified! In a similar way, you can identify any unauthorized router connected to the network.
Let’s say the hacker is going to attack you over DHCPv6 as shown below.

Now the attacker responds to DHCPv6 discovery requests with advertise messages, which can also be checked.

The hacker has been caught again. Importantly, these techniques are applicable only within the broadcast segment.
NetBIOS Spoofing
Hackers who have penetrated into a local network containing multiple Windows nodes can employ a fairly simple but effective technique: start responding to all broadcast NetBIOS requests with attacker’s IP address. As a results, users mistakenly connect to the attacker, unknowingly disclose their credentials in the course of pass-through authentication, and become victims of NTLM Relay attacks followed by sophisticated multistage attacks.
NetBIOS is similar to DNS; the only difference is that in a broadcast network segment, anyone can be a client and a server simultaneously. In other words, anyone can request both hostname to IP mapping or IP to hostname mapping and respond to such queries. Under normal circumstances, a Windows system responds with its IP address only if its network name was specified in the NetBIOS query. Therefore, if you broadcast NetBIOS queries with a random name from your host on a regular basis, and someone responds to your query, this clearly indicates an NetBIOS spoofing attempt, and you can identify the node delivering such an attack:
defence/netbios.py#!/usr/bin/python3import logginglogging.getLogger("scapy.runtime").setLevel(logging.ERROR)from scapy.all import * # scapy==2.4.5from threading import Threadfrom random import randomfrom string import ascii_uppercasefrom time import sleepfrom sys import argvfrom os import systemconf.iface = argv[1]broadcast = conf.route.get_if_bcast(conf.iface)conf.verb = 0def nbns_responses(p): global name, ip if NBNSQueryResponse in p: if bytes(p[NBNSQueryResponse][0].RR_NAME).decode() == name: ip = str(p[NBNSQueryResponse][0].NB_ADDRESS)alerts = []def alert(ip): if ip in alerts: return print("[!] NetBIOS spoofing detected %s" % ip) system("zenity --warning --title='NetBIOS spoofing detected' --text='NetBIOS spoofing: %s' &" % ip) #system("echo 'NetBIOS spoofing detected' | festival --tts --language english") alerts.append(ip)def rand(length): return "WIN-L" + "".join(map(lambda x:ascii_uppercase[ int(random()*len(ascii_uppercase)) ], range(length)))def nbns_query(name): send(IP(dst=broadcast)/UDP(sport=RandShort())/NBNSQueryRequest(NAME_TRN_ID=RandShort(), FLAGS=0x0110, QUESTION_NAME=name, QUESTION_TYPE='NB'))names = {}while True: thr = Thread(target=lambda:sniff(timeout=5, prn=nbns_responses)) thr.start() ip = '' name = rand(10) nbns_query(name) thr.join() if ip: if not names.get(ip): print("[*] {name} = {ip}".format(name=name, ip=ip)) names[ip] = name elif names[ip] != name: print("[!] {name} = {ip}".format(name=name, ip=ip)) alert(ip) sleep(3)
You can see how Responder started by the hacker responds to your decoy requests.

And you quickly detect the attacker.

Sure as hell: two random NetBIOS queries and two identical responses to them indicate the presence of a hacker with Responder.
This check is so simple that it can be performed using improvised Windows tools. All you have to do is try to resolve a random short name. When short names are resolved, the request first goes via NetBIOS and then via DNS.

The first NetBIOS request was sent before the start of Responder; while the second request was poisoned by the hacker tool, and the IP address shown in the screenshot is most likely the attacker’s address.
Honeypot
Sooner or later, the attacker will advance from the network level to the application level. Let’s switch to this level, too.
Network port scanning is just reconnaissance: the attacker is interested in computers that can be hacked (and hacked quite easily). Security holes making a host vulnerable to hacking include software bugs, OS bugs, and configuration flaws (misconfigs). The latter ones are most dangerous since they are exploited in a 100% legitimate way, and their detection is more difficult (antiviruses are useless). In addition, such vulnerabilities can exist even on recently updated systems: errare humanum est.
SSH
Being one of the most common services on Linux computers, the Secure Shell (SSH) protocol running on the standard TCP port 22 will inevitably attract hacker’s attention. A weak root password is a brilliant example of a critical misconfig and one of the popular ‘low-hanging fruits’. After all, a compromised Linux system provides the attacker with an excellent foothold: no antiviruses, no annoying users, and, importantly, such computers aren’t turned off at the end of the business day.
To detect an SSH password brute-forcing attack, all you have to do is stand in the attacker’s way (i.e. listen TCP port 22). At the port scanning stage, this will inevitably make you one of the potential targets for such attacks. Using SSH Honeypot, you will be able to see incoming authentication attempts, including even passwords.

A bona fide user won’t connect via SSH; while the IT personnel won’t use standard passwords from a wordlist (like in the above screenshot).
Therefore, it’s a hacker trying to test SSH for weak passwords.

Of course, a real attacker would deliver this attack against a wide range of targets, including your honeypot.
SMB MS17-010
Another good bait for an attacker is a simulated vulnerability. MS17-010 (a.k.a. WannaCry) is a brilliant example of a popular vulnerability, and hackers always search for it on Windows nodes in local networks. This is the juiciest ‘low-hanging fruit’: the vulnerability immediately grants the attacker full access to the system, and it can be present on both old (Windows 2000) and relatively new (Windows 10/2016) systems.
The vulnerability lies in the SMB service that is present by default on every Windows computer on TCP port 445 (responsible inter alia for network drives).
To simulate a vulnerable service, you can use the smbserver
script from the popular impacket
Python hacker library. The existing MS17-010 scanners check the response to the TRANS_PEEK_NMPIPE (
SMB command request with the maxParameterCount=0xffff
parameter. If you respond to it with the code STATUS_INSUFF_SERVER_RESOURCES
instead of the code STATUS_NOT_IMPLEMENTED
, the attacker would think that your system is vulnerable. To perform this operation, you have to patch smbserver.
a little.

Imagine a happy attacker who has found a much-desired “MS17-010 not patched” system among hundreds (or even thousands) of hosts.

And you catch the bastard!

Honeypot is an excellent bait in networks with high security levels. For an attacker, such a host is a ray of light in the realm of darkness.
Importantly, MS17-010 is one of the most popular vulnerabilities giving an internal attacker the first domain account. Accordingly, in this round, this technique is your last defensive barrier protecting the internal infrastructure.
There are plenty of other relevant ‘low-hanging’ vulnerabilities, and you can simulate any vulnerable service to promptly detect malicious activity and confuse the attacker.
Conclusions
The first round of your confrontation with the hacker will end when the intruder finds the first domain account. After that important milestone, the attacker will act in a different way.
In the first round, you have an advantage since the hacker knows nothing about your internal infrastructure and has no choice but to take a significant risk of being detected while searching for targets. You have all prerequisites to win this round. But what if the hacker managed to gain a domain account and advanced to the Active Directory level undetected? At this point, the second (and final) round of your confrontation begins, and it will be discussed in the next article.
See you soon!

2022.01.12 — First contact. Attacks against contactless cards
Contactless payment cards are very convenient: you just tap the terminal with your card, and a few seconds later, your phone rings indicating that…
Full article →
2022.01.12 — Post-quantum VPN. Understanding quantum computers and installing OpenVPN to protect them against future threats
Quantum computers have been widely discussed since the 1980s. Even though very few people have dealt with them by now, such devices steadily…
Full article →
2023.04.19 — Kung fu enumeration. Data collection in attacked systems
In penetration testing, there's a world of difference between reconnaissance (recon) and data collection (enum). Recon involves passive actions; while enum, active ones. During recon,…
Full article →
2022.02.09 — Kernel exploitation for newbies: from compilation to privilege escalation
Theory is nothing without practice. Today, I will explain the nature of Linux kernel vulnerabilities and will shown how to exploit them. Get ready for an exciting journey:…
Full article →
2023.03.26 — Poisonous spuds. Privilege escalation in AD with RemotePotato0
This article discusses different variations of the NTLM Relay cross-protocol attack delivered using the RemotePotato0 exploit. In addition, you will learn how to hide the signature of an…
Full article →
2023.02.12 — Gateway Bleeding. Pentesting FHRP systems and hijacking network traffic
There are many ways to increase fault tolerance and reliability of corporate networks. Among other things, First Hop Redundancy Protocols (FHRP) are used for this…
Full article →
2022.06.01 — Routing nightmare. How to pentest OSPF and EIGRP dynamic routing protocols
The magic and charm of dynamic routing protocols can be deceptive: admins trust them implicitly and often forget to properly configure security systems embedded in these protocols. In this…
Full article →
2023.03.03 — Nightmare Spoofing. Evil Twin attack over dynamic routing
Attacks on dynamic routing domains can wreak havoc on the network since they disrupt the routing process. In this article, I am going to present my own…
Full article →
2023.07.07 — Evil Ethernet. BadUSB-ETH attack in detail
If you have a chance to plug a specially crafted device to a USB port of the target computer, you can completely intercept its traffic, collect cookies…
Full article →
2023.07.29 — Invisible device. Penetrating into a local network with an 'undetectable' hacker gadget
Unauthorized access to someone else's device can be gained not only through a USB port, but also via an Ethernet connection - after all, Ethernet sockets…
Full article →