 Without further ado, uh, this is Elvis Callado. He's going to be presenting on some really cool, uh, research that he manipulated. Yeah, sure. Yeah, sure. Alright, awesome. Thank you so much for joining us and here we go. Tossed. Is that good? Alright. Thank you everyone and welcome for coming. This is my talk called Green Waves. Alright, let's get started. So this device up here that you see is called the Green Wave G1100. It was distributed by Verizon FiOS and Frontier. They're an ISP up in the northeast and we have Verizon for the file service which is not available in my area but this is what they gave you. So if we look a little there we got our FCCID. So what do we do with our FCCID? We go online and we find the internal photos and then we find the processor and we look it up. There's no data sheet for that unfortunately but we see the shield is on cover, we see two memory modules and if you see something like over here you may be going, hey, what's going on over here? Well, you have every reason right to be because this over here is JTAG. Awesome. So I just grabbed my, I think it was like JTAGulator or my Arduino. It's 33 Logic so it doesn't really matter. Uh, got the pinouts. So this in the middle, open up the device, this thing right here. In the middle we have four pins and what do you think it is? You are, right? So we have ground, receive, transmit, 33. Unfortunately when we turn on the device, standard in is blocked so all we get is standard out so receive is, you know, we can't type anything. Crap. We cannot do anything whatsoever. We just see standard out, we just see print logs but we're not seeing it, we can't do anything. That's, that's boring. So after some thinking because I want to keep everything software based I don't want to touch hardware like yeah there's a NAND flash, we can remove it. That's the last thing I want to do. Like I'd rather go with the software route because it's ripping crap out and I mess up, I got to buy a new one and I just forget all that. So I just solder some, so it takes like a hot glue gun. Uh, you know, find an area on the board that has no copper exposed, put a little bit of hot glue on there, take some header pins, just stick it on there, wait for it to dry and then I take some wires and I just, you know, solder it on and it's not the prettiest thing in the world. Uh, but you know and then I just attach some wires, put it on my FTDI base breakout board over here, turn on open OCD with my configuration on my FTDI board and we see automatically, boom, we do have a JTAG interface, we have the ID, we see the manufacturer ID is ARM base, woo hoo. So then we open up our own target configuration, so we set the reset config, we have test reset, we have system reset, it's a push pull situation, uh, we have a new like tab with the ID at the very end of it and then we create a Cortex-A, uh, target that's little Indian and then after that we run it again with our two configurations, the board and the target and look, oh, also we have six break points, four watch points and you know, I can just tell it into open OCD, like always and give it commands or attach GDB to it and start analyzing memory once I halt the processor. So before we get on to the next slide, so the first thing I started doing once I had JTAG was I don't have a data sheet for this chip whatsoever, so I'm dumping memory addresses, if something is not, you know, unaccessible, I just write that out. So I'm dumping, dumping, dumping, halting the, uh, the boot up process in different stages, I'm trying to find the kernel boot arguments. So after about an hour or two, I think about two or three hours, it was kind of a while, I finally found it and I set a watch point to the very last character that kernel argument, kernel boot argument, uh, so that when it's done writing for a watch point, I can set a break point, well, it'll, you know, break and uh, I can overwrite it. So instead of a knit calling slash a knit, um, I can set, no, instead of calling this upon initialization because I don't have view boot access, like yeah, I could ground clock on the, uh, on the NAND or so or, you know, whatever and make it fail and maybe I can, you know, do a second retry and get into it, but again, I don't want to touch hardware. So, um, I'm able to overwrite the kernel boot parameters, set a knit to BNSH. All right, awesome. And then we continue execution and awesome, we get a root shell. We actually can actually do something and you actually probably saw me typing up some commands to load everything up. So great. So this gives us access to rip the firmware off and get debug capabilities, right? So the very first thing I do is I go through all the RCS initialization scripts, I get everything running and I look for all the running daemons. I don't care if it's WAN base, LAN base, everything's open scope in my eyes. So I'm looking at anything that's listed on all interfaces zero to zero or, uh, you know, an internal interface. Uh, IP tables can maybe come into play later, but we'll get into that later. So very first thing, I'm looking for low hanging fruit and someone please script me out. UDP 1900 is. Yes, awesome. It is known as SSDP. It is a piece of crap and everyone talks about it. But anyways, we have three binaries here. We have three different SSDP servers. WPS monitor. Front tier four is about a 32 megabyte C++ file. Have fun with that. It's kind of fun to look at. Fun. Uh, we have mini UP and PD, which probably is vulnerable to the readout of bounds volume that I posted earlier this year. So anyways, today we're going to be talking about WPS monitor. So before I even start ripping things out, I need to know my environment. Um, because I need to know like, you know, do I need info leak? Uh, do we have an extra keyboard stacked? Do we have an extra keyboard? Well, what the hell am I looking at? Right? So very first things I do is I look at all, you know, there's a Lib UPP library. You can see like, oh, I'll Lib UPP. It's nothing until one. So remove all like assumptions out of your head. Uh, and also we have ASLR on the imported libraries. Surprise. We look at a stack in the heap. We have depth. Awesome. Uh, we also look at the heap over and over again, you know, and we see that ASLR does impact the heap based headers in the stack. Cool. Uh, the only thing that we see here is that this WPS monitor, the main binary itself is not ASLR, uh, whatsoever. So we do have a static binary. We have a gadget. The problem is we have null bytes in this 32 bit address. So if we have a string based overflow or anything like that, we can't use this because of limitations of a string. You know. So, after that, this device does have USB devices. So I plugged in the FAT32 device in and then just DD, uh, you know, look at mount, see where the file says to be mounted from, DD down to, uh, the USB drive. And then after that, one, two, three, bada-bing, bada-boom. We use bin walk, like always, and we extract the file system. So now we're going to get more into the nitty gritty, happier stuff. Vuln hunting. And so like, you know, everyone has their own way of like, you know, going about vuln hunting. Like some people have all, you know, super dope scripts. And some people get lucky, like, oh, man, I just looked at a string. And that sucks, right? It's like, oh, I looked at strings from the vuln. And that's exactly what I do first. I'm looking for low hanging fruit, least path of resistance. So I'm looking for a percent S, right? Because what are the destinations for a format string? We have a buffer or some sort of file descriptor in Linux, right? We have syslog, uh, or we print the standard out, or we're gonna, you know, save it something to a buffer and do whatever, right? So I see this very first response. HP11 OK blah, blah, blah. I see percent S here. See percent S there. Percent S here. Over here is a percent S. And over there, there's a percent S as well. And that's very interesting to me. So I'm like, all right, what is, what is this response? Right? Like what function is using this? So I see this immediately. Looked at x refs. And I'm like, oh, that's nice. Sprint F. But, you know, remember, Sprint F is there copying all those like vulnerable C functions can be used in non-vulnerable way, right? So just because it's printed out doesn't mean it's vulnerable. So we look up, what is R0? The destination buffer coming from. So we look at, it's from R5 going to R7, you know, then adding some more to R7 and putting it on the R0. So this right here seems to me that we're accessing some sort of member and a structure, right? Or, you know, an object, but still a structure, a C. So we're accessing something. This could be like a pointer that, you know, maybe Malik is saved, you know, Malik is being saved to or whatever. Like, you know, we get an address from Malik. We save it there. Uh, maybe it's calculating the length beforehand and, you know, maybe it's not vulnerable. Like I said, who knows? Or maybe this is a character buffer, um, inside the structure that has a fixed size. Who knows? So we need to do more research. So the next thing I do is I'm looking at the UPNP, um, uh, specifications going, what is this, uh, message for? And we see that we have something called a SID, which is a unique identifier. And we have this timeout second dash and this is actual subscription time. Something in R, we probably have second dash and some integer, right? So I'm like, well, what's causing this response? And we see this. It's called a subscribe. Subscribe, publish your path. And I'll, I'll show that. What's that afterwards? We have something called a callback. Host and user agent are optional. So that's why they're not bold. Callback is, uh, mandatory. It is wrapped around, uh, angle brackets or less and greater than whatever. Uh, we have NT set to UPNP event, which is static, has to be that. And then we have timeout second dash and then it requests, uh, duration. Second dash, um, again, probably an integer. Second dash 20. Second dash 900. Whatever. So, uh, what is this for? Like, what part is this? What is a publisher path? So you probably have done like, I set an M search request on multicast and then I get an XML and then I get all this crap. But everyone talks about the control URL, the soap actions. And that's not what we're talking about today. We're talking about this, the event URL, which is called the GINA stat. I forgot what it stands for. Tell them ahead, but just trust me. It's called GINA. Um, so the very first things we do is we launch up some notepad editor, VIM, whatever, but this is not VIM. I think it's Zed or something like that. Uh, so we use, you know, requests. We're gonna send a request that, come on. Uh, we do second dash and then a string instead of like an integer. Because I just want to see first hand if this percent S that I'm seeing in the response is even worth looking at. Uh, this is, you know, maybe pass it to a toy first. I mean, you know, I get zero back and I get second zero. Like that's not exploitable or anything worth looking at. So I need to dig deeper. So we just send it and awesome. I sent a string, I get a string back. That's awesome. So okay, this seems kind of interesting now. So that percent S is what we control. So okay. So next things we can do is we have two things we can do. We can be super seat, um, super like awesome CSI, double hacking keyboard, lead dudes that were, you know, ball of clavus and crap, or fuck it, we can just black box it, right? Um, I mean like, yeah, we can chase down the structure and like, you know, we can find CSI functions and find where arguments, you know, it's being passed to you. We know that, you know, like a stir copies a character buffer of character pointer. So this is a character pointer or whatever. Or maybe if we look up certain strings online like on get duck duck go, uh, Google, whatever, maybe we find the structure that we're clobbering potentially and we find everything, but this is supposed to be confidential. So I didn't have all this at the time. So screw it. We'll just black box it. Kobe. So next thing. So I set up a for loop that same as that code just in a for loop. I'm incrementing now by one byte at a time, that second dash. And I have GDB attached. It's going to keep going and going and going and going and going and going. Any kind of reset sets to me just try again and keep going. Right? Just keep going. And I get a segmentation fault. I'm like, oh my god. There's poly static sizes. This is awesome. Oh my god. I got to call my dad. But hold on. Let's not call my dad. Because this is just loading and compare. We're not writing anything. We're just loading and compare. That's not anything useful. And we go in IDA and we look around and yeah, alright, comparing it to R1, which I don't know the value of. It's an unknown. But you know, we have this compare. It's looking at zero and it's going to branch out and return. Ah. So alright. So I'm kind of messing around at this point because I'm thinking we have this UPNP server. What kind of states can we put this in? Kind of request can I send to this thing? We have an HP stack. We have a SOAP stack, SSP stack. We have this GINA stack. So I start thinking, I'm like, well what kind of other states can I do this in? And I find this. And I'm not going to read this wallet text to you. Basically what this says is that once you subscribe, you get a SID. You are a unique identifier ID. Right? So from there, is this that you subscribe for 20 seconds? And then you change your mind. No, no, no, I meant to subscribe for like 100 seconds. Well, you send a second subscription with your SID and with a new timeout value. I was like, ah, maybe we can like hit some new code with this type of thing. So we subscribe first, save the SID, and then we cause the overflow and see what happens, right? So I do the thing again. And we get a different site fault. I'm like, oh. Better be something good, right? So I start looking and I'm like, oh, we see this load. You know, offset 24 to R3. We do a compare branch on zero. So if it's null, we don't call it. You're not going to call null. And then it jumps to it with the uh, with the exchange. So we can jump modes in thumb mode, arm mode, whatever, right? And I'm looking at this, I'm like, what's R3? I'm like, oh, that's the value I control. That's my name. That's awesome. So, okay. So we have, so I got lucky, right? I got super lucky, but I don't care. That's my luck. So going on, I kind of have a way to obtain PC control. We're one pointer away, right? We're almost there. Still can't use WPS monitors a gadget because we're still bounded by the limitations of a string. Can have a null byte because that's the terminator. Uh, ASLR and import libraries that don't have an infleek. So whatever, right? So now to the exploit development of this. So we're thinking, we're thinking, I have one pointer away. I have ASLR. I have depth on a heap and stack. One pointer away. Holy crap. You know what this reminds me of actually? So back in the day, who's ever done Internet Explorer exploitation, IE 8, 7, 4, 1. I don't care. Anyone? Yes, awesome. Cool. So that's exactly what it reminds me of. I'm like, okay, new tactic. Screw the infleek. Let's find a way to spray the heap. Let's figure out to do some, you know, some David Blaine magic stuff. And then, you know, maybe we can trigger the overflowing code exact, right? And speaking of which. Oh, whoops. I need to start this. So you're about to witness the world's slowest exploit. My exploit takes about 20, 28 minutes and 30 seconds to run. So we're, we're going to start it. Just want to make sure it's running before I go back to my slides. Alright. One second please. This is slow. Alright. There we go. Alright, cool. So let's go back. Alright. So this says spray the heap, do some magic, trigger overflow, get code exact. So we look at the heap. So I need, I need information now. What is the base address of this heap, like loading it every single time? So I need a target address to maybe grow this heap towards, right? So look at it once, maybe twice. Look at it again, and again, and again, and again, and again, and again, and again, and again. That's okay. You know, we can do that later, right? We need more off-screen. That's, that's boring. So, um, also I need to know how much memory do I have? Like Internet Explorer, everyone had like, you know, maybe back in the day, like 512 megs. Yeah, my age is showing, right? Or, you know, at least a gig. So spraying the heap is not really that much, you know, not much, you don't have to worry about it, and running out of memory and stuff like that. But we have 117 megabytes free. Or, you know, I don't want to be, you know, taking up everything. So let's just call it 100. 100 megs. So theoretically, if the heap always loads at zero, just think about that. The maximum size I can grow the heap to is 0 6, 0 6, 0 6, 0 6, or whatever, right? So awesome. I can grow the heap to a very large size potentially, if I find a primitive to allow me to. So after doing all that stuff and putting everything to like an array, oh that's an array, into a spreadsheet, and seeing like the top and bottom and see, like what's, what's going on here? Like what's the, you know, like what's the highest address the heap actually loads on to and stuff like that? So I actually saw that it loads under 0 303 all the time. We see like an 0210, but it always loads under 0 303, so I'm like, all right, cool. So I start looking at the description functionality. Like how does this work? I need to find primitives. I need to fill the heap. I need to do memory leak. Not info leak and memory leak. I need to fill up the heap. So I start looking at this. So I start looking at Stirling and it goes to a calic. And I find out that that pointer there is the starting, it's the URL portion of the callback. So after the IP colon port slash, and then the end of it, that's, that's where we're at. So that's where that pointer is to. That's slash, and then maybe like ABCD, right? The closing bracket is null terminated at this point. So we're just going to add some sort of size to it. So it's going to be size of some structure, right? So we have some structure. And where the last element is some character buffer array. And then we call calic. If you're not sure what calic does, it takes the values of R1 and R0, multiplies them, checks for overflow condition. This is a very high level. And then it calls malloc, gets a pointer back, mem sets it and returns it back to you. So everything's going to be initialized to 0. There's some other crap that goes on in there, but it's not relevant to this. So we go into GDB, we set some break points, and you know, we get the length and we get to turn edges because I need to learn how to, you know, I need to start spraying this stuff. So I set up a for loop to subscribe over and over and over and over and over again. And crap. All right, I'm getting the same pointer over and over again. Just so in my head, I'm like, all right, so it's being freed, alec'd again, freed, alec'd again, freed, alec'd again. What, like, what the hell is going on? So step back. If I were to develop this, if I were, you know, on some team where I'm stressed out to get something delivered by the end of the week, I'm like, well, having one block for subscriptions for multiple devices makes no sense, right? If I'm just using the same block, we're free one block with two devices, that's almost like a used out the free situation, or only I support one device at a time. So I go, well, let's change something in my subscription. They can change IP address maybe, change the port number, change the URL. So for simplicity, I just do like a four I and range or two, whatever, and use the I to add it to my port range. So we get a new, you know, port number upon every single iteration, and bada bing, bada boom. I can now spray blocks of 4k. Awesome. I have a way to fill the heap. So in theory, this is what I'm doing. Subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe, subscribe. So we're just filling up the heap with a bunch of subscriptions with different port numbers. Okay, cool. Let's cool. You can fill the heap. We can spray the heap, but we still need to do some dope David Blaine magic, all right? Then we go to the street magic, you know, some, some crazy shit. So I start reading the manual some more. We go back to the architect, you know, the specifications, and I see this request now, unsubscribe with the publisher path with your SID. I'm like, all right, let's go back to the code. And I find this function called delete subscriber. I wonder what it does. And I see this little wrapper of free here, which literally just takes a pointer passes to free. So I set a break point there. I go, well, what is this pointer? Right? Like we have runtime capabilities. Like, I don't feel like spending all the time reversing all the things. Don't limit yourself to just one way. Use the easiest ways. So I'm like, oh, so if I subscribe, and I reverse the array of all the cities that I saved, and I set them to unsubscribe, they're, they're freed. These are my blocks. I'm using the awesome. So I have an ability to spray the heap, and I have the ability to free blocks at will. And I can make holes in the heap if I want to or whatever, right? So back to monkey in a round. Because this is the heap spray portion, but I'm like, okay, I'm still bounded by the limitations of a string. I can't do anything yet. I can fill up the heap. That's, that's fine. But, you know, I can't use WPS monitor as a gadget yet. So I started talking to a colleague who works on different products but also has experiences with heap stuff. I'm just bouncing ideas back and forth with my colleague. It's kind of like rubber ducking. And so I sent him my IDB. And I'm like, hey man, I'm looking at this. You know, this is my limitations, this is what I can do so far. You know, you can look at all the, you know, references to malloc, calic. If you're super hardcore, ex malloc, you know, if you turn it all, kill the application, super hardcore. But we start going back and forth and he asked me a question. He goes, hey, this function here about base 64 decoding uses malloc. What is that all about? Like a UPMP, base 64. I'm like, oh, shit. Awesome. So we go back to soap. The thing I did not want to talk about whatsoever. And I started looking for an action with one argument because I don't want to deal with multiple arguments and it's just, it gets kind of messy. And I find this, this delete AP settings. Sure, whatever. What kind of type is this new AP settings argument? Go all the way down to the bottom of XML. We see it's a base 64 type. So we can send a soap request to this action and inside the XML, inside the text, we just, you know, base 64 encoded string. I can base 64 encode nulls. Okay. So what I do next is like, all right. So when I send the soap action, I set a break point. I look at the heap block and it's actually the decoded data that I sent to it. It's not the base 64 string. Awesome. I can now write nulls and I can probably use WPS as some sort of gadget if I can figure out the way to spray my fake object into the heap. So I try this out. So we do it. We unsubscribe. We call the soap action. We unsubscribe. We call the soap action unsubscribe. And then I look at this. This is early development of my structure. That's why we see like 0202, 0303, just lining everything up. The very first one is my first gadget. So whatever. But I'm trying to set things up. So I'm doing everything by hand at first and I'll, you know, make it nice and pretty later. So, okay, we can spray the heap now. We're kind of almost there of doing some magic. But wait, roadblock. All right. I do my spray and do my technique and I'm like, all right, let's look at this address and it's not there anymore. Shit. All right. Well, what's going on? So to think about the layman's terms, like super simplistic, you can't build a house without a roof, right? That seems silly. So my technique right now, I'm like, you know, I got all these subscriptions. I unsubscribe. Do your soap action. I unsubscribe. Do your soap action. Unsubscribe. So, you know, blah, blah, blah, blah. And we're going down the line and, you know, and then the rest, right? But then the Linux kernel is like usually an application. You got all this free space in Melik. You don't need this anymore. So it eats it all the way and revokes it from me and gives it to another application or anything else that needs the memory, right? So that's what's going on. So I'm like thinking, I'm like, well, instead of freeing everything, what if I leave the last allocation there? Because in the seconds, there's actually an option to do infinite, where you'll never, ever run out of time for your subscription. It's forever until the application, no, until like reboots or something. But either way. So now I fill up the heap. I pop the last allocation off of my array, reverse it. Now I do a unsubscribe on the second to last and I go from there, right? So this is awesome. So this is working fine until... Come on. Until this happens. So my way to do the base 64 thing is right into the same block over and over again. I'm no longer putting something on top of the free list, occupying it, getting freeed again, free something else, put on top. It's not, it's something else just racing to it. Something else is causing some issues. So now I've got to figure out what the hell is being freed. So I'm going to set just a simple break point on free. If it's null, just keep going. I don't care about null being passive freed. So we just keep going and we're just going to wait. And actually it does some stuff every 60 seconds because there's also other imported libraries and you know, we've got to see if they're doing something or the main binary is doing something. Because if there's a race condition, this makes the exploit that we're trying to do much less reliable and it's not really worth going for anymore. So I look at it and I'm like, all right, let me set an M search request. Because if you use Google Chrome for example, when you open up your browser, go to YouTube, your browser sends an M search request on multicast because it's looking for something called a dial server, which is a layer of UPMP developed by Netflix. You can find the GitHub, find the code. You can also look at the Chromium code branch and find the dial code. But anyways, we send an M search request. We see that there's port and it's being freed. Okay. We find the sizes by looking at the heap header manual and stuff like that. So every 60 seconds, this device sends out a notify request on multicast. Sends it out and says to everyone, hey, you know, I'm here. Here's Maximil. Go and chat. That's cool. If not, you know, no big deal. And then last but not least is someone sends an M, like a get request, like a device is getting the XML in order to send a scope request or a subscription. This is what it looks like. So I'm going over all these different instances as to like what can get in there, what kind of requests and the sizes so that I set up my heap a little bit differently. So now I have two arenas. So I have one arena where I have spaces for these objects to fit in too perfectly. And they can jump in there all they want because I'm making holes. It'll never get like condensed or whatever. It may get trimmed. It doesn't matter. Then I have my other arena where I have that last allocation being set and I do the whole thing. So now we shift gears. So now what I'm doing is a free, replace, free, replace, free, replace, blah, blah, blah. And then we do an allocation back up. So we resubscribe and we come back down. And also what we're doing is between every single iteration is that we have a UDP socket listening on multicast. We select it upon every single iteration. There's something to read. We slurp it up. And we also maybe do some more subscriptions and replacing just to unfoo bar anything at the top of the free list because we don't want anything else to race there. So next we can spray the heap. We can do some magic now. We can now use WPS monitor. We can write nulls to the heap and stuff like that. I guess base64 decoded. That's awesome. But we don't have an exploit chain yet. So I'm thinking, I'm like, all right, let's cause the crash and we look at what do we control? Right? I don't use like, sometimes I use like, point of bug and stuff like that. But if you use an open OCD and you have point of bug running, you have a lot of issues that may occur. So I just haven't commented out my gdb init. But anyways, the only register that we have control of really is R4. R4 points to our overflow string. And yeah, the first pointer is going to point to something in the heap, blah, blah, but let's just assume the very first one is just 41, 41, 41, 41. So I have a pointer that points to my data. That's all I have. So I start looking online. I'm like, all right, let's think back about Internet Explorer days. You know, what do we do? Oh, we did a stack pivot, right? We have like one shot. So we do a stack pivot. So if the heap was executable, we have a bunch of like nops and then shellcode, nops, shellcode, we jump to nops. We, if we have depth, we have a bunch of returns. So, you know, we shift the stack to the heap and then we return, return, return. Then we have our drop gadget to call virtual protect and we X2 shellcode, but it being but a boom. So I start looking online and I see this. So this was from 2012, a rock scone talk about exploiting stuff on R and blah, blah. And it has this load multiple decrement before instruction. And what does it do really? And it's saying that, oh, you know, if you have a source register, you can populate the other registers and you can, you know, do a stack pivot because it writes to SP. I'm like, oh, man, God. So I open up Redair and I look for this load multiple, load multiple deduct before with R4 and I see some instructions. So I plug it in, very first thing and illegal instruction. Well, what the hell? Like what? Why? So we look at the ARM manual and we see this restriction on the second line. The register destination list cannot contain SP. The destination list that I had before has SP to second to last one. This is now an illegal instruction. I can't use this technique on this device. So all right, back to the drawing board. So what I do next is I develop a rejects for IDA. I'm looking for load where the last, the last register, you know, second operand or whatever of that opcode is R4 being dereft. That's all, that's what I want. So I set up a rejects to do that. I find a bunch of them, I go through them by hand and I find this gadget here. And then it says like dereft R4 and R3. We add all these offsets and we get R2 and we have R1 and R0. I'm spraying 4K blocks here. Hex 1000 is 4K. So we're just going to jump into another block that I'm in control of with my data. So this right here gives me the primitive of calling a function with two arguments. Okay, cool. But the problem is though once, once this function, like once what I call returns, it's going to use the stack now and it's going to pop PC and I no longer have control. So I only have a one shot situation. So I'm thinking, I'm thinking, like what can I do? I'm like, alright, so let's look at functions that write, like that write to memory that are not bounded by character limitations. So I started looking at mem copies. This thing has tons of them. So you know, I'll put on my music or whatever and I start grinding through this. And I find this mem copy here and you don't have to read all this. I know it's probably hard in the back and I apologize. I'll sum it up. So this right here, if you look at the second to last instruction, r0, the destination, is a stack based buffer. Even though the stack frame is kind of large at like 2k, you know, hex 800, we still have a destination buffer that's a stack. And r0 and r1 are in our control now because that was the last gadget that gave us control. And r1 is in r4, r0 is in r5. We look in, r4 is n, r5 is the source. So instead of bringing the stack point to the heap, like fuck it, let's just bring the heap to the stack. Just clobber the shit out of the stack. I control n. I can clobber the shit out of the stack. So that's what I do. And we look at the bottom of this thing so we adjust the stack frame so we have to be careful now. This is a large adjustment, 2k. So we're not going to jump back and do stuff. We're now just incrementing the stack. We have to be careful not to run out of stack space and cause us, you know, like an interrupt to happen or a signal to happen and kill the program. So now we have control of r4 to r7. Now we brought the heap to the stack. So now, next gadget. R7 is going to contain a pointer to the IAT table entry, uh, inside WPSMarkz where it's not ASLard, uh, uh, start to unsign long. But with a pointer of minus 4 and this next slide you'll see why. So then after that we pop from the stack r3 to r7pc. Next thing. We deref r0 now, which is now going to take the IAT table plus 4 and it's going to, it's going to deref that pointer from the IAT table. Now we have a libc function, a pointer. Now we're inside libc. I start to unsign long. We don't need to leak it anymore. Pop from the stack. Next one. We add r3 because, look, we have r3 to r7. r3, uh, it's going to be an offset. Now we're going to add it. Well, r3 and r0 are going to be added together and we're going to save it to r0. So now it takes start to unsign long. I take an offset and I add it and I get to, since the system wasn't working, I didn't want to debug it, p open. So since the, since the, uh, WPS monitor didn't use system, it didn't import, p open or anything else I can use to execute shell commands, uh, since back in the day, like, you know, with inter-explore exploitation, uh, if you had some way to get into kernel 32 DLL, you just add or minus an offset to get to virtual protect in order to make the, you know, allocation that you want executable or whatever the hell you want to do with the permissions. So then from there in gadget 6, this looks really large, but we can pick another allocation that's like maybe a megabyte away. You don't care. We're gonna write to the heap now. We have a pointer to p open and all these gadgets I found by hand. If I try to use some wrapper thing and try to automate it, I would not have found these gadgets. Rapper and everything's gonna say, hey man, there's a mem copy with R0 and R1, well R1 and R2 and R0 is being stacked. It's not gonna tell me that. So anyways, this right here I'm gonna write to the heap. I'm gonna write the p open, uh, pointer that I just calculated into the heap now. Keep going. We're almost kind of towards the end of the stack limitations here. So now I invoke gadget 1 again, which is our last gadget, gadget 7. So this one, remember, I can call something with two arguments. So R2 is gonna be p open, R0 is gonna be a string, R1 is gonna be R, because you have to provide something for p open, and then okay, cool. So let's put it all together. So we spray the heap, we save all the subscription IDs, we don't free the last description ID, that's our roof. We free and replace the blocks with unsubscribe and we replace everything with the soap action with base 64 encoded fake structure, our rob chain, and ending with a command. Everything is aligned to 256, or actually it's, yeah, so everything is 256 by the line, whatever. So we free five, I'll be very occupied by five, free them again, go to the next five. If anything comes in multicast, fix up the heap if needed by doing resinscriptions and freeze again. Trigger vol, maybe we win. So we sue everything and we see this, right? So let's, let's check out this guy. Why is it 11 percent? No, it is at 11 percent. Why is it 11 percent? All right, so I guess I'm not doing the exploit live anymore. That sucks. Oh, that sucks. Oh no, why? It's on. All right, I'm sorry, I guess I'm not doing this live. But it is reliable. I can demo it later if you guys want to see it. But uh, sorry, so we're stuck at 11 percent. But what we were doing though was the free and replace of everything that we were doing. We create two arenas and we're going all the way down. It should have been around 60 percent by now or so. So that's, that's all right. Man, let's see down here. But anyways, if, if this was working properly and didn't want to just foobar out of nowhere, we would be in the context of reading all that stuff. But the funny part about this as well, just to look up, is that there's actually one process, uh, let's see here. One process ran by nobody. It's another UPNP server. So whoever actually made the process, you know, the, the, uh, the process run under nobody, like that guy deserves a high five. So anyways, let's go back to everything. Um, uh, man, I really wanted to show that shell. Oh well, it's actually still going. It's just going really slow. Anyways, so we do have a shell and I wanted to just show you guys some bonus stuff as well. So besides the shell and all that stuff. Um, so before I remember I was saying that, you know, I was looking at daemons that were running on a particular, you know, uh, all interfaces, already just a LAN and I found one of 5916 who was being filtered by IP tables. So I started thinking, I'm like, huh, what if we use that genus stack to pivot like a server-side request forgery, right? So we set the callback address to 120 local hosts 5916 with this URL. And so we attached S trace to that daemon to see if anything's coming in. We send the request and yes, we do get that. So if you are trying to hit something that's maybe token based, so it's a TCP based connection and maybe it's like, oh, it's doing like stir-chir, they start to be getting up something or stir, like a stir-stir, like some sort of substrain that's token based. You can use this to maybe hit that part of the code and maybe change configuration or something like that. So it's a way to pivot. So last but not least, I also wanted to give a buzzing demo, but I'm not sure if it's uh, if it's going to cooperate with me, but um, I mean, after all this, so finding the bone and all that stuff taught me something valuable. So uh, I was doing this by hand and I was like, you know what, I've been finding a lot of the same kind of programming issues with this protocol and stuff like that. I have a background in network engineering, I also have a background in QA. So I was like, let me start making a fuzzer. And I encourage everyone else to do this as well because what do we have? We just have HP, we have XML. If you could just make something to just send out an M search request, get the, you know, get the, the XML file back and just parse that, make the XML parser, go through everything, save everything, make your own fuzzer. Like you'll save so much time. So instead of a few days like it took me by hand to find this volume, it would have taken me 30 seconds. So actually, let's see, now it's going, it's going now. All right, so maybe if we have time towards the end, I'll check up on it and see for uh, for all good. So anyways, oh man, everything going wrong is, that's awesome. So anyways, so if an ISP asks you, and this is going to be super cheesy, but whatever, I'm going to do it. If an ISP asks you, could you, would you install this router in your house? You must say, no, I do not, would not install this in my house. I do not want it here or there. I do not want it anywhere. I wouldn't want it for free. I wouldn't want it if it could download up to 10 GB. But anyways, that's enough of that stuff. This is who I am. So I go by Blackout Online. Someone had the real name Blackout, so I changed the L21, 020, cool, Elite Sauce, what up. I'm a zero-day researcher at Exodus Intelligence. I do embedded devices, both SOHO, I do enterprise network solutions, firewalls, virtual appliances, whatever, I don't care. If I can get it, I'm going to audit it. Smart devices or anything else that catches my eye. We're also hiring at Exodus Intelligence. We're looking for another zero-day researcher so if you're interested for getting paid in front of nowadays, I get a bonus on top of that for selling your phones to us, like you know, hit me up. But that's about it. So again, that's who I am. Thank you for coming to my talk, Label Greenways and Ham. Take care.