 All right, so I'm going to be talking about drive-bys, automatic browser fingerprinting and exploitation with the Metasploit framework. The tool itself is called Browser Autopone, and it's an auxiliary module for the Metasploit framework. There are exploit modules that everybody, I'm sure, is familiar with, and also auxiliary modules, and that's what Browser Autopone is. The first thing it does is it fingerprints a client to try to determine what exploits might work. And I started this tool almost a year ago, and when I first wrote it, it sucked, and now I think it doesn't. So this is a basic guide to what I'm going to be saying today. A bunch of boring intro stuff. Then we're talking about cluster bombs, some guided missiles, and that's broken down into fingerprinting and targeting. Then some stealth. Hopefully the demos won't break, and I'll compare Browser Autopone to some other things that I think suck more. So I'm James Lee. I'm also known as Egypt. I'm co-founder of Teardrop Security, which is a consulting company focused on penetration testing and forensics analysis. I'm also a developer for the Metasploit project, and I'm a member of ATT&CK Research. I started submitting patches, and bug reports to Metasploit in 2007. HD thought that my stuff didn't suck that much, so you put it in, put some of it in, and eventually gave me commit access in 2008, when I promptly broke the repository. So I think I've gotten better, but no guarantees. Originally Metasploit was a game. It was an end-curses-based game that you could play anywhere. It later became a full-fledged exploitation framework written in Pearl, but Ruby is a lot better. So in 2005, HD and the core dev team at the time, Scape and SpoonM, rewrote the whole thing in Ruby, which of course is way better than Python. It's an extensible framework, and it's more than just using exploits. It makes it a lot easier to write exploits, and there's a lot of non-exploit tools available within Metasploit. We'll talk about some of that a little bit later. I love Metasploit. It's part of the reason I started submitting patches, started part of the reason I wanted to make it better, is because I know how awesome it can be. One of the biggest advantages to having a framework like Metasploit is that all of the payloads and encoders are modular, so you can write an exploit and then use any of these other payloads that are already available. So in the olden days, back in 2000, everybody just hard-coded their shell code at the top of their big, ugly C file, and that was a real pain in the ass. So if you wanted to use different shell code, you didn't know if the code you had would work with this exploit until you tried it, and it wasn't modular, it wasn't extensible, and Metasploit replaced all of that with something much better. There are a bunch of protocols that already work in Metasploit, so you don't have to do all the boilerplate crap to make HTTP or SMTP or whatever work with your exploit. You don't have to go through all of the effort of writing that code, because it's already there. There's also stuff for finding vulnerabilities and for taking CrashPox to a real exploit using some of the pattern offset things, and there's a few other tools that are there to make writing exploits a lot easier, and Metasploit supports the traditional server-side exploits and also client-sides, which is what we're gonna be talking about today. And if you don't believe me that client-sides are important, then talk to Chris Gates. He's done a whole bunch of stuff about client-sides. I won't beat this into the ground too much, but any time you can get in the middle, browser exploits become incredibly interesting, so Carmettasploit does that for us. Dragorn is working on integrating AirPone, which gives you basically the same stuff, and as soon as you get in the middle, it's basically game over. And if you can't get in the middle, users still suck. So just send an email or put an iframe in their corporate web server or whatever. That part doesn't really matter. As long as you can get them somehow to talk to my web server, then we win. Client exploits in Metasploit are relatively easy to write. There's extensive HTTP support. All of that stuff is already there. There's heapspray in two lines of code. That's a fairly complex technique, and you can do it in two lines of code in Metasploit. There's also support for other more complicated stuff. Soterovs.net, DLL, and heap feng shui stuff are both integrated, and it's fairly easy to use them. It's a lot easier than having to write it yourself and crapping out some big, ugly HTML file. Everything is in Ruby. It's a lot easier to read, and in general, much better. There's also a lot of protocol level IDS evasion. It's very easy to randomize HTML and JavaScript. All of that stuff is very easy to just mangle around and make it look different, so it's harder for IDS guys to trigger on it. And you can write a simple exploit in around 10 lines of code. This is what one looks like. This one's kind of contrived example, but so you've got some class ID, some active X control with a vulnerable method, and so we've got, you know, I've elided the class ID here because it doesn't really exist, but we set up the heap spray with this little chunk of code. We spray the heap with our shell code. That's this guy. And the place where we want to go and a block size, and it just does it all for you. Then we trigger whatever the heap corruption is, and it gives us a shell. Or they can be arbitrarily complex. For example, ANI load image chunk size is 581 lines of code. It's got to build up an image. It's currently our biggest HTTP exploit, so it's got to build up an image. It's got to throw the payload in there, randomize some stuff, and it's a fairly complicated exploit. And as of June 28th, Menisploit has 85 browser exploit modules. That's changed in the last couple of weeks. There's been a few ODAs in Internet Explorer and Firefox, and we have support for all of those. So we've got 85 exploits, or something like 80, 7, 88 now. What do you do? How do you figure out which one to send? The problem is one of scale. You've got a bunch of people connecting up to you, which exploit do you send? If you send one Internet Explorer exploit, and all your people connect up with a vulnerable version of Firefox, you're missing out on shells, and everybody loves shells, you don't want to miss out on them. So the solution, and the first thing that I tried, was sort of a cluster bomb approach. For those of you playing at home, this is an MK44, lazy dog cluster bomb used in Vietnam. So this approach was basically using a user agent match. If it's Internet Explorer, you send all of our Internet Explorer exploits, and it's effective in a lot of ways, but it has a lot of downsides too. And originally, the browser auto-pwn module had all of the exploits basically inside the auto-pwn module itself, and so it was sort of a pain in the ass when new exploits came out, and you couldn't easily remove or add new exploits. That's changed. Now there's another big problem with that one. If you send all of the Internet Explorer exploits, and only one of them is going to work, if another one crashes it before that one runs, you don't get your shell. And like I said, everybody loves shells, and you don't want to miss your shells. So the solution here is a GBU paveway bunker buster. Laser guided missile for blowing up bridges. Freaking cool. So the first thing you need for a laser guided missile is to know what to point the laser at. You got to know what the client is, what the OS fingerprinting, or what the OS is running, and we use JavaScript fingerprinting to do all of that. And once we figure out what the target is, we're much less likely to crash or hang it or get that stupid little dialogue that says, you know, this script has been running too long, please don't give me my shell. So we only send exploits that are likely to succeed. It doesn't make sense to send Firefox exploits to IE, or IE6 exploits to IE7. So having fingerprinting gives us a much more granular way of deciding which exploits to send. And most of the available stuff for detecting what a browser is, use the user agent string, which is just a string that goes in the headers of an HTTP request that supposedly uniquely identifies any given browser. The problem is that it's really easy to spoof. And in fact, Firefox, Opera, and Safari all have things that allow you to change the user agent to look like IE, because a lot of websites are stupid and broken and you have to look like IE for their website to work. So they provide a way for you to easily change your user agent. And this totally breaks all of that detection. It's also easy for a proxy to change or just completely to remove. So if you've got some corporate proxy and everybody has to funnel through that proxy, the proxy can change anything in the way. And that makes it much harder for us to detect. Now, all of this is harder to change in JavaScript. There are ways to do some of it, so for example, Firefox, using the user agent switcher add-on will also change all of the JavaScript objects that tell you the stuff that's in the user agent. And so if you use user agent switcher to change to IE7, then the JavaScript objects also look like IE7 with a couple of exceptions that we'll see in a minute. In Internet Explorer, there's basically no way to change that. All of that shows up in, as JavaScript, it's really JavaScript or it's really the right thing. But it doesn't matter anyway with Internet Explorer as we'll see in a minute. So for figuring out what the client is, we've got a number of JavaScript objects that only exist in a given browser. Examples, window.opera only exists in opera. That one sort of makes sense. Who the hell would make something called window.opera if you weren't opera? Array.every only exists in Firefox. And some of these things only exist in certain versions. So these are new features that have been added since 1.0 only had these objects and now 1.5 has these objects as well. So an example of this is window.create.popup only exists in IE5.5 and newer. Array.every only exists in Firefox, I believe 1.5 and newer. Another way, another sort of method for figuring out what the client is, is used often by web developers is IE's conditional comments, parser bugs, rendering differences. So there's an example in IE6 or older, you could put a backslash in front of the star of the end of a comment and IE5.5 would not treat that as the end of a comment. So you could have a bigger comment for IE5 than for everybody else and use that to determine that it's definitely IE5. The problem with this is it's not really precise. It's reliable and it'll definitely tell us that it's IE5.5 or older but it's not precise, it only tells us that. Luckily, Internet Explorer gives us these awesome functions called script engine major version, script engine minor version, and script engine build version. The great thing about these three functions is they're almost unique across all combinations of OS and client. So if we have the output of these three functions, we can reliably and accurately determine not only the browser, but the browser version, the operating system it's running on, the flavor of operating system, so XP or 2000 or whatever, as well as the service pack level of the operating system. Opera gives us a nice little win here that's got a function called opera.version. Hey, that's all I need. Firefox doesn't have anything awesome like that. It just gives us the simple ways of using object detection to determine that it is Firefox and we can get sort of a high level version this way. So you can tell for sure that this is Firefox 3.0 by the existence of document.getElementsByClassName. Nobody else uses that and it only shows up in 3.0 and newer. So we can use that and check the user agent and see if the user agent is lying. So if the user agent says it's Firefox 3.0 and I know for sure that it's Firefox 3.0 because of my object detection, then I can be fairly certain, not 100%, but fairly certain that the user agent is not lying. And once I know that, I can use the more precise value that's in the user agent, 3.08 or whatever. Safari is still sort of a work in progress. I haven't spent a lot of time trying to fingerprint it yet. We don't have any relatively new exploits for Safari yet. I'm working on that. But there's a couple of objects that exist in Safari but it's mostly pre-standards compliant in this regard in JavaScript implementation. There's not many extensions to the JavaScript, the standard JavaScript libraries. So that's kind of a pain in the ass in Safari. You can't really tell much more than that it is Safari at this point. It's possible that I'll find some other stuff later but for right now all I can tell is that it is Safari. Now if you're printing the OS from the server side using the traditional user agent string matching is subject to the same problems for fingerprinting the client in the same way. And we could also use something like P0F for a passive fingerprinting using TCP artifacts and things that are different about any given operating system from others. But that sounds like work. So we've got JavaScript and JavaScript gives us a lot of stuff. Like I said with Internet Explorer, it basically gives us everything. We know the operating system, what version of the operating system it is and what service pack level it's running. So I can tell reliably the difference between XP service pack zero and one, XP service pack one and two. Well, 2003 is the sort of outlier. It has a couple of overlaps with XP. So I can't always tell the difference between 2003 and XP but the service pack levels are the same. So it's okay. Opera doesn't really give us anything awesome but it does give us this function called opera.buildnumber and that's basically unique amongst operating systems. It doesn't give us the version of the operating system or the service pack level. But it does give us the platform and that's enough to tell us with a certain degree of likelihood that the user agent is not lying. So we can use sort of that same hybrid approach that we used for Firefox earlier to determine the operating system using opera. Firefox, like I said, has the navigator.platform, navigator.useragent and all of those things are affected by the user agent string. So if someone changes the user agent string using user agent switcher or going through the about config, all of that will change too and that sucks but we've got navigator.oscpu which doesn't change. It's completely independent as far as I can tell from the user agent string itself and again this only gives us the platform but on Windows it gives us the platform and the version so we can tell using this simple little object we can tell that it's Windows XP. We can't tell the service pack level but most of the time that's okay. It's interesting that the Linux versions also give us the CPU which is totally cool because now it means it's Linux on Intel so I don't send any PPC shellcode with it saving me a shell. Since I don't really do anything specific for anybody else all we're left with at this point is the user agent. For the most part that's okay. Most people don't lie about their user agent. If they are lying it's likely that they're patched anyway. People that change their user agent are people that kind of know things about computers. It doesn't necessarily mean that they're not lying but or that they're patched just because they lie but I think there's probably a really strong correlation there. The advantage of a user agent string matching is that it's completely generic and it works on everybody basically. Of course the downside is it can be spoofed but sometimes that's okay. Right now we're not doing any fingerprinting on third party stuff. Quicktime, Adobe, other plugins and whatnot. That's sort of planned for the future but with ActiveX it doesn't matter because for an exploit we have to know the ActiveX class ID or the ActiveX class name anyway. So we don't necessarily have to do any fingerprinting to determine is Foxit reader installed because there's an ActiveX client or ActiveX class ID. We just say is this class ID installed. The easy way to do that is if you've got a class name you can just call new ActiveX object and if it doesn't throw an exception you're good to go and you can go ahead and try the exploit. Unfortunately if you've only got a class ID and you don't have the class name writing it out using document.write or creating it with document.createElement gives you a DOM object instead of an ActiveX object. Well that's kind of a pain in the ass. Having a DOM object means that it is an object and it evaluates the truth so we can't just check it for existence and the only way to tell is to try to run a method or access a property of that object that only exists in the ActiveX control and not in a regular DOM object. Fortunately for an exploit we already have to know that. So to exploit some vulnerable method you have to know the name of that method. So all we have to do is check the type of that method on the object. If it's a DOM object the method isn't going to exist and we end up with an undefined type. For anything else if it's an ActiveX method then it'll come back as an unknown type which I think is a little weird but suits our purposes well enough as long as it's not undefined. The other possibility is that it comes back as some regular JavaScript type like integer or string or whatever. At that point I don't really care just as long as it's not undefined. So now we've figured out what the target is, we know what we're looking at, we know what we're up against. Now we need to figure out what it's vulnerable to. We can do sort of a course determination server side and this is how a browser auto-pwn implements it. First we build the fingerprint using JavaScript, we send all that to the client, the client runs it for us, figures it tells us what it is, sends that back to the server. The server takes this, dumps it into a database, figures out which exploits might match this combination of OS and client and throws it back to the client. So then on the client side we've got all of these exploits and we can make a fine determination of which ones might work. So the example here is Mozilla Navigator Java requires the Java plugin to be enabled. So the test for that is very simple, you just make sure that Java is enabled and then go ahead and try the exploit. If it's not enabled then don't bother, you don't wanna do a heap spray for no reason. So now we've sorted all of this stuff, we figured out that we know what the client is and we can try to pick out a missile. If you're interested in this sort of thing this is an array of Iranian and North Korean missiles. I especially like and I would like to point out to you the no-dong. I also think it's slightly ironic that it's much shorter than all the others. So now we've picked a missile, there's another problem, AV, AV sucks. It sucks for a couple of reasons. You know if a user is browsing along and they go to all the effort of clicking on your link for you, they go to your evil web server, the AV catches you, they don't click on your link anymore. I like people clicking on my links, I want people to give me shells, AV stops my shells. So the solution here is some stealth and if we don't look like we're evil then AV will let our shells come back and everybody likes shells. And the way we do that is largely through obfuscation. We can randomize identifiers in JavaScript. That's relatively easy. All we have to do is know the names of all of our identifiers, randomize them up into ASCII strings and that makes it a lot more difficult to fingerprint. Secondly, we can build strings out of things that become strings. So string.from.charcode can take a bunch of hex digits and turn them into their ASCII equivalents. We can use that, we can use Unescape. There's a number of different ways of building a string from things that aren't strings and won't trigger AV. Another solution is using Ajax to send a little bit of it at a time. So you go download some with Ajax, some JavaScript with Ajax, you run it, you go download some more, you run it, you go download some more. So now we're getting little chunks of the payload and it doesn't look quite as evil. The downside to obfuscation is, of course, that it's not crypto, it's just obfuscation. And a human would be able to figure this out relatively easily. We're not really targeting a human to a human that might wanna figure out what we're doing because basically all we wanna do is get around AV. If a real person starts looking at our JavaScript, then, well, they've already determined that we're malicious. And we would like to avoid that if possible beforehand. So like I said, obfuscation is not crypto, but encryption is crypto, that's cool. So we can put a key, like an XOR key or whatever kind of key in the URL and reference it via JavaScript. So now, if somebody, W gets our evil JavaScript but doesn't save the URL that they downloaded it from, they can't decrypt it. And using this, a simple XOR is enough to beat all the AVs, all the nids. And the best part is if they figure it out, it's really easy to just make it better and use RC4 instead of XOR or use something like that. The problem is this is sort of a DRM solution. We have to have the key on the client side someplace for the, so it can be unencrypted and so that it can run our evil. I think that's okay, though. So now I'm gonna try some demonstrations and I hope they don't break. So first, we've got several, oh, let me cat that file. First, we've got several actions with browser auto-pwn. The first is defanged detection and all this does is show which browser is connecting up to you and all of this shows up on the browser itself. So this is not something you'd wanna do in an actual engagement, but it's useful for making sure all the detection works and it stores it all in a database for us. So we can see we set up a database. We set our surfboard, which is where the browser will connect to. Setting the bug equals true doesn't randomize any of the JavaScript and it prints more stuff so we can see exactly what's going on. So the first step here is fire up IE6. Hey, look at that. We know that it's IE6 on XP, service pack zero, English on an X86 architecture, it's IE and it's 6.0. So all of that is pretty straightforward, fairly simple. Now, Firefox from the same box. Now I think this is interesting because since I'm using virtual box, it appears to browser auto-pwn that everybody is coming from the same IP address. I'm natting through, so it looks like all of these browsers are coming from the same IP address. The difference is at this point that they've got different user agents. And we can see here, it's Windows XP. We can't figure out the service pack level on Firefox, but that's okay because we still know that it's Firefox and we know that it's 1.0. Close that guy. See if we can have two versions of Firefox at the same time. Yeah, yeah, shut up. So here we go. Same thing, Windows XP, Firefox 3.5. Where is my user agent switcher? There we go. This I think is fun. Now we've changed our user agent. We look exactly like IE did. Right? Same user agent, different detection. This is Firefox 3.5. Opera for some strange reason runs on my JavaScript twice. Thank you. So it's not exactly the same user agent. We've got this little EN tacked on to the end, but it's very similar to the Internet Explorer user agent we saw earlier. I still know it's Opera. I still know it's 9.0. So all that's fun. We can also do it, yeah, yeah, go away. P-A-S-S, okay. Again, it looks like it's coming from the same box because it's virtual box. Everything looks like it's coming from the same IP address. So browser auto-pwn can't tell them apart based on the IP. But we've got this same exact user agent string coming from the same IP address. Now I know it's Linux and I know that it's 9.60. So now for the fun stuff. I have to wait here while all of our exploits run. 12 modules found. Hey, that one gave us a shell. Boot. Hey, that one gave us a shell too. Boot, ah, stupid part. You know you wanna give me a shell. Ah, I knew I should have sacrificed the goat. So that's that. I'll try this again. Oh, I lost my place. Thank you, open office. So I hope that worked. It mostly did. Now, how do we go from seeing all of that cool stuff to making your ODE work with Metasploit and using browser auto-pwn? And we have to wait for open office. Thank you. Keep going. Come on. You can do it. Maybe I should have turned those virtual machines off. Do I get a mouse? Yay, I got a mouse. Let's try this. Boot. So it's relatively easy to write exploits for this framework now. All we have to do is add this little auto-pwn info call to the top of the exploit class. We have a UA name which tells us which browser this is going to work against. We have Vulntest, which is a piece of JavaScript to run before we determine that this exploit will work unless it's ActiveX. And we'll talk about the difference there in a second, but all of the information that you need to go into Vulntest comes from the exploit anyway. Everything in there is stuff that you already had to know to make the exploit work. So here's an example with Mozilla Navigator Java. You have to have Java installed, which we can determine based on the existence of Java enabled. And you have to have Java enabled. So we check to make sure that it is. And if that is true, then we're good to go and go ahead and try this exploit. Note also that we've got a rank here. This tells us, well, that was a terrible drawing, but this tells us what kind of exploit it is. If it's a reliable EXE writer, it goes first. We want to sort things by how unlikely they are, or how unlikely they are to crash the browser. It's much better for us if we can just get a shell without ever alerting the user. So we try those things first. Here's an example with ActiveX Control, the venerable MSO6067 keyframe. Pioneered the heap feng shui technique by Alexander Sodorov, that guy's a pimp. But the volntest here is a method in the ActiveX object. And the class ID is the class name. So as long as we know those two things, we can determine whether all of that stuff is going to work. This is a similar chunk of code, but it's for a completely different exploit using a class ID instead of a class name. We still have to know the method name to try, but all of that is contained in the exploit anyway. So here's a quick summary. We've got reliable target acquisition. We can reliably determine who our client is, what operating system they're running on, and we've got smart missile detection. We only send exploits that might work. We don't send exploits that are more likely to crash or hang the browser, or do a heap spray unnecessarily, causing the user to potentially click away. We're stealthy in the sense that it's difficult for AV to detect us, and it's really easy to write new exploits. All of our detection results are stored in a database, and so you can potentially take this and tie it with a bunch of statistical stuff and make it better. There's also a number of exploit packs out in the wild available for commercial purchase, but most of these come from places that don't have extradition treaties with the US, and they're kind of difficult to get, and so I'll talk about them briefly. Impact and fire pack are sort of related. They use a lot of the same code. They're not exactly the same, but they either had a common ancestor or somebody stole some shit. They're mostly old exploits, though, and all of their detection is server-side, so it's much less reliable than mine, and it's really difficult to change or add new exploits to their pack. Part of that is because it's written in PHP, and PHP sucks. They also use a similar obfuscation and XOR technique, but mine is better. NeoSploit is sort of an oddity among exploit packs. It's an elf. It's compiled binary, and it runs as a CGI, so getting a hold of the source code proved to be pretty difficult, and I never actually found someone who had the source code, and unless you've got that source code or you do some serious or virtual engineering, you won't really know what it does, and I don't think, as a penetration tester, it's a good idea to run code when you don't know what it does. LuckySploit is pretty incredible. It runs real crypto in JavaScript. They implemented RSA, and they implemented RC4 in JavaScript. Holy crap. Unfortunately, it's still really hard to get, and the legitimate way of getting any of these exploit packs is to send $4,000 to some dude in Russia. Really? No thanks. In contrast, BrowserAutoPone is awesome. It's easy to write new exploits. It's easy to take out the old ones if you don't like them. There's an option that I didn't really talk about called Exclude in the advanced options. You can just type show advanced, and you'll see Exclude and match, and Exclude is a regular expression that if any exploit name matches that regular expression, then it won't try to run that exploit. Match is the opposite of that. If any, if any exploit name doesn't match, it'll run, or it won't run. Yeah, you know what I mean. One of the best parts is that it's free. It's a three-clause BSD license. Take it, use it, sell it, I don't care. I would prefer if you'd give me some credit, and I would prefer if you would give back. If you take my framework and make it awesome, I wanna make it awesome too, so please give me patches. However, it's BSD, so really do whatever you want. Another big advantage is that it's not written in PHP. PHP is stupid. All of my OS and client detection, well, almost all of my OS and client detection is client-side. So I don't have to rely on something that can easily lie. And it works better in the case of a spoofed or borked UA. So there are other, so there are third-party tools in Windows that will change the Internet Explorer user agent, and some of them actually break it. Like, thank you, whatever. They will try to insert their own little string in there and say, Internet Explorer plus some super hoody widget. Well, super hoody widget puts their string in there and it breaks the user agent and then nobody can tell what's going on unless you use my detection methods. So some of the things I'd like to make better. The payload selection right now is sort of limited. Basically, if the exploit is a Windows only exploit, I always use Metropoter. If it's not, if it can be a Windows or a Linux or whatever, so for example, most of the Firefox exploits are this way, we always use a command shell. That's kind of a bummer because most of the time I'd rather have Metropoter. Fortunately, a lot of people, a lot of really smart people are coming together and trying to write Metropoter for POSIX. And once that happens, we'll have a generic payload for everybody that's Metropoter. And Metropoter is freaking cool. It's much better than a command shell. CMD sucks. And I would much rather be able to upload files and all of that stuff. And another problem is stopping when you get a shell. This might be really difficult. In the presence of net and proxies, everybody comes from the same IP address. One of the thoughts I had was making everything, a download exec payload, and then I can have all of the browser auto-pwn stuff determine which payload gets run. And so I can set a unique ID for each host in the download part of that download exec. The part that sucks about that is we end up with exes on the target. And that's not cool. I'd much rather be in memory if we can do it. I'd also like to make the JavaScript obfuscation a little bit easier to use. Right now, you have to, at code writing time, you have to know the names of all of the identifiers that you want randomized. That's kind of a bummer, but getting around that basically means I have to write a JavaScript compiler and crap. I don't wanna do that. Another fun thing is a standard called UAProff for mobile devices. And it allows very fine-grained control or very fine-grained detection and advertisement of things that a mobile device can do. So this thing can send SMS and yada, yada, yada. I would like to integrate that, but we don't really have many exploits for mobile devices yet, so it's not a high priority. I'd also like to integrate it with MetaFish. MetaFish is a really freaking cool tool put together by Val Smith, Colin Ames, and Dave Kerb. And you should check out their talk later today, basically going all the way from email to shell in one tool. Totally awesome. So you can download it here. Please submit patches. I love patches. Thank you. And I'm gonna be in Q&A room two. If you have any questions, take them there.