What was covered today
OverTheWire Bandit levels 4 through 7, Python chapters 3 and 4 (functions and lists), and writing a working port scanner from scratch in Python.
The port scanner
Here is the complete code. I will explain every meaningful line afterward.
import socket
from datetime import datetime
print("=" * 50)
print(" Python Port Scanner")
print("=" * 50)
target = input("\nEnter IP address or domain to scan: ")
print("\nTarget: " + target)
print("Started: " + str(datetime.now()))
print("-" * 50)
open_ports = []
for port in range(1, 1025):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
result = sock.connect_ex((target, port))
if result == 0:
print("[OPEN] Port " + str(port))
open_ports.append(port)
sock.close()
except KeyboardInterrupt:
print("\nScan interrupted.")
break
except socket.gaierror:
print("Could not resolve hostname.")
break
print("-" * 50)
print("Scan complete. Open ports: " + str(open_ports))
How it actually works
The core of this entire script is four lines:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
result = sock.connect_ex((target, port))
if result == 0:
socket.socket(AF_INET, SOCK_STREAM) creates a TCP socket. AF_INET means IPv4. SOCK_STREAM means TCP. This is the same type of connection your browser makes when it loads a website.
sock.settimeout(0.5) tells the socket to give up after half a second if there is no response. Without this, the scanner would wait indefinitely on filtered ports and take hours to complete.
sock.connect_ex((target, port)) attempts a full TCP connection to the target on the given port. This is different from connect() — connect_ex returns an integer error code instead of raising an exception. If it returns 0, the connection succeeded. The port is open. A service is listening.
That is the entire concept of port scanning. Attempt a connection. Record whether it succeeded.
Nmap does this same fundamental operation with many more features layered on top — service version detection, OS fingerprinting, script scanning. But underneath all of that, at the core, it is still: attempt TCP connection, record result.
Understanding that made Nmap feel less like a black box.
Testing it
I ran it against 127.0.0.1 first — my own Kali machine. Then against scanme.nmap.org — the legal practice server.
The results matched what Nmap found on Day 3. Two different tools, both written to do the same network-level operation, report the same open ports. That cross-validation felt important. It confirmed I understood what the tool was doing rather than just hoping it worked.
OverTheWire Bandit levels 4 through 7
The Bandit levels today introduced the find command with property-based searching. This is where it started feeling most like real security work.
Level 5 → 6 required finding a file that was exactly 1033 bytes and not executable:
find. -type f -size 1033c! -executable
The ! is the negation operator. It means NOT. So this finds files that are NOT executable. Combined with the size filter, only one file matches.
Level 6 → 7 required searching the entire server for a file owned by a specific user and belonging to a specific group:
find / -user bandit7 -group bandit6 -size 33c 2>/dev/null
Searching from / means the entire file system. This generates hundreds of permission denied errors as it tries to read directories we cannot access. 2>/dev/null sends all those errors to nowhere.
One file path appeared in the output. That was the answer.
This exact command structure appears in privilege escalation checklists. After gaining initial access to a Linux system, attackers search for files owned by privileged users that they might be able to read or write — configuration files, private keys, scripts. The find command is how they locate them efficiently.
Level 7 → 8 was grep:
grep "millionth" data.txt
The file has millions of lines. grep found the one relevant line instantly. This is used constantly in security work — searching log files for specific events, finding credentials in configuration files, and parsing tool output to find relevant lines.
What Python chapters 3 and 4 added
Chapter 3 was functions. The port scanner has no separate functions — everything is in the main script. But once I add features like service name lookup or output saving, those will become functions. Understanding return values made the socket code make more sense: connect_ex returns an integer, I check if that integer equals 0, and I make a decision.
Chapter 4 was a list. The open_ports list in the scanner is a direct application of Chapter 4. Append to the list inside the loop, print the full list at the end. Simple, but it made the chapter feel immediately practical rather than theoretical.
What this building taught me
I could have run Nmap to scan ports. I have been running Nmap. But I would not have understood what was actually happening.
Building the scanner made me think about:
- What is a socket, and why does it need to be created and closed for each port?
- Why does settimeout matter, and what happens without it?
- What does connect_ex actually do under the hood versus connect?
- Why does returning 0 mean success in socket programming?
These questions did not come up when I ran Nmap. They came up when I had to write the code myself.
That is the difference between using tools and understanding them. Both matter in cybersecurity. But understanding is what makes you dangerous — in the right way.
The code is on my GitHub. Link to my profile. Week 2 starts tomorrow with Security+ study beginning in earnest.
Top comments (0)