to the monday september 14th office hour
stream
um
let's open it up so you've all um
actually let me jump in on my ipad
um with uh
twitch
so you can follow along all right all
right now i'm on my ipad
um okay questions
let's hear it you've all been working
hard on the shell coding uh sorry in the
sandboxing
what is up
ah there's zoom shadow keep forgetting
the zoom check
okay several questions
is there a good resource to find the
argument options for the exit syscall
yes man to exit
let's take a look man to exit
all right this is uh what it is
um the argument is status
boom that's it you just exit the status
the way it works is
let's um
okay move rax
60 that's exit move
rdi
42 that's the exit code cisco
we assemble it
we launch exit.elf and here is the
return value
this dollar dollar sign question mark is
a variable that
the shell automatically creates with the
return value of the last
program to run and there you go so
there's a question
but mam doesn't have the status macros
um let's see what man has
the status macros i have no idea what
you mean by the status macros
okay so there's uh the the semantic
meaning of the exit
um uh argument which
you know exit zero typically means the
the program executed correctly so if i
do
ls slash that executed well exit zero if
i do lsat
loss something that doesn't exist
something non-zero means there was an
error right that's a typical convention
for your purposes you don't care what
the convention is you're using
exit to talk to yourself potentially
right so
you don't care about those macros you
can just exit with whatever you want
um otherwise if there is a
a macro do you have like a
i guess exit success and exit failure
all right we're going to go through this
if there's a macro somewhere
that
that you want to look up you can just
include the right header file that
defines the macro
you need to do that and then you can
just print the macro out
here it is exit success
and then what was the other one exit
failure
i'm guessing because it lines up in in
size too so that's
nice and neat okay
exit success zero exit failure one by
the way this also works for other things
like
at f d cwd
for some other problems
um
you need to include some other stuff
you can see what you need to include
from the
i like to have them sorted by size
that's like descending that's nice
anyways um see what you have to include
from the man
page and here's add cwd is negative 100.
um all right so
uh that is uh
awesome um
uh let's let's swap back and forth
because probably have the students
on on the zoom because there's only 17
people
on or sorry i have the students on the
twitch actually
real quick before we keep going let me
send out an announce a reminder
announcement to the
course
don't forget about office hours
happening now
on zoom
and twitch
all right cool so um
let's swap to twitch and then back um
how does
the buff from read work so buff
from read here is read
it takes a buffer it takes a file
descriptor
and it takes a count right it will read
count number of bytes so if you pass in
10 it'll try to read 10
or however many is available greater
than zero so it'll wait until some
data is available on this file
descriptor and read
at most count amount of data
it could read less it it can't read more
um from again from the file descriptor
provided
zero for standard input or you know
whatever other ones
and it'll store them into buff and buff
is a address in memory
that's it that's all read does um
so how level 10 is supposed to be done
level 10 um if you look
at level 10 so let's bring up pwn
college
whoops level 10.
ah we still don't have the c download
going huh
okay level 10. if you launch it in
practice mode
ssh in
all right going to challenges baby jail
and we look at level
10 teaching one that's c
all right what you can see is level 10
only allows read
and exit all other sys calls are
disallowed so obviously
read is just an uh a way to get data in
right that's that's all you you get
the only other thing you get is exit and
you need some way to
get data out keep in mind uh go
look at the last um part of the
set cop escaping set comp lecture
i sincerely hope people aren't trying to
tackle these problems without watching
the lectures thoroughly
look at the second the last part of that
and think how can you get data out with
exit
and also keep in mind that the flag's
the same every time you're on the
program
if you can only get one bit out you win
because you can just keep
running again and again and again and
get different bits out
okay and then the follow question just
having trouble figure out how to store
that i'm assuming that means the flag
right so when you read
uh obviously um
the other hint uh very important
thing to keep in mind is be aware of the
order of operations
right so for example level 10 first does
the open
oh there is no uh there's no second oh
sorry there's no shear truth
so it first does the open and then does
the second so here
you can open any file you want go for it
right um
so yeah so you can open the flag that
gets you
the flag being opened so then you can
read from the flag with read
obviously and of course the shell code
that you are working with is mapped
writable so you can write to that
shellcode or right to the stack
so you can use that as your buffer
all right follow-up question let's let's
stick with this on level 11
you get a different set instead of exit
you get nano sleep
the question is if you run nano sleep
and then the and then
exit um
will the sleep actually happen before
the program dies because you try to exit
yes
yes it will uh seccomp isn't prescient
it doesn't uh look ahead
it just does goes with the flow as you
try to execute syscalls
it'll uh check if you're allowed to so
it'll it'll execute the nano sleep
happily
it'll kill you as soon as you try to
exit
all right let's swap back to uh
the zoom chat um
how do you decide which fd is going to
be used in
open at where's open at
connor we don't have a g on here
is conor on the on the chat
participants
man
man connor's just a twitch guy he's not
on the zoo
all right all right connor says why
would you ever use a g
you use a g because it's just
it's nice that's fast all right open
that starts on level
four is our first time you see open ad
what does it do well
we're allowed to no that's the fake flag
we get to specify one file to open and
it can't be
the flag file it can't contain the word
flag right and it can't be a link
to a flag so no escaping that
um so we we get to specify the flag
uh a file to open
then our shell code runs
and all that our shell code can do is
open add read write and send file
so there aren't a lot of choices on
which file scripture to use an open act
you either use standard input standard
output standard error
some other file descriptor you pull out
of somewhere magically which you can do
or this uh path that you specify
um and i mean it should be fairly
obvious that the intended
thing to do is to use the path that you
specify
awesome so that makes sense then let's
uh swap back
um
there's a question about a tutorial on
okay
hint about number nine
let's take a look at level nine okay
here's level nine actually let's let's
let's look at the testing when all those
prints aren't helping
all right level nine nice and simple
the crazy thing about level 9 is every
rule
except for or every syscall except for
close stat
f-stat and l-stat up to cisco number 512
which is all the syscalls
are set up to kill
the process so you're only allowed close
stat f-stat and l-stat
all right i'm going to give you this
massive hint this line is not present in
any other challenge it's present here
figure out what it means re-watch
escaping setcomp and use it
all right let's see what else
uh someone's saying is there some sort
of trick to using
nano sleep yes read the man
page here is nano sleep
it takes a structure
you can't just call nano c you have to
give it a correct structure
so this is a pointer to data somewhere
that you have to build up
in memory for example push onto the
stack
and in this data you
give it the amount of seconds and
nanoseconds to sleep
and that's it that's all you really need
in fact this second thing where it'll
if the syscall is interrupted there are
various reasons why they can be
interrupted like
your program receiving a signal um it'll
actually update
another point place in memory with how
much time it is
left out of its original sleep amount
but that's fine you can you can make
ram null so you don't have to build a
structure for this guy
just the structure here nice and simple
uh build it up in memory point rdi to it
done uh the easiest thing of course is
to
play around with this in c and see what
assembly is generated to build up the
the
code the data
um okay back
to zoom
how does link at work all right
let's look at link at man to link at
link and link at makes a new name
for a file so that's pretty interesting
right um
uh sorry my mind just went blank um
link ad so open ad allows you to just
open a file
given a a uh
file descriptor you know the directory
open a file relative to that directory
uh link ad is the same way but it just
it's slightly different
in that it takes the
file descriptor for an open directory
a path relative to that open directory
right this is exactly like open app
right put in uh let me man to open that
instead of opening this path
relative to the directory it makes a
link
creates a new file on the file system
that actually points to the same data
like a pointer and memory so to say
right based on
another father scripture which by the
way nothing's stopping you from passing
in the same file scripture to both old
and new
uh file descriptor
referencing a directory directory file
descriptor
and a new path
so that new path can be
anywhere relative to the
directory
nice and straightforward
kind of right the the the
um the level that does link that gives
you link at
is level five
oops that's the pioneer all right here's
the link at level
what does it do it's ch roots and ch
ders
but before that it opens
a file of your choice so far it's
exactly like level four
right and then it gives you link at
open read write and send file level four
gave you open at read write and send
file
okay so what's different open at was
replaced with
link at and open right
you escaped from the jail using open at
in the previous one
so it
could be reasonable to assume that you
use
link at to violate the jail in some way
then later you use open normally open on
its own
in this scenario i will tell you cannot
escape from the jail
because the jail is correctly built ch
root and ch diff
so our open call is going to be stuck in
the jail
so logically it follows that using link
at
you can do something so that open
functioning properly within the jail can
still get you the flag
so what is that something that you can
do with lincat
right if you can't jump out of the jail
maybe you can pull the flag into the
jail
all right
keep let's look at zooms does second
blocks this calls happening in the
second stage execution of shellcode as
well
yes yes absolutely in fact it goes
further than that satcom will block all
cis alder
will block the cisco it blocks of the
children of the process
as well there is no way
within the same process tree to escape
setcomp
someone has a question i can't seem to
exit jail with open ad just still
under the confines of ch root
um i think we
okay i see later on down this person is
less confused now that's good
um
okay
trying to call send file with exec v at
and i get the flag with s trace but the
actual actual challenge
prints nothing
i think it depends on how you're running
the actual challenge
i'd have to see the the uh
the the call
or the the the the trace there's not
enough information in that question
quite yet um all right any level 12 tips
what is level 12 again
that's the binary all right level 12
uh all you get
is read
so you can read the flag
right there's nothing stopping you from
reading the flag nothing here
filters flag or anything and then like
level 11 and 10.
um but that's it that's all you can do
you can't call sleep can't call exit
any other thing you call will just force
your
program to crash or you will
will force your program to get killed
but all you need to do
is get one bit out with level 10
and 11 you you you saw that all you have
to do is get a bite out
level 12 give you a hint all you can do
is get one bit out
a yes or no a one or a zero
how do you do that
so the only thing that's important is
from the outside you
as the human observer can tell the
difference
between the first bit of the flag being
a one
versus a zero figure that out and you've
solved the challenge because then
you can just as easily adapt that to the
second bit
of the flag and the third bit of the
flag
and the fourth bit of the flag and the
fifth bit of the flag
you can through multiple executions
right
however many bits the the flag is long
that many bits is how many times uh
times you have to
keep executing and then put the flag
together it's exactly like 10 and 11.
just much less throughput in your
side channel
yeah so question is do you have any tips
for automating it yes use uh phone tools
so in phone tools
you can um
use uh do you have a python
okay here's pawn i can create a process
let's just do bin cat
oops and i can talk with this process
and of course it's been cat oh gosh
freaking python 3. it's been cat so it's
going to
just cat back whatever um
print to it
hello oops
oh this probably didn't flush
so
okay now that flushed now this should
work
here uh
you there's
there is caching at all levels of um
communications in in linux in uh
libc itself in python in
uh the kernel when pipes are concerned
like standard input and so forth
so when you say when you write it might
load
queue it up but not actually do the
right which is super annoying
when you're running into situations when
you think okay this should have
been written out what's going on try to
flush
the file you're interacting with
and then it should
go through so here let's let's review
what i did
i loaded up bin cat as a process
i
wrote wrote i wrote
hello
has a byte object
flushed it and then
i read it back out as a
you know from standard out so this is me
communicating with the process
i can do stuff like close
standard input now cat will terminate
for example cat terminated and i can see
that it terminated with process
zero and i can get
the process
return code and here's with zero
right so just an example of
launching a process interacting with it
and seeing
the termination code
yeah so you definitely want to and this
is all programmatic i can launch
so if i do history let's now i can do
stuff like
ah hold on i don't have my
ipython profile on here and i don't know
how
the default things go so let me
profile default i'm i'm looking it up in
a different
here's the config
thank you okay now it's and
let me configure my python properly real
quick maybe you should make this the
default counter
okay
here we go this makes my python
usable all right now
i'm in vi mode so i can interact with
this just like a text editor so i can
write big scripts
so if i want to launch cad
10 times
phone dot process bin cat
r.stdn.right
let's just write the file or the the
this is a format string that basically
just says write
the number in into cat
cd in that flush
i can print the std out
read up to 10 bytes from it but it'll
only read of course
um what's what's available there which
would be less than 10 it'll be just
the printed string representing that
number
and let's do
close scdn
wait for the process
okay run this ten times ah
this doesn't return where exited are
that
rock dot return code and there i've
scripted
oops i forgot to wait all right that
wait
wait for the price to exit boom and
here i've scripted
why is this none
okay that's weird
let's just sleep for a second here when
in doubt just
put in some sleeps let the system catch
up
oops in module time
there we go it's happily printing out
stuff to us
see so i'm running 10 times
uh cat printing and
the number the iteration number
it uh
prints that back out to me excuse me and
then it exits with zero
very cool in the same way now i can do
add more logic you can imagine that this
i might actually be the bit index you're
interested in the byte index
here you launch the challenge instead of
cat
here you write a customized shell code
to get the specific bit
instead of um you know just the the
index
and then here instead of just printing
out the return code you check the return
code
and and uh build up some knowledge based
on that return code
nice and simple but it is very doable
awesome okay um yeah i highly recommend
getting very familiar
with using pawn tools and python it's
very
very powerful
um okay
uh on twitch the real adam dupay asks is
there a hidden benefit to using ipython
that vim doesn't offer or is it just a
preference
um it's a little easier to
modify the script and run it immediately
right and vim you have to modify it from
a different terminal
run it there's no real benefit but
um i tend to build out scripts like this
quickly
in ipython especially in vim mode it has
all of the
sorry like i can hit k to go up j to go
down
l and h to go left right uh
vim users you know uh tend to do that
[Laughter]
for for speed over even the arrow keys
you know it's
it's just nicer than normal i python and
yeah except for sometimes
this terminal gets confused between
insert and navigate mode
why is that anyways we'll figure that
out
okay back to zoom
give a hint about nine uh we went
through that right did i
did i already cover nine i think i
covered nine earlier
level one testing yeah so
tl dr for nine understand very
very clearly what this does this line
only appears in level nine
so obviously it is critical to the
solution
um
okay
okay there's a question about challenge
two
uh and challenge eleven let's take a
look at challenge eleven i
vaguely feel like we already talked
about it yes yes we already talked about
challenge 11. um just keep in mind on
challenge 10 you used
exit to
retrieve the flag and challenge 11 you
have to use nano sleep
[Applause]
um
okay so question um
for level two so let's look at level two
again
do you have to use open at in a send
file call
it's just called three two two what is
this called three two two
oh exactly yeah okay um so
this person is using exactly e at in
their shell code
to retrieve the flag
i guess that will be much easier
that even work
i think you're just uh
so you can use exactly yet
trying to think of what will happen i
think the
the new program should also run with the
same ch route and then fail to load its
libraries
is my guess um
i would try oh exactly yeah is over
complicating level two
level two keep in mind is exactly the
same as level one with one difference so
if you diff
level one testing one dot c
and level two testing what's going on
here
and level two testing one that see the
only difference
okay there's a a couple differences
the big difference is
level two lets you open a file that's
one thing
and level two has you
enter shellcode instead of just a file
name
but keep in mind that the uh
uh the
way that level one and level two build
the jail is the same
here's level one just ch roots
no ch there here's level two
also they're just ch roots change root
no change there right
uh so you can
write shell code for level two that does
exactly the same as the solution for
level one did
in the binary itself s trace that and
then write that as shell code for level
two
that the the intended goal from level
one to level two is to
write shellcode to do the same thing
right
cool um just as a as a hint i don't
think open at is necessary either for
level two
no sorry i lied it isn't necessary of
course
uh just write this call to no
s trace level one and see what level one
does after um
so again the difference is here
this you just need to basically write
shellcode for
this
oh yeah yeah you shouldn't even need uh
open up cool okay
um let's take another one from
zoom
uh how to escape with mkdir this one my
favorite levels
right because this shows that
uh
why do i have oh okay this shows that
ch root is not a sufficient
sandboxing mechanism right if you don't
also
use setcomp very very carefully um
so what happens here we properly
make the ch route right we see it's root
and then we see there into the new slash
we're locked
locked in right
and all we get
is is ch0 ch root
mkdir open read write and send file
right we've seen
in comparison to for example the link at
example
where link at is what you use to
pull information from outside of the
jail and then open read write
or open and send file if that's your
preference
are used for the actual retrieval from
within the jail this is kind of
analogous right um
using this these three ch0ch route and
mkdir
you can escape
watch my ch truth lecture there's
one slide that that i talk about
see a truth has no memory when you see h
root
your oth root is forgotten completely
what happens if your new ch route wasn't
set up properly
don't get stuck in this thought that if
you have a church within a ch root
then you
[Music]
have to escape first the inner and then
the outer siege root once you create the
inner situation truth no longer exists
period it's gone it's forgotten all you
have to escape is the inner ciad
it's like imagine you're stuck in a jail
and there you have a cardboard box
so you lock yourself in the cardboard
box and then the outer jail ceases to
exist because
the universe can only track one jail for
you at a time then of course you can
break out of the cardboard box
awesome um back
to twitch for a second
help with link at we did link at watch
the
vod all right if we have time let me
have
15 minutes and then i i actually have to
go
this time at four um
how to hack vbox uh maybe we'll get to
that later in the course
um
all right if i missed something
let me know
ah for level eight
if you don't have a patch just pass by i
i think i missed level eight right
level eight is a beauty
all right here's level eight it builds
the ch root creates a fake flag just for
fun
and then it runs your shell code with a
set comp
where you only get open at read write
and send file
but you can't specify a path like the
other levels
all right for this one thoroughly read
the module page on pwn college all right
um where is it where is it
here i'm gonna go pwn.college
go to
scroll down to the modules go to
sandboxing
read these tips and tricks extremely
carefully
the answer is in there
so it says eight made me feel very smart
when i figured it out that is great to
hear
yeah read those the that errata it's
it's good stuff
um link at tips um check out the vod if
we
really stall out for questions i'll go
through link at again
um otherwise
yeah check out the the recording we went
through it earlier in the
um thing i mean unless there are no
other questions and then we'll we'll
roll
for lincat again
what's up we got a voice question
yeah question is what is at
underscore
fdcwd all right
basically in the man page this it states
this interesting
thing this is the man page for open ad
and it says if path name
is relative as in dot dot slash
or dot slash or just a name
right and drfd is the special value at
fdcwd as we saw
um i made this macro.c earlier in office
hours
where i just printed out this macro this
value is negative 100.
if you pass in negative 100 to link at
open at the various at
system calls they will resolve their
argument relative to the current working
directory what happens
is in the linux kernel
for your process there is a working
directory that is implicitly open
um for my shell for example i can go to
proc self
this has a bunch of infrared like my my
um
uh my uh memory mappings for
for bash right so here's you know bash
and
and and it has libc mapped in and a lot
of
very neat bash stuff okay anyways uh we
also have
the current working directory
which is right now in this proc
slash my process id right okay
let's go back that that current working
directory it's not a file descriptor
that's explicitly open actually if i go
back here and look at
the file scriptures that are open here
is
zero one two so this is standard in
standard out standard error
and then two five five for some reason
as well no idea what that's about
i can also with bash open other file
descriptors so i can open file scripture
128
um and just say okay let's open this to
slash lag
so i have file description 128 open now
i could read from 128
right there is an implicit file
descriptor
with uh specified by passing
negative 100 um to
um open at link at the at
system calls and that is this cwd
uh thing is not an actual file
descriptor opened by your process but
the kernel
tracks the current working directory you
can actually figure out what the current
working directory is
using the get cwd uh system called
um on in in bash you can type pwd it'll
tell you the current working directory
by you know getting the um
uh using that system called
whoa hold on okay okay
um
yeah and actually you can um if you if
you're interested in
there have been pwd you can see how it
works
here it does it gets uses the get cwd
system call
and then prints out what it received
very cool stuff okay anyways
that is an implicit file descriptor
you can open that relative to it by
passing
negative 100.
and that is relative to the last place
you cheered into
and if your process never called ch
there then it's the last place that
its parent ch there it into or his
parents parent whoever last called
ch there
all right all right let's see what's the
meaning of life we'll get to that if we
um have time
um getting bad address errors with nano
sleeve all right
very important nano sleeve does not take
the number of seconds
to sleep nano sleeve takes a pointer
to a structure that should have two
fields one of which is the number of
seconds and one which is the number of
nanoseconds
okay uh
this the first argument of nanosleep
needs to be a valid
mapped address just like if you were
passing a buffer to read
it needs to be there on the stack or or
somewhere else it doesn't have to be
writable it can just be read only but
you know it can also be readable the
second argument could be
that address or an or an address or null
the second argument is where nano sleep
stores
the return um if it was interrupted how
much time was left
um oh
oh interesting that's how it does it
so uh connor says on um
twitch that bash keeps file descriptor
255 around
if we scroll up there's this 255 that i
have no idea why it was open
and you can see actually it's very cool
these are all open to my terminal this
is a device representing
this terminal that i'm showing you
anyways 255 is open
so you can redirect standard in standard
out center air and you can still
see stuff like control c is this how it
does sec faults
hold on hold on hold on real quick we
need to let's instead of exit that as
crash.s
okay that should crash
okay so if i run crash okay
and if i even redirect okay what if i
how do i close
no okay i got all excited for nothing
never mind all right okay okay okay
sorry sorry about that tangent
um i went crazy and went on tangent
that's fine um okay question how do we
determine if it's a valid address well
it's
i mean it's the exact same if you do a
read to shell code how did you determine
that that's a valid address
one easy way is look in gdb and see what
uh the mappings are right if you gdb
whatever challenge you break at start
or you break where your shell code runs
you run
and then info proc map well here's the
mapping
right now for for this uh binary of
course
the challenge will have more mappings
and it creates
it memory maps um
your shell code so that you can always
use that as scratch space
for example level two
uh testing one dot c
does this memory map for your shell code
into this
location so that entire page from ox one
two three seven oh
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
t a o x 1 2 3 8 0 should be mapped
all right um
yeah what's up
so okay so the question was
if i understand it correctly and let me
repeat it back to you
um oftentimes when doing memory
operations you have to say
keyword pointer blah is that what you're
saying
like move rax comma keyword pointer
and then in in brackets the the thing do
you have to use that
when you are passing in
let's do this exit that s
or let's say the argument yeah okay so
well let's say we're building up an
argument
to read uh what what what what esses do
you have
let's do let's look at stage two that s
my
this is uh
exact bin sh right so are you saying you
have to use
keyword pointer here
ah okay so let's say that we
we're making space on the stack so we
we're gonna call read
so we move rx to zero and we wanna use
uh rdi to zero so that's read from
standard input we want to
um make some space on the stack
so we subtract ox 100 from rsp
made space on the stack
um and now we want to do move rsp into
rsi
so the second argument the buffer points
to the stack
and remove rdx ox100 read 256 bytes
and then call the cisco not here
you don't have to use keyword pointer or
anything
right the only time you have to specify
the memory access
size is if it's ambiguous
and nothing here is actually a memory
access does that answer the question
oh it depends so let's say you do this
and you read in your your you're the
flag
right and then
so now your flag is at is our size
pointing to your flag and you want to
read in the the or read out the second
argument write out the second um byte of
the flag or something right if you can
only write one byte let's say
uh let's set up the the right so we
move our ax1 move rdi once this is right
to standard out
move rdx one so you can only can only
write out one byte
and then if we do a syscall
and we run this it'll read out the first
uh byte of the flag so actually let's
let's let's do this all the way
um what is uh
open is file descriptor two
wait did i just break something no okay
oh no okay is everyone still there
can you hear me on zoom
perfect all right open this file
descriptor
or spot scripture is syscall 2
uh we want to
rdi we open the file name
and here we do file name
string flag
you're right absolutely right thank you
alright p plus file name good catch
um rsi will be
zero so just read only cisco open
then we don't want to read from standard
in we want to read
from what whatever file descriptor open
returned open returns
it's a rax is the return value
so we move rex to rdi and then this is
open read and then write one you can
assemble it
okay here we go open read
open read pawn college flag and write
one
just get the p right
okay and then let's exit cleanly so we
don't look like amateurs
okay boom
just just p okay now let's say we wanted
to read the second
uh argument or the second byte well
that's very easy
uh rsi is pointing to our
the beginning of our flag all we have to
do is
add one to rsi now it's pointing to the
second button
uh let's let's
so now we assemble it
run it here's the w if i do the third
byte
add two to it assemble it
run it the n and so on and in fact
you can imagine if you're
programmatically generating
this um you could simply replace this
with a format
string for python for example or if
you're
a super hip person that uses f strings
there
for example but you can you can generate
this automatically
all right um someone said
on twitch i have to use the stack to
call a syscall within a syscall
i have no idea what you mean by that
absolutely no idea
i see what i closed earlier the zoom
chat
ah zoom question any hammocks i
recommend buying yeah there's an awesome
one unfortunately
we are out of time uh get hammock
recommendations
next time all right i have to go i'm
sorry about cutting off right at
um the end of the hour
but um hopefully this was helpful
the vod is available to watch of course
and we'll put it on youtube
um as soon as we can export it
and yeah thank you for watching if you
have more questions
shoot us an email phonedashcollege
asu.edu
ask on discord or just shoot us an email
personally
otherwise connor will be streaming his
office hours
tomorrow at 2 arizona time
um good luck and the program
the challenges the practice problems are
due
at four arizona time
on wednesday happy hacking
bye bye