Description
A Windows binary claims to write the flag to flag.txt, but the file path is wrong and WriteFile seems to write only one byte. Use Frida to hook CreateFile and WriteFile, fix the path, and intercept the flag data before it is written.
Unzip with the password picoctf and confirm the binary with file bininst2.exe.
Run bininst2.exe to see it runs but produces no visible output and no flag.txt.
Install Frida (pip install frida-tools) on a Windows machine.
Use frida-trace -i CreateFile -i WriteFile bininst2.exe to auto-generate handler stubs, then edit those handlers to intercept and fix the calls.
pip install frida-tools# Auto-generate handler stubs:frida-trace -i CreateFile -i WriteFile bininst2.exe# This creates a __handlers__ folder with JS files for each functionSolution
Walk me through it- Step 1Hook CreateFile to fix the pathThe auto-generated CreateFile handler shows the binary is passing
<insert path here>as the filename - a literal placeholder that will always fail. Edit the CreateFileW handler to print the filename argument and replace it withflag.txtso the file can be created.js// In __handlers__/kernel32.dll/CreateFileW.js onEnter(log, args, state) { log("CreateFileW called, filename: " + args[0].readUtf16String()); // Replace the broken path with flag.txt var newPath = Memory.allocUtf16String("flag.txt"); this.newPath = newPath; // keep a reference so it stays alive args[0] = newPath; },Learn more
frida-trace is a command-line tool that auto-generates Frida handler stubs for named functions. Running
frida-trace -i CreateFile -i WriteFile bininst2.exespawns the process and creates JavaScript files in a__handlers__folder - one per intercepted function. The stubs just log calls initially; you edit them to add custom logic like reading or replacing arguments.The
args[0].readUtf16String()call reads the first argument to CreateFileW as a wide (UTF-16) string, which is how Windows API functions expect string parameters. Settingargs[0] = newPathreplaces the pointer with a new allocation, redirecting the file creation to the correct path. Thethis.newPathassignment keeps a JavaScript reference alive so the native memory is not garbage-collected before the function finishes. - Step 2Hook WriteFile to capture the flag dataThe WriteFile call has a bug where it writes only one byte. Hook WriteFile to print the buffer before it is written. The buffer contains the Base64-encoded flag.js
// In __handlers__/kernel32.dll/WriteFile.js onEnter(log, args, state) { var buf = args[1]; var len = args[2].toInt32(); log("WriteFile buffer: " + buf.readUtf8String(len)); },bash# Re-run frida-trace with the edited handlers:bashfrida-trace -i CreateFile -i WriteFile bininst2.exeLearn more
The
WriteFileWindows API takes a handle, a buffer pointer, a byte count, and an output pointer for bytes written. When the byte count is wrong (here, only 1), the file is created but mostly empty. Hooking the function and printing the buffer contents at call time shows the full data the binary intended to write, even though the write itself fails to store it correctly.This technique of intercepting file writes to capture data before it lands on disk is a standard malware analysis technique. Encrypted ransomware, for example, passes plaintext data through WriteFile before encrypting it to disk; hooking WriteFile lets an analyst recover the original files.
- Step 3Decode the Base64 flagThe WriteFile buffer contains a Base64 string. Decode it to recover the picoCTF flag.bash
# The buffer output will be something like:bash# cGljb0NURntmcjFkYV9mMHJfYjFuX2luNXRydW0zbnQ0dGlvbiF9bashecho 'cGljb0NURntmcjFkYV9mMHJfYjFuX2luNXRydW0zbnQ0dGlvbiF9' | base64 -dLearn more
The binary encodes the flag as Base64 before writing it, which is why the file would be unreadable even if WriteFile worked correctly. By intercepting the buffer in the WriteFile hook, you capture the encoded bytes and can decode them directly without needing to fix the write itself.
Flag
picoCTF{fr1da_f0r_b1n_in5trum3nt4tion!_b21a...}
Use frida-trace to auto-generate handler stubs, edit CreateFile to fix the filename and WriteFile to print the buffer, then decode the Base64 output.