Video summary
The video introduces the core concept of binary exploitation by explaining how attackers trick a computer into executing user-supplied data as code. This principle relies on the Von Neumann architecture, where there is no fundamental distinction between instructions stored in memory and data; both are simply sequences of bytes that the CPU fetches based on an instruction pointer. The lecturer illustrates this with examples like SQL injection and cross-site scripting, showing how these attacks manipulate servers or browsers to interpret input as executable logic rather than harmless information. At a lower level, modern systems like JavaScript engines utilize Just-In-Time compilation to dynamically generate machine code at runtime, demonstrating that the ability for data to become code is an inherent feature of this architecture rather than a bug, though it creates significant security vulnerabilities when control flow can be redirected onto attacker-controlled memory regions on the stack.
To demonstrate these concepts practically, the instructor walks through a vulnerable C program using the `gets` function, which reads input without checking buffer boundaries. By manipulating the return address and passing pointers to specific functions as arguments, they show how an application can accidentally jump from reading data into executing that same memory region as instructions. The lecture highlights the importance of understanding x86-64 calling conventions, such as using `RDI` for the first argument and `RSI` for subsequent ones, which are crucial when crafting payloads to redirect execution flow. A key takeaway is that if a programmer or attacker can control where these pointers land on the stack, they effectively gain the ability to execute arbitrary code simply by arranging bytes in memory that mimic valid assembly instructions.
The tutorial then focuses on writing "shellcode," which is compact machine code designed to spawn a new shell process with elevated privileges once executed. Since standard input functions like `gets` stop reading at newline characters or null bytes, crafting effective shellcode requires careful attention to byte size and content; for instance, using the XOR operation (`xor`) allows an attacker to zero out registers efficiently in just one byte instead of multiple instructions. The video also explores advanced techniques such as embedding strings directly within instruction opcodes by leveraging endianness rules or utilizing system calls like `execve` via specific register values (e.g., setting `RAX` to 59 for the Linux x86-64 syscall table). Furthermore, it discusses constraints imposed by different input functions, noting that while some allow null bytes, others restrict newlines or whitespace, requiring attackers to work backward from their desired outcome and design payloads that survive potential mangling of the input stream.
Finally, the lecture emphasizes reverse engineering skills as essential for overcoming these limitations, suggesting a strategy where one starts with the goal—such as spawning a shell—and works backward to determine what bytes are needed before they reach the vulnerable function. This approach allows attackers to bypass restrictions like limited buffer sizes or forbidden characters by using jumps over corrupted sections of code or compressing their payload into minimal space. The session concludes by introducing tools like `pwntools` in Python, which automate tasks such as assembling shellcode and interacting with processes interactively, thereby reducing the manual effort required to craft complex exploits while reinforcing that all these capabilities stem from a deep understanding of assembly language, memory layout, and system call mechanics learned throughout the semester.
Read the full video transcript
let's start
recording because now we're moving on
to now for the final module you're going
to be digging in and going back to
putting the skills that you've been
building throughout the semester of
understanding and learning web
application of sorry not web
applications because we just covered
that um but what we've learned about
assembly so you've been learning how to
write assembly code you've been learning
how to reverse engineer programs now
we're going to start putting those
pieces together to actually exploit
vulnerabilities in binary
applications and first we'll start with
shell
coding
so
the so
fundamentally what we're going to want
to be doing and where we're going is
trying to answer the question how do we
trick the computer into executing some
of our data as code and we actually have
already seen an example of this and
we've been doing this
so when we're doing a SQL injection what
are we trying to
do like what's the goal of a SQL
injection
to run well anytime I interact with the
application it's running SQL code on the
server yeah so specifically we trick the
server into taking something that should
be our data right because it's data that
we provide to the application so it
should just be data that's stored in the
database or used to query the database
but we trick the database into treating
that as code as part of a SQL query if
we think of a SQL query as code similar
exact same thing with cross site
scripting right cross-site scripting is
fundamentally you're tricking the
browser into interpreting your user data
as JavaScript
code this also goes into command
injections are exactly the same thing
you're tricking the the shell bsh into
treating your user data as code now
we're going to go those are all kind of
I would think at
a at kind of a high level now we're
going to actually go down to the Machine
level and start thinking about at the
Machine level what is
um um how how can we trick the CPU into
start executing our data as code and
this goes back all the way uh to like
the first some of the first initial
designs of computer architecture so
the yeah there we go
so the Von Newman architecture this is
from 19 45 which is a design of a
computer system um this is kind of a
fundamental difference in CPUs and
computer architectures
is fundamentally a Von Newman
architecture sees and stores code is
data so how does the CPU we've been
talking about data when we access things
from memory right what's like the lowest
level of thing that we can of
information that we can access from
memory bites yeah just bites right it's
bittes in memory so if we ask for a bite
we get a bite if we ask
for uh quad word we get eight bytes I
think that's right I don't know the size
is but ask for one bite you get one bite
two bytes you get two byes kind of
flipped around four bytes same thing
eight
bytes and fundamentally your the
instruction pointer where your Cod your
program is going in order to start
executing is exactly the same thing so
there's fundamentally no difference
between code and data right the code
that you write in assembly is compiled
down to bytes that are loaded into
memory and we tell the CPU start
executing from here but fundamentally
there's absolutely no difference between
the code that you write and provide
that's in those bits that those bytes in
the computer's memory versus the bytes
that you're storing as data and that
goes all the way back to Von Newman
architectures um whereas Harvard was
another style of architecture at the
time that stored data and code
separately so here you'd have a
different memory for code and a
different memory for data
um almost
everything that we've been using and
learning is a is based on the Von Newman
architecture does anybody have a device
that is not in this list like on them or
know of them x86 arm myips power PC
spark risk risk is definitely on there
for sure
toaster a toaster what what CPU does a
toaster run so a lot of them actually
will run one of these things usually be
like a cheap myips processor um there
definitely are use cases I think uh very
specific things I haven't seen these but
they definitely do exist of these crazy
architectures um and so what we're going
to be talking about and focusing on is
what happens if the CPU mixes up code
and data what happens if the CPU starts
executing or starts executing something
but it's actually your data and not
code like one thing to think about is
from everything you've learned about
assembly and CPUs does the CPU have a
way of determining
this no and this actually is a good
thing so uh anybody know how so
JavaScript we looked at JavaScript right
how does your browser
execute that
JavaScript yeah so it has a JavaScript
engine that um used to be JavaScript was
really slow because it would interpret
each line essentially so it go through
and do whatever it needed to get done
but as it became clear that JavaScript
performance was incredibly important
they do things like what they call just
in time so jit compilation where they
figure out oh we're executing this code
a lot which means it's very important
which means I'm going to take that code
compile it to x86 put it in memory and
then start executing just that code and
so now it's executing um x86
instructions instead of interpreting it
which is incredibly fast and you get
insane speed UPS this is why JavaScript
engines are so fast now because they use
all these crazy tricks and the way
they're able to do that is because of
this architecture they can dynamically
create code x86 instructions at runtime
and execute that so you can think that
actually gives you a lot more power I
mean it enables powerful things to be
able to do that in this vuman
architecture so it's not something that
anybody would really want to do and say
hey let's fix this fundamental problem
and how tell the CPU ahead of time
what's code and what's data because we
actually want these this thing in our
applications we want to be able to do
that
so
it's a weird
example okay anyways
the one
of I
see
sorry I'm trying to understand what this
is trying to get at but uh that makes
sense oh oh oh I see ah okay wow that's
a weird example okay
so I guess we can execute this
example
please tell me I have a dojo spawn up
yeah okay cool
[Music]
so ah I already have an example that
see okay so here's my program let's just
run this so we have to run it with
special compilation options which gets
to some things I'll talk about
don't tell me things are
dangerous so I'm seeing weird Behavior
right I'm running it and I'm sometimes
seeing helloa and I'm sometimes seeing
illegal instructions let's look at the
code so the code
here if we look at the main function
we have some fixed character array so a
buffer of 10 24 bytes on the stack we
then call the gets function with that so
gets if you're not familiar uh this does
reads from standard input and puts the
data wherever we send it so it's going
to put all of our input at name here and
then specifically what it's going to
do uh gets is really bad if you actually
noticed uh when we we were
compiling here it actually told us
that should have told us tells us that
the gets function is dangerous and
should not be used and if we look at the
man page that's because it reads a line
from sandard input into the buffer
pointed by S until either a terminate
new line or end of file which it replac
with a null bite no check for buffer
overruns is performed this means that it
will it has no idea what size this
character array is and it will keep
writing whatever the user's input is and
because you cannot know in advance how
much data will be sent this is
fundamentally an insecure function but
let's look back at this so we read in to
name 1024
bytes we then uh seed random based on
the time this just sets up we're setting
up a random based on time and now we say
if random mod 2 so what's the mod two
going to do
even or odd so roughly 50% of the time
we'll do this otherwise we'll do this
and so what we do here is say hello we
call the hello function passing in name
is the first parameter by two is the
name one so that's when we passed in a
and we saw farewell it said hello a and
then said farewell which was what we saw
but 50% of the time it crashed and if we
look here it says it passes in as name
Name by one and it passes in as n as by
Funk which is the function here the name
so what that's what that's going to do
is start trying to execute code on the
stack let's look at this in
GDB that's not
right wait do I not have my okay I can't
I can't live like
this there we
go sorry I need to use uh I don't need
to but it's way better for me to use
Jeff so we can see
things okay so let's look at the code
here x20i so we're look at
instructions I want to stop so let's
break it hello because that's where
we'll be uh
is that function call and then we can
bring up
the here no here the
code
so so
continue uh what do you want to
say blah blah
blah okay now we call
hello and we know based on the
uh
so we can step through here uh what's
the calling Convention of x86
64 how do I know in which of these
registers is which
arguments I actually can't remember I
think it's RSI RDI but is that right
actually maybe RDI RSI I was hoping
someone would
know
we'll look it
up yeah RDI RSI so I had it backwards
RDI RSI RDX rcx cool so
RDI which is name has this which is the
address of by 2 and
RDI wait I said that the wrong way RDI
which is the first argument name is our
string blah blah blah our SI the second
argument the function we're going to
call is here here so if we step through
this we're setting up the function frame
doing some stuff calling the print F so
we're calling print F and passing in
this argument to blah blah blah that's
where we see hello space blah blah
blah so we should see that up here hello
blah blah blah blah blah then keeping
going we see a call to
RDX x5i let's look at what this is this
is by two so if we look back at the code
we would see
that we will see that we are here at buy
two so this will after we go here this
will go into buy two and it will say
farewell so let's run it
again okay now I'll have to run this I
guess 50% of the time
okay uh
rerun
okay is this
gonna be very
annoying okay well there's an easy way
to fix that and that's what I was just
telling somebody else when you control
the thing you can do whatever you
want
boom if you don't like it change the
code okay compile it GDB
it break
hello okay so I'll type in csse
365 okay now we're calling this
function and RDI what we're going to
Output is here by one but now let's say
we've somehow tricked it into pass we're
passing in a pointer to a function that
we're going to call but that's actually
the buffer that we have on the stack
that we were just reading characters
in oh no
what what are the
odds container gets killed right in the
middle did you do that on purpose
Conor
okay
okay now here we are so now we've
accidentally as a programmer passed
in or we've tricked it into passing
in to swapping those two values so
passing in by one as our first argument
and the buffer on the stack so as we
step through we'll see the print F so so
we call the print F and if we look at
the output it will
say it definitely should
say oh I didn't uh sorry I stepped into
it so I'm gonna do fi to jump out of it
Finn and it says hello blah blah blah
blah blah what's this blah blah blah
blah
blah it's not it's garbage in the sense
that not asky characters but
specifically what it is is it is if we
go here right what the program is doing
is it calls print F and passes as the
percent s the second argument to print F
so what's going to be interpreted as a
string is actually this byy one function
so if we examine this as a string it
will keep printing out these characters
until it gets to a n bite and so because
it doesn't know right again these
functions are very stupid right print F
says print me out a string take whatever
memory address I give you and just
output it until you get to a zero so
let's look at the call at the call here
we call
RDX and now we have this value on the
stack that came from
[Music]
us but it will be interpreted as
instructions and will be
executed so I can step into there and I
can actually see that we're actually
kind of executing some stuff until we
get to here we try to dreference RSI and
it blows up because that's not valid
thing and that's why we get a seg
segmentation fall but if it's executing
some code that comes from
us do you know how to create bytes that
the computer can interpret as x86 64
instructions to do what you
want yes because you had a whole module
writing assembly code you've written a
web server and assembly code you've read
code written code right that's what
we've been building up for because
that's now at this moment you've tricked
the computer into interpreting your data
as
code cool so essentially what this is
doing is it's actually jumping back to
our code on the stack because that's
where that buffer existed in the
function and just executing and
interpreting those bites that it got
from us as
code
okay do we want to make it do
something we'll get there in a second
okay but and this is an incredibly old
concept so this is actually the um
Morris internet worm was one of the
earliest uh this actually took down the
whole internet they um because there was
a a bug in the replication strategy of
this
um in the replication strategy of this
worm where it was supposed to look if it
was already running and if it was it
would like kill itself but there was
problems in that so this worm would just
infect machines and then get on those
machines and then look for other
machines and infect those machines and
there would be so many copies of this
worm running that it would slow down the
machine to where it was unusable um and
so it actually used a lot of different
attack vectors it's really cool to look
this up uh but in in this finger D
service this uh used this shell coat
injection the other crazy thing is this
worm was I think cross system and cross
architecture compatible so it would like
had its own Shell Code that it would
compile for the Target architecture and
then go there it was insane and they
literally had to shut down the internet
so they had to they had they distributed
patches for the whatever the services
that were running and they all had to
like shut down their machines because if
one like if a couple machines were
infected those would spend so much time
trying to look for other infected
machines that would slow those machines
down so they had to like shut everything
down disconnect them update their own
local copies of stuff and then turn them
back on so that the internet could work
um it gets even crazier if you look into
this uh the person who did this RTM he's
actually I think a professor at MIT was
or still is um and at the time he was a
grad student his dad was also I think
the director of the NSA at the time um
so it's like really uh anyway super
interesting
um so this is like a fundamental con
things that we're learning here
okay cool so how do we write Shell Code
you actually already have a very
intuitive understanding of this because
you've been writing assembly code that
you can turn into bytes uh that's one of
the key things that we've learned so
this is with the if you go all the way
back to when we were uh doing the
assembly module you gave the program
bytes that it took and executed
essentially you were writing little
Shell Code programs you just didn't
really know that yet um and so what we
actually want to do if we get to where
we're trying to
go shell
here has a very specific meaning it this
is what like a hacker terminology this
is like you're trying to pop a shell
means that you are trying to call execve
bsh so that that way a shell is now
running with the permissions of the
target
program so for instance on the dojo the
programs you know well actually I think
we have looked at this
since right so we we learned about set
uid in the access control module so this
means that it's owned by root so when it
executes it executes as root and so if
we can get it to execve vsh now we have
a shell as root and we can do whatever
we want
so that is our goal as attackers
and but there are some constraints so
think about
where we were here right think about
there's some user data on the stack and
then let's say we could we redirect
control flow onto our code one of the
key things is that Shell Code needs to
be position independent so it it has to
not matter where that code lives because
otherwise you don't know exactly where
it's going to be in memory and you can't
rely on any fixed layouts the other cool
thing is you can share Shell Code then
is there's all these repositories of
different Shell Code that does different
things that you can then
[Music]
reuse um cool okay
so so I had my hello let's
do uh shell code code.
s oh wait but if
I yeah there we go I need my prefix
there or let's do this actually this is
good so anybody remember what exit code
60 is I would bet it's
exit I actually don't remember how to
get all the output though
as ah there we go look at
that okay do test. S8
so cool
okay so this is like
ah okay nope that's not right anyways uh
okay we already saw this so test. s this
is some assembly code that probably I
wrote when we were doing these assembly
modules I have no idea this was so long
ago that it's out of my brain at this
point but we're moving one into
RDI 60 into Rax and executing a CIS call
and so using exactly what we did in the
assembly modules right compiling that to
an object file then using object copy to
copy that to a binary I now
have this binary file that's 16 bytes so
I had my hello that's reading from input
from
us
so by running that in I don't get a
Segal
anymore
why because I'm running real x86 code
not like a string that I had of csse
365 so let's debug it just to
check break hello
and then I can run it the cool thing is
you can do redirection here inside GDB
so here I'm running it and I'm saying
use this file ASM dobin as the standard
input run to here hello I can look at my
arguments uh RDI is by one RSI is this I
can double check x-5 I so and examine
five instructions here shows me move one
into RDI move 3 C into Rax CIS call I
can start doing next
instructions here until I get to the
call and now I can step and I can see
I'm actually on the stack this s fffff
this is somewhere on the stack we're
moving one into RDI we're moving 3C into
Rax and we're calling CIS call to exit
with error code one so now we've tricked
this program into executing x86 64 code
that we control of whatever we want
so
now if we wanted
to let's grab
[Music]
here cool okay so
now I want to
do
execve I want to call this CIS call how
do I do
this do you
remember CIS call table your friend the
CIS call table
exact v e is 59 oh we so
close Okay uh in here so move Rax
59 CIS call so that'll call the right
one now I need to get
uh
so now I'll need uh so RDI needs to be
string bin
sh R SI needs to be zero and R we said
it was RDX
right yeah
RDX needs to be zero so the zeros are
easy what's a way of zeroing at a
register without using a move
exor and our input to the program may be
limited when we did gets it read up
until a new line but our input it may
only get 12 16 bytes that we can trick
it to execute as code so uh one of the
reasons I use xor here is because it's
only one bite this is what I know from
experience where they're moving zero
into RDX takes I think four or five
bytes because it encodes the zero as
like four null bytes um so that's
actually if you really want to go you're
not I think you're only doing three
levels of shell coding but if you want
to get into it more further and further
levels add more and more restrictions to
your shell code like you can't use
certain characters you have to do it in
10 bytes or eight bytes or what's the
final one Connor do you remember it six
byes I think six by Shell Code um so it
forces you to get creative and
understand and be able to to do those
things okay so I exort RSI Rd RDX now I
need to get this string
so normally we did something like this
right was
it had to data
section have something like uh actually
can't remember how to do
this was it
asky sdz like this
yeah B
sh
I need to give it a
name let's make sure that
compiles that's shocking does that
actually
work okay we're not referencing it but
that's okay okay so then we do that and
then we want to
move into Rd I what was it like offset
of
bsh but I'm not sure yeah I don't know
either
but try it but then definitely look at
it to make sure it makes
sense wow is that
not
that's because uh of Shell Code okay
this makes sense of why we thought that
might blow up ah
see messed
up yeah but I think it adds the null
bite at the end which is
important yeah but it's saying it
doesn't exist so or unknown pseudo op I
could do the null bite myself that seems
Sil what was
it yeah good
job see to add the null bite ourselves
do we crazy people
okay let's make
sure okay cool so here's my input so
moving ah my offset definitely did not
work
um okay I'm gonna GP because I feel like
I did
this yeah move offset buff so
add
what why is it not Intel syntax this is
driv me
insane Ah that's
right I feel like you're just
tell this is like I feel like I'm just
dancing okay so the offset of is not
working this is what I'm double checking
is this in
here
uh okay let's
do is it something like this
yeah
oh there we go did that
work hey there we go okay so load
effective address so calculating the
current instruction pointer plus the
offset into there move that into RDI
clear out RSI clear out RDI move 3B into
Rax call CIS
call let's always before we just
randomly try something and decide if it
works or not I always like to debug it
first so let's break on
hello okay now here I can before I even
do anything I can double check this by
doing checking here so RSI I know is my
buffer so
x2i load effective address RP plus 5
plus F which is this address exor exor
CIS call and I can even check that
address make sure it's the string
bsh so let's step
through print F skip over that because I
don't care about you print F Now call
RDX step into there so now I can see
loading effective address into RDI so
RDI should now have the string if I look
at here RDI now points to the string
bsh xor RSI xor RDX move 3B into Rax CIS
call executing no Pro new program that
looks like
success this is a classic problem uh
so did it work or not
work it work but
it yeah let's look at this I think this
should help
illuminate okay so if we scroll up we
see our execve
bsh so this is exactly what we wanted
it's
executing and we could look at exactly
all these things step step step but the
key thing is it's reading from zero
which is standard input and it's getting
back zero why because the standard input
of this program is the output of cat ASM
bin so if there's no more in put to read
we gave it our whole file and it read it
all
so you can
um The Cheap Trick actually the best way
to do this this is why you use pone
tools because you can change it to
interactive and just interact with it
and not have to worry about this you can
just send the bytes you can uh write
your shell code in your python script in
pone tools assemble it and then send
those bytes along uh another the cheap
trick is to just add a so Dash here
means the command line so concatenate
sorry not the command line uh standard
input so first output assembly. bin and
then wait for input from the command
line from standard input and then write
that to standard output so what this
will first do is write out to assembly.
bin everything and then if I do things
like now I'm typing on here as if I'm
talking to that bsh command through the
cat
uh the other thing I noticed why was it
hanging here I typed in LS it didn't do
anything that's because gets reads until
a new
line so we didn't actually send it a new
line uh so we could figure that out and
then we could do things like
um how do I
do
anyways
cool so we just wrote little Shell Code
already and we can fundamentally do
whatever we want
so we'll check this Shell Code
out that's crazy this is like exactly
almost what we
did well I guess is do string implied do
ask EZ so it does the thing yeah see we
didn't even cheat and we got there
together as a group so exactly the same
code here effectively uh just slightly
different right
um so this
is uh how we put data in our code which
we already saw we can use string we can
use asky Z with one I uh we can useb to
put bytes directly in our code uh we can
this is another uh kind of classic
technique is having the data be part of
our instruction so we can move this is
you have to read it from right to left
because of endianness
SLB N I know 2f is a slash so I don't
know what the other ones are I'm just
guessing but if this is correct SLB i n
slsh well I miss mess up slsh and then
null bite so moving that into RBX
pushing RBX onto the stack now the btes
on the stack are the is the string and
so we can move RSP into RDI so now
because because RSP points to the start
of the stack so now we have our string
there on the
stack but we can also do anything so we
can we don't have to just execute a
shell we can have it let's say uh one of
the classic ones is a connect back Shell
Code so if you're executing a remote
system you can have it make a TCP
connection back to you and have a spawn
a shell that is listening to your input
on an IP port so you set up a thing
that's listening there and you can type
in commands it goes executes it and
tells you the response uh this example
is calling open
flag and then sending that file to file
descriptor one what's file descriptor
one
normally zero is standard
input standard output yes so send the
flag whatever is in that file the
scriptor to to standard output um and so
you can step through this but this is
exactly this should look very similar I
remember debugging with some of you in
recitation your assembly code it looked
very similar to this right doing or and
building a web server you're just doing
system calls this is exactly what shell
coding is you're just doing it for a
let's say to achieve exploitation rather
than to build a web
server
cool okay we don't need to go over this
because we have
that running it great if
you oh Dev standard in that's lame uh we
saw that anyways uh tools on here so you
can
use I guess should we do this same
example using pone tools would that be
useful to
show
okay all right and I'm going to cheat
and have my code up here uh I guess do
most of you use from pone import
Star
yeah I hate that but
fine uh okay so P equals uh
process so execute the hello
process um then so what we can
do and a way to do this is to write your
assembly code here now because it's
special pone tools you don't need to
have all this stuff at the top and
everything so all we're going to have is
this extra code so let's go
here so now this is a
string that exists so I can write my
code uh in as a python
string and to double check that this is
actually
working
let's I'm going to open up another
terminal open up a handy dandy IPython
to have it right here as I execute um
from
pone import
Star so let's try
this oh I see
because ASM oh but I shouldn't call it
ASM because isn't that the
function yeah
uh okay broke
it
yeah okay Shell Code well we will call
you Shell
Code all right there is an error and
you'd probably have to dig through you
can try to figure out what's going on
here but I can already see this -32 is
wrong we did not set up the context uh
context. Arch is that right equals x
a664 there's actually another really
cool way to do it um how is somebody
doing that do you remember from the
workshop we did where they said it based
on the process
Contex or Contex something like that
context. EXE
yeah let's see oh yeah okay I'm not
going to get into that
but let's set the architecture
correctly now when we assemble it now we
get our Shell Code
bytes
okay so that should be good we can even
check by I think we can do
disam I like to do this just to double
check and of course it prints we want to
print it out so I can again remember
it's exactly what I did before uh with
object dump right now I'm just doing it
in Python and using IPython to kind of
test that the little pieces of my script
are going to work okay so assemble it
and p. send line and I know I want to do
send line instead of send because it
gets is going to read until the end of
the
line okay and I'll do p.
interactive so now I have the terminal
here I can just interact with it pretty
cool
questions so you already have all the
skills you need to be able to do all
this stuff you've already been using
pone tools to interact with the process
to parse complex things you've learned
assembly I guess you don't even need me
to teach you anything
right they all laughed at me
okay okay but there are are some
problems that can occur um these are
things these are just more of a reminder
you may have forgotten this since you
have built a web server and assembly but
one thing is be very careful about the
size of the memory access that you're
using right so we all talked about that
the difference between accessing one by
versus two bytes versus four bytes
versus eight bytes right so you can do
it implicitly based on the size of the
register that you're using so BL versus
RBX it's going to be one by versus eight
bytes you can also specifically use
these
um
uh annotations I guess uh to specify to
the compiler that you want to move a
single bite so this is move bite pointer
or word pointer or dword pointer this is
being very explicit telling the compiler
compiler you only want to access one
bite um yeah like we talked about
so there was something I didn't show we
could have actually really messed up our
Shell Code uh and it could have been
very annoying if there was what what
would have happened if there was a new
line in our Shell
Code it would read Because gets reads a
line so it would read up until that new
new line and then stop reading the rest
of our Shell Code and only execute half
of our
code um actually let's look at
that
we can easily simulate that let's say in
here there was a DOT
BTE hex1 is a new line
character yeah so instead of getting a
shell now I get a segmentation fall and
the reason
is well if we looked in here we would
see that this new line This 10 is
actually causing it to only read in part
of our input we don't we won't see the
sing let's dou
check okay let's read from
here it didn't readed that
in why did it read that
in H ah I was wrong it's 10 in decimal
not 10 in HEX see this is why
I you have to double check your
assumptions I could have just assumed
that all day long Okay so let's look at
our so load that and then we can
see and this will drive you crazy if
this happens to you that your string
isn't even in there so it's hard to
see that half of your input didn't even
make it in and that's because it's not
that the program necessarily forbid a
new line character uh hex a it's the
fact that by reading and using gets
reads to the end of a line in a new line
so you can't have any new lines and so
this is why uh being careful about these
things if I was really good in my python
script I would have called an assert and
I would have asserted that in my shell
code there are no new lines that way my
python script blows up rather than
waiting and having my payload not work
and then having to debug the remote
system so this is why depending on how
the the program is Reading in your input
um for instance string copy can't have a
a null bite whereas scanf gets gets line
F gets can have no bytes but can't have
new lines
um scan F also uh goes to a white space
so you can't have sometimes a hex 20
which is the space character or tabs um
often times and this can get very fun is
your shell code can be mangled or
changed and right because it's input
from you the program May operate on that
input and then you corrupt something and
redirect control flow to your data so it
could be compressed or uncompressed or
encrypted or decrypted so the trick is
to work backwards so start with what you
want the Shell Code to look like and
just like you did in the reverse
engineering modules you started from the
key that you wanted very similarly you
can start from the Shell Code you want
try to work backwards
um sometimes there may be parts of the
input like let's say it takes your input
and then right in the middle it writes
some text file or some input that you
can't
control um you can do if you know that
and you should know that by
understanding the program you can use
tricks like jump so you can execute part
of your shell code and then jump over
just like in the assembly module when
you had those knops the knops of like 53
bytes that you jumped over it's the
exact same tricks that you can use to
write Shell Code that can survive being
overwritten
um other tricks uh you know if we
control standard input and standard
output then we can get a shell or get it
to give us the flag but sometimes we may
not be able to read the flag back maybe
the program closes standard input and
standard output maybe uh it's a remote
system and so running a shell doesn't
make sense and we can't do a reverse
shell and
so what we can do is use things you can
use tricks just like you're learning now
in web applications of doing Blind SQL
injections you can do similar techniques
using shell coding you can do timing
attacks so you can check the value of a
bite and sleep for a certain amount of
time and you can write a script that
does that um so there's all kinds of
cool things
there other things to remember is that
your code is being executed in the
context of the program and the program
has a bunch of registers and a bunch of
data that's already in location so as
you think about uh shrinking things you
can actually think about do we need a
shell can we put the flag somewhere else
in some other file that's already open
uh do you need to communicate the flag
in band uh so you need to think about
all of these things and with
that you'll be
great good stuff