WEBVTT
00:00:00.000 --> 00:00:15.065
34c3 intro
00:00:15.065 --> 00:00:30.130
Herald: All right, next lecture here is
from Artem. Next to the fact that these,
00:00:30.130 --> 00:00:38.819
how would I spell it, earning a nice
amount of money probably at a lab that's
00:00:38.819 --> 00:00:46.589
quite renown in the world as Kaspersky and
from that point on he's not just looking
00:00:46.589 --> 00:00:52.539
in this lecture to exploit a development
for Cisco stuff we all suffered from this
00:00:52.539 --> 00:00:57.609
last year or we all heard about it and
don't know the impact maybe, but he's
00:00:57.609 --> 00:01:05.019
going to explain us the work he did on
that field so please can I ask your warm
00:01:05.019 --> 00:01:14.299
welcoming applause for Artem Kondratenko,
do you, okay good, please give him a warm
00:01:14.299 --> 00:01:21.960
applause and start.
applause
00:01:21.960 --> 00:01:26.149
Artem Kondratenko: Hello everyone, so
excited to finally be able to attend Chaos
00:01:26.149 --> 00:01:31.880
Communication Congress. Very happy to see
y'all. So without further ado let's jump
00:01:31.880 --> 00:01:38.229
into some practical IOS exploitation. So a
few words about myself, my name is Artem,
00:01:38.229 --> 00:01:43.659
I do stuff, mostly security related stuff
but mostly my areas of expertise are
00:01:43.659 --> 00:01:48.869
penetration tests, both internal external
and also do research in my free time and
00:01:48.869 --> 00:01:54.289
get a bug bounty here and there and this
talk is actually kind of a continuation of
00:01:54.289 --> 00:01:59.729
my talk this summer at Def Con about Cisco
Catalyst exploitation.
00:01:59.729 --> 00:02:04.600
So for those of you who are out of
context, let's recap what happened earlier
00:02:04.600 --> 00:02:14.450
this year. So year 2017 was reaching
vulnerabilities for Cisco IOS devices. So
00:02:14.450 --> 00:02:20.140
we had at least three major advisories for
Cisco IOS that represented three remote
00:02:20.140 --> 00:02:24.280
code execution vulnerabilities.
So the first one is vulnerability in
00:02:24.280 --> 00:02:30.600
cluster management protocol which resulted
in unauthenticated remote code
00:02:30.600 --> 00:02:36.560
execution via telnet, second one is SNMP
overflow and the DHCP remote code
00:02:36.560 --> 00:02:40.310
execution.
In this lecture I'm gonna be talking
00:02:40.310 --> 00:02:47.060
about two of those vulnerabilities because
DHCP RCE is yet to be researched. So
00:02:47.060 --> 00:02:51.880
hopefully by the end of this talk I'm
going to be able to show you a live demo
00:02:51.880 --> 00:02:56.810
of exploiting the SNMP service in Cisco
IOS.
00:02:56.810 --> 00:03:05.870
So but first what happened earlier: So on
March 26, 2017 we had a major advisory from
00:03:05.870 --> 00:03:10.790
Cisco that announcing that hundreds of
models of different switches are
00:03:10.790 --> 00:03:15.230
vulnerable to remote code execution
vulnerability. No public code, no public
00:03:15.230 --> 00:03:21.070
exploit was available and no exploitation
in the wild. So it was critical and main
00:03:21.070 --> 00:03:24.380
points of the vulnerability were as
follow:
00:03:24.380 --> 00:03:30.970
So Cisco switches can be clustered, and
there's a cluster management protocol
00:03:30.970 --> 00:03:36.430
built on top of telnet, and this
vulnerability is a result of actually two
00:03:36.430 --> 00:03:43.880
errors, a logic error and a binary error.
So the telnet options get parsed
00:03:43.880 --> 00:03:49.940
regardless whether the switch is in
cluster mode or not and the incorrect
00:03:49.940 --> 00:03:56.560
processing of this cluster management
protocol options result in overflow. So
00:03:56.560 --> 00:04:00.980
what is interesting about this
vulnerability that actually the source of
00:04:00.980 --> 00:04:06.010
research for Cisco guys was another
internal research. But the "Vault 7" leak
00:04:06.010 --> 00:04:13.210
that happened in March this year so many
hacking techniques and tools were released
00:04:13.210 --> 00:04:20.440
to public by WikiLeaks, and among many
vendors that were affected was Cisco
00:04:20.440 --> 00:04:25.090
Systems.
So basically except for the advisory you
00:04:25.090 --> 00:04:30.240
could go to WikiLeaks and read about this
potential exploitation technique for Cisco
00:04:30.240 --> 00:04:35.490
Catalyst. So basically these were notes of
an engineer who was testing the actual
00:04:35.490 --> 00:04:43.750
exploit, there were no actual exploit in
the leak. So basically this worked as
00:04:43.750 --> 00:04:49.210
follows: there was two modes of
interaction, so for example an attacker
00:04:49.210 --> 00:04:55.330
could connect to the telnet, overflow the
service and be presented with a privileged
00:04:55.330 --> 00:05:02.860
15 shell. The other mode of operation was
the … is to set for all the subsequent
00:05:02.860 --> 00:05:08.790
… connections to the telnet, there
will be … without credentials so I
00:05:08.790 --> 00:05:14.620
did. We discover this exploit, full
research was presented at DEFCON 25. I was
00:05:14.620 --> 00:05:20.620
targeting system catalyst 2960 as a target
switch. I also described a PowerPC
00:05:20.620 --> 00:05:25.340
platform exploitation and the way you can
debug it.
00:05:25.340 --> 00:05:31.430
You can look at my blog post about
exploiting this service, and also the
00:05:31.430 --> 00:05:37.530
proof accounts of exploit on my github
page. But today I want to talk about
00:05:37.530 --> 00:05:42.200
something else, about another
vulnerability that was announced this year
00:05:42.200 --> 00:05:49.490
about SNMP remote code execution.
So the actual motivation behind this
00:05:49.490 --> 00:05:55.840
research was that I was conducting an
external pentest, and it was revealed an
00:05:55.840 --> 00:06:00.510
nmap scan revealed that a Cisco router
where the default community string was
00:06:00.510 --> 00:06:07.090
available. So the goal was to get access
to the internal network.
00:06:07.090 --> 00:06:13.450
So the actual advisory said that the
attacker needs a read-only community
00:06:13.450 --> 00:06:19.700
string to gain remote code execution on
the device. The target router was a 2800
00:06:19.700 --> 00:06:26.650
integrated services router, which is a
very common device on the networks.
00:06:26.650 --> 00:06:34.389
So the technical specs for it is it's a
it has a MIPS big endian architecture, you
00:06:34.389 --> 00:06:39.990
don't have any client debugging tools for
it available, and it's interesting in that
00:06:39.990 --> 00:06:46.919
sense that the firmware is relatively new
for this router, and it might be
00:06:46.919 --> 00:06:52.771
interesting to look at the defensive end
exploit prevention mechanisms employed by
00:06:52.771 --> 00:06:59.370
Cisco IOS. When I say relatively new is
the interesting thing is that this device
00:06:59.370 --> 00:07:04.040
is actually end of support, it's not
supported. So the last patch for it was
00:07:04.040 --> 00:07:12.360
came out at 2016, and to remind you the
advisory for SNMP overflow appeared in
00:07:12.360 --> 00:07:19.040
2017, in June 2017, but nonetheless this
is still widely used device.
00:07:19.040 --> 00:07:27.760
If you search for SNMP banner on Shodan,
you will find at least 3000 devices with
00:07:27.760 --> 00:07:37.550
SNMP service available with default public
string. So this devices are all supposedly
00:07:37.550 --> 00:07:43.710
vulnerable to SNMP overflow. And the
question is whether we can build a mount
00:07:43.710 --> 00:07:49.140
code execution exploit for it. So since
we're going to be exploiting SME protocol,
00:07:49.140 --> 00:07:54.460
let's make a quick quick recap of how it
works, just light touch.
00:07:54.460 --> 00:08:01.930
So SNMP comes with several abbreviations
like MIB, which stands for management
00:08:01.930 --> 00:08:07.919
information base, and is kind of a
collection of objects that can be
00:08:07.919 --> 00:08:12.860
monitored from the SNMP manager. And so a
management information base actually
00:08:12.860 --> 00:08:21.370
consists of object identifiers. And as an
example: you all know that printers
00:08:21.370 --> 00:08:25.550
usually use SNMP, For example if there is
a certain level of ink in the cartridge,
00:08:25.550 --> 00:08:31.729
you can query the SNMP service on this
device for the percentage of ink left. So
00:08:31.729 --> 00:08:39.179
that's a kind of example how it works.
Management information base looks like a
00:08:39.179 --> 00:08:42.219
tree.
So you have your base element at the top
00:08:42.219 --> 00:08:47.839
and your leaf elements, So all these
elements represent an object that could be
00:08:47.839 --> 00:08:53.509
queried. We're going to be looking at get
requests. And that is why the advisory
00:08:53.509 --> 00:08:57.790
states that for their vulnerability to be
triggered you only have to know the read-
00:08:57.790 --> 00:09:03.110
only community string. So it's a
relatively simple protocol, you just
00:09:03.110 --> 00:09:08.199
supply the object identifier you're
querying and you'll get back the result.
00:09:08.199 --> 00:09:14.999
So here for example we get the router
version, the description field. And you
00:09:14.999 --> 00:09:24.170
can also do this with a readily available
Linux tools like snmpget. So before we
00:09:24.170 --> 00:09:28.629
will build an exploit, we have a starting
point. So how do we look for for the
00:09:28.629 --> 00:09:35.110
crash? So the advisory actually states
that there are nine different vulnerable
00:09:35.110 --> 00:09:41.399
management information bases and you only
have to know the read-only community string.
00:09:41.399 --> 00:09:50.089
So for the fuzzing to be done I'll be
using Scapy as a tool to as a toolkit to
00:09:50.089 --> 00:09:54.310
work with network protocols, and here you
can see that I'm building an object
00:09:54.310 --> 00:09:59.160
identifier, a valid object identifier that
references the description field, and then
00:09:59.160 --> 00:10:04.921
I'm appending some letters "a" which is 65
in ASCII table. Then I build an IP packet,
00:10:04.921 --> 00:10:12.149
I build a UDP packet and an SNMP packet
inside of it with community string public
00:10:12.149 --> 00:10:17.320
and object identifier.
So of course this will not trigger the
00:10:17.320 --> 00:10:23.589
overflow, because this object identifier
is completely fine. How do we get all the
00:10:23.589 --> 00:10:28.670
object identifiers that our router will
respond to? So basically there are two
00:10:28.670 --> 00:10:36.230
ways: you can take the firmware and just
extract all the OIDs from it. It's easy to
00:10:36.230 --> 00:10:43.670
grab them, they're stored in plain text.
Another way is to actually look at the
00:10:43.670 --> 00:10:52.399
vulnerable MIBs and visit the website OID
views and get all object identifiers from
00:10:52.399 --> 00:10:59.399
this website. So as a matter of fact the
first crash I had was in ciscoAlpsMIB,
00:10:59.399 --> 00:11:08.959
which is kind of related to airplane protocol,
which does not concern us because it's not
00:11:08.959 --> 00:11:16.759
a focus of our exploitation.
So the actual overflow was in one of its
00:11:16.759 --> 00:11:23.290
object identifiers. So this request this I
actually crashed the router when you
00:11:23.290 --> 00:11:30.480
connect to the Cisco router of via a
serial cable you will be and there's a
00:11:30.480 --> 00:11:36.480
crash you will be presented with a stack
trace. So we see here that we got a
00:11:36.480 --> 00:11:45.890
corrupted program counter, and we also see
the state of registers that we have at the
00:11:45.890 --> 00:11:55.270
moment of crash. So here you can see that
we have control of a program counter, it's
00:11:55.270 --> 00:12:04.110
called EPC, and also we control the
contents of registers s0, s1, s2, s3, s4,
00:12:04.110 --> 00:12:08.160
s5, s6.
Further inspection also provided me with
00:12:08.160 --> 00:12:14.959
knowledge that we have 60 spare bytes on
the stack to work with. But before we
00:12:14.959 --> 00:12:20.369
build we exploit we have some problems,
issues to be solved.
00:12:20.369 --> 00:12:26.149
And that is: yes, we do control the
program counter, but where do we jump to?
00:12:26.149 --> 00:12:34.880
Is ASLR on? Can we execute shellcode
directly on the stack? Is stack
00:12:34.880 --> 00:12:42.660
executable? If we can place the shellcode
on it, is data caching a problem for us?
00:12:42.660 --> 00:12:49.179
And if we launched our shellcode, can we
just bash the code? Is the code section
00:12:49.179 --> 00:12:54.060
writable? Is the code integrity check on?
But the most important question is: how
00:12:54.060 --> 00:12:59.119
can we return the code flow back to the
SNMP service?
00:12:59.119 --> 00:13:07.930
Because IOS is a single binary running in
the memory, and if you have an exception
00:13:07.930 --> 00:13:15.019
in any thread of this big binary, the Cisco
device will crash. And if we look at the
00:13:15.019 --> 00:13:16.829
advisory, one of the indicators of
00:13:16.829 --> 00:13:23.129
compromised Cisco states is device reload,
so exploitation of the vulnerabilities
00:13:23.129 --> 00:13:29.499
will cause an affected device to reload.
We will build an exploit we'll try to
00:13:29.499 --> 00:13:36.110
build an exploit that will not crash the
SNMP service on it. Before we dive deeper
00:13:36.110 --> 00:13:45.149
into the firmware I want to reference
previous researches on this matter. This
00:13:45.149 --> 00:13:53.670
is by no means a complete list but these
researchers actually helped me a lot and
00:13:53.670 --> 00:14:00.899
seemed interesting and very insightful to
me. You should definitely check them out
00:14:00.899 --> 00:14:07.029
so for example "Router Exploitation" by
Felix FX Lindener and "CISCO IOS
00:14:07.029 --> 00:14:12.079
SHELLCODE" by George Nosenko is a great
resource for IOS internals and great
00:14:12.079 --> 00:14:16.699
reference to how IOS works in terms of
exploitation
00:14:16.699 --> 00:14:22.499
and the third resource "How to cook
Cisco" is a great info on exploiting
00:14:22.499 --> 00:14:29.189
PowerPC-based Cisco switches and also
great info on bypassing common mechanisms
00:14:29.189 --> 00:14:38.129
and exploit prevention stuff in IOS. So
basically if I were to tell you how IOS
00:14:38.129 --> 00:14:42.929
works in one slide it's basically a single
binary running in memory. Everything is
00:14:42.929 --> 00:14:50.860
statically linked into a single ELF file
which gets loaded on startup, of course
00:14:50.860 --> 00:14:57.720
you have no API whatsoever. Everything has
no symbols whatsoever. Yes, there is a
00:14:57.720 --> 00:15:03.579
glibc library at the end of the firmware
but it's also kind of hard to use it
00:15:03.579 --> 00:15:10.170
because you have so many different
versions of firmware and the offsets jump
00:15:10.170 --> 00:15:14.310
and you don't know the exact location of
those functions. So to start with static
00:15:14.310 --> 00:15:19.209
analysis you should probably copy the
firmaware from the flash memory of the
00:15:19.209 --> 00:15:27.589
router. Use the copy command, it supports
TFTP and FTP protocols so you download
00:15:27.589 --> 00:15:32.439
this firmware, the next thing you do is
unpack the firmware. The firmware itself,
00:15:32.439 --> 00:15:38.949
when the router starts loading it, has an
initial stop that does the unpacking but
00:15:38.949 --> 00:15:43.779
you don't have to reverse engineer that,
you just use binwalk, that will do the
00:15:43.779 --> 00:15:53.259
unpacking for you. You load the result of
unpacking with binwalk to IDA Pro, you
00:15:53.259 --> 00:15:58.420
have to change the processor type to MIPS
32 big-endian and we know that this is
00:15:58.420 --> 00:16:05.139
MIPS, because we saw the registers. These
registers tell us that it was indeed MIPS
00:16:05.139 --> 00:16:13.040
architecture. So one thing I want to note,
the actual firmware gets loaded into
00:16:13.040 --> 00:16:20.519
address 800F00 but the program counter is
located at address 4 and this is because
00:16:20.519 --> 00:16:29.089
IOS when it loaded the firmaware
transfers, I mean maps to memory 2400F00
00:16:29.089 --> 00:16:35.120
and this is important because to have
correct cross references in IDA Pro you
00:16:35.120 --> 00:16:43.220
have to rebase your program to 4 and after
that you will have all correct string
00:16:43.220 --> 00:16:48.929
cross-references. We will have all the
necessary strings and your static analysis
00:16:48.929 --> 00:16:56.009
setup will be complete. But in order to
build an exploit it will not suffice to
00:16:56.009 --> 00:17:00.740
only have the, you know, IDA Pro loaded
with the firmware with all the cross
00:17:00.740 --> 00:17:07.140
references, you probably want to, you
know, set up a debug environment. It is
00:17:07.140 --> 00:17:14.689
well known that IOS can be debugged via a
serial port and actually there's a "gdb
00:17:14.689 --> 00:17:23.109
kernel" command that is used to start the
internal gdb server, or it was because
00:17:23.109 --> 00:17:29.139
functionality was removed in the recent
versions of IOS and you can't really run
00:17:29.139 --> 00:17:38.950
the gdb. But nonetheless there's a way to
enable the gdb and this way is to reboot
00:17:38.950 --> 00:17:46.389
the device, send an escape sequence to the
serial line, this will bring up the rom
00:17:46.389 --> 00:17:52.500
monitor shell so rom monitor is a simple
piece of firmware that gets loaded and run
00:17:52.500 --> 00:17:59.720
just before your firmware starts running
and in this ROMMON you can manually boot
00:17:59.720 --> 00:18:08.950
your firmware with a flag and which will
launch the whole firmware under gdb. And
00:18:08.950 --> 00:18:17.980
after your firmware is loaded, the gdb
will kick in. Now you can't just use your
00:18:17.980 --> 00:18:25.919
favorite gdb debugger and Linux and
connect it to IOS via a serial port
00:18:25.919 --> 00:18:35.000
because IOS uses a slightly different
subset of commands of gdb protocol. It has
00:18:35.000 --> 00:18:43.679
a server-side gdb but the client side
should be accustomed to this gdb server.
00:18:43.679 --> 00:18:48.630
Basically there is no publicly and
officially available client-side debugging
00:18:48.630 --> 00:18:56.300
tools for IOS and that is because this is
intended for Cisco engineers for to be
00:18:56.300 --> 00:19:02.240
done. Although there have been some
efforts from the community to build tools
00:19:02.240 --> 00:19:08.750
to debug several versions of routers and
switches with IOS and if you look for ways
00:19:08.750 --> 00:19:15.929
to debug Cisco IOS you will find, you most
definitely will find a tutorial that says
00:19:15.929 --> 00:19:21.610
that you can actually patch an old version
of gdb that still supports IOS, but it
00:19:21.610 --> 00:19:26.120
actually never works because I tried it
and all I could do is read memory, the
00:19:26.120 --> 00:19:34.950
stepping, the tracing, it just doesn't
work. So another way is to use a cool tool
00:19:34.950 --> 00:19:42.389
by NCC group, it's called IODIDE, it's a
graphical debugger for IOS, it really
00:19:42.389 --> 00:19:48.769
works, it's a great tool, but the thing is
it is only, it targets PowerPC
00:19:48.769 --> 00:19:54.830
architecture and it has some some problems
you probably have to patch the debugger to
00:19:54.830 --> 00:19:58.639
be able to work with it and the third
option, the last resort
00:19:58.639 --> 00:20:05.380
is to implement your own debugger for the
router. And to do that you have to know
00:20:05.380 --> 00:20:12.370
which commands actually Cisco supports,
and not a lot, so you can basically read
00:20:12.370 --> 00:20:18.520
memory and write memory and set and write
registers and the only program counter
00:20:18.520 --> 00:20:25.230
control command is a step instruction. So
basically it's kind of easy to implement
00:20:25.230 --> 00:20:31.870
such a debugger because all the
information is just sent as a plain text
00:20:31.870 --> 00:20:40.820
over a serial cable and appended with a
checksum which is just a CRC. So this way
00:20:40.820 --> 00:20:48.179
I was able to, you know, make a quick
Python script using Capstone to be able to
00:20:48.179 --> 00:20:55.450
debug IOS, you can inspect registers,
there's a basic breakpoint management, you
00:20:55.450 --> 00:21:02.169
just write a special control double word
to be able to break. You can step over a
00:21:02.169 --> 00:21:06.789
step over step into and also a good feature is
to be able to dump memory, which we will
00:21:06.789 --> 00:21:15.170
use later. So to find the overflow, the
SNMP overflowing the code, how do you do
00:21:15.170 --> 00:21:20.840
it? Basically you can follow, since we
have all the string cross-references, you
00:21:20.840 --> 00:21:28.960
can follow the strings, that reference
SNMP get requests and just step until the
00:21:28.960 --> 00:21:35.139
crash, but a more efficient method is just
to crash the device and start inspecting
00:21:35.139 --> 00:21:41.570
the stack after the device is already
crashed. You just have to dump some memory
00:21:41.570 --> 00:21:47.180
on the stack and look into the values that
reference the code, some of them will be
00:21:47.180 --> 00:21:58.809
return addresses and this will give you a
hint where the crash actually is. So the
00:21:58.809 --> 00:22:03.500
actual program counter corruption happens
in the function epilog, I call this
00:22:03.500 --> 00:22:12.549
function snmp_stack_overflow, so you can
see here that at the end of a function we
00:22:12.549 --> 00:22:18.720
load the values from the stack to
registers $s0 to $s6 and also we load
00:22:18.720 --> 00:22:24.610
value into register $ra and this is an
important register, it's called a return
00:22:24.610 --> 00:22:31.049
address register and almost every function
in MIPS uses this register to jump back to
00:22:31.049 --> 00:22:39.779
its parent function. So basically we have
some space on the stack, but the question
00:22:39.779 --> 00:22:47.789
is can we place our shellcode on this on
the stack? And can we execute it? Because,
00:22:47.789 --> 00:22:51.789
you know, stack location is
unpredictable, every time you trigger this
00:22:51.789 --> 00:22:57.370
vulnerability a separate space on the
stack is allocated and you cannot really
00:22:57.370 --> 00:23:04.679
predict it. So, no valid jump to stack
instructions in the firmware like we did
00:23:04.679 --> 00:23:11.980
on Intel x86 like jump ESP. No such
instructions in the firmware, but even if
00:23:11.980 --> 00:23:19.131
we could find such an instruction, the
address space layout randomization (ALSR)
00:23:19.131 --> 00:23:26.070
is on, which means the code section and
data section is based on different offsets
00:23:26.070 --> 00:23:31.789
each time we reboot the device, which
means that we can't reliably jump to the
00:23:31.789 --> 00:23:39.950
instruction. And also an unfortunate thing
is that data caching is also in place. So,
00:23:39.950 --> 00:23:49.309
about ASLR, this is the first first time I
encountered the randomization in IOS.
00:23:49.309 --> 00:23:56.120
Previous researchers, that I've been doing
with, they said a lot about diversity of
00:23:56.120 --> 00:24:01.919
the firmware. So, basically you had so
many different versions of firmware when
00:24:01.919 --> 00:24:07.139
you exploited the Cisco device it couldn't
really reliably jump to any code because
00:24:07.139 --> 00:24:11.940
there's so a vast diversity of different
firmware that was built by different
00:24:11.940 --> 00:24:17.990
people but here we actually have the stack
address based randomization and the text
00:24:17.990 --> 00:24:26.110
section and data section is loaded on
different offsets after each reboot. So,
00:24:26.110 --> 00:24:32.929
another thing that really upsets us is
data caching, so when we write our shell
00:24:32.929 --> 00:24:38.580
code to stack, we think that it will be on
the stack but what actually happens,
00:24:38.580 --> 00:24:43.070
everything gets written into data cache
and when we place our program counter to
00:24:43.070 --> 00:24:51.140
the stack we get executing garbage
instructions which results in a crash once
00:24:51.140 --> 00:24:58.539
again. So this problem this is basically a
data execution prevention, well it's not
00:24:58.539 --> 00:25:06.150
it's a it's a cache but the solution to
this problem is the same as for data
00:25:06.150 --> 00:25:12.419
execution prevention and it is return
oriented programming, so but unfortunately
00:25:12.419 --> 00:25:21.139
we still have ASLR so we can't really jump
to anything because it's on a random
00:25:21.139 --> 00:25:28.580
offset but here the rom monitor, that I
was talking about comes to our rescue. So
00:25:28.580 --> 00:25:34.620
this little piece of software that gets
loaded before the actual firmware might
00:25:34.620 --> 00:25:40.149
actually help us. So
the first thing we want to find where
00:25:40.149 --> 00:25:45.549
this bare-bones firmware is
located and the interesting feature of
00:25:45.549 --> 00:25:52.740
this ROMMON shell, it's actually allowing
you to disassemble arbitrary memory parts
00:25:52.740 --> 00:25:59.179
and if you target the disassembler at an
invalid address you will get a stack trace
00:25:59.179 --> 00:26:06.039
revealing the actual address of the rom
monitor. And what's the most interesting
00:26:06.039 --> 00:26:13.070
thing as the rom monitor is located at
bfc0000 and you can dump it using the
00:26:13.070 --> 00:26:19.070
debugger or you can just search the
internet for the version and download it.
00:26:19.070 --> 00:26:28.620
The most interesting part about this piece
of firmware, is that rom monitor is
00:26:28.620 --> 00:26:34.470
located at the same address and it's
persistent across reboots and it's really
00:26:34.470 --> 00:26:41.610
great because we can use it for building
ROP chains inside of it. So now we have a
00:26:41.610 --> 00:26:49.610
theoretical possibility of circumventing
ASLR, defeating the cache problem. So how
00:26:49.610 --> 00:26:56.190
do we build an exploit, so the overview is
as follows: we jump to ROMMON, we initiate
00:26:56.190 --> 00:27:02.929
a ROP chain, which makes an arbitrary
write using the code reuse technique and
00:27:02.929 --> 00:27:10.669
after that we have to recover the stack
frame to allow the SNMP service to restore
00:27:10.669 --> 00:27:16.049
the legitimate code flow. This is really
important because we will be writing only
00:27:16.049 --> 00:27:22.470
four bytes and that is not enough for a
full fledged shellcode and if we don't
00:27:22.470 --> 00:27:28.529
crash SNMP we can exploit this
vulnerability over and over again, thus
00:27:28.529 --> 00:27:33.090
building a shellcode in the memory. So
after we build the shellcode we make a
00:27:33.090 --> 00:27:44.289
jump to it. So, here's how it works: we
overflow the stack, we overflow the return
00:27:44.289 --> 00:27:51.779
address so it points to rom monitor, we
jump to the rom monitor, then what we do
00:27:51.779 --> 00:27:57.680
we actually find a gadget that reuses the
data on our stack to make an arbitrary
00:27:57.680 --> 00:28:04.499
four byte write just before the text
section. Then we have to find a gadget
00:28:04.499 --> 00:28:11.529
that will recover stack for us so we can
restore the legitimate SNMP execution call
00:28:11.529 --> 00:28:19.730
flow. So this is basically an overview of
one cycle of how we write a four byte
00:28:19.730 --> 00:28:27.970
double word. Now, a little bit on building
ROP chains, so what is it? what is return
00:28:27.970 --> 00:28:38.179
oriented programming? So basically the
idea is to not execute the shellcode
00:28:38.179 --> 00:28:45.389
directly but is to use existing
code in the binary to execute your
00:28:45.389 --> 00:28:52.200
payload. So you use stack not as a source
of instructions but you use stack as data
00:28:52.200 --> 00:28:59.720
for the code that you're reusing. So
basically you change the snippets of code
00:28:59.720 --> 00:29:07.720
we call them gadgets and you chain them
together with jump or call instructions
00:29:07.720 --> 00:29:17.159
and candidate gadgets has to meet two
requirements: It has to actually execute
00:29:17.159 --> 00:29:22.820
our payload and also it also has to
contain instructions that will transfer
00:29:22.820 --> 00:29:28.340
execution flow to the next gadget or, if
it's the last gadget it should transfer
00:29:28.340 --> 00:29:37.780
execution back to the SNMP service. The
problems with the return oriented approach
00:29:37.780 --> 00:29:42.419
is that there is a limited set of gadgets
available, so if you're talking about the
00:29:42.419 --> 00:29:46.980
firmware it's around 200 megabytes of code
so there are plenty of different gadgets
00:29:46.980 --> 00:29:51.330
there, if we're talking about a rom
monitor it's only 500 kilobytes of code,
00:29:51.330 --> 00:29:58.669
so not a lot of code available and the
second major problem is that gadgets,
00:29:58.669 --> 00:30:04.549
because most of them are function
epilogues, they modify the stack frame
00:30:04.549 --> 00:30:09.409
because they delete the local variables
after they jump back to the parent
00:30:09.409 --> 00:30:15.790
function and you have to account for that
because this, my crash, the process you
00:30:15.790 --> 00:30:23.720
are exploiting. ROP chains can be
basically forced to do anything but
00:30:23.720 --> 00:30:31.419
mostly, most of the times we do arbitrary
memory writes and this actually might lead
00:30:31.419 --> 00:30:39.600
to arbitrary code execution. So the idea
for for looking for gadgets is that you
00:30:39.600 --> 00:30:46.200
find a gadget that loads data from the
stack into the registers and then you find
00:30:46.200 --> 00:30:50.580
a second gadget that works with the data
in the, in those pages for example you
00:30:50.580 --> 00:30:58.399
have one register $v0 which contains the
value you want to write and the other
00:30:58.399 --> 00:31:09.929
gadget $s0 which has the address you want
to write to. So we actually want to find
00:31:09.929 --> 00:31:15.659
gadgets that also load data from stack to
return registers so we can jump to the
00:31:15.659 --> 00:31:24.159
next gadget. I don't have to look for
these gadgets manually in IODIDE, in there
00:31:24.159 --> 00:31:29.860
are a lot of different tools for building
ROP chains, one of those tools is Ropper
00:31:29.860 --> 00:31:32.480
you can find it on GitHub it's a really
handy tool.
00:31:32.480 --> 00:31:36.379
You just search for necessary
instructions to build
00:31:36.379 --> 00:31:48.669
the necessary ROP chain. So now the last
technical part of how the ROP chains in
00:31:48.669 --> 00:31:54.940
this particular exploit work and then
we'll get to the demo. So this is how a
00:31:54.940 --> 00:32:02.830
perfectly, you know, healthy stack frame
looks like. So you basically have local
00:32:02.830 --> 00:32:07.499
variables on the stack, you have return
adress, you also have a stack frame of
00:32:07.499 --> 00:32:13.389
parent functions underneath the stack
frame of our vulnerable function. So when
00:32:13.389 --> 00:32:19.679
we overflow the local variables with our
long object identifier here's what
00:32:19.679 --> 00:32:27.769
happens: We overflow the local variables
and these variables actually partly get
00:32:27.769 --> 00:32:34.210
written to $s0 and $s6 general purpose
registers we also, of course overflow the
00:32:34.210 --> 00:32:41.299
return address, which will jump for us to
rom monitor and we also have some 60
00:32:41.299 --> 00:32:46.590
bytes, after that we overflow the stack
frame of the next function and we use that
00:32:46.590 --> 00:32:54.970
data also for our ROP chain. What we do
here, we take the value of $a0, we control
00:32:54.970 --> 00:33:01.919
the value of $a0 as you remember and we
move it to register $v0 and that's for
00:33:01.919 --> 00:33:10.039
only solely purpose because there are no
other gadgets in rom monitor that use $s0
00:33:10.039 --> 00:33:16.510
as a target register to write data so we
have to use register $v0. After that the
00:33:16.510 --> 00:33:22.279
most important part is that we load the
return address from the ROP data too and
00:33:22.279 --> 00:33:31.289
also we load the address we will write to
from the ROP data too. So basically right
00:33:31.289 --> 00:33:40.539
now after this gadget stops executing we
have $s0 points to a memory we want to
00:33:40.539 --> 00:33:49.700
write to and $v0 contains 4 bytes we will
be writing just before the code section.
00:33:49.700 --> 00:33:57.649
So the final gadget that is performing the
arbitrary write is the gadget that takes
00:33:57.649 --> 00:34:08.190
the value of register $v0 and writes it to
a pointer reference that referenced by
00:34:08.190 --> 00:34:15.040
register $s0 and the last thing it does
actually transfers the control back to the
00:34:15.040 --> 00:34:22.150
gadget, which will recover the stack for
us. Most important gadgets it allows us to
00:34:22.150 --> 00:34:28.139
run the exploit several times, you might
have noticed that the previous gadgets
00:34:28.139 --> 00:34:36.460
actually moved the stack pointer 30 bytes
and hacks down them down the
00:34:36.460 --> 00:34:38.360
stack and this actually means
00:34:38.360 --> 00:34:44.510
that the process that we will return
to will crash if we don't point the stack
00:34:44.510 --> 00:34:50.770
pointer just between two stack frames. We
find a gadget that will move the stack
00:34:50.770 --> 00:35:00.340
pointer down to 228 bytes in hex, which
will result in a perfectly healthy stack.
00:35:00.340 --> 00:35:08.690
Also we load the return address to
register $ra and it points to the parent
00:35:08.690 --> 00:35:16.660
function that called our own vulnerable
function so this way we perform an
00:35:16.660 --> 00:35:22.850
arbitrary four byte write. We can do this
several times until our shellcode is
00:35:22.850 --> 00:35:28.350
actually built, just before the text
section and the final thing we do, we
00:35:28.350 --> 00:35:34.850
overflow the stack again and jump to the
shellcode. A few words about the
00:35:34.850 --> 00:35:45.910
shellcode: The device I was working with had a
telnet service and it had a password, so I
00:35:45.910 --> 00:35:52.150
designed a simple shell code that will
just patch the authentication call flow.
00:35:52.150 --> 00:35:58.610
So as you can see here we have a function
"login password check" and a result which
00:35:58.610 --> 00:36:09.170
is in $v0 register is checked whether the
authentication was successful or not. We
00:36:09.170 --> 00:36:13.700
can build a shell code which which will
just patch this instruction which checks
00:36:13.700 --> 00:36:19.900
"login password check" and it will allow
us to make a credential list
00:36:19.900 --> 00:36:29.780
authentication against telnet service. So
what it does: basically the shell code
00:36:29.780 --> 00:36:35.780
inspects the stack and the return address
in it to calculate the ASLR offset
00:36:35.780 --> 00:36:43.170
because, of course the ASLR is on for the
code section and we want to patch
00:36:43.170 --> 00:36:52.470
something in it and after that it writes a
0, which is a nop instruction in MIPS, to
00:36:52.470 --> 00:37:00.770
a call that checks for password for telnet
and also for enable password and then it
00:37:00.770 --> 00:37:10.610
just jumps back to SNMP service. So now
the long-awaited demo. Let's see if I can
00:37:10.610 --> 00:37:42.480
make it a live demo. All righty, so here
we have the serial connection to the
00:37:42.480 --> 00:37:52.820
device, you can see we have a shell. So
what we do now, we inspect the password on
00:37:52.820 --> 00:37:56.460
the telnet service to make sure it's
working as intended. So we see that bad
00:37:56.460 --> 00:38:03.700
passwords. We don't know the valid
password for the device, what we do now is
00:38:03.700 --> 00:38:16.050
we launch the actual exploit, as
parameters it takes the host, community
00:38:16.050 --> 00:38:26.200
and shell code in hex. So this is the shell
00:38:26.200 --> 00:38:41.300
code I was talking about that patches the
code flow in authentication. So let's
00:38:41.300 --> 00:38:53.580
write sudo. So here you see that we
initiate writing the four byte sequences
00:38:53.580 --> 00:39:02.490
into the text section. Basically this
writes the shell code into the memory. So
00:39:02.490 --> 00:39:17.180
after the exploit finishes this, we just
have to jump to the shell code. So let's
00:39:17.180 --> 00:39:57.530
see. Please do not crash. So, yes. So back
to the slides. And of course you can build
00:39:57.530 --> 00:40:02.500
a shell code that will unset this behavior
and patch the process back to enable the
00:40:02.500 --> 00:40:07.940
password and on the side notes how
reliably can you exploit this
00:40:07.940 --> 00:40:15.220
vulnerability? So, of course the SNMP
public community will leak you the version
00:40:15.220 --> 00:40:20.560
of the particular router but it does not
leak you the version of ROMMON and we're
00:40:20.560 --> 00:40:29.380
basically constructing ROP chains in the
rom monitor. So actually you have not that
00:40:29.380 --> 00:40:34.080
many versions of rom monitor available.
You have only five if we're talking about
00:40:34.080 --> 00:40:41.500
2800 router. So the worst-case scenario is
just you crash it four times. It's not
00:40:41.500 --> 00:40:46.410
like you have to crash it four thousand
times to you know beat the ASLR but
00:40:46.410 --> 00:40:52.340
there's a second option which is
interesting. ROMMON is designed to be
00:40:52.340 --> 00:40:57.590
upgraded, so basically a system
administrator can download a new version
00:40:57.590 --> 00:41:02.800
and update it but the thing is that read-
only region that contains the stock ROMMON
00:41:02.800 --> 00:41:10.300
is always in place and it is always at the
same offset, so even if you updated the
00:41:10.300 --> 00:41:15.760
rom monitor, the read-only version of it,
the old version that always been there,
00:41:15.760 --> 00:41:24.650
will always be at bfc00000. So basically
the assumption is that all the devices
00:41:24.650 --> 00:41:29.031
manufactured at the same time and place,
they will have the same read-only rom
00:41:29.031 --> 00:41:38.030
monitor, you can query your serial number
of your router using snmpget. So for
00:41:38.030 --> 00:41:44.760
example my lab router is manufactured in
the year of 2008 and Czech Republic. So
00:41:44.760 --> 00:41:51.720
and it has the following version of rom
monitor. So guys to, you know, to
00:41:51.720 --> 00:41:57.210
summarise about all this, do not leave
default credentials on external networks.
00:41:57.210 --> 00:42:02.730
So public communities are not designed to
be placed on external networks
00:42:02.730 --> 00:42:09.990
for the Shodan to find it. Take care of
what you expose on the external networks.
00:42:09.990 --> 00:42:17.270
Of course patch your devices and watch
for the end-of-life announcement by
00:42:17.270 --> 00:42:28.200
Cisco. Sorry? Sure why not? Alright guys
thank you so much for your attention
00:42:28.200 --> 00:42:40.510
applause
thanks for having me.
00:42:40.510 --> 00:42:42.600
Herald: I suppose there are some questions
00:42:42.600 --> 00:42:50.250
in this audience, please take a microphone
if you can. no one on the internet? They
00:42:50.250 --> 00:43:00.590
are flabbergasted there it seems.
Microphone number one.
00:43:00.590 --> 00:43:07.110
Mic 1: Yeah, I'm a random network admin
and I know that people tend to use the
00:43:07.110 --> 00:43:13.320
same SNMP community on many of their
routers. My view is that basically if you
00:43:13.320 --> 00:43:19.171
can get access to read only on those
routers you will be able to hijack that or
00:43:19.171 --> 00:43:25.140
like use the same principle. So basically
don't use the same SNMP community on all
00:43:25.140 --> 00:43:29.910
your devices that would be also something.
Artem Kondratenko: the main thing is to
00:43:29.910 --> 00:43:34.800
update your routers because it's a patched
vulnerability, the patch was released in
00:43:34.800 --> 00:43:42.860
September of 2017 but if you tend to use
the end-of-life products like router 2800
00:43:42.860 --> 00:43:48.940
you probably should use a strong community
strength for it.
00:43:48.940 --> 00:43:55.040
Herald: Thank you. Someone else having a
question there? Yes someone on the
00:43:55.040 --> 00:44:00.390
internet is alive. It's alive.
Signal Angel: Let's try it. Yeah now I've
00:44:00.390 --> 00:44:05.050
actually got a microphone. The Internet is
asking how much time did you put into this
00:44:05.050 --> 00:44:08.830
whole project?
Artem Kondratenko: While working on this
00:44:08.830 --> 00:44:19.070
exploit consumed around I'd say four
weeks. Four weeks from the discovering the
00:44:19.070 --> 00:44:26.320
device on the external network to the
final exploit. Yes. Thank you.
00:44:26.320 --> 00:44:31.460
Herald: I have a question maybe for you as
well. Is that you you're as well a lot of
00:44:31.460 --> 00:44:36.070
you have lots of volunteers who are
working with you as well in researching
00:44:36.070 --> 00:44:38.440
these exploits or?
Artem Kondratenko: Volunteers?
00:44:38.440 --> 00:44:41.730
Herald: Yeah I don't know.
Artem Kondratenko: No, actually we don't
00:44:41.730 --> 00:44:44.260
have any volunteers, this is all part of
my work.
00:44:44.260 --> 00:44:52.300
Herald: Okay. Thank you very much for
thank you very much for this in its really
00:44:52.300 --> 00:44:56.420
revealing lecture, if someone wants to...
Artem Kondratenko: Oh I just forgot to
00:44:56.420 --> 00:45:02.460
say, is my mic on? okay so the actual
proof of concept and the debugger will be
00:45:02.460 --> 00:45:07.570
released in a few days, so the Python
script with the capstone and the actual
00:45:07.570 --> 00:45:12.070
proof of concept I'll publish it and in a
week or so.
00:45:12.070 --> 00:45:16.039
Herald: okay thank you.
00:45:16.039 --> 00:45:20.550
34c3 outro
00:45:20.550 --> 00:45:36.741
subtitles created by c3subtitles.de
in the year 2018. Join, and help us!