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
False
using the line:guessed = mp.Value('b', False)
. - Before checking the value of guessed, the code invoked
guess()
from thejail
module 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 thenobody
user 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
guessed
through input without causing an exception and without satisfying the conditionrandom.random() == r
, wherer
is the output fromeval()
. - After conducting some research, we discovered that using the
inspect
module 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,
guessed
was initialized as anmp.Value
, which allows sharing a ctypes variable across multiple processes. Consequently, we can considerguessed
as 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
guessed
inguess()
from oureval()
injail()
and overwrites its value toTrue
. - To ensure a valid expression and avoid exceptions, our payload includes
== 0
at the end. - The final payload is as follows:
Text Only
Flag: shellmates{PYTHOn_FR4mE_0bj3cTs_ARENT_s3CuR3_ARE_Th3y}