← Back to Writeups
CUSTOMMediumForensics

Mem

XESXOR9/2/20264 min read
#forensics#custom#medium#bash_history_recovery#command_line_forensics#gpg_symmetric_decryption#little_endian_byte_reversal#memory_dump_analysis#multi_step_encoding_reversal#string_extraction#linux

Mem

Platform: spbctf | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-03-17 | Status: Solved Techniques: bash_history_recovery, command_line_forensics, gpg_symmetric_decryption, little_endian_byte_reversal, memory_dump_analysis, multi_step_encoding_reversal, string_extraction

Summary

Linux memory dump forensics. Attacker obfuscated THEFLAG.txt through 5-step encoding chain (od -t x4, base64, xxd -E -b, tr, GPG), then shredded originals. Solution: extract bash history from RAM to reveal commands and GPG passphrase, reverse each transformation step, handle little-endian byte order from od -t x4.

Mem - spbctf

Description

Ыж оставил незалоченную линуховую консоль, и куда-то отошёл. Пока его не было, кто-то жестоко надругался над флагом в файле THEFLAG.txt, а потом и вообще зашифровал его и грохнул оригинал с диска. Вернувшись, Ыж не растерялся и снял дамп оперативки со своей машины. Восстановите содержимое THEFLAG.txt.

(Translation: Someone left an unlocked Linux console. While away, an attacker obfuscated the flag in THEFLAG.txt through multiple transformations, encrypted it with GPG, and securely deleted all original files with shred. The owner took a memory dump. Recover THEFLAG.txt contents.) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

File provided: mem.rar containing a 134MB Linux memory dump

Analysis

Initial Recon

Extracted mem.rar (23MB compressed → 134MB raw memory dump). Since this is a Linux memory dump and the task mentions bash commands, started by searching for references to THEFLAG.txt using strings.

Bash History Recovery

Found the complete bash command history still resident in memory:

bash
strings mem | grep -B2 -A10 "cat THEFLAG.txt"

This revealed the full attack chain:

bash
cat > THEFLAG.txt
cat THEFLAG.txt | od -t x4 | tr -d ' ' | tsort > ttt1.txt
cat ttt1.txt | base64 -w23 | tac | xxd -E -b > ttt2.txt
cat ttt2.txt | tr a-zA-Z0-9 0-9a-zA-Z | sed 's/ //g' > ttt3.txt
gpg --armor --symmetric --batch --passphrase mys3cr3tP4SSW0RDnotAflag < ttt3.txt > encrypted_flag.txt
shred -u THEFLAG.txt ttt1.txt ttt2.txt ttt3.txt

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

PGP Message Extraction

Found the full PGP-armored encrypted message still in memory:

bash
strings mem | grep -A100 "BEGIN PGP MESSAGE"

Solution

Step 1: GPG Decrypt

Decrypted with the passphrase visible in bash history:

bash
gpg --decrypt --batch --passphrase "mys3cr3tP4SSW0RDnotAflag" encrypted_flag.txt > ttt3_recovered.txt

Step 2: Reverse tr Mapping

The forward transform was tr a-zA-Z0-9 0-9a-zA-Z. This is NOT its own inverse!

  • Forward: a-z → 0-9a-p, A-Z → q-zA-P, 0-9 → Q-Z
  • Inverse: tr 0-9a-zA-Z a-zA-Z0-9 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
bash
cat ttt3_recovered.txt | tr '0-9a-zA-Z' 'a-zA-Z0-9' > ttt2_recovered.txt

Step 3: Reverse xxd -E -b

The xxd -E -b command outputs binary representation with big-endian grouping. Parse binary back to bytes:

bash
cat ttt2_recovered.txt | sed 's/^[0-9a-f]*://' | sed 's/[^01]//g' | tr -d '\n' | \
  fold -w8 | while read byte; do printf "\\x$(printf '%02x' $((2#$byte)))"; done > ttt2_binary.txt

Step 4: Reverse tac + base64

bash
cat ttt2_binary.txt | tac | base64 -d > ttt1_recovered.txt

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

Step 5: Reverse od -t x4 | tr -d ' ' | tsort

This was the trickiest step:

  1. od -t x4 outputs 4-byte words in little-endian format (on x86)
  2. tr -d ' ' removes all spaces, collapsing address+data into single tokens
  3. tsort does topological sort, but with single-word lines it just reorders

Recovery process:

  • Sort lines by the 7-digit octal address prefix
  • Extract hex data after the address
  • Reverse each 4-byte word from little-endian to big-endian byte order
  • Convert hex to ASCII ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Example: 676e6f43 (little-endian) → 436f6e67 (big-endian) → "Cong"

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

with open('ttt1_recovered.txt') as f:
    lines = f.readlines()

# Parse lines: 7-digit octal address followed by hex data
data = []
for line in lines:
    line = line.strip()
    if len(line) >= 7:
        addr = int(line[:7], 8)  # Octal address
        hex_data = line[7:]      # Remaining hex
        data.append((addr, hex_data))

# Sort by address
data.sort(key=lambda x: x[0])

# Extract and reverse each 4-byte word (little-endian to big-endian)
result = b''
for addr, hex_str in data:
    # Each 8 hex chars = 4 bytes in little-endian
    for i in range(0, len(hex_str), 8):
        word = hex_str[i:i+8]
        if len(word) == 8:
            # Reverse byte order
            reversed_word = word[6:8] + word[4:6] + word[2:4] + word[0:2]
            result += bytes.fromhex(reversed_word)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(result.decode('utf-8', errors='ignore'))

Result

Recovered THEFLAG.txt content:

Congratulations! You won. Here's the flag: REDACTED

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