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!