1
00:00:00,000 --> 00:00:09,804
preroll music
2
00:00:09,804 --> 00:00:24,745
Herald: Our next speaker for today is a
computer science PhD student at UC Santa
3
00:00:24,745 --> 00:00:30,805
Barbara. He is a member of the Shellfish
Hacking Team and he's also the organizer
4
00:00:30,805 --> 00:00:35,816
of the IECTF Hacking Competition. Please
give a big round of applause to Nilo
5
00:00:35,816 --> 00:00:36,228
Redini.
6
00:00:36,228 --> 00:00:39,510
applause
7
00:00:39,510 --> 00:00:46,671
Nilo: Thanks for the introduction, hello
to everyone. My name is Nilo, and today
8
00:00:46,671 --> 00:00:52,330
I'm going to present you my work Koronte:
identifying multi-binary vulnerabilities
9
00:00:52,330 --> 00:00:56,486
in embedded firmware at scale. This work
is a co-joint effort between me and
10
00:00:56,486 --> 00:01:02,101
several of my colleagues at University of
Santa Barbara and ASU. This talk is going
11
00:01:02,101 --> 00:01:08,247
to be about IoT devices. So before
starting, let's see an overview about IoT
12
00:01:08,247 --> 00:01:13,904
devices. IoT devices are everywhere. As
the research suggests, they will reach the
13
00:01:13,904 --> 00:01:19,762
20 billion units by the end of the next
year. And a recent study conducted this
14
00:01:19,762 --> 00:01:25,769
year in 2019 on 16 million households
showed that more than 70 percent of homes
15
00:01:25,769 --> 00:01:31,836
in North America already have an IoT
network connected device. IoT devices make
16
00:01:31,836 --> 00:01:37,660
everyday life smarter. You can literally
say "Alexa, I'm cold" and Alexa will
17
00:01:37,660 --> 00:01:43,573
interact with the thermostat and increase
the temperature of your room. Usually the
18
00:01:43,573 --> 00:01:49,610
way we interact with the IoT devices is
through our smartphone. We send a request
19
00:01:49,610 --> 00:01:55,164
to the local network, to some device,
router or door lock, or we might send the
20
00:01:55,164 --> 00:02:01,139
same request through a cloud endpoint,
which is usually managed by the vendor of
21
00:02:01,139 --> 00:02:07,290
the IoT device. Another way is through the
IoT hubs, smartphone will send the request
22
00:02:07,290 --> 00:02:13,663
to some IoT hub, which in turn will send
the request to some other IoT devices. As
23
00:02:13,663 --> 00:02:18,879
you can imagine, IoT devices use and
collect our data and some data is more
24
00:02:18,879 --> 00:02:23,376
sensitive than other. For instance, think
of all the data that is collected by my
25
00:02:23,376 --> 00:02:29,731
lightbulb or data that is collected by our
security camera. As such, IoT devices can
26
00:02:29,731 --> 00:02:37,081
compromise people's safety and privacy.
Things, for example, about the security
27
00:02:37,081 --> 00:02:44,330
implication of a faulty smartlock or the
brakes of your smart car. So the question
28
00:02:44,330 --> 00:02:53,126
that we asked is: Are IoT devices secure?
Well, like everything else, they are not.
29
00:02:53,126 --> 00:03:00,953
OK, in 2016 the Mirai botnet compromised
and leveraged millions of IoT devices to
30
00:03:00,953 --> 00:03:06,965
disrupt core Internet services such as
Twitter, GitHub and Netflix. And in 2018,
31
00:03:06,965 --> 00:03:13,294
154 vulnerabilities affecting IoT devices
were published, which represented an
32
00:03:13,294 --> 00:03:20,915
increment of 15% compared to 2017 and an
increase of 115% compared to 2016. So then
33
00:03:20,915 --> 00:03:27,710
we wonder: So why is it hard to secure IoT
devices? To answer this question we have
34
00:03:27,710 --> 00:03:33,635
to look up how IoT devices work and they
are made. Usually when you remove all the
35
00:03:33,635 --> 00:03:40,415
plastic and peripherals IoT devices look
like this. A board with some chips laying
36
00:03:40,415 --> 00:03:45,604
on it. Usually you can find the big chip,
the microcontroller which runs the
37
00:03:45,604 --> 00:03:50,535
firmware and one or more peripheral
controllers which interact with external
38
00:03:50,535 --> 00:03:57,188
peripherals such as the motor of, your
smart lock or cameras. Though the design
39
00:03:57,188 --> 00:04:03,445
is generic, implementations are very
diverse. For instance, firmware may run on
40
00:04:03,445 --> 00:04:08,775
several different architectures such as
ARM, MIPS, x86, PowerPC and so forth. And
41
00:04:08,775 --> 00:04:14,349
sometimes they are even proprietary, which
means that if a security analyst wants to
42
00:04:14,349 --> 00:04:20,041
understand what's going on in the
firmware, he'll have a hard time if he
43
00:04:20,041 --> 00:04:26,060
doesn't have the vendor specifics. Also,
they're operating in environments with
44
00:04:26,060 --> 00:04:30,563
limited resources, which means that they
run small and optimized code. For
45
00:04:30,563 --> 00:04:38,041
instance, vendors might implement their
own version of some known algorithm in an
46
00:04:38,041 --> 00:04:45,265
optimized way. Also, IoT devices manage
external peripherals that often use custom
47
00:04:45,265 --> 00:04:51,245
code. Again, with peripherals we mean like
cameras, sensors and so forth. The
48
00:04:51,245 --> 00:04:57,479
firmware of IoT devices can be either
Linux based or a blob firmware, Linux
49
00:04:57,479 --> 00:05:03,127
based are by far the most common. A study
showed that 86% of firmware are based on
50
00:05:03,127 --> 00:05:07,900
Linux and on the other hand, blobs
firmware are usually operating systems and
51
00:05:07,900 --> 00:05:15,010
user applications packaged in a single
binary. In any case, firmware samples are
52
00:05:15,010 --> 00:05:20,020
usually made of multiple components. For
instance, let's say that you have your
53
00:05:20,020 --> 00:05:26,410
smart phone and you send a request to your
IoT device. This request will be received
54
00:05:26,410 --> 00:05:33,190
by a binary which we term as body binary,
which in this example is an webserver. The
55
00:05:33,190 --> 00:05:37,990
request will be received, parsed, and then
it might be sent to another binary code,
56
00:05:37,990 --> 00:05:43,150
the handler binary, which will take the
request, work on it, produce an answer,
57
00:05:43,150 --> 00:05:48,130
send it back to the webserver, which in
turn would produce a response to send to
58
00:05:48,130 --> 00:05:54,100
the smartphone. So to come back to the
question why is it hard to secure IoT
59
00:05:54,100 --> 00:06:01,060
devices? Well, the answer is because IoT
devices are in practice very diverse. Of
60
00:06:01,060 --> 00:06:05,890
course, there have been various work that
have been proposed to analyze and secure
61
00:06:05,890 --> 00:06:11,500
firmware for IoT devices. Some of them
using static analysis. Others using
62
00:06:11,500 --> 00:06:15,910
dynamic analysis and several others using
a combination of both. Here I wrote
63
00:06:15,910 --> 00:06:19,690
several of them. Again at the end of the
presentation there is a bibliography with
64
00:06:19,690 --> 00:06:28,990
the title of these works. Of course, all
these approaches have some problems. For
65
00:06:28,990 --> 00:06:33,850
instance, the current dynamic analysis are
hard to apply to scale because of the
66
00:06:33,850 --> 00:06:39,430
customized environments that IoT devices
work on. Usually when you try to
67
00:06:39,430 --> 00:06:45,400
dynamically execute a firmware, it's gonna
check if the peripherals are connected and
68
00:06:45,400 --> 00:06:49,780
are working properly. In a case where you
can't have the peripherals, it's gonna be
69
00:06:49,780 --> 00:06:55,390
hard to actually run the firmware. Also
current static analysis approaches are
70
00:06:55,390 --> 00:07:00,580
based on what we call the single binary
approach, which means that binaries from a
71
00:07:00,580 --> 00:07:05,620
firmware are taken individually and
analysed. This approach might produce many
72
00:07:05,620 --> 00:07:11,530
false positives. For instance, so let's
say again that we have our two binaries.
73
00:07:11,530 --> 00:07:17,320
This is actually an example that we found
on one firmware, so the web server will
74
00:07:17,320 --> 00:07:22,990
take the user request, will parse the
request and produce some data, will set
75
00:07:22,990 --> 00:07:27,430
this data to an environment variable and
eventually will execute the handle binary.
76
00:07:27,430 --> 00:07:33,670
Now, if you see the parsing function
contains a string compare which checks if
77
00:07:33,670 --> 00:07:37,930
some keyword is present in the request.
And if so, it just returns the whole
78
00:07:37,930 --> 00:07:43,780
request. Otherwise, it will constrain the
size of the request to 128 bytes and
79
00:07:43,780 --> 00:07:51,790
return it. The handler binary in turn when
spawned will receive the data by doing a
80
00:07:51,790 --> 00:07:59,380
getenv on the query string, but also will
getenv on another environment variable
81
00:07:59,380 --> 00:08:04,060
which in this case is not user controlled
and they user cannot influence the content
82
00:08:04,060 --> 00:08:10,480
of this variable. Then it's gonna call
function process_request. This function
83
00:08:10,480 --> 00:08:16,690
eventually will do two string copies. One
from the user data, the other one from the
84
00:08:16,690 --> 00:08:22,930
log path on two different local variables
that are 128 bytes long. Now in the first
85
00:08:22,930 --> 00:08:28,360
case, as we have seen before, the data can
be greater than 128 bytes and this string
86
00:08:28,360 --> 00:08:33,460
copy may result in a bug. While in the
second case it will not. Because here we
87
00:08:33,460 --> 00:08:40,810
assume that the system handles its own
data in a good manner. So throughout this
88
00:08:40,810 --> 00:08:45,550
work, we're gonna call the first type of
binary, the setter binary, which means
89
00:08:45,550 --> 00:08:50,530
that it is the binary that takes the data
and set the data for another binary to be
90
00:08:50,530 --> 00:08:57,700
consumed. And the second type of binary we
called them the getter binary. So the
91
00:08:57,700 --> 00:09:01,570
current bug finding tools are inadequate
because other bugs are left undiscovered
92
00:09:01,570 --> 00:09:08,080
if the analysis only consider those
binaries that received network requests or
93
00:09:08,080 --> 00:09:12,750
they're likely to produce many false
positives if the analysis considers all of
94
00:09:12,750 --> 00:09:19,410
them individually. So then we wonder how
these different components actually
95
00:09:19,410 --> 00:09:23,430
communicate. They communicate through what
are called interprocess communication,
96
00:09:23,430 --> 00:09:28,890
which basically it's a finite set of
paradigms used by binaries to communicate
97
00:09:28,890 --> 00:09:36,660
such as files, environment variables, MMIO
and so forth. All these pieces are
98
00:09:36,660 --> 00:09:42,150
represented by data keys, which are file
names, or in the case of the example
99
00:09:42,150 --> 00:09:49,440
before here on the right, it's the query
string environment variable. Each binary
100
00:09:49,440 --> 00:09:53,280
that relies on some shared data must know
the endpoint where such data will be
101
00:09:53,280 --> 00:09:57,540
available, for instance, again, like a
file name or like even a socket endpoint
102
00:09:58,080 --> 00:10:02,910
or the environment variable. This means
that usually, data keys are coded in the
103
00:10:02,910 --> 00:10:10,770
program itself, as we saw before. To find
bugs in firmware, in a precise manner, we
104
00:10:10,770 --> 00:10:14,100
need to track how user data is introduced
and propagated across the different
105
00:10:14,100 --> 00:10:22,680
binaries. Okay, let's talk about our work.
Before you start talking about Karonte, we
106
00:10:22,680 --> 00:10:27,930
define our threat model. We hypotesized
that attacker sends arbitrary requests
107
00:10:27,930 --> 00:10:33,360
over the network, both LAN and WAN
directly to the IoT device. Though we said
108
00:10:33,360 --> 00:10:38,640
before that sometimes IoT device can
communicate through the clouds, research
109
00:10:38,640 --> 00:10:42,690
showed that some form of local
communication is usually available, for
110
00:10:42,690 --> 00:10:50,040
instance, during the setup phase of the
device. Karonte is defined as a static
111
00:10:50,040 --> 00:10:54,270
analysis tool that tracks data flow across
multiple binaries, to find
112
00:10:54,270 --> 00:11:00,690
vulnerabilities. Let's see how it works.
So the first step, Karonte find those
113
00:11:00,690 --> 00:11:04,590
binaries that introduce the user input
into the firmware. We call these border
114
00:11:04,590 --> 00:11:09,180
binaries, which are the binaries, that
basically interface the device to the
115
00:11:09,180 --> 00:11:15,570
outside world. Which in the example is our
web server. Then it tracks how a data is
116
00:11:15,570 --> 00:11:20,760
shared with other binaries within the
firmware sample. Which we'll understand in
117
00:11:20,760 --> 00:11:25,170
this example, the web server communicates
with the handle binary, and builds what we
118
00:11:25,170 --> 00:11:30,630
call the BDG. BDG which stands for binary
dependency graph. It's basically a graph
119
00:11:30,630 --> 00:11:39,720
representation of the data dependencies
among different binaries. Then we detect
120
00:11:39,720 --> 00:11:45,360
vulnerabilities that arise from the misuse
of the data using the BDG. This is an
121
00:11:45,360 --> 00:11:52,650
overview of our system. We start by taking
a packed firmware, we unpack it. We find
122
00:11:52,650 --> 00:11:58,740
the border binaries. Then we build the
binary dependency graph, which relies on a
123
00:11:58,740 --> 00:12:04,800
set of CPFs, as we will see soon. CPF
stands for Communication Paradigm Finder.
124
00:12:04,800 --> 00:12:10,320
Then we find the specifics of the
communication, for instance, like the
125
00:12:10,320 --> 00:12:16,140
constraints applied to the data that is
shared through our module multi-binary
126
00:12:16,140 --> 00:12:20,550
data-flow analysis. Eventually we run our
insecure interaction detection module,
127
00:12:20,550 --> 00:12:26,040
which basically takes all the information
and produces alerts. Our system is
128
00:12:26,040 --> 00:12:32,430
completely static and relies on our static
taint engine. So let's see each one of
129
00:12:32,430 --> 00:12:37,320
these steps, more in details. The
unpacking procedure is pretty easy, we use
130
00:12:37,320 --> 00:12:42,600
the off-the-shelf firmware unpacking tool
binwalk. And then we have to find the
131
00:12:42,600 --> 00:12:47,730
border binaries. Now we see that border
binaries basically are binaries that
132
00:12:47,730 --> 00:12:54,150
receive data from the network. And we
hypotesize that will contain parsers to
133
00:12:54,150 --> 00:12:57,930
validate the data that they received. So
in order to find them, we have to find
134
00:12:57,930 --> 00:13:04,170
parsers which accept data from network and
parse this data. To find parsers we rely
135
00:13:04,170 --> 00:13:12,900
on related work, which basically uses a
few metrics and define through a number
136
00:13:12,900 --> 00:13:18,000
the likelihood for a function to contain
parsing capabilities. These metrics that
137
00:13:18,000 --> 00:13:22,470
we used are number of basic blocks, number
of memory comparison operations and number
138
00:13:22,470 --> 00:13:29,070
of branches. Now while these define
parsers, we also have to find if a binary
139
00:13:29,070 --> 00:13:34,110
takes data from the network. As such, we
define two more metrics. The first one, we
140
00:13:34,110 --> 00:13:39,480
check if binary contains any network
related keywords as SOAP, http and so
141
00:13:39,480 --> 00:13:45,240
forth. And then we check if there exists a
data flow between read from socket and a
142
00:13:45,240 --> 00:13:51,660
memory comparison operation. Once for each
function, we got all these metrics, we
143
00:13:51,660 --> 00:13:56,070
compute what is called a parsing score,
which basically is just a sum of products.
144
00:13:56,070 --> 00:14:01,710
Once we got a parsing score for each
function in a binary, we represent the
145
00:14:01,710 --> 00:14:07,680
binary with its highest parsing score.
Once we got that for each binary in the
146
00:14:07,680 --> 00:14:14,370
firmware we cluster them using the DBSCAN
density based algorithm and consider the
147
00:14:14,370 --> 00:14:18,240
cluster with the highest parsing score as
containing the set of border binaries.
148
00:14:18,240 --> 00:14:25,620
After this, we build the binary dependency
graph. Again the binary dependency graph
149
00:14:25,620 --> 00:14:29,790
represents the data dependency among the
binaries in a firmware sample. For
150
00:14:29,790 --> 00:14:35,430
instance, this simple graph will tell us
that a binary A communicates with binary C
151
00:14:35,430 --> 00:14:40,770
using files and the same binary A
communicates with another binary B using
152
00:14:40,770 --> 00:14:47,310
environment variables. Let's see how this
works. So we start from the identified
153
00:14:47,310 --> 00:14:53,010
border binaries and then we taint the data
compared against network related keywords
154
00:14:53,010 --> 00:14:58,320
that we found and run a static analysis,
static taint analysis to detect whether
155
00:14:58,320 --> 00:15:04,680
the binary relies on any IPC paradigm to
share the data. If we find that it does,
156
00:15:04,680 --> 00:15:09,360
we establish if the binary is a setter or
a getter, which again means that if the
157
00:15:09,360 --> 00:15:13,320
binary is setting the data to be consumed
by another binary, or if the binary
158
00:15:13,320 --> 00:15:20,520
actually gets the data and consumes it.
Then we retrieve the employed data key
159
00:15:20,520 --> 00:15:25,860
which in the example before was the
keyword QUERY_STRING. And finally we scan
160
00:15:25,860 --> 00:15:30,450
the firmware sample to find other binaries
that may rely on the same data keys and
161
00:15:30,450 --> 00:15:35,820
schedule them for further analysis. To
understand whether a binary relies on any
162
00:15:35,820 --> 00:15:42,510
IPC, we use what we call CPFs, which again
means communication paradigm finder. We
163
00:15:42,510 --> 00:15:52,290
design a CPF for each IPC. And the CPFs
are also used to find the same data keys
164
00:15:52,290 --> 00:15:56,280
within the firmware sample. We also
provide Karonte with a generic CPF to
165
00:15:56,280 --> 00:16:00,390
cover those cases where the IPC is
unknown. Or those cases were the vendor
166
00:16:00,390 --> 00:16:06,090
implemented their own versions of some
IPC. So for example they don't use the
167
00:16:06,090 --> 00:16:13,350
setenv. But they implemented their own
setenv. The idea behind this generic CPF
168
00:16:13,350 --> 00:16:19,740
that we call the semantic CPF is that data
keys has to be used as index to set, or to
169
00:16:19,740 --> 00:16:27,870
get some data in this simple example. So
let's see how the BDG algorithm works. We
170
00:16:27,870 --> 00:16:31,890
start from the body binary, which again
will start from the server request and
171
00:16:31,890 --> 00:16:38,250
will pass the URI and we see that here. it
runs a string comparison against some
172
00:16:38,250 --> 00:16:44,850
network related keyword. As such, we taint
the variable P. And we see that the
173
00:16:44,850 --> 00:16:52,800
variable P is returned from the function
to these two different points. As such, we
174
00:16:52,800 --> 00:16:57,180
continue. And now we see that data gets
tainted and the variable data, it's passed
175
00:16:57,180 --> 00:17:02,310
to the function setenv. At this point, the
environment CPF will understand that
176
00:17:02,310 --> 00:17:08,460
tainted data is passed, is set to an
environment variable and will understand
177
00:17:08,460 --> 00:17:13,680
that this binary is indeed the setter
binary that uses the environment. Then we
178
00:17:13,680 --> 00:17:18,540
retrieve the data key QUERY_STRING and
we'll search within the firmware sample
179
00:17:18,540 --> 00:17:28,066
all the other binaries that rely on the
same data key. And it will find that this
180
00:17:28,066 --> 00:17:29,880
binary relies on the same data key and
will schedule this for further analysis.
181
00:17:29,880 --> 00:17:37,020
After this algorithm we build the BDG by
creating edges between setters and getters
182
00:17:37,020 --> 00:17:45,150
for each data key. The multi binary data
flow analysis uses the BDG to find and
183
00:17:45,150 --> 00:17:51,270
propagate the data constraints from a
setter to a getter. Now, through this we
184
00:17:51,270 --> 00:17:56,610
apply only the least three constraints,
which means that ideally between two
185
00:17:56,610 --> 00:18:02,760
program points, there might be an infinite
number of parts and ideally in theory an
186
00:18:02,760 --> 00:18:06,690
infinite amount of constraints that we can
propagate to the setter binary to the
187
00:18:06,690 --> 00:18:11,790
getter binary. But since our goal here is
to find bugs, we only propagate the least
188
00:18:11,790 --> 00:18:17,040
strict set of constraints. Let's see an
example. So again, we have our two
189
00:18:17,040 --> 00:18:24,060
binaries and we see that the variable that
is passed to the setenv function is data,
190
00:18:24,060 --> 00:18:29,490
which comes from two different parts from
the parse URI function. In the first case,
191
00:18:29,490 --> 00:18:35,040
the data that its passed is unconstrained
one in the second case, a line 8 is
192
00:18:35,040 --> 00:18:40,470
constrained to be at most 128 bytes. As
such, we only propagate the constraints of
193
00:18:40,470 --> 00:18:49,980
the first guy. In turn, the getter binary
will retrieve this variable from the
194
00:18:49,980 --> 00:18:55,830
environment and set the variable query.
Oh, sorry. Which in this case will be
195
00:18:55,830 --> 00:19:03,390
unconstrained. Insecure interaction
detection run a static taint analysis and
196
00:19:03,390 --> 00:19:07,650
check whether tainted data can reach a
sink in an unsafe way. We consider as
197
00:19:07,650 --> 00:19:12,660
sinks memcpy like functions which are
functions that implement semantically
198
00:19:12,660 --> 00:19:19,050
equivalent memcyp, strcpy and so forth. We
raise alert if we see that there is a
199
00:19:19,050 --> 00:19:23,100
dereference of a tainted variable and if
we see there are comparisons of tainted
200
00:19:23,100 --> 00:19:31,620
variables in loop conditions to detect
possible DoS vulnerabilities. Let's see an
201
00:19:31,620 --> 00:19:37,260
example again. So we got here. We know
that our query variable is tainted and
202
00:19:37,260 --> 00:19:43,770
it's unconstrained. And then we follow the
taint in the function process_request,
203
00:19:43,770 --> 00:19:52,740
which we see will eventually copy the data
from q to arg. Now we see that arg is 128
204
00:19:52,740 --> 00:20:01,050
bytes long while q is unconstrained and
therefore we generate an alert here. Our
205
00:20:01,050 --> 00:20:04,980
static taint engine is based on BootStomp
and is completely based on symbolic
206
00:20:04,980 --> 00:20:09,750
execution, which means that the taint is
propagated following the program data
207
00:20:09,750 --> 00:20:14,430
flow. Let's see an example. So assuming
that we have this code, the first
208
00:20:14,430 --> 00:20:19,620
instruction takes the result from some
seed function that might return for
209
00:20:19,620 --> 00:20:25,755
instance, some user input. And in a
symbolic world, what we do is we create a
210
00:20:25,755 --> 00:20:33,630
symbolic variable ty and assign to it a
tainted variable that we call TAINT_ty,
211
00:20:33,630 --> 00:20:40,290
which is the taint target. The next
destruction X takes the value ty plus 5
212
00:20:40,290 --> 00:20:46,890
and a symbolic word. We just follow the
data flow and x gets assigned TAINT_ty
213
00:20:46,890 --> 00:20:54,300
plus 5 which effectively taints also X. If
at some point X is overwritten with some
214
00:20:54,300 --> 00:21:00,900
constant data, the taint is automatically
removed. In its original design,
215
00:21:00,900 --> 00:21:07,860
BootStomp, the taint is removed also when
data is constrained. For instance, here we
216
00:21:07,860 --> 00:21:11,880
can see that the variable n is tainted but
then is constrained between two values 0
217
00:21:11,880 --> 00:21:19,770
and 255. And therefore, the taint is
removed. In our taint engine we have two
218
00:21:19,770 --> 00:21:26,610
additions. We added a path prioritization
strategy and we add taint dependencies.
219
00:21:26,610 --> 00:21:32,430
The path prioritization strategy valorizes
paths that propagate the taint and
220
00:21:33,030 --> 00:21:39,030
deprioritizes those that remove it. For
instance, say again that some user input
221
00:21:39,030 --> 00:21:46,110
comes from some function and the variable
user input gets tainted. Gets tainted and
222
00:21:46,110 --> 00:21:51,180
then is passed to another function called
parse. Here, if you see there are possibly
223
00:21:51,180 --> 00:21:57,930
an infinite number of symbolic parts in
this while. But only 1 will return tainted
224
00:21:57,930 --> 00:22:05,490
data. While the others won't. So the path
prioritization strategy valorizes this
225
00:22:05,490 --> 00:22:09,990
path instead of the others. This has been
implemented by finding basic blocks within
226
00:22:09,990 --> 00:22:16,140
a function that return a nonconstant data.
And if one is found, we follow its return
227
00:22:16,140 --> 00:22:21,870
before considering the others. Taint
dependencies allows smart untaint
228
00:22:21,870 --> 00:22:26,310
strategies. Let's see again the example.
So we know that user input here is
229
00:22:26,310 --> 00:22:33,900
tainted, is then parsed and then we see
that it's length is checked and stored in
230
00:22:33,900 --> 00:22:40,755
a variable n. Its size is checked and if
it's higher than 512 bytes, the function
231
00:22:40,755 --> 00:22:48,210
will return. Otherwise it copies the data.
Now in this case, it might happen that if
232
00:22:48,210 --> 00:22:53,535
this strlen function is not analyzed
because of some static analysis input
233
00:22:53,535 --> 00:23:00,780
decisions, the taint tag of cmd might be
different from the taint tag of n and in
234
00:23:00,780 --> 00:23:07,380
this case, though, and gets untainted, cmd
is not untainted and the strcpy can raise,
235
00:23:07,380 --> 00:23:15,540
sorry, carries a false positive. So to fix
this problem. Basically we create a
236
00:23:15,540 --> 00:23:21,360
dependency between the taint tag of n and
the taint tag of cmd. And when n gets
237
00:23:21,360 --> 00:23:28,410
untainted, cmd gets untainted as well. So
we don't have more false positives. This
238
00:23:28,410 --> 00:23:33,330
procedure is automatic and we find
functions that implement streamlined
239
00:23:33,330 --> 00:23:40,140
semantically equivalent code and create
taint tag dependencies. OK. Let's see our
240
00:23:40,140 --> 00:23:48,240
evaluation. We ran 3 different evaluations
on 2 different data sets. The first one
241
00:23:48,240 --> 00:23:55,140
composed by 53 latest firmware samples
from seven vendors and a second one 899
242
00:23:55,140 --> 00:24:02,340
firmware gathered from related work. In
the first case, we can see that the total
243
00:24:02,340 --> 00:24:09,720
number of binaries considered are 8.5k,
few more than that. And our system
244
00:24:09,720 --> 00:24:15,900
generated 87 alerts of which 51 were found
to be true positive and 34 of them were
245
00:24:15,900 --> 00:24:21,960
multibinary vulnerabilities, which means
that the vulnerability was found by
246
00:24:21,960 --> 00:24:27,990
tracking the data flow from the setter to
the getter binary. We also ran a
247
00:24:27,990 --> 00:24:32,010
comparative evaluation, which basically we
tried to measure the effort that an
248
00:24:32,010 --> 00:24:37,260
analyst would go through in analyzing
firmware using different strategies. In
249
00:24:37,260 --> 00:24:41,280
the first one, we consider each and every
binary in the firmware sample
250
00:24:41,280 --> 00:24:49,050
independently and run the analysis for up
to seven days for each firmware. The
251
00:24:49,050 --> 00:24:57,390
system generated almost 21000 alerts.
Considering only almost 2.5k binaries. In
252
00:24:57,390 --> 00:25:04,020
the second case we found the border
binaries, the parsers and we statically
253
00:25:04,020 --> 00:25:11,070
analyzed only them, and the system
generated 9.3k alerts. Notice that in this
254
00:25:11,070 --> 00:25:15,630
case, since we don't know how the user
input is introduced, like in this
255
00:25:15,630 --> 00:25:21,120
experiment, we consider every IPC that we
find in the binary as a possible source of
256
00:25:21,120 --> 00:25:28,470
user input. And this is true for all of
them. In the third case we ran the BDG but
257
00:25:28,470 --> 00:25:33,060
we consider each binaries independently.
Which means that we don't propagate
258
00:25:33,060 --> 00:25:37,800
constraints and we run a static single
corner analysis on each one of them. And
259
00:25:37,800 --> 00:25:45,750
the system generated almost 15000 alerts.
Finally, we run Karonte and the generated
260
00:25:45,750 --> 00:25:55,230
alerts were only 74. We also run a larger
scale analysis on 899 firmware samples.
261
00:25:55,230 --> 00:26:01,380
And we found that almost 40% of them were
multi binary, which means that the network
262
00:26:01,380 --> 00:26:08,220
functionalities were carried on by more
than one binary. And the system generated
263
00:26:08,220 --> 00:26:16,620
1000 alerts. Now, there is a lot going on
in this table, like details are on the
264
00:26:16,620 --> 00:26:21,660
paper. Here in this presentation I just go
through some as I'll motivate. So we found
265
00:26:21,660 --> 00:26:27,360
that on average, a firmware contains 4
border binaries. A BDG contains 5 binaries
266
00:26:27,360 --> 00:26:34,050
and some BDG have more than 10 binaries.
Also, we plot some statistics and we found
267
00:26:34,050 --> 00:26:39,030
that 80% of the firmware were analysed
within a day, as you can see from the top
268
00:26:39,030 --> 00:26:46,350
left figure. However, experiments
presented a great variance which we found
269
00:26:46,350 --> 00:26:51,300
was due to implementation details. For
instance we found that angr would take
270
00:26:51,300 --> 00:26:56,220
more than seven hours to build some CFGs.
And sometimes they were due to a high
271
00:26:56,220 --> 00:27:01,650
number of data keys. Also, we found that
the number of paths, as you can see from
272
00:27:01,650 --> 00:27:09,480
this second picture from the top, the
number of paths do not have an impact on
273
00:27:09,480 --> 00:27:15,030
the total time. And as you can see from
the bottom two pictures, performance not
274
00:27:15,870 --> 00:27:23,610
heavily affected by firmware size.
Firmware size here we mean the number of
275
00:27:23,610 --> 00:27:29,610
binaries in a firmware sample and the
total number of basic blocks. So let's see
276
00:27:29,610 --> 00:27:35,190
how to run Karonte. The procedure is
pretty straightforward. So first you get a
277
00:27:35,190 --> 00:27:38,790
firmware sample. You create a
configuration file containing information
278
00:27:38,790 --> 00:27:45,150
of the firmware sample and then you run
it. So let's see how. So this is an
279
00:27:45,150 --> 00:27:51,450
example of a configuration file. It
contains the information, but most of them
280
00:27:51,450 --> 00:27:55,290
are optional. The only ones that are not
are this one: Firmware path, that is the
281
00:27:55,290 --> 00:28:00,300
path to your firmware. And this too, the
architecture of the firmware and the base
282
00:28:00,300 --> 00:28:07,170
address if the firmware is a blob, is a
firmware blob. All the other fields are
283
00:28:07,170 --> 00:28:12,381
optional. And you can set them if you have
some information about the firmware. A
284
00:28:12,381 --> 00:28:18,330
detailed explanation of all of these
fields are on our GitHub repo. Once you
285
00:28:18,330 --> 00:28:23,981
set the configuration file, you can run
Karonte. Now we provide a Docker
286
00:28:23,981 --> 00:28:28,666
container, you can find the link on our
GitHub repo. And I'm gonna run it, but
287
00:28:28,666 --> 00:28:41,402
it's not gonna finish because it's gonna
take several hours. But all you have to do
288
00:28:41,402 --> 00:28:53,225
is merely... typing noises just run it
on the configuration file and it's gonna
289
00:28:53,225 --> 00:28:57,630
do each step that we saw. Eventually I'm
going to stop it because it's going to
290
00:28:57,630 --> 00:29:02,537
take several hours anyway. Eventually it
will produce a result file that... I ran
291
00:29:02,537 --> 00:29:07,857
this yesterday so you can see it here.
There is a lot going on here. I'm just
292
00:29:07,857 --> 00:29:14,780
gonna go through some important like
information. So one thing that you can see
293
00:29:14,780 --> 00:29:21,923
is that these are the border binaries that
Karonte found. Now, there might be some
294
00:29:21,923 --> 00:29:26,360
false positives. I'm not sure how many
there are here. But as long as there are
295
00:29:26,360 --> 00:29:32,131
no false negatives or the number is very
low, it's fine. It's good. In this case,
296
00:29:32,131 --> 00:29:38,879
wait. Oh, I might have removed something.
All right, here, perfect. In this case,
297
00:29:38,879 --> 00:29:45,444
this guy httpd is a true positive, which
is the web server that we were talking
298
00:29:45,444 --> 00:29:52,185
before. Then we have the BDG. In this
case, we can see that Karonte found that
299
00:29:52,185 --> 00:30:00,252
httpd communicates with two different
binaries, fileaccess.cgi and cgibin. Then
300
00:30:00,252 --> 00:30:10,799
we have information about the CPFs. For
instance, here we can see that. Sorry. So
301
00:30:10,799 --> 00:30:19,775
we can see here that httpd has 28 data
keys. And that the semantics CPF found 27
302
00:30:19,775 --> 00:30:26,823
of them and then there might be one other
here or somewhere that I don't see .
303
00:30:26,823 --> 00:30:35,835
Anyway. And then we have a list of alerts.
Now, thanks. Now, some of those may be
304
00:30:35,835 --> 00:30:44,135
duplicates because of loops, so you can go
ahead and inspect all of them manually.
305
00:30:44,135 --> 00:30:50,982
But I wrote a utility that you can use,
which is basically it's gonna filter out
306
00:30:50,982 --> 00:31:02,100
all the loops for you. Now to remember how
I called it. This guy? Yeah. And you can
307
00:31:02,100 --> 00:31:13,368
see that in total it generated, the system
generated 6... 7... 8 alerts. So let's see
308
00:31:13,368 --> 00:31:20,579
one of them. Oh, and I recently realized
that the path that I'm reporting on the
309
00:31:20,579 --> 00:31:25,970
log. It's not the path from the setter
binary to the getter binary, to the sink.
310
00:31:25,970 --> 00:31:31,426
But it's only related to the getter binary
up to the sink. I'm gonna fix this in the
311
00:31:31,426 --> 00:31:37,552
next days and report the whole paths.
Anyway. So here we can see that the key
312
00:31:37,552 --> 00:31:43,395
content type contains user input and it's
passed in an unsafe way to the sink
313
00:31:43,395 --> 00:31:49,688
address at this address. Now. And the
binary in question is called
314
00:31:49,688 --> 00:32:02,416
fileaccess.cgi. So we can see what happens
there. keyboard noises If you see here,
315
00:32:02,416 --> 00:32:12,480
we have a string copy that copies the
content of haystack to destination,
316
00:32:12,480 --> 00:32:20,751
haystack comes basically from this getenv.
And if you see destination comes as
317
00:32:20,751 --> 00:32:30,001
parameter from this function and return
and these and this by for it's as big as
318
00:32:30,001 --> 00:32:38,895
0x68 bytes. And this turned out to be
actually a positive. OK. So in summary, we
319
00:32:38,895 --> 00:32:46,529
presented a strategy to track data flow
across different binaries. We evaluated
320
00:32:46,529 --> 00:32:52,972
our system on 952 firmware samples and
some takeaways. Analyzing firmware is not
321
00:32:52,972 --> 00:32:58,156
easy and vulnerabilities persist. We found
out that firmware are made of
322
00:32:58,156 --> 00:33:02,660
interconnected components and static
analysis can still be used to efficiently
323
00:33:02,660 --> 00:33:07,730
find vulnerabilities at scale and finding
that communication is key for precision.
324
00:33:07,730 --> 00:33:12,229
Here's a list of bibliography that I use
throughout the presentation and I'm gonna
325
00:33:12,229 --> 00:33:12,956
take questions.
326
00:33:12,956 --> 00:33:18,431
applause
327
00:33:18,431 --> 00:33:27,366
Herald: So thank you, Nilo, for a very
interesting talk. If you have questions,
328
00:33:27,366 --> 00:33:32,470
we have three microphones one, two and
three. If you have a question, please go
329
00:33:32,470 --> 00:33:37,684
head to the microphone and we'll take your
question. Yes. Microphone number two.
330
00:33:37,684 --> 00:33:41,995
Q: Do you rely on imports from libc or
something like that or do you have some
331
00:33:41,995 --> 00:33:46,733
issues with like statically linked
binaries, stripped binaries or is it all
332
00:33:46,733 --> 00:33:51,895
semantic analysis of a function?
Nilo: So. Okay. We use angr. So for
333
00:33:51,895 --> 00:33:57,277
example, if you have an indirect call, we
use angr to figure out, what's the target?
334
00:33:57,277 --> 00:34:02,627
And to answer your question like if you
use libc some CPFs do, for instance, then
335
00:34:02,627 --> 00:34:08,313
environment CPF do any checks, if the
setenv or getenv functions are called. But
336
00:34:08,313 --> 00:34:12,873
also we use the semantic CPF, which
basically in cases where information are
337
00:34:12,873 --> 00:34:17,687
missing like there is no such thing as
libc or some vendors reimplemented their
338
00:34:17,687 --> 00:34:21,977
own functions. We use the CPF to actually
try to understand the semantics of the
339
00:34:21,977 --> 00:34:25,888
function and understand if it's, for
example, a custom setenv.
340
00:34:25,888 --> 00:34:29,900
Q: Yeah, thanks.
Herald: Microphone number three.
341
00:34:29,900 --> 00:34:36,905
Q: In embedded environments you often have
also that the getter might work on a DMA,
342
00:34:36,905 --> 00:34:43,233
some kind of vendor driver on a DMA. Are
you considering this? And second part of
343
00:34:43,233 --> 00:34:47,793
the question, how would you then
distinguish this from your generic IPC?
344
00:34:47,793 --> 00:34:52,502
Because I can imagine that they look very
similar in the actual code.
345
00:34:52,502 --> 00:34:58,752
Nilo: So if I understand correctly your
question, you mention a case of MMIO where
346
00:34:58,752 --> 00:35:03,956
some data is retrieved directly from some
address in memory. So what we found is
347
00:35:03,956 --> 00:35:08,434
that these addresses are usually hardcoded
somewhere. So the vendor knows that, for
348
00:35:08,434 --> 00:35:13,280
example, from this address A to this
address B if some data is some data from
349
00:35:13,280 --> 00:35:18,857
this peripheral. So when we find that some
hardcoded address, like we think that this
350
00:35:18,857 --> 00:35:21,688
is like some read from some interesting
data.
351
00:35:21,688 --> 00:35:28,073
Q: Okay. And this would be also
distinguishable from your sort of CPF, the
352
00:35:28,073 --> 00:35:32,180
generic CPF would be distinguishable...
Nilo: Yeah. Yeah, yeah.
353
00:35:32,180 --> 00:35:35,775
Q: ...from a DMA driver by using this
fixed address assuming.
354
00:35:35,775 --> 00:35:39,827
Nilo: Yeah. That's what the semantic CPF
does, among the other things.
355
00:35:39,827 --> 00:35:41,336
Q: Okay. Thank you.
Nilo: Sure.
356
00:35:41,336 --> 00:35:43,856
Herald: Another question for microphone
number 3.
357
00:35:43,856 --> 00:35:46,117
Q: What's the license for Karonte?
Nilo: Sorry?
358
00:35:46,117 --> 00:35:51,130
Q: I checked the software license, I
checked the git repository and there is no
359
00:35:51,130 --> 00:35:53,440
license like at all.
Nilo: That is a very good question. I
360
00:35:53,440 --> 00:36:00,610
haven't thought about it yet. I will.
Herald: Any more questions from here or
361
00:36:00,610 --> 00:36:04,410
from the Internet? Okay. Then a big round
of applause to Nilo again for your talk.
362
00:36:04,410 --> 00:36:24,820
postroll music
363
00:36:24,820 --> 00:36:31,630
Subtitles created by many many volunteers and
the c3subtitles.de team. Join us, and help us!
364
99:59:59,999 --> 99:59:59,999