can you guess?
Category: Misc
Description
Can you guess it right?
Note: the chall.py file is used for setup purposes only and is out of scope of the challenge.
Connect with nc -v localhost port
Attachments: can-you-guess.zip
Write-up
- Our initial step was to conduct a quick manual taint analysis to understand the challenge's flow and where we want our input (i.e. source) to flow to.
- We began by examining
chall.py, the entry point for the challenge. Our objective was to print the flag (i.e. our sink). - Upon inspection, we noticed that guessed was initially set to
Falseusing the line:guessed = mp.Value('b', False). - Before checking the value of guessed, the code invoked
guess()from thejailmodule as a subprocess. - Here's an overview of the logic in
jail.py:Text Only - Our observation revealed that the control flow ultimately leads to
jail()fromguess(), which employseval()on our input. However, we faced a challenge becauseguess()sets our effective and real UID and GID to65534, which corresponds to thenobodyuser with limited permissions. - As
jail()returns, it is compared againstrandom.random(), and if the conditions are met, guessed is set toFalse. - In summary, our goal was to manipulate
guessedthrough input without causing an exception and without satisfying the conditionrandom.random() == r, whereris the output fromeval(). - After conducting some research, we discovered that using the
inspectmodule would enable us to view variables from other stack frames. - Additionally, if variables are in the global scope, we can manipulate their values. However, manipulating local variables of other stack frames is not possible as they are read-only.
- Interestingly,
guessedwas initialized as anmp.Value, which allows sharing a ctypes variable across multiple processes. Consequently, we can considerguessedas a reference to shared memory. - This implies that only the reference to guessed is read-only, while it can be used to dereference and the value itself can still be modified.
- With this understanding, we devised a payload that inspects the local variable
guessedinguess()from oureval()injail()and overwrites its value toTrue. - To ensure a valid expression and avoid exceptions, our payload includes
== 0at the end. - The final payload is as follows:
Text Only
Flag: shellmates{PYTHOn_FR4mE_0bj3cTs_ARENT_s3CuR3_ARE_Th3y}