Challenge Info
I have been learning to use the Windows API to do cool stuff! Can you wake up my program to get the flag?
Download the exe here. Unzip the archive with the password picoctf
This challenge is #1 of a 2 part series
Basic forensics & info
File
command for basic info:
1 | C:\Users\river\Desktop\ctf\pico\BinaryInstrumentation1\bininst1>file bininst1.exe |
Running the program:
1 | C:\Users\river\Desktop\ctf\pico\BinaryInstrumentation1\bininst1>bininst1.exe |
Knowing that the program is a Windows executable, and based off the output when running it, I assume we’ll have to target the Windows API Sleep
call using Frida, a dynamic instrumentation toolkit that will let us trace, monitor, and modify the behavior of applications. Specifically, we will use frida-trace
to trace function calls (Sleep
, in this case`):
1 | C:\Users\river\Desktop\ctf\pico\BinaryInstrumentation1>frida-trace -i Sleep -f bininst1.exe |
When we run frida-trace to instrument a function like Sleep, it automatically creates JavaScript handler files for each implementation of that function it finds. This is a powerful feature of Frida that allows us to not just observe, but also modify program behavior at runtime.
In our case, Frida generated two handler files:
\__handlers__\KERNELBASE.DLL\Sleep.js
\__handlers__\KERNEL32.DLL\Sleep.js
For clarification, both Sleep.js
files are the same. Frida generates two handlers because of how Windows API functions are implemented:
KERNEL32.DLL
is the higher-level library that applications typically link againstKERNELBASE.dll
is the lower-level implementation that KERNEL32.DLL often forwards calls to
In most cases, the Sleep
function in KERNEL32.DLL
will just simply forward the call to KERNELBASE.dll
. For this challenge, we should be able to modify either one because:
- If the program calls Sleep directly from KERNEL32.DLL, modifying that handler will work
- If KERNEL32.DLL forwards to KERNELBASE.dll, modifying the KERNELBASE handler will work
- If we modify both, we’re covered either way
So, for the sake of this challenge, I will be modifying the KERNEL32.dll
one.
KERNEL32.DLL\Sleep.js
The file for your convenience:
1 | /* |
defineHandler({ ... })
- This is a Frida function that registers a new handler for the targeted function (Sleep in this case).onEnter(log, args, state)
- This callback function is executed right before the actual Sleep function is called:log
- A function you can use to print messages to the Frida consoleargs
- An array containing the function arguments (in this case, Sleep takes one argument for the sleep duration in milliseconds)state
- An object where you can store data to share between onEnter and onLeave
log('Sleep()')
- This simply logs “Sleep()” to the console when the function is called, but doesn’t include any details about the arguments.onLeave(log, retval, state)
- This callback is executed after the Sleep function returns:retval
- Contains the return value of the function (this is empty, so it actually doesn’t even do anything whenSleep
returns)
Solution
To solve the challenge, we’d need to modify this file and change the Sleep
duration argument. Ultimately, i decided to come up with a modification that not only replaces the sleep duration with 0, but also logs the original sleep duration, just for troubleshooting / analysis purposes:
1 | defineHandler({ |
After modifying & saving, we can re-run frida-trace
and see if it works:
1 | PS C:\Users\river\Desktop\ctf\pico\BinaryInstrumentation1 > frida-trace -i Sleep -f .\bininst1.exe |
Interestingly, the original duration was -2ms, which would have taken forever
The flag looks like it’s encoded via base64, you can either put it through CyberChef or decode it the cool way:
1 | [marcial@arch ~/desktop/cyber/pico/binaryinstrumentation1]$ echo "cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YWNjMzh9" | base64 -d |
flag: picoCTF{w4ke_m3_up_w1th_fr1da_f27acc38}