hold on let me start this stream real
quick and then i'll address that
oh that's awesome
let me see how my audio sounds one
second
that's good enough okay
so okay and you can see my
terminal that
works yeah okay i am streaming on a new
computer so i hopefully don't
run into any issues but at least the
stream will not crash like it did on my
old computer so that's good
um okay so
before i started the stream we're kind
of talking about how some of the
challenges
aren't yet released they will be
released tonight of course that means
that now this office hours
isn't going to be able to focus on those
unreleased challenges yet
um if uh necessary
slash it seems like it makes sense i can
potentially
hold another office hours
maybe either tomorrow or on sunday uh
for an hour
to address the new challenges um we'll
kind of see
there's lots of questions and it makes
sense to hold another office hours i
could probably go forward
and do that but for now let's focus on
the challenges that do exist and also
let me
quickly ping the discord just to make
sure people know
that office hours are happening right
now
okay um
so all right let's get started then what
um
questions are currently do people have
for
the currently released levels for baby
race
level two testing okay
let me start by
launching that challenge and then
there's also a question can we talk
about using
python my exploits have been all over
the place
uh yes
level three how to change the wind
variable okay we got all sorts of
questions
let's start by taking a look at level
two testing let me
launch it i guess you can see my mouse
moving but
okay whatever that'll work um
oh right i'm not sharing on zoom uh i
don't
is it possible for you to watch the
twitch stream on zoom
because i'm not exactly sure on this new
setup how i'm gonna
share the zoom okay that would be
very helpful all right thank you okay
let's
okay so we're going to be looking at
level
two okay
let me ssh into the instance
okay so if we
launch baby race level two testing one
uh of course we have to
um actually you know what i'm going to
work on teaching
i'm going to solve it in a testing way
and then once we have the solution i'll
move it over to testing
that way it is easier to explain what's
going on
but once we have our working two
teaching we'll switch it over to testing
okay
so if we launch it we can see
the challenge allows you to open a
single file
and then this file will be opened and be
sent to you
just like level one challenge will
verify that the file's path does not
include flag
it's not a sim link okay
so if we for instance gave it like etsy
password
on the teaching levels we of course do
several blocks to make the timing attack
easier
we just hit enter to get through those
and we can see
that we called lstat on the path
to kind of check to see if it was a sim
link
um in some of the later levels we'll
start calling stat but it'll be on the
directory it'll be important to
understand kind of the difference
between l stat and stat
the high level overview is that l-stat
will not follow
um the path if it's a sim link it'll
just like
tell you about the fact for instance
that it is a sim link
you can imagine that if you wanted to
check if a file is a sim link it would
be very annoying if it followed the sim
link then
because you could never then check if
it's a sim link
so else that lets us check if something
is assembling
okay and we can see that we can leak out
etsy password probably
not nearly as great as being able to
leak out the flag
and of course based off the description
if we pass it flag
it path contains flag okay so
how do we solve this then um
let me start by launching tmux
and let's quickly go through the um
non-scripted solution to the challenge
just uh to kind of demonstrate it
so what we want to do is provide it with
a path
actually let's quickly look at what
needs to happen
so we provided it with the path slash
flag
and we can see that it's blocking until
input if we hit enter
it says the path contains flag so we
instantly failed there but we can
overcome that
by giving it say home
ctf uh a
and if we hit enter um the issue now
is that the it says oh i guess do i
already have that filing
existing hold on let me switch the other
terminal and
cd into my home directory um
let's just make a directory called race
and start working out of this so it's a
little more clear what's going on okay
so
instead of ctf a let's go with ctf race
a and if we hit
enter of course it tells us that we
can't get the file status
because the file does not exist
if we however make the file exist so if
we do like touch a
and now if file fault a exists if we run
this again
we will see that it seems like we
succeeded because before
we would break out we would did this
blocking and then calling
lstat and then it failed but here we
called lsat and then we're blocking
again
so now if we hit enter again presumably
it just sent
us the contents of a of course since we
have a teaching mode set
up what we can do is that we can
we can specify this a file
here we just finished checking to see if
it's a sim link
we confirm that it's not and now if we
switch back into our other terminal
we can remove a and then we can make it
be a symbolic to
the flag so now we can see here
that a is a symbolic pointing at slash
flag
and we've already checked to verify that
it's not assembling so that the
challenge thinks everything's good to go
we can read it out because it's not a
sim link
and now we hit enter and of course it
gives us our flag
um now the question is how do we
do this without this very convenient
blocking until input
we got to be very fast and we've got to
script it
so um i could show you i guess how to do
it from like a command line like
insane scripting but let's just
immediately jump into python
um okay so in order to do this
i'm going to make this
terminal be emax
and this terminal will continue to just
be here
and what we will do is we will um this
is like going crazy
on this large screen size hopefully
it'll work
um emacs x dot pi
um yeah
oh maybe
this is showing up weird yeah showing up
right there as well
let me
let me just run it um without my emacs
config
oh why it's hold on maybe it's not an
issue
maybe i'm confused no everything looks
fine the issue is that we're in tmux and
that's why we see like this double
rendered bar um yeah okay we'll just
roll with this then uh oh no it once you
start typing it double minus hold on
okay
let's do this although that also double
renders it
that's annoying i guess it's just a
cosmetic issue though um
well you know what we don't need to be
in tmux if we're uh
going to do it this way yeah let's just
do it without tmux that's the
same solution um ctf
race x dot pi
okay in fact we can actually just
make our terminal appear here
and everything will be great
okay and we can
reasonably well see that on the stream
i will roll with it okay so if we do
pwn dot process of baby race
and we want to pass it a path that is
going to be what it tries to read from
and we can pass it home ctf
race a
and then we can do
with pawn.process blah blah blah
as process and then we can do
process um actually let me
run the challenge again so we can see
what we want to
block on home ctf race a
and we can see that we want to just like
basically receive until blocking until
input
process receive until
blocking until input
and then we want to
send line like nothingness
um and then
actually the first thing we want to do
once we are blocking until input we can
go ahead and create the file
so what we want to do is import os
and then we want to do os open
home ctf race a oso creates
i believe that is valid oh
we want uh
actually i think this is right let's see
if this works
um okay so we do not have an a file
currently
if we run x dot pi
um
hold on let's do it here
let's make sure we know how to create a
file
oops that is not at all what i wanted to
do
that did create the file though but let
me uh
run it from the command line
why is this hanging oh this is hanging
because oh that's annoying
hold on
um let's go with
that
python x dot pi
okay created our file good enough
okay so
the next thing we want to do is we want
to
start scripting this so let's remove
that a file
from there let's okay so we want it to
be created the first thing
is that a needs to exist so that it can
stat it and check or else tat it and
check that it's not a sim link
so at this point it now exists and then
we want to wait for our next action
and and our next action that we want to
do
is that we actually want to delete it so
we want to do os
unlink home ctf
race a
that will delete the file and then we
want to os
dot sim link
slash flag to be home ctfa
and then what we want to do
is send that and then process
read all i think that is the last
block and let's just print it
um and we can decode it
yeah okay python x dot pi
um
what
hold on
why am i so confused right now um
[Music]
oh lowercase p duh thank you
um okay
python x dot pi
okay sweet and we can see that the flag
comes out alright thank you for the help
okay so this is of course in teaching
though in testing it's going to be
much more tricky because we don't get to
wait for these blocking so how do we
adapt our solution for that um
well we can kind of think that two
things
need to happen here in fact
let's kind of slightly restructure this
in a way
and why i'm about to do what i'm doing
will make more sense as we go on
let me start by creating the file and
then right here we're going to call
unlink as well the reason i'm doing this
is i'm setting it up so that we have
a looping structure right we want these
two things to happen if we assume
that we start everything out with the
file existing
for the first iteration we want these
two sys calls to
execute and then in the second one we
want these two to execute
and then also actually real quick i'm
going to os dot close this so that we
don't like run out of file descriptors
or something insane we've got a finite
amount and if we keep calling
open i don't think since we're calling
it through
os nothing's going to call close for us
automatically and we should just
clean up after ourselves um
okay so this assumes now that we have a
file
and then in fact we're
kind of you can try
and also do the following just i want to
get basically the program
into a state where
it just works no matter how we run it so
let's just unlink it
and then create it and then run through
this so
let me do pythonx dot pi
um no such file okay so we need to
handle
if there's not a file so if there's not
a file we can't unlink it
accept file not found error
[Music]
actually really i think we
just want to do this never mind hold on
let's do it this way
and then python x dot pi then we don't
have to worry about that right because
we can run this multiple times
just fine uh no we can't
um we can't create it
okay so let's we try to do this
and then we accept permission
error
let's do os unlink in this case
and then create it okay so this should
put us
in
all right you know what i'm over
complicating this
let's do just the try except let's just
try to
unlink it and then try to create it and
then no matter what happens
it will exist rather than sit here and
try and
handle the correct exceptions let's just
do something
that will work okay
so now we can run this multiple times in
a row
and whether the file exists or whatever
it should be good to go
okay so this initializes us into having
our
our setup here okay so now what we need
to do
is let's break this into the two steps
let's call
a function step one and let's say that
in step one we want to perform the
following action
we want to unlink close that's
it or we want to unlink we want to
create the file and then we want to
close the file
so instead let's call step one here and
then let's create a function called step
two
and
step two we'll do that and now our x
split should still work we just replaced
it with some functions
okay
and now
what we want to do is now we're getting
ready for our
testing
run where we don't have these blockings
but basically
we're going to get ready to do the
following in fact i will
just start changing it let me copy all
of this and comment it out so we know
what we did that worked for
teaching mode and let's just re-adapt
our script to testing mode
in fact before we start doing that let
me switch into testing mode
um let's see here
testing launch
okay
so we have our script
again now that we're in the new
um we're now we're in testing mode okay
and if
we run our script we will see that it
doesn't work
because it tries to
um oh well that also doesn't work
because we're running
the wrong challenge we're running
teaching instead of testing
and then okay so let's see this should
again fail
and we're going to see that it fails
because of an end of file
it's doing this receive until
block blocking until input of course in
the testing version
that does not exist and in fact we can
see that
yeah hold on
that is the wrong thing um let's just
maybe type it all right whatever
level two testing one
um let's do it again baby race level two
testing one um
home ctf race a
oh my god this is terrible baby race
level two testing one home ctf race a
and it yeah just immediately um
left it basically just sent us the
contents of a which is an empty file
okay anyways let's make this actually
work
so what we need to do is we need a
separate thread basically
constantly alternating between step one
and step two
if we can make our program just
constantly make it so the file system is
potentially at the conclusion of step
one
which basically means that home ctf race
a exists as some real
file and that the the file system
can also potentially be in the state
where home ctf race a
points at flag then it's just a matter
of
chance on when
as the program executes what the current
file system state is as everything goes
okay so let's make it so that we are
running step one and step two
in a uh
loop basically so if we do os fork
equals zero so fork is uh
basically split off a child process and
in that child process
the value of fork will be zero
if it's the child process and in the
parent process it'll be the pit of the
child
so let's do if os fork equals zero
this is in the case of the child and
then
we will do while true and we will call
step one
and we will call step two so now we have
a separate process
a child process that's executing for us
that is constantly just flipping the
state of the file system
as fast as it possibly can i can't think
of
a very i mean there's maybe a couple
options
there's one optimization i have in mind
how we can make this faster but let's
assume this is good enough
um so it's just super fast
alternating between home ctf race a not
existing
in the case that if the file system at
the end of this
syscall the file will just not exist
or at the end of either of these sys
calls it doesn't matter which because
closing the file doesn't affect the
the file system at the end of this a
will be
a real file and at the end of this
the file system will be
um hold on the file system will be
with a pointing to flag so we kind of
have three states that the file system
can be in
and we're just running it as fast as we
can to alternate between those three
states
and we're just kind of basically hoping
that the program
catches it at that right time that when
it goes to check to see if it's a sim
link
that we are at the end of this condition
um and when it goes to actually open it
that we're at the end of this condition
and hopefully for neither of those two
checks it's in the unlinked condition
um that's kind of what we are taking a
chance on for this
race so if we run it enough times
hopefully
that will just work so let's start by
clearing this out clearing this out
clearing those out
and we all we do is just read everything
and decode
okay so if we do python
x dot pi we're going to see that it only
runs once which is
fine and presumably it's going to fail
um where is it failing though
um no such file
[Music]
okay
[Music]
unlink
wait what
so we unlinked it and then we created it
and then we get ready so we do this
initialization before we go into step
one step two
um hold on let me run it again
hold on let's
let's just assume that the file doesn't
exist um
what happened here
what i don't think i've ever seen
question marks before oh is the process
running
oh we have uh it running still okay
let's just peak hill python
okay that makes way more sense okay i
didn't realize that the uh
i figured that when we killed it that it
would stop hold on is that not true
yes
hold on
what are these other python oh these
other python processes might be for my
editor
um yeah let's just assume that it's done
okay so if i run python x dot pi
name accept oh except
exception
okay do we have
i don't think any of these are but let's
just pkill python again for good measure
and then let's run pythonx dot pi
and then
hold on now we do have python
still running all right i think
something is
up because of the way that i'm doing
this
um okay let's ignore
let's get rid of this and let's just
manually delete the file
let's not be fancy let's just manually
delete the file before we run our script
okay um
so all we want is that and that and then
um oh but then the issue here is that we
need it to exist
that's fine we can make it exist
before we delete it so at the beginning
let's just do it in the child as well
okay so the child is going to create it
that way
it can unlink it and everything will
just make sense and we can just
repeatedly loop through these steps okay
so if we do this now
um
why
hold on let me how do i want to test
this
maybe what we need to do
i think the issue is that the main
python process processes exiting but for
some reason this one
isn't why would that happen
okay let's just be super lame and import
time
and time sleep 20. then
we don't have to worry about that
hopefully um
p kill python again python x dot pi
yeah maybe python isn't the way maybe
this uh maybe you're right i don't know
this is this is feeling miserable
um okay uh
no such file or directory in step
one how is that possible we just created
it
right here home ctf race a
definitely exists okay that's not while
true let's just do
if true let's run it once ps
aux grep python
p kill python okay let's also just get
this whatever we'll p
kill python if we have to still
not entirely sure why we have to because
i would assume that when the parent dies
the child should be
forced to die as well but it doesn't
feel that way
um okay and then this week
killed python and okay so let's run it
okay finally we get something that makes
sense error file is a sim link
though it doesn't oh we just ran it
twice because
okay hold on if we
are a parent thread
we will execute this otherwise we will
not whatever good enough
because we can see that it just ran
twice and we can actually see that it
interleaved the two executions of it
which is kind of interesting
p kill python and then
python x dot pi
um files i'm like okay that's what we
expect okay
so now instead let's
make things work let's uh a while true
do this
okay it's rma
um actually hold on real quick if i
yeah let's just rna okay if we now
run this a bunch of times
and look basically for
results equals this to make this
be the result and if um
what is it pawn or is it uh if
let's just say if pawn in results that
should be sufficient
we can print the result and then we
can um
we can break out of this loop
okay and
oh wait how is this the step one step
two shouldn't be there either
highly confused about that okay so
hopefully this is
beginning to make sense even though uh
everything's becoming a disaster in this
case you say it's pawn underscore
college
yeah that sounds correct let's just uh
make it slightly more clear with that
the phone college in results
okay so what we're doing now
is that we have a child process that is
repeatedly
sim-linking unlinking and making that
path be just
a normal file as fast as it possibly can
so the first time through it'll delete
the file
and then it will make it be a normal
file and then it will delete the file
and it'll make it be a sim link so just
constantly alternating the file system
and now we are going to constantly run
the process so we have
the file system rapidly being altered as
fast as possible
we have the challenge process being run
basically as fast as
possible and we're waiting for the right
interleaving of events to occur so now
if we run
python x dot pi
we begin a wait
and boom pops out didn't take too long
um so when the parent died does
dies does the child so that's what i
thought but for some reason we're seeing
it
still existing no so it's not all of
these user bin pythons i think that's my
editor and i don't know why my editor is
going out of control
i'm sure there's some emax memes there
but the second to last one python x dot
pi still exists
which doesn't make sense to me
because this isn't like
it should be like a damon or whatever
let me think here
trying to think about our verify scripts
maybe it's not an issue for our verify
scripts that this keeps running because
we just
kill it anyways huh like we kill a whole
container that's
verifying that it works which will
definitely kill it and not just continue
to waste resources
okay whatever we can actually overcome
this very easily
what we can do is the following and it's
not really
something that needs to be overcome but
let's uh
uh show how we can handle this and not
make it so we don't have to keep calling
a p kill python um
let's do let's say that pid
equals that and then the child process
will be if pit equals zero and then in
the parent process we now have the pid
and what we can do is
at the end we can just do it outside of
the loop os dot
kill
um always thought kill
what am i thinking uh the pid
and then the signal we want to send
let's just send a nine
and this will kill that'll make it so
that we can clean up after ourselves
or you could os dot system p kill python
yeah that's uh
also a solution hopefully this one is
slightly more
uh less nuclear
um okay so if we run this now let's just
see if we're cleaning up after ourselves
clearly we already got the flag so i
mean you could just destroy the
container and be on your way and maybe
you don't care about cleaning up after
yourself
but let's just show that we can okay now
if we grab for python
we can see it's only these oh no wait we
don't see
we see that there is a python hold on
let me p kill python one more time maybe
i didn't kill it before i don't remember
ps aux grip python okay so it definitely
doesn't exist now and now if i run
pythonx dot pi
wait for our flag okay ps aux grep
python
[Music]
okay i think that's a good sign right ps
aux
there's no python okay we cleaned up
after ourselves the other thing though
is if we
want to even more correctly clean up
after ourselves we need to handle the
condition if we like kill this because
we give up or whatever like if we right
rapidly hit control c
right away rather than like letting it
finish
we can see that ps aux grep
python that didn't kill it i don't
understand what happened there hold on
but what i was
going to show is that you can do this
try finally
maybe it's not such an issue but you can
do a try finally
and what's going to happen here is that
in this block if we receive our
sig kill by hitting ctrl c this finally
block will still
exit execute so that would also allow us
to clean up after ourselves
but either way maybe we are rambling too
much about how to clean up after
ourselves and this still just works
anyways
let's verify that this still just works
anyways
very slowly getting very unlucky
unless
hmm
um yeah i can talk about that but i'm
going to talk about three first because
there is a
prior question on that but yeah okay why
is this not execute
finishing hold on
so something that might actually speed
things up potentially
is if we do pwn context
log level equals critical
so basically just turn off all of
punctual's logging which is
potentially due to buffering slowing
stuff down
um okay right we can deal with that
let's rm
a python x dot pi
and it needs to comes out you know what
happened i think when we had our try
finally oh no this is try finally still
here
i think what happened is that um we
hadn't cleaned up
our home ctf race a file and since the
file
existed was an issue and we can see
again we can just run it super fast it
just
instantly pops out
um yeah we just have to make sure that
this a file doesn't still exist because
if we run it now
because a does exist we are going to run
into an issue
uh no we won't we only run into an issue
if it's a sim link i think
i don't know make sure the a doesn't
exist um
okay so anyways enough talking about
cleaning up
after this code um let's take a
a look at three so
three is slightly different
um let me launch the challenge
it's a siege in
and if we run it um
okay well let's start by just giving it
like let's see password
uh we can see that this challenge will
verify
again not flag again not simlink but
this time it checks to see if the file
is less than 256 bytes
um and it tells us also
i guess that's all it tells us okay um
oh it's let's see oh no it's too large
okay so we can see the etsy password is
too large makes sense etsy password
takes more than 256 bytes
um let's do home
ctf actually let's just go to home ctf
race let's create file a
let's do baby race level three teaching
one home ctf race a
and we can see that it's calling
lstat and it seemed to not complain
because we're blocking again getting
ready to continue
and it tells us at the end the value of
the win variable is zero
you should be thinking kind of back to
maybe some of the baby mem levels
when you hear win variable
so this win variable exists on the stack
in fact if we do an s trace
of this we can see
that
we called l-stat and we can see that in
fact called l-stat
and then we're blocking again and then
we can see here
that it read in 40 96 bytes
um and maybe you're thinking hey but the
size limit was for 256 bytes maybe the
buffer is 256 bytes
and if you reverse the program you will
in fact see that the buffer
is about 256 bytes
and that immediately after it is a win
variable
but we're reading in 4 000 bytes
and of course now you get to exploit via
this timing
uh or via this race
uh condition issue
because it kind of thinks that there
should be only 256 bytes but then it
goes
in and reads up to 40 96 and suddenly
there's not just 256 bytes in there
there's more
and you can overflow um
my webcam is frozen
how did that happen
huh
what happened
one second
well that's terrifying
um hold on
okay my audio's back now
that still is broken
[Music]
um
oh well that works except it's like
taking up all of the screen now uh but
it's still frozen isn't it
well that's lame all right whatever
we'll just uh
remove that from happening then for now
well for this office hours we will i
will look into it later
very sad okay we will move on
so
looking at level three as we were
talking about we
are checking if it's 256 bytes
if it's not
200 or if it's less than 256 bytes we
continue
but due to racing it we can then make it
be more than 256 bytes and then when it
goes in and reads it it can overflow its
buffer so that's kind of the general
idea of three i'm not going to go into
directly solving it on stream
but that is the idea okay
so and then there was also a question
about level five
okay getting past level five testing
seems
tough even though my exploit is in x86
assembly and i'm using a file
system maze
anything i can do to win the race
against the binary
okay
so i will start by saying that you don't
need to write assembly yourself using
python is
sufficient let's say the verify scripts
use python and it works just fine
okay um how to make it
faster so there's a number of things you
can
do in the case of five
in order to make it faster part of it is
going to be just make sure you
run it for long enough there's a chance
you it's
slightly more complicated um because
um slightly more complicated
because you need to account for being
able to have
your pro or your file system be in an
additional state so you're kind of
instead of um needing to alternate
basically between
two states that the file system can be
in
um you have to alternate through three
um
okay let me stitch in
and this is a
um this makes it a little more tricky so
let's first though see
what does level five do and again we
need to pass it a path
home ctf race a okay
so we can see the file
will be sent to you no flag
don't make it sim linked the challenge
will verify
that the directory the file is in is
owned by
root okay so this is a new constraint
this means it's going to be looking
at the directory of our file so for
instance when we pass
home ctf race a it is going to be
looking at home ctf
race
and verify the directory the file
is owned by root and that other users
are not able to create files in that
directory
so for instance that would make
the root directory work because root uh
the root directory is owned by roots
and it is not writable by other users
this would also mean let's say the slash
root directory
in fact i can't even view it but we can
see here
that this is also owned by root and not
readable by other people
but something that wouldn't work is
slash
temp slash temp has the issue
that um where is it
temp has the issue that
other users are allowed to write into
this directory
so it basically is trying to
again defend against race conditions in
a new way
and the way that it's doing that is
basically saying i will only look
at directories
which are owned by root and other users
aren't able to write in which basically
means that our user theoretically is not
able to make
files in that directory in order for
uh it's a pass okay so
we can of course overcome this and
the way we overcome it is using race
conditions so the first thing that's
going to happen
when it goes through and checks maybe i
should run this in tmux again
um run with this home
ctf race a let me create a
second terminal we can go into home ctf
race
we can see that a already exists let's
just delete it
um so it's currently blocking it's going
to be checking
if a is a
um actually maybe it'd be easier to
show exactly what it's doing using s
trace
um i guess
though it happens after so if we hit
enter
um
ah let's just run without s trace let's
just describe what's happening okay
so it's checking to see if the file
exists here so we're going
to fail here because it fails to get the
file status
and that's because a doesn't exist but
if we make a exist
we can run it here and we can hit enter
and we get past that
we called lstat i'm not following
symlinks
it's basically it seems to have worked
[Music]
and then we're getting ready to
call stat so as before we're calling
lstat
on the entire path now we're calling
stat on the directory
so actually let's switch to s trace
if we hit enter and then let's hit enter
again we can see that right here it
basically removed the slash a at the end
um and it's just looking at the
directory we're doing the stat on that
um
and then we can see let's just run it
without s trace
if we hit enter and then enter again we
can see
error directory not owned by root
because home ctf race is not
owned by root but something that's
useful for us
is the fact that stat is
going to follow symlinks which means
that if we make
let's say we create let's move a and
let's make a directory
inside of race called a
okay and then we go into a
here and we create a file a
well now what can happen
is as we're blocking again until input
so actually we didn't run it with slash
a slash a
so we're blocking until input it's
happy with our path we gave it um the
issue
now is that we're about to see if
um we're about to see if home ctf
race a is owned by roots
which of course it is not
we want it to be owned by root so how we
can do that actually
is that we can remove the file a we can
come back
up we can remove the directory a and
then we can
sim link slash
say root to b a
um sim link
not found oh link dot dash s oops
link dash s okay so now we have this
a directory which is pointing at slash
root and because we're calling stat it's
going to follow that
link and then
it doesn't care that like slash root
contains a file a
because we're just looking at the
permissions of the directory in this
case
so now if we hit enter again
we can see that we just passed that
check
and now once we hit enter again it's
going to
read out our file for us so we need to
make it correct again so we want to
remove this sim link we want to
make dur a we want to enter a and we
want to
link um this a to b
it's a flag and now
if you were to do and it's not going to
work for us because we're not sued
but if we were to do home ctf race a
a it would be printing out flag and we
can see in fact if we do ls-al
it's pointing at flag so now if we hit
enter
it gives us our flag okay so that kind
of
demonstrates what's going on in terms of
how you
exploit this at least in teaching mode
the question now is how do you make this
as fast as possible
in order to beat the race
okay so if i i'm going to start by
leaving
tmux if we
a max home ctf race x dot pi
we need a couple of things to happen so
let's
switch there
actually let's stick to teaching for
right this moment and then let's give it
home ctf race a slash a
and then let's read until
blocking i think is what it says right
blocking until input
and then once we're satisfied with the
state of the file system we can send
line
okay so what we want to do we're going
to have
basically three steps so let's just call
step one initially
let's call step two and then let's call
step three
okay and
step two step three
and let's set up what we want
so we want home ctf race a
to be a directory so we can do make dirt
and then we want
what else do we want we want to create a
file
which will be slash a slash a
um okay so this
puts us in a state where we can confirm
that this is not a sim link
okay and then what we need to do is we
need to
unlink a slash
a and we need to uh
rm dir uh
home ctf slash a
um and then we want to
sim link home ctf race a
to points at let's say root
so that should satisfy what we want the
state of the file system to be in for
three
for the the sec the second step
and then for the third step what we want
to do is we want to
unlink home ctf race a
you don't call rmdir because it's a sim
link you unlink sim links even if it's
pointing at a directory um so we unlink
home ctf race a and then we want to
make that be a directory
and then we want to sim link
that like this
and aaa okay
and this is all that needs to happen
okay let's get rid of this just to
verify our stuff is
working uh
let's just put like an if false pass
that way our structure of our program is
still ready to go
and then we call step one we call step
two we call step three
and we see if we were correct
okay so
let's go ahead then and
run it actually let's start by making
sure that a doesn't exist
okay now if we run it
and we cannot
read until oops
process
and we can make that not happen
okay
we can see that our approach is working
um if we now go ahead and rm
um yeah okay yeah
if we rm a or r and r
a we can run it again if we don't rm
it we are in an inviolated state but
that's fine
we'll just make sure we rma before we
start everything
okay so we're almost we're getting close
um let's see here
now what we want to do
um in fact let's just delete this stuff
okay
if we
we want to put this in a loop so the
issue now with this
entering into a loop is that
the what do i want to do
so we can see that this is the current
state of the file system we'll have a
directory a
and we'll have a symlink so we need to
unlink the
in order to loop around we need to
unlink a a
and we need to r endure a
um okay
let's actually just manually add in our
final clean up steps
let's do step three now and then
[Music]
actually no let's let's do it right
let's we want to do the following
this is what it's going to look like
anyways because this is what the state
of the file system is
at the end of three so let's just do
that at the beginning
and then let's make it so step one
cleans up so
os unlink
ctf race a
a and then os
rm der home ctf
race a okay
now if you run this then
unlink
permission denied
oh right because we're not running in
testing mode
um okay
let's also let's just make sure our
solution still works before we jump into
testing mode because
it would not be great if it didn't um
okay python x dot pi
wait am i something oh we're not
we started i see we started our thread
yeah so what we need to do is we need to
comment this out again
okay that's from pythonx.pi
okay so our solution still works at a
high level
um now we want to
make it be
um now we want to make it work for
testing
okay so let's leave this
uh yeah just exit let me
switch into testing mode
and now let's go ahead and emax
uh emacs home ctf
race x dot pi
okay and then
let's go ahead and
set everything up okay so if
pid equals zero right
oh whatever i did before didn't fix it
did it but this is fine okay
so we're getting ready to
create our background process that's
changing our file system
and we can get rid of this we can
get rid of all of this
and we can do that
and we can do that and let's just say
that's irrelevant now
okay so in theory this has the ability
to work potentially it's very unlikely
for it to work
but at least has the ability to work so
let's
let's see maybe we just get lucky and it
works
oh right not quite have the ability to
work almost has the ability to work
we change this path to be correct
and we should rm a make sure that's gone
okay now if we run it let's see
if within i don't know maybe give it
like 15
20 30 seconds i don't know maybe even up
to a minute but we're not going to
see if it spits the flag out in fact we
can see
if we do um
oops how do i do this
oh that doesn't work like that
uh one second
we want to do this
let's make a another terminal
okay and then if we just
look at this
you can see that it's rapidly doing
stuff
um yeah i think it's going crazy
we've been running for a while and it's
not working so maybe
um it's not our lucky day uh so let me
close that
let's kill that okay so this seems
probably not fast enough we have a lot
of
things going on right we've got
like five sys calls happening here
and we have three sys calls happening
here
we've got three more syscalls happening
here
that's kind of a lot of sys calls and if
you think about what is involved with
our race
every step of the way the the process is
basically going to execute a few
assembly
instructions maybe not so many but
really the
the amount of overhead that is
contributing to our chances of winning
is basically it calling one cis call
so we need our like in this case like
five
sys calls to execute
at like this insane rate it's basically
this is too slow we want to make it as
fast as possible
and there are tricks that we can do to
make it faster beyond
just this uh what jana has talked about
with the maze and like nice square i
honestly haven't looked at
those things yet there's things we can
do just in our solution itself
with the syscalls that we're calling to
make it significantly faster
faster we make it probably the faster or
more likely it is that we're going to
win
um okay so how can we do that then
well what if we use more
sim links so here we're like
closing and opening a file um
and then like we're making a directory
here
and we're just calling a lot of things
in theory we can have our file system
set up to be ready for us
so what we can do is that we can make
let's say um let's make dur
home ctf race um
let's just call it b so this exists as a
directory
now i'm not a sim link or whatever and
then let's go ahead also
and create a file inside of b
called a
yup okay and
so now we have a directory b that
contains this
file a and then let's also make a
directory
c
um and c will contain a symlink to the
flag
okay so now we have b that already has
a real file that'll pass the first check
we have c that has our sim link to the
flag
so what is left what is left to clean
this up
um what's missing is our directory a
and all we want a to b now is let's just
make a be a sim link
let's make a b assembling to either b or
c
um so
um or to slash root also to point out
because
we need um this only sets up two of the
three
states that we need the file system to
be in the third is that we need a
pointing to root but that is also just
the symbol link okay so let's
go ahead and unlink
um slash a in fact also let's go ahead
and
os dot make dur home ctf
uh race a so that it exists when we go
to unlink it
okay so if we
unlink a
and then what we want to do in the first
step is we want to
sim link a
os symbolic
that's probably not exactly what we want
we want to sim link a
to b
home ctf race a
okay so after this
a so we unlink a
so a no longer exists and now a is
pointing to b
and what is at b so let's let's actually
just uh comment here
so we have race a and let's say a
because this is the
the file that's always trying to be
accessed oops
and this is pointing at home ctf
race b a right because we just made a
home ctf race a b
assembling okay
so this works
and then the next thing we are going to
do
is we are going to unlink a again or i
guess this will be in the
step c or step two sorry
um we are going to
make a point at c
uh sorry not c we want in the second
step we want it to point at root
because root is owned by roots and is
not writable by other users
okay and it's going to follow the some
links so that's fine
and the final thing we want to do
actually let me copy this one
so we can say now like home ctf race a
points to slash root which is going to
pass that check
and then the final thing we want to do
is point at c and now we're going to
have like home ctf race
a a pointing at home ctf
race c
a which is going to be pointing at home
or it's just going to be pointing at
flag
because we set up our sim link here home
ctf race ca
points to the flag
and yeah okay so let's see
if this works then we have the
conditions that a b and c must not exist
at the start of this so let's make sure
those don't exist
and let's see if we win
um something went wrong
hold on oh i think i know what went
wrong um
let's make sure that python is not still
running um i think what went wrong
is where are we calling unlink
okay so the issue is that unlink doesn't
work
against directories um
but what we can do is
in this state we can rm dir a
because um
actually no because this will be a sim
link here
it'll always be a sim link actually so
what we want
to do this is fine we just need to fix
how we uh created at the start
we need this to be a sim link at the
start so that um
we can just unlink it in our step one so
we want this to be
a similar to i don't know let's just say
to root as well why not
okay so now we can now this is
unlinkable so now we can just call
unlink whether it was in the initial
state where it's pointing at root or
whether it's at the end of step three
where it's pointing to race c and now
a is always going to be a symlink okay
um oh did i forget to kill stuff
um rmra rmrb
rmrc
now we see if the flag shows up
yeah i can confirm that these
are solvable without the mazes um it's
very possible
that the maze would help um
um okay maybe it's worth running
more instances of this
let's just really hit the server hard
hold on
maybe it's a bad idea but let's go for
it anyways um
let's close out of this
okay ps aux okay
pythor let's get this home ctf
race
that's r m r a
b c okay
and then what we want to do
i'm just kind of guessing here let's
okay first let's start by running it
making sure yeah that doesn't uh
help us let's make sure that's cleaned
up
okay rmrb rmrc
okay so let's actually real quick let's
change some of our logic
so that we can multi-process on this
pawn.process thing
so let's go ahead
let's even get rid of this forking
mechanism let's go ahead and make a
y dot pie
in y dot pi all we're going to do
is the following
and we're going to create steps one
through three
um and then we need to import os
okay so now this is going to rapidly
this will be basically the thing that's
changing our file system
and then let's make z dot pi
and let's make that be this logic
and then we need to import process
and
yeah actually let's
make it so we do our forks here also
let's do hopefully this isn't too crazy
let's go with os fork
um you can actually just call fork a few
times
and each time it'll double the number of
things doing this so this means that
there's two this means there's four that
means there's eight
i don't know let's go up to 16. so this
means we will have
16 different baby race level fives
running at the same time
okay um
let me do that let's launch into
teamwork so that we can
analyze what processes are running
easily
um and i'm going to create a new
terminal and this one i'm going to run
y dot pi okay
and then here we can see
that insanity is happening with the file
system now
which basically just means where a is
pointing
um you can see it's just moving all over
um okay so that's running correctly
now if we do python z dot pi
um max q
z dot pi
did i not say this or what happened
oh no my terminal is just being insane
hold on let's kill this real quick leave
tmux unfortunately
max z dot pi
um this needs to be import phone
okay let's just make sure this runs
seems to do something
um emacs z
dot pi did we get rid of that critical
message
yeah let's make the critical also um
make the log level be critical
okay and now let's
do ps aux okay we're good let's run tmux
let's run python y dot pi
uh whoops we need to rm ra
rp rc oops
and then let's do python y dot pi
okay and now our file system is rapidly
changing
and then let's go ahead and do python z
dot pi
okay and then let's look at what
processes we have running
okay so we have a ton of z dot pi's
running
um which
two six four four which is running some
number
of baby race level five
um
let's see if we can see
the file system so we can definitely see
that actually let's make sure that
b looks correct so
b is pointing at
a which is just a file
and then c is pointing at
flag and then a
is the thing that's constantly
alternating
so that showed that it can point to b
that just showed that it'll point to c
um and that just showed that it'll point
to root okay so everything
is in order
my question is
what's happening
um it's possible that if we just keep
leaving this running for a bit
that we'll get our solution as
unsatisfying as that might be
hmm
let me try and think about what's going
on here
i may have to readdress what's happening
in like a next office hours but let me
let me see if i can think about this
hmm
i'm not really sure why this wouldn't
work so something that we can
test is if our
current approach still works in
teaching
i think it would
oh nick i just got killed okay
it's actually kind of surprising that it
got killed
um
trying to think
so one other optimization we can make
is the following let's try it i'm not
exactly sure about it
but let's see what happens if we do the
following let me
close out of all of these
okay let's change y dot pi
to do something else and what that
something else is going to be
is the following we're going to make a
y2 dot pi
and y2.pi's only responsibility
is just going to be to call unlink
all it will ever do is unlink a
and now instead what we can do here
is just try to do this and accept
exception
pass and
basically repeat that for all of these
not exactly sure
if this will make it easier or not if
this will actually help our solution but
let's give it a try
let's unlink
okay so all we're doing now is just
trying to symlink and instead uh
the the person is going to do the unlink
is going to be a separate process so
this
potentially can make us under the right
circumstances like twice as fast
in theory because if we interleave y and
y2
such that y2 correctly calls the unlink
before this guy calls
simlink or whichever person that needs
to call simling calls it
there's a chance it can work let's uh
i'm slightly skeptical
of the idea but let's see what happens
that's rmrb rmrc
t-mux let's
run python let me just make sure that
everything looks correct
yep all we're doing is simlinking now
at y2 dot pi
and all we're going to be doing here is
just spam on linking okay
so let's create a new terminal
this terminal is going to call y dot pi
and then let's create another terminal
and this is going to call y2.pi
uh we need hold on we need to add an
exception there as well
say t-max real quick
oops
okay so this is going to run now
and actually if we look at it we should
see that a is not changing
it'll always be a root because no one's
ever unlinking it so the other syscalls
that are running in y
are failing but once we add our unlinker
now stuff is unlinking so let's see if
we can verify that
stuff is changing so a is
occasionally pointing at other things
which seems to be exactly what we want
root
bee okay does it ever point at c i'm
sure it would because
there's not really a reason it would
point at two but not the third
let's see if we can find it
and points at c okay so now and how many
processes do we have running wait how is
z dot pi still running that pi i don't
know what the deals with that
ps aux rep all right let's just look at
what's running
wait what p kill
how do i specify this
okay let's just peak hill python
okay which means we need to relaunch y
dot pi
uh which means that we need to remove a
move b remove c
and then we need to python
y dot pi python y to that pi
see if we see a changing
seems to be changing okay
and now it's from python z dot pi
okay somehow okay amazing this is uh
incredible you know i was actually
highly skeptical of this idea it came up
with it on the spot
and somehow it actually works amazingly
that is i love to see that okay
so let me try and explain why even
though i was skeptical of the idea that
it works
the idea of what we were going for with
this approach
of having basically this y pi and y2
pi split into two separate things um
actually maybe it'll be easier if we
let's just kill pickle python
kill python okay
and let's leave this okay let's look at
our solutions
again let me try and explain why even
though i was skeptical of it it works
so the idea with this solution is that
as we are running
through wait what
oh no we're running z dot pi okay okay
so as we're running this
so we we do fork four times in a row
that just basically means we're going to
parallelize out to 16 attempts
basically we have 16 processes running
this concurrently just increasing our
odds
and all we're doing is just praying that
whatever the state of the file system is
as the program runs and moves through is
correct
so what is the thing that's changing our
file system so we have y and y2
so in y all we try to do once we set up
how everything works and basically that
means making
b um making b
a be a real file and c slash a
point to the flag and then just the idea
now is that in step one step two and
step three we're just changing what
a points to so in this configuration a
points to b
in this configuration a points to root
and then this configuration a points to
c so we're just hammering through this
as fast as possible
so before what we had is an unlink right
before we would do this
but that in theory
is going to take twice as long right now
you have to perform
two syscalls you have to perform an
unlink and then a sim link and your
process can only execute
one syscall at a time but if we split
that
out into a y2.pi that does the unlinking
this guy is just going to spam try to
unlink the file as fast as it can
but now we have two processes altering
our file system
if we were kind of like almost racing y
and y2
this is like a whole nother dimension of
racing
we've got y and y2 racing each other
to set up the file system in a way that
even makes sense
so we're basically hoping that this
unlink gets called and then one of these
symlinks gets called
but it's happening in two separate
processes which means that
we could in theory enter the kernel
concurrently from two separate processes
and perform the process of unlinking and
symlinking
simultaneously and depending on
what kind of uh locking mechanisms exist
in the kernel
to determine what happens um
we could get lucky enough where even
though both are executing in the kernel
at the same time the unlink goes through
and then the sim link goes through
but we don't have to pay the double
overhead
of entering the kernel back to back we
can do it like
simultaneously and that's kind of the
idea of this approach and it looks like
this approach actually works
if anyone has any questions on that i
can try and explain
but it looks like this is a
looks like a very good solution in fact
for um
making the testing variants work for
five and uh as it turns out also six
there's gonna be a slight twist on six
but i'll probably let you guys look at
that
okay any final questions i'm going to
start wrapping up office hours
yeah you could probably mute the audio
on the stream
that's probably the
yeah that's the basic idea that you
split off
into separate processes so we have for
this solution
we have z dot pi and all z dot pi's
responsibility is
is to just run baby race level five
testing one
with um home ctf race aa as the
argument to it and basically just see if
the flag was in there and print out the
flag if it was that's all it does
well that and fork to 16 times so that
it's running this
all 16 times
but then there's y dot pi and all
y dot pi does is it tries to symlink in
three different ways
you in theory i guess could split each
attempt to simlink into a separate
process but i don't think that would
help you
yeah i don't think i think it's not
maybe
it might even hurt you if you were to
split these symlinks into separate
processes
i'd have to think about it more um but
all why dot pi's responsibility is
is to attempt to sim link a to a
directory
in the first case it's to symbolic a to
b in the second case it's to assembling
a to root and then the third case is to
symbolic a to c
and we've already pre-set up so that b
and c
um are configured in a way that it's
going to pass the condition i'll
pass the check so we just have to get
one sys call through
um we just have to get one sys call
through in order to make the file system
be in the right state
but we also have why we also in order
for these sim links
to eventually go through before you can
sim link you have to unlink
and we in y2.pi
call just unlink as fast as possible and
we split y2 and y into separate things
rather than do
like os dot unlink here which is what we
had before and it wasn't working
um rather than do this
this is in theory like twice as slow
right because you need to enter the
kernel
twice ever so you have to kind of think
about
how much time things take and doing a
syscall is actually an expensive
operation it takes
time to enter the kernel and the context
switch and the context switch back
and that's basically what we're racing
against right the the target for the
challenge program is just making some
sys calls and we have to beat those
syscalls with our syscalls
so we want to be as fast as possible we
don't want to do these
um in order we want to do them at the
same time like that
apparently i was suspicious of the idea
but that seems to actually work really
well
so rather than call them in order which
didn't work for us
we just call them at the same time and
it works it's great alright any final
questions
yeah on the idea of the teaching ones in
this module is to make sure you
understand
what sequence of events needs to occur
but you don't necessarily
care strictly about being super fast in
order to perform that because that's
the blocking just means you can kind of
set everything up
at your own speed like you can just do
it all even without a script
um but then the testing is like yeah you
need to be ultra fast
um yeah
all right i am going to end this office
hours thank you everyone for joining
um i will uh we will
post the additional challenges tonight
um
yeah there's another question
uh go for it real quick
okay so the maze i not gonna be able to
answer you might have to wait for yawn's
office hours i haven't done anything
with the mazes
um before i i mean honestly i'm
skeptical about their idea
because the colonel seems like i should
be able to go through it fast but i
don't know john says it works
i don't know i would potentially wait
for his office hour slash message him
um to do the maze but i can definitely
confirm that it is
solvable without the maze as we just
demonstrated here um on the other hand
it's possible that the maze will be
conceptually simpler to you than what
i'm doing and that the maze will in fact
work but i
i can't say anything about the maze
because i don't know enough about it
yep okay i am going to end the office
hours
yup see ya