Адский круг (Adskiy Krug)
Адский круг (Adskiy Krug)
Platform: hackerlab | Category: Misc | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-25 | Status: Solved Techniques: base64_decoding, nested_archive_extraction, rot13_cipher, scripting_automation
Summary
Task: ~800 nested ZIP archives with encoded passwords. Solution: Automated extraction using Base64→ROT13 decoding for each password.
Адский круг — Hackerlab
Description
Архивы имеют случайные названия. Паролем к каждому архиву является строка, которая выводится при попытке его разархививации. Она закодирована в ROT13→Base64. Раскодируйте её и укажите в качестве пароля.
Analysis
The task consists of ~800 nested ZIP archives. Each archive:
- Is password-protected
- Contains the next archive with a random name
- Shows an encoded hint string when attempting to extract
Important observation: Despite the description saying "ROT13→Base64", the actual decoding order is reversed:
- Base64 → ROT13 (first Base64, then ROT13)
Example:
Encoded: UDY4TDRV
Base64 decode: P68L4U
ROT13: C68Y4H ← this is the password
Solution
Step 1: Structure Analysis
bash read-only • copy allowed# Download and extract the initial archive unzip task.zip # Get 1DKD81.zip # View contents unzip -l 1DKD81.zip # Archive: 1DKD81.zip # Length Date Time Name # --------- ---------- ----- ---- # 12345 2024-01-01 00:00 UDY4TDRV
The string "UDY4TDRV" is the encoded password.
Step 2: Password Decoding
python read-only • copy allowedimport base64 import codecs encoded = "UDY4TDRV" # Base64 decode decoded_b64 = base64.b64decode(encoded).decode() # "P68L4U" # ROT13 password = codecs.decode(decoded_b64, 'rot_13') # "C68Y4H"
Step 3: Automation
python read-only • copy allowed#!/usr/bin/env python3 """ Automatic extraction of ~800 nested archives """ import zipfile import base64 import codecs import os import glob def decode_password(encoded): """Base64 → ROT13""" try: decoded = base64.b64decode(encoded).decode('utf-8') return codecs.decode(decoded, 'rot_13') except: return encoded def extract_nested(start_zip, work_dir='.'): os.chdir(work_dir) current_zip = start_zip count = 0 while True: count += 1 print(f"[{count}] Processing: {current_zip}") try: with zipfile.ZipFile(current_zip, 'r') as zf: # Get the filename inside (this is the encoded password) names = zf.namelist() if not names: print(f"Empty archive: {current_zip}") break inner_name = names[0] # If this is win.zip — final archive if inner_name == 'win.zip' or current_zip == 'win.zip': print(f"\n[!] Found final archive!") # Show contents of win.zip with zipfile.ZipFile('win.zip', 'r') as win: for name in win.namelist(): print(f" Password hint: {name}") break # Decode password password = decode_password(inner_name) print(f" Encoded: {inner_name} → Password: {password}") # Extract with password zf.extractall(pwd=password.encode()) # Remove processed archive os.remove(current_zip) # Find next zip zips = glob.glob('*.zip') if not zips: print("No more zip files found") break current_zip = zips[0] except Exception as e: print(f"Error: {e}") break print(f"\nTotal archives processed: {count}") if __name__ == '__main__': extract_nested('1DKD81.zip')
Step 4: Execution and Result
bash read-only • copy allowedpython3 solve.py # [1] Processing: 1DKD81.zip # Encoded: UDY4TDRV → Password: C68Y4H # [2] Processing: next_random.zip # ... # [~800] Processing: final.zip # # [!] Found final archive! # Password hint: CODEBY{REDACTED}
The final archive win.zip contains a file whose name is the flag.
Notes
- Decoding order: The description can be misleading. Always check both orders (A→B and B→A)
- ROT13 property: ROT13(ROT13(x)) = x, so encode and decode are the same operation
- zipfile in Python: Supports passwords via
pwd=password.encode() - Final archive: Often contains a hint in the filename, not in the contents