thanks for coming back hope you enjoyed
your coffee next uh presentation is Mr
Roland
so good morning everyone
my name is Roland night
I'm a PhD student from the crazy slab
the I.T security research group of the
University
of technology and economics Budapest
and today I will talk about how we are
fuzzing trusted applications via shared
memory
first I will talk a bit about trusted
applications what they are how they work
why they are good for us then little
Basics on fuzzing in case any of you is
not familiar with it
then I will tell you how we emulated our
trusted application
and finally
how we wrote Our custom fuzzer
and
before we proceed any further I must
warn you that all that I'm going to tell
you today is work in progress
so
so please tune your expectations
accordingly
so first trusted applications
they are special pieces of software
executed by trusted execution
environments
they are digitally signed and of course
this signature is verified before
execution
and they are isolated from normal words
applications
usually by some Hardware feature which
in our case will be armed trust Zone
and their integrity protection and
isolation make them ideal for
implementing security critical
applications like
certain cryptographical functions
Financial applications or digital Rights
Management related stuff
so first arm trust Zone it is a harder
feature implemented in arm cores of
course
our CPUs often contain register called
the
security configuration register
which includes a so-called non-secure
bit and depending on the value of this
bit
certain memory regions and Hardware
elements
can or cannot
be used by the CPU this is enforced by
the system bus
and by the value of this bit we can
partition the execution into a so-called
normal world where we usually have Linux
or Android
and the so-called secure world
where is our trusted execution
environment Opti
so Opti stands for open source portable
T it is ported to more than 50 iot
platforms
and
it's mainly an operating system for the
secure world but it has additional
components as well
like it has a driver for it
the normal word in the Linux care now
and things like that and
Opti Works in a way that normal
applications can request the execution
of trusted apps by calling the library
function
which we'll call the T driver in the
kernel then a so-called secure monitor
core will be executed the context switch
happens and from that point optivia run
and it will execute the requested
trusted application
and of course as I said previously
trusted apps are Integrity checked and
they are loaded to those sections of the
memory that are cannot be accessed from
the normal word
so when we decided to fast trust the
applications we had a very specific one
in mind
which we developed a little earlier
and we created this to perform root key
detection checks on the Linux kernel
it consists of several integrity and
consistency checks it's approximately
four thousand and five hundred lines of
C code so it's a medium-sized project
and it uses four Services implemented in
The Trusted kernel think of them as
something like loadable karna modules
for Linux except that they are not
loadable but they are compiled into the
trusted care now
and the checks executed by our
application can be divided to three
sections plus an initialization phase
and we plan to fast this separately a
bit later I will tell you why
so
uh
first we have our initialization phase
here we compute a set of reference
hashes what we later used by the other
sections
then we check function pointers in the
layer quad virtual file system of the
Linux kernel which is responsible for
hiding differences between file system
drivers
then we check data structures holding
information about tasks tasks are
basically how the Linux care analysis
threads or processes
after that we have a bunch of
General Integrity checks like we check
if someone modified the code of the
kernel or any of the system was very
replaced and things like that
then we check files for persistent
rootkit components and finally we have
checks targeting various layers of the
network stack
so next
next bit about fuzzing
fuzzing is a form of automated security
testing
and the basic idea is to execute our
application with random or semi-random
test cases
it is highly effective because it can be
excellently parallelized
and if we have access to the source code
then certain compiler instrumentations
can even further improve buzzing
of course it has some limitations as
well like reaching codes in many nasty
divs for example might be complicated
and monitoring the application to detect
crashes
can be problematic as well especially in
the iot domain
so
I wrote this image to explain the
general workflow of a fuzzer
so first we have our input files they
are placed in a queue
then we have our executable and
first we pick one input file from the
queue mutate it somehow like
replace a byte with something random
flip a bit or append some chunk to the
end of file things like that
then we execute our application with
this mutated input
and of course we monitor it to detect if
we could crash it
if we could then the crashes of course
reported to the user and the input that
caused the crash is saved for later
analyzes
and if the input is considered to be
interesting then it's placed back in the
queue and
it starts all over again
so uh
in the image I showed you it was about
how we use input files but our
application doesn't take its input from
files but it reads its input directly
from the memory
so the question is how we fast this kind
of application
well we originally developed it in a
quemo based environment
so we can
quite easily manipulate its memory
and the basic idea is let's just
mutate the memory as it is
well the problem is that it is used by
the Linux scanner and the kernel
wouldn't be very happy if we just
started to randomly overwrite things in
its working memory
so we would probably have a lot of
crashes and most of them would be
relevant
so this is not the way
next idea was to Let's fake everything
else into an other unused region of
memory like just copy everything and
modify the application to read from that
this is feasible but to do so we would
need to change the application a lot
and we would like to avoid that because
the more we modify the application
to be testable the less we actually test
the application we want
so since the kernel is the root of all
our problems then let's get rid of the
kernel
well the problem is that Optus
the T running our application uses the
kernel as well
so it wouldn't work without the care now
as well
also trusted apps cannot be executed on
regular systems for a bunch of reason
even if we wrote a wrapper to execute it
and even if we executed it on an arm six
arm 64 computer then we still have the
problem that it uses a custom system
quotes like the system course doesn't
match the ones used by the Linux scanner
and here comes Marcel's eiberts last
year activity talk where he showed us
that it is possible to emulate trusted
applications
and to do so he used an emulation
framework called killing
and that's what we will do as well
so of course there are pros and cons of
emulation
Pros are that we can execute our trust
step in Parts only it also gives us
coverage information regarding what
parts of the code we actually executed
and it is quite trivial to identify
crashes in this setup since if our
trusted app does something naughty then
the emulation Frameworks will simply
throw us an exception
of course there are downsides as well
like we need to implement a bunch of
system cores used by our application
also there are the services I mentioned
earlier that we use those need to be
modded as well
and some Library functions will require
special attention as well
so with system course we are quite lucky
because in killing it is quite easy to
hook them we just need to implement the
desired functionality
in a python function and by calling
another function we can add a framework
that when this system core happens I
want you to execute this python function
here you can see a list of the system
calls we implemented so far fully or
partially in functionality these variety
from logging to session management up to
Secure Storage management
secular storage is by the way a
mechanism provided by the T so the
trusted apps can store data
persistently in an Integrity protected
encrypted and drawback protected way we
use this to store reference issues by
the way
then I said we have Services used by our
application
well if we are not running the whole
application but execute it in parts then
we only need to implement two of the
four services
and calling these services are done by
System codes as well
so we had to implement four commands
executed
three of them are to produce hashes
which
didn't really require much attention
because we need to patch these hashtags
out of our application anyway
I know I said earlier we don't want to
modify our application but at this point
we don't really have a chance if we want
to reach code Beyond these checks
and the fourth of these commands is to
read physical memory the memory of the
Linux kernel
and a bit later I will tell you how we
implemented this and why it was a bit
tricky
but first I've said there are some
Library functions
well luckily when trusted applications
are compiled the functions we used in
the codes are all compiled into the
application so we don't need to mock any
of them
but some initialization needs to be done
since
optios is a lot different from
other operating systems like Linux or
Android
the implementation of the Heap differs
as well
in this special case it's the Heap is
actually
placed into the BSS segment of our
application which is used to store
Global uninitialized variables
so we so when we just simply call a
molok for example from our application
then it will return out of memory
because as far as it knows there is no
stack well no Heap so we need to test on
how the application that yes there is a
heap and it is there in the BSS segment
and please use that
we need to call this function
to do so and here the emulation
framework is useful again because it can
create snapshots
from the execution state of our
application so we only need to perform
this initialization once
then we can execute our application with
random input and then we can roll back
to this snapshot and execute it with a
different input so it makes our file
sync a lot faster
and finally how we implement it
are faster
so
so fuzzers need valid example inputs to
mutate like I showed you the files in
the example
like we can get a valid example inputs
by dumping memory image from quemo but
there are problems with it
first of all it's too big
fuzzers don't really like huge input
files for example the manual of AFL the
most well-known fuzzler states that
please please try to keep your input
file below one kilobyte
well with a full memory image we can't
do this
and also our input file is quite sparse
in the nature that we don't read the
whole input file only parts of it
and even from the parts we read we don't
parse all of them
so as you can see in this image if we
for example mutate it here
and we don't read that part of the file
then it was useless it's like if we did
nothing
then again if we mutate in a part that
we read but do not parse then again it
was a useless mutation
so we need to handle this problem
somehow to avoid a lot of useless work
so mutating the whole
input file as one is ineffective
so we came up with the solution to
we take and we take a dump from cuermo
and then we Implement our read memory
function in a way that
it will read the requested data from the
unmodified input file
and that will be mutated but first we
apply a mask on it to guide the fuzzer
to avoid useless mutations
and this image is supposed to explain
what I've just told we have our
application
it attempts to read this structure from
the memory then the killing framework
takes the execution
reads the requested data from the dump
then a mask
is added to that
and the masked data is given to the
mutation engine which will only mutate
those parts that are allowed to be
mutated by our mask so this way we can
avoid a lot of useless work
and earlier I mentioned that
The Killing framework can give us
coverage information meaning that it can
tell us which parts of our application
were executed
this is useful because this way we can
Implement coverage guided fasting where
the basic idea is that
um
those inputs that make more parts of the
code executed are better because they
have a bigger chance to
through gear crashes
and here you can see the basic algorithm
to implement coverage guided fuzzing
first we have a set
of interesting inputs which initially
only contains the test cases we added to
the fuzzer we also have a set to store
the already discovered code blocks
and then in the loop we choose one from
this set of interesting inputs we
mutated somehow then execute our
application with it and then we get
coverage data
and if we discover that these inputs
could
reach those parts of the code that we
haven't discovered yet
then we consider this to be an
interesting input we add it back to the
queue and updates the set of four
editing code blocks
most fathers by default know how to do
this but due to our special needs at
input generation we had to implement
this for ourselves
which we could do and which we did
except for once more detail
we still need to choose a strategy about
how to choose an input from the queue of
the interesting ones
and finally
I would like to summarize all this
most importantly we didn't find any bugs
yet
hopefully we will
the earlier mentioned
five plus one sections of our
applications are
three of them are already implemented or
three of them can already be executed in
the emulator
the other two and the init sections are
still work in progress
and
we have we already have a lot of code to
Implement some system codes and do some
deep initialization
when these will reach more major States
we plan to open source this also others
can fast their trusted applications as
well
as I said we almost completely
implemented coverage guided passing
and we found a solution to fuzz
applications that take their inputs from
memory even if this input is quite
sparse in nature
and finally I must thank to the setted
projects which financed this work
and that's all please feel free to ask
questions
thank you very much
[Applause]