 Don't rock us too hard owning Ruckus AP devices, which will be, I think, one of the more hardcore hacking talks as we like it here at the Congress. Please give our speaker a warm round of applause. Just one minute, and I'll be good to go. What is that? Awesome. OK, so I'm doing the live demos, so I need to just be prepared with some stuff with a terminal here. This is always good, and another one. Why not? And OK. Wait, what the? Come on. Almost got it. All right, yeah, now I am almost good to go. Awesome. Well, thank you, and thanks, CCC, for inviting me to speak here. Before I begin, I would like to ask if anybody is familiar with Ruckus network devices. Raise your hand. All right, OK, all right. Well, CCC is going to hate me for the next slide. But the first time I saw Ruckus access point was when I intended Blackhead USA this year. I noticed that Ruckus provide the conference Wi-Fi. And when I got back home, I was wondering how many vulnerabilities were discovered on Ruckus equipment. So I did a quick research on cvdetails.com, and I saw that Ruckus had 11 CVEs, and five of them were critical. Those CVE were post-authenticated command injection. Well, this means no pre-auth RCE were found on Ruckus devices, and only post-authentication. So that either means that they are really, really secure, or I'll let you answer this question yourself. So wait. Before I begin, who am I? My name is Galzwar. I'm from Tel Aviv, Israel. I'm a research leader at Aleph Research by HCL Abscan. And I've been doing reversing for around 10 years. And I focus on offensive and embedded devices research. And in this talk, I will be using this Ruckus R510 Unleashed. Ruckus has an Unleashed version for every access point they provide. Unleashed are access points that don't rely on Wi-Fi controllers. However, all access points on this list share the same vulnerable code base. And I noticed that some vulnerabilities also work on zone director product line, which is their Wi-Fi controller. The vulnerabilities, I will show, affect this firmware version and prior. Firmware analysis was pretty much straightforward. No compression, no encryption. And on the R510, you can even get the kernel B config from some odd vision. Well, another cool thing about this research is that I did this entire research with device emulation. Only when I actually found a vulnerability, I actually bought a device. Now I would like to talk about my device emulation environment. I'm using my simple yet useful emulation dockers. On my Docker Hub, I got pre-built QMU systems for different architecture, such as ARMv7, ARMv6, MIPS, and MIPSEL. And these dockers really help me emulating and setting up different routers. For this research, I used Docker that wraps an ARMv7 QMU that runs Debian kernel. And now I would like to show you how easy it is to set up an environment. And that, of course, does not work. So let me just, hmm, just a minute. OK, so just a few more minutes, and I'll show the video. OK, got it. Whoops. Awesome. OK, so here I'm just starting my Docker with port 5575. And I am going to fast forward a bit because it's not the edit one. And here it just starts up. It takes a few minutes, so I cut it out from the original video. All right, now I'm going to go to the firmware extraction folder and just start the squashFS root system. And now I can just copy it using SCP to the port that Docker mapped to. And now I just tar it and then SSH to the Docker. And I got the tar gz file. I'm going to extract it. Get into the folder. Sorry. Get into the folder. And just use truth to change my root to this squashFS. In any minute, yeah. All right, so now I'm running truth, change my root. And now I got the rocker's banner and the busybox, the rocker's busybox. And I can see there in it these scripts, which are the startup scripts. OK, this is it for the doctors. And let's start with some exploits. So this is my first RCE. In this attack, I will fetch admin credentials without authentication and then pop a busybox shell with jailbreak through SSH. And let's start with live demos, because demos are fun and what could possibly go wrong, right? Just about everything, but yeah. All right, so for this, I got my terminal. And awesome. Let me just do this. OK, great. So now I'm going to fetch a file from the router. So I'm just using Wget. And this is my router IP address, the one here. And I'm fetching a file from slash user slash WPS to all. Oh, shit. Thank you very much for that. Live demos, right? Yeah, they told me not to do that. OK, so this is the right terminal. And let me just adjust it as well. Got it. So this one you see, right? Yay. OK, so I'm using Wget. And I'm just going to fetch a file from the router IP address from user WPS tools, tool cache slash var slash rpmkey.rev. So I probably got a typo here. And yeah, so now I got the number eight. And now I'm going to fetch the same file only with eight and pipe it through strings and grab something called all-powerful-login. And hopefully, I got a typo. OK, got it. Powerful-login. Yeah, I'm going to copy-paste the hell out of it with the right number, which is eight. And this is it, finally. So those are the admin credentials. I just fetched them unauthenticated, just like that. And now to finish my exploit, I will just log into the ssage using the credentials I just fetched. And now I will enter the debug mode, script mode, and use exec command to run being a sage. And as you can see, I got my busybox, and I am the admin, and I am part of the root group. And this is it. Thank you. Wow, live demos are tough. OK, so let's understand what we just saw here. So I started by examining the web server configuration. Rokus uses embed this as its web server interface. And this is how the configuration file looks. We see that it uses slash web as its web root directory. And we also see that it uses EGS handler for dot EGS and dot JSP extension. EGS is embedded JavaScript backend language that the web server uses. But the most important thing is what we don't see here. We don't see any file fetching restriction. Whoops. That means I can fetch any file from slash web directory regardless of its file extension or type. In other words, no access control whatsoever. Yeah, so now that I know I can fetch any file, I would like to look for some interesting file to fetch. There are 67 files that are not standard web pages. Eight of them are symbolic links. And one, in particular, is this symbolic link to slash TMP there. Yeah. That means every file I will fetch from slash user slash WPS underscore tool underscore cache going to fetch files from the TMP folder. Yeah. And since I was emulating the router using QMU system mode, I could run the system in its scripts. And I noticed that some files are written to slash TMP on system startup. One of them was this one, rpm.log. This log shows that every day, the router writes a backup file called rpm key with a different reversion number. And that file looked like a really good file to fetch. The problem was that it writes it to slash bar slash run. I can only fetch files from slash TMP. Well, it's not a problem since slash bar slash slash bar slash run is also symbolically linked to slash temp slash bar slash run. Yay for me. Right. So now let's see how I was able to fetch this rpm key file. So yeah, slash user slash WPS tool cache is symbolically linked to TMP. Var run is symbolically linked to TMP var run. Now I was needed to get the rpm key reversion number. Here it's 11. Well, there's a file called rpm key.rev that just stored this number. So I first needed to send a request to get this number. And after that, I can just fetch the right rpm key file. OK, so now that I fetch this rpm key file, I notice that it contains some binary data. So I just pipe it into strings. And as you can see here, these are the admin credentials in plain fucking text, right? Yeah. OK, great. So to finish my RCE, I wanted a busybox shell. SSH can be enabled from the web interface. But the thing is, Rockus are using their own CLI. At first, I tried to run a busybox with hidden command called exclamation mark, v54 exclamation mark. And as you can see, it's supposed to exit the CLI and enter the operation system shell. But the problem was that it needed the device serial number. And I don't necessarily got this number. So I had to use a different approach. Eventually, I used the CLI debug script mode that was only supposed to run store shell scripts. However, this exit command is vulnerable to past reversal. So I just used it to run being a sage, and I got a busybox shell as root. Awesome. So after this beginner's level CTF vulnerability, it got me thinking, there are probably more vulnerability to discover here. And I was wondering in how many ways I can get code execution on those devices. So this is my second RCE attack. Here, I'm exploiting a stack overflow vulnerability with unauthenticated request to an agile page. OK, but before that, I would like to talk about GDRA script I wrote that really helped with the reversing process. So Rocus has left all the log strings in the binary. As you can see here, we got debug error info warn just about everything. And here, we can see a GDRA decompant code for a function. And it's debug log print. What's even better is that Rocus also print the function name for every log print. So I wrote a script that just searched for this log print and renamed the unnamed function with the function from that log print. So here, I just updated the name to get ZDDN instead of the undefined function. And here, we can see a binary called EMFD. I was able to reduce its undefined function from 1,500 to less than 900, which makes the reversing process way shorter. Based on that script, our team member, Vera Mence and I, wrote a generic script for GDRA. This script searched for patterns in GDRA, decompiled code, and renamed the function with matches. Now, I would like to show you how this script can work not only on Rocus code. Here is a GDRA decompiled code for a dropper executable that was compiled with a trace option. Here, we see that its log string contains a function name. This is buff get ECDSA, private key. Our script uses regex to match the log print and group the function name. Then, it replaces the function name with the group matches. So this is how we managed to retrieve function name for dropper binary as well. So this script is already available on Alif GitHub account. Feel free to use it. It's really useful for many projects. But back to my second attack. So now, I would like to present three important binaries in the web interface. The first one is slash b and slash webs. This is the actual embed this web server. It handles HTTP request and execute handlers according to the configuration we just saw. It then sends command through a Unix domain socket to EMFD. EMFD is an executable that contains the web interface logic. It maps function from the web pages to its own function. It then implement web interface commands such as backup, network configuration, retrieve system information, and much more. Libemfd.so is a library that is used by EMFD for web authentication, some sanitation, and some code execution. And now, in a diagram, so webs listen to HTTP slash HTTPS. If it receives a JSA page, it uses EGS handler to pass function to EMFD. EMFD then checks if the function name is mapped, and if so, he calls the function pointer. And eventually, EMFD runs some kind of shell command. For example, if config, IP tables, route, and et cetera. I will get back to this later, but look at this carefully, because this is where everything messed up. For example, when I'm sending an HTTP request to slash admin slash underscore update guest image name.jsp, webs invoke the EGS handler. This handler uses a function called delegate, which sends a command to EMFD through a domain unique socket. EMFD then maps every string it received to a function pointer and runs it. Here we see that EGS handler uses upload verify string to send to EMFD, and EMFD then maps this string to a function also called upload verify. All right. Next, let's talk about how the authentication mechanism work. So there are four permission levels, admin, user, FM, and guest. Here we see that each user has a page with a delegate function call. For example, FM login uses off FM, and user login uses off user, and so on. Once a user is authenticated, his session is stored for a specific period of time. Each JSP page should check if the session is valid before calling other delegate function. Here we see that underscore CMDState.JSP calls session check before he calls the adjunct CMDState, and that means he checks for a valid session before he runs the adjunct CMDState. All right. So I use grep and got 67 pages that did not perform any kind of check. I then listed all the different functions that can be reached without authentication, and one function that looked very interesting was this adjunct restricted CMDState. Here we can see that it does not perform the session check, and it can be reached by sending a request to slash-tool slash underscore RCMDState.JSP. But enough with the talk. Let's go to my second demo, which is the Stack Overflow Exploitation. Again, I'll just use my terminal. You can't see it. Yeah, yeah, just a minute. Live demo is all tough, apparently. OK, here am I. Yeah, OK, so now everybody see? Yeah, awesome. So now first, I would like to telnet my router on port 12345 and see that nothing works, which is good. And now, this is my payload. So this is my overflow, and I'm going to call 10 at D with minus L and minus P, 12345. OK, and now let me just post this payload, and hopefully I will not have any typos. God help me. Tools and underscore RCMDState.JSP. Great, so in a second, it should work. Awesome, so I got a message OK, which is a great indication. And now I can just telnet my router on port 12345. And as you can see, I am the admin. And again, I am the part of the group root. Yeah, and this is it. Thank you. OK, so to understand how I was able to exploit this stack overflow, I would like to explain how the Adgex request works. I was able to run both Embeddys web server and EMFD on the QMU system emulation. And that's how I was able to inspect a standard web request like that. Here I call the underscore CMDState.JSP page, which is mapped in EMFD to a function called Adgex CMDState. Makes sense. Adgex CMDState receive an action attribute from the request. Since the action is do command, it uses something called adapter command. Adapter do command then calls a do command function. Do command is a large switch case function that executes different command based on the attribute it gets. In this example, it gets getConnectStatus, which calls a function called CMD getInternetStatus. Now let's look on a page that do not perform session check. EMFD maps underscore RCMDState.JSP to a function called Adgex Restricted CMDState. This is where the R stands for. The function also called Adgex CMDState, but with a very limited set of commands. This specific request pass ZapD to do command, and it runs an executable called Zap. This is how Zap command runs in the shell. We see that we can control its server and client argument by passing the attribute server and client. The thing is server and client are not sanitized good enough. So I can just pass unintended argument to Zap. For example, this minus d slash temp slash b, crush me please. OK, so I was able to find Zap sources online. Ruckus described it as a robust network performance test tool. And when I examined the code, I noticed there's a stack overflow in the minus d argument. Here's the code that parses minus d argument. Let's see what it does. So first, it replaces all commands character with spaces. Then it copies every segment to a temp buffer. Since it expects a number, this is a very small buffer. And well, they try to be secure by copying string with strn copy, but they use the entire string length for n. So it doesn't really protect the string in any way, and I was able to smash the stack. As for exploitation, R510 uses both NX and ASLR. To overcome NX, I decided to use rope gadget. I used two gadgets to run system with a pointer to my payload. In this case, I'm using telnet d that runs slash bin slash sage as a login page on port 12345. As for ASLR, since Zap is forked from EMFD, I can use a brute force approach, and by that, overcome its 9-bit of randomness. OK, so now I would like to look at a request that runs Zap command again. So if I can control the server and the client attributes, why can I just use it for command injection? So to understand this, I need to understand how Zap command is being executed. Here we can see that do command uses exec syscmd implementation to run Zap. Exec syscmd implementation is a function in libemf. This function first called find syswrapper function, and then it uses vfork and exec v to execute the shell command. Let's look on find syswrapper decompiled code. We see it looks for slash bin slash syswrapper underscore wrapper dot sh. If the script is available, it updates a global variable that I named syswrapper path. Now, exec syscmd implementation executes slash bin slash syswrapper, and in our case, it runs Zap command with the argument from the adject request, such as server and client. Here we can see the syswrapper dot sage line count, and it seems like a very big script. But it handles many commands, but what interesting me is the Zap execution command. Here we see that slash bin slash zap is being executed with opt variable. This variable received both server and client values from the request. However, ops get its value with quotation mark, and that stops me from injecting code. And, well, that made my life sucks for a while, to be honest. But what kept me entertained and motivated was that Rockus had the weirdest CLI in their firmware. So before I continue to my next attack, I would like to show you other Rockus CLI. So this is the CLI I had to escape for the first attack. This is an entire different CLI that also being used by the device. I noticed that it can be reached after system startup. This CLI also got a hidden command, exclamation mark, V54 exclamation mark, that also supposed to escape to busybox. But it also needed the device serial number, and it was no good to me. However, this V54 command uses content from this file, slash writable, slash etc, system access. The content of the access file was written by another hidden command called Rockus. I discovered that by passing this string to Rockus command, I was able to inject code and escape the shell. But now for the weird stuff. When I called Rockus command to save my payload, this is what I got. And this one, and this one. Yeah, waf waf, bow bow, and rough. Yeah, Rockus CLI actually box at me. Yeah, so when I called V54 to execute my command injection, I was asked, what the chow? As in chow chow dogs? What the actual fuck? No, seriously. Well, at the end, I was able to run a busybox shell, and I didn't really care about those weird Easter eggs. But it was still pretty entertaining. Yeah. Well, I still wanted to achieve pre-off remote code execution by command injection. And I just knew that EMFD got to be vulnerable. It took me some time, but eventually I made this possible. And this is my last attack, where I found a command injection vulnerability, and I was able to reach it without authentication by writing a web page. All right, so as I mentioned before, EMFD executes code in a really messy way. EMFD sometimes uses libmf, other times called shell script sys wrapper. And sometimes it just runs the command itself with libc. These are all the different functions that EMFD uses to execute shell code. Here we see that there are 107 libc system function call. So I had to find a page that uses this function call without sanitation. I was able to find four functions that call system and were vulnerable to command injection. And today I will be showing the last one, which is cmd import AVP port. All right, so to reach the vulnerable function, I need to send an adjunct request to slash admin slash underscore cmd state dot jsp. And my request should look like this. I'm passing a command with cmd equals import AVP port. This also uses do command to call cmd import AVP port function. This function uses libc system function unsafely. Here we see the function decompiled code. All I had to do is to pass command injection in the upload file attribute. And as you can see, it just executes the code. Right, so this is it. That's a win. Well, not exactly. I still needed to be authenticated to reach this function. Well, the problem was that cmd states page check for session. And only then it calls the vulnerable function, adjunct cmd state. All right, so I need a different approach. And what if I could write a page that only calls adjunct cmd state and do not use the session checkhole? It might actually work. For this, I decided to use the zap executable again. Zap has a lot of different arguments. And we already know that we can pass unintended arguments to it without authentication. One of them is set a path for the zap's log. However, writing a log is not enough for me. I need to control the content. For this, I used tag, sub, and note argument. They are a string, so they get a string and just write it in the log file for some extra information. Here is the log file writing code. It gets the file path directly from minus l. And I can control the log content by passing argument, note, tag, and sub. OK, great. But there are more problems to solve here. I wanted to write a page, and it has to be in the slash web directory. The problem was that slash web is a part of the squash fs file system, which is a read-only file system. I needed to find a writable path inside web directory. Luckily, slash web slash uploaded directory is symbolically linked to slash writable slash etc slash errspider. And this directory is on a writable file system. Yay for me. OK, so now I knew that I can write a file with my content to the web directory. The only problem left to solve was that ZapExecutable needed to connect to something called TxStation. Otherwise, it won't write anything to the log file. Since I got ZapSources, I could just compile ZapD, which is the TxStation. And now I can set Zap to connect to a station on my computer. Awesome, so this was the request I needed to send. It executed this Zap command. Notice that I used two arguments, minus s sub and minus t tag, to write my delegate call. Finally, Zap has wrote a file to slash web slash uploaded slash index dot jsp. Although this page was full of junk, that didn't bother me because what interest me was the delegate call to the vulnerable function. Now I can chain those two vulnerabilities together. First, I write a page to slash web slash uploaded slash index dot jsp. Now I can send a command injection payload to the page I just wrote. And this is the time for my last demo, which is the most difficult one, so good luck to me. OK, so first, I will need another terminal. Yeah, this is it. And so in this one, I will run ZapD, which is the TxStation. And I will listen to port 444 with Netcat. Great. And now for my other terminal. OK, great. So now I would like to show you the page create payload. So as you can see here, I'm using the server and set it to my computer. And I'm using the minus l to write a page and minus t and minus s to write the delegate function call to Ajax's cmd state. And now I can just post it. Page create, this is it, to my router to slash tools slash underscore RCMdState dot jsp, no typos. And in a minute, it will just reply and say, OK, awesome. So now I wrote the page. Next, I would like to show you my command injection payload. So here I am using NC on the router. And with Netcat, I'm just connecting to my computer on port 4444 with a reverse shell. And again, I will post this command injection to the router on uploaded slash index dot jsp. Oh, yeah, shit. Sorry about that. OK, again, great. And now, hopefully, I'll see that I am the root user. One more second, again. And now, be root. Yes. OK, OK. Yeah, yeah, wow, that's, yeah, live demos. How about that? You don't see them anymore. OK. In conclusion, I demonstrated three pre-auth RCE today. The first one was credential leakage with CLI jailbreak. The second one was stack overflow without authentication. And the last one was command injection with authentication bypass. I also shared my Docker setup and introduced a very useful GDRA script that helped with my research and can help others. Rocker's networks was informed about these vulnerabilities. I requested 10 CVEs for this research, and they confirmed these CVEs. If there are any Rocker's user here, you should stop what you're doing and go and check that you're running the latest firmware update. If not, you may be victim to some very serious abuse. So again, please check your firmware ASAP. OK. And well, this research was a lot of fun. It involved all sorts of different vulnerabilities. It was also an excellent opportunity to check our Docker emulation environment, which proved itself very useful. A blog post with all the details will be posted. But since Rocker's asked really nicely, I will wait with my post until January 6. So stay tuned for my blog at Aleph Research Blog. And while you're there, check our amazing research. And this is it. Thank you very much for listening. Thank you for this great talk. So now we have quite a lot of time for Q&A. So you already know the game, queue up at the microphones, or ask a question on the internet. We will today start with the internet. So please. All right. So there are a couple of questions here. The first question is, will this work on unleashed firmware of Rocker's AP? Yes, it definitely will. Not the latest, but the entire research was conducted on the unleashed version. All right. Now let's do an in-room question first. And microphone number one, please. So thanks for the great talk first. Then you mentioned that there were 107 handlers for which cold system at some point. I hope you didn't check them manually. So my question would be, you probably used GDRA to search for those. How would it be? Yeah, so the system, the reference count just gave me a really good indication that they're doing something wrong. And when I actually searched for command injection, I first looked what are the reachable pages that uses system. So that narrowed the list to something smaller, which was still around like 15, well, 15 or so. So I just saw that the command injection was done pretty much manually with GDRA. No fancy scripts here. So no analyzing of the call tree in GDRA? No. OK. Thanks. Sure. All right, microphone number two, please. First of all, let me just express what the actual fuck. Then secondly, from a networking consultant perspective, the quad one usage in your scripts, it's easy. But please don't do it, because people tend to use quad one as a legit IP address in their systems for dummy IP addresses, which is actually a DNS server on the public internet. And just comment. The actual question is all your attack vectors are against when you are able to reach the system on a layer three basis, right? Yeah, correct. So all of the attacks are from both the internet or the LAN. But yeah, only layer three. So OK. And in the end, I can only offer you that I have some hardware from an orange vendor. I can offer you if you want to do some further exploration on other vendors. Yeah, why not? All right. The internet has another question, I think, right? Right. So the internet wants to know, is the virtual smart zone mode also affected? No. Only access points and some of the vulnerabilities, as I said, also work for the zone director. All right. Number two, please. Thanks again for the entertaining talk. And I noticed that on some of the slides, there was like a hard-coded cross-site request for GERI token. So I just wanted to ask, what's up with that? And were you able to find more places where there are basically security boundaries crossed by a hard-coded string like that? Yeah, so I tried to focus my research more on the low level and stack overflow and command injection from the binary analyze. But yeah, we saw some web vulnerabilities. One of them is SSRF and another might be with tokens that is still hard-coded. There are a lot of things to keep on looking in those fingers. So you didn't report that one? No, the hard-coded one, not yet. OK, thank you. All right, the internet. Right. So how much time did you invest in total for ripping this device into little pieces in so many ways? So it took me one month. The first exploit I found relatively fast. I think it took me around two days. And after that, the other analyze took me around three weeks or so. All right, microphone number two. Thank you for this awesome talk. I really enjoyed it. The first bit of the presentation was a little bit fast for me, the docker part. How did you discover that you can run the Ruxus firmware in your own docker container? Can you please repeat your question? How did you discover that you can run the Ruxus firmware in your own docker container so that you can discover all these flaws? Yeah, so I skipped a few steps. So I basically used beanwalk. And after I extracted the, so I downloaded the firmware, used beanwalk. And then beanwalk usually extracts the squashFS, which is the firmware file system, different file system. So I just copied it to my docker. And because it's a cross architecture docker, it runs the ARM architecture. And I was able to actually run the code from the firmware, the user space code. OK, thank you. Sure. All righty, any other questions? You have 30 seconds to invent a question. Do you have 30 seconds of content? No, I can do a fancy dance or something like that. All right, yes, please. OK, I wish I could. I wish I could. All right, still no questions? Well then, a good night to every one of you. And thank our speaker again, please.