wine picoCTF 2022 Solution

Published: July 20, 2023

Description

A 32-bit Windows PE binary that runs on Linux under Wine. Reverse-engineer the password check in Ghidra and supply the correct input to print the flag.

Download the Windows PE binary from the challenge.

Install Wine. For a 32-bit PE on a 64-bit host, configure a 32-bit prefix once with WINEARCH=win32 WINEPREFIX=~/.wine32 winecfg, then run subsequent commands with the same env vars exported.

Open the binary in Ghidra: it auto-detects PE format on import, so no manual format selection is needed.

bash
sudo apt-get install wine32
bash
WINEARCH=win32 WINEPREFIX=~/.wine32 winecfg
bash
WINEARCH=win32 WINEPREFIX=~/.wine32 wine vuln.exe
  1. Step 1Run the binary under Wine
    Running the EXE prints a banner and a single password prompt on stdin: Enter password:. Type anything; the binary either prints Wrong! and exits, or Correct! Here is your flag: .... There is no menu and no immediate flag drop.
    bash
    WINEARCH=win32 WINEPREFIX=~/.wine32 wine vuln.exe
    Learn more

    Wine (Wine Is Not an Emulator) is a compatibility layer that allows Windows executables to run on Linux without a full Windows VM. It implements the Windows API on top of Linux system calls, making it possible to run most 32-bit Windows programs.

    In CTF challenges, Windows binaries are often distributed to require Wine or a Windows VM. Using Wine on Linux is more convenient for scripting automated exploits and using Linux analysis tools like Ghidra, objdump, and Python.

  2. Step 2Reverse-engineer the password check in Ghidra
    Load the PE into Ghidra, find the string comparison function, and extract the expected password value.
    bash
    # In Ghidra: File > Import File > vuln.exe
    bash
    # Search > For Strings to find password/flag strings
    bash
    # Decompile the main function to see the strcmp or comparison logic
    Learn more

    Ghidra supports PE (Portable Executable) format just as well as ELF. After auto-analysis, navigate to the entry point or main(). Look for calls to strcmp, strncmp, or inline byte comparisons that validate user input.

    The decompiler view makes it easy to spot patterns like: if (strcmp(input, "secretpassword") == 0) print_flag();. The hardcoded string is the password you need to supply.

    Alternatively, strings vuln.exe on Linux dumps all printable strings from the binary. Filter for password-shaped candidates:

    strings vuln.exe | grep -E '^[A-Za-z0-9_!]{6,}$' | head
    # Sample output:
    # AcceptEx
    # Enter password:
    # Correct!
    # Su93r_S3cr37_P455w0rd     <- the embedded password
    # picoCTF
    # DispatchMessageW

    The regex keeps strings of 6+ "identifier-style" characters and discards short tokens, format directives, and most Windows API names. The hit list is short enough to eyeball; the real password is usually the only line that looks like an English-ish or leetspeak phrase rather than a Win32 symbol.

  3. Step 3Supply the password and capture the flag
    Run the binary again under Wine with the correct password to trigger the flag output.
    bash
    echo 'CORRECT_PASSWORD' | wine vuln.exe
    bash
    # or use Python to pipe input:
    python
    python3 -c "import subprocess; p = subprocess.run(['wine', 'vuln.exe'], input=b'CORRECT_PASSWORD\n', capture_output=True); print(p.stdout.decode())"
    Learn more

    Once you have the password from static analysis, pipe it into the binary via stdin. Windows programs running under Wine accept stdin just like Linux programs, so standard piping works.

    If the binary expects a GUI dialog for input, you can use wineconsole or set up WINEDEBUG= environment variables to suppress Wine debugging output that might clutter your terminal.

Flag

picoCTF{...}

This challenge was not solved during the competition. The flag is printed after supplying the correct password found by reversing the PE binary in Ghidra.

Want more picoCTF 2022 writeups?

Tools used in this challenge

Related reading

What to try next