 All right, thank you everyone. Yeah, as he mentioned, we're going to be talking about some hacking of data center power equipment and components. So let's dive right in. My name is Sam Quinn. I'm a lead senior security researcher at Trellix. You can find me at Twitter or X or whatever they're going to call it next week at EIP. My core technical interests include exploitation, hardware hacking, and embedded systems, and IoT devices. And I'm Jesse Chick. I'm a security researcher who does not have a company, MX. And you can find me on Twitter at ravenousbytes. And I'm really into full system emulation, reverse engineering of all kinds. And Sam and I share a passion for hacking IoT and embedded systems. All right, so let's dive into what is a data center. Of course, this is the ideal picture everyone sees in their mind. However, it really actually just looks like a sterile environment with servers. The term data center kind of referred to multiple things. It could be the facility itself that houses a lot of these servers in cage spaces like this, or an individual cage space kind of shown in this picture, or a co-located server rack that companies call their data center. For the context of this talk, both utilize similar power equipment. So it's kind of interchangeable there, but it's something to bring up. The next is why we chose to even hack data centers in the first place. For one, there's a lot of company initiatives to go full cloud. Trellix, my company, is one of those. There's also some national interest to improve cybersecurity. It's the number one item in this national cybersecurity strategy. And then last year, I guess, there was some bipartisan bill even. And I thought it was funny because they end quote to keep our data safe. They're trying to get more money to do that. So we wanted to check out how they're really doing in that respect. So our approach was to actually ask some industry experts in data center configuration and the people that actually run data centers what would be good attack vectors for us to research. And we asked them what keeps them up at night. And one of the things that they always mentioned was, when there's no power, you really can't do anything. So power is a big component of data centers that we definitely wanted to look at. So that was kind of some inspiration for us. There's also quite a few brands and unique devices that people use in their data centers. They have quite a variety there. But they're all controlling critical stuff if you kind of think back to the data center itself. And then lastly, there's little to none end to end vulnerability research that we found in the field. So this is kind of the first step that our team is doing into trying to figure out a kind of a holistic audit of data center security. And of course, we started with that power one from these industry experts. The first target I should say that we looked at is this DSIM. It's a data center infrastructure management. I'll be saying DSIM from here on out because that's quite a mouthful. A DSIM though is used by IT administrators to manage, configure, and monitor all of the components inside of a data center, even including capacity planning or even logging and of course controlling some of the critical components like PDUs or power that is used in that data center. This is in a way a single pane of glass for a lot of these administrators to manage the data center components. And of course, because no one goes into data centers, no one wants to at least, this also allows for remote management, which is what we kind of thought that this was juicy for. The kind of scenario we wanna portray for the kind of our talk here is how we envisioned this attack being like chained together in multiple vulnerabilities of how you can as an attacker get into a data center. So if you can imagine this DSIM software is running either on in the cloud or even on a on-prem server, some on the network, some somewhere on that. The from talking to like the experts in data center configuration, they mentioned that a lot of the critical stuff that's inside the cage space or data center itself would be on particular VLANs or firewall off from the greater network. However, if you can imagine via this like blue arrow here, that if the DSIM is already set up to manage those and get logs back and forth, that there are those communication channels already in place, meaning that if we can attack this DSIM, we could potentially utilize those communication channels through those firewalls and management VLANs and whatnot and gain access to the devices inside the data center. The software that we ended up looking at first was this cyber power panel enterprise, which is quite a mouthful there. This is one of the software that would be able to manage the infrastructure in the data center. One reason that we thought it was a good target was for one, it's free. Second, it has both Windows and Linux support, but also that enterprise really caught our attention. At a glance, it's a typical web application, meaning that it's all of the good stuff is hidden behind a login page and there's no other unauthenticated endpoint that you can get to without first getting past this. It runs HTTP by default, so there's that, but it also uses C-sharp as like the server that runs the application, and then a SQL database backend, and those will kind of make more sense a little bit further as we go through this initial recon stage. What we ended up doing right off the bat is actually looking how the software sets up its database initially through the installer scripts. And one thing we noticed here highlighted in red is these two users that are actually kind of in there by default, they don't change later. So these are like default users, cyber power and SI, and they have these encrypted passwords right next to them and then the salts for that encryption here. At first, I definitely thought it was base 64, but it is actually indeed an AES encrypted password and not even a hash of the password, meaning that the password can be fully extracted out if those AES passwords are, or that AES password is found. So that's exactly what we ended up trying to do. And C-sharp, if you don't compile it with extra protections, is practically open source if you use the right tools. So we used DNS by and actually got this amount of detail out of just the disassembly here. In looking through that, we found this decrypt AES function that had the AES password, it seems like here, but it's slightly obfuscated. I'm sure we could have figured out how to do it, but DNS by has a handy feature of being a debugger as well. So just setting a break point on something that calls that, you can get the AES password out in plain text, which is we you tech for some reason. The next bit is because the decompiled representation of the application is so good, you can actually just copy it out and then run it in a own C-sharp function. So that's what I did. I just copied that decrypt AES function out into its own file, passed in those encrypted values plus the salt, and we're able to get these default credentials in plain text. So this was our first CVE that we filed against the cyber power here. However, it wasn't all the sun shines and rainbows for using that as a means to bypass authentication. When we passed those in, we actually were greeted with a log in failed and looking deeper into why that happened was they have checks for that default user and eventually we'll hit this failed to log in result. But kind of looking at that, one of our researchers was kind of interested in seeing how strong that check is and actually supplying a non ASCII value like X01 here, was able to actually, for the C-sharp server, those are indeed different strings so that code block didn't get hit. However, when the username eventually gets passed down to the SQL database, somewhere in the line that got stripped out and we were actually able to log in through that login page using these default credentials. And during that, we actually found an even cooler way. So we'll kind of dive into this second authentication bypass here now. So as I mentioned, there is this username and password method of logging into this DSIM software. There's also an active directory component, as it makes sense, it's an enterprise managed application but also there was this LDAP function that was the kind of coder eye and of course this is probably way too small to see so I'll blow it up here. The LDAP function when you supply an LDAP user uses this validate user function block here and you can see that it is checking if the function returns the string exception. For a long time I was actually reading that as returning an exception nodes, the string exception from this validate user and if it doesn't return an exception then the status equals true and then you're logged in. However, looking at the code, LDAP must have meant like a lazily disabled access protocol because it actually shows this function here, all it does is returns a blank string and of course that does not actually equal exception so any person that tries to log in using this LDAP method just automatically gets authenticated which is pretty cool. So I'll go ahead and show that in a live demo here using the elite hacker tool of Firefox only. So you can see this is the login page. What we'll do next is just right click and open the hacker menu which is, and then you search for LDAP, you see that it says display none, we can go ahead and change that to block and now just type in admin, no password necessary, choose LDAP as the authentication method and now you're fully logged in as admin. So at this point, that's actually quite a big thing. Now you can actually read those logs, manage the data center infrastructure. That's one step that we really thought that was pretty impactful. However, I'm gonna pass it over to Jesse to see how he took it even further. There we go, how's that? All right, so even though we were able to now carry out actions on the admin console with administrator privileges, that wasn't enough for us. We wanted to be able to go beneath the surface and start executing commands on the underlying windows or Linux operating system. So why might we want to do that? Well, as Sam mentioned, once we compromise a DCIM, we now have the ability to, at least in theory, control things like power management and network switches and that kind of thing using the DCIM as an admin would, but we don't yet have the ability to pivot to that data center environment and start executing our own code on other devices potentially. So that's our next step, is to be able to launch those kinds of attacks and we need operating system privileges for that. So let's see how we went about doing that. Well, we were able to get a near-perfect decompilation from DNSPI, so we started searching through for dangerous function calls, things like the equivalent of system in C or exec or something like that. In this case, it's this execute command function that you'll see at the bottom of that region boxed in red. And what's being passed to it is this command that begins with net use, which is how you add a new networking device in the windows environment. So it looks like this command is being constructed using several variables that are clearly assigned elsewhere. So our first thought is could this be a good spot for a command injection? Are these values user controlled? And it turns out that three of them are. So when we traced back through the X refs all the way back to the front end, we realized that this particular block of code is invoked when somebody tries to add a remote network storage device for backup purposes or something like that. And so in order to test this hypothesis, we tried to inject our own PowerShell command via the username parameter. And sure enough, as you can see from this process explorer output here, not only did PowerShell spawn, but is running with system privileges. So this was the fourth CVE that we discovered on this device, which is just your classic OS command injection. So now we'll demonstrate how we can chain the first authentication bypass that Sam mentioned with this command injection to achieve unauthenticated code execution. So in the top left there, you'll see that we have a Python server that's going to be serving a text file that contains our reverse shell in PowerShell, of course. And in the top right, we have a netcat listener that's going to catch that, excuse me, reverse shell. And we'll be executing our exploit from at the bottom. So first off, there's the auth bypass. It's the first of the two that Sam mentioned with that X01 meta character. And it's just going to save off the session ID into a local file called cookie.txt. So there you go. Now we have our cookie. You can see what it looks like. It's long and disgusting. And now here is our exploit. So as I said before, we're injecting by the username parameter. Others would have worked, but we chose to stick with that one. And all we're doing here is instructing PowerShell to query our Python server, download hack.txt, and then execute its contents as PowerShell. So clearly Sam's run it there, perfect. And we can see that hack.txt was successfully downloaded, the command worked. And now we have an interactive session on the underlying Windows operating system and are executing commands with the highest possible privileges. Which brings us to our second target, which is a Power Distribution Unit, or PDU for the remainder of this talk. You can think of this as just a glorified power strip for plugging in your rack servers or network switches, that kind of thing. And the fancier ones actually get an IP on that local network and have a nice web-based management interface for remote administration. So why might we want to target a PDU? Well, if we're able to access it directly and start executing a tax against it, as we now are able to, having compromised the DSIM, we can do all sorts of things. We can, for example, cut power to core business resources. Or if we're able to fully poem the device, we can establish persistence within that data center network and attempt to compromise other core services inside of that data center. So now I'll just introduce you to the particular product that we hacked, which is the Dataprobe iBoot PDU. This is most likely to be found either on-prem or in small to mid-sized data centers, maybe used for some niche purposes in another setup. We discovered that ATMs are often hooked up to them, for example, interestingly enough. But one other thing that we found really intriguing about this product in particular is that Dataprobe offers this free cloud service, which acts as a reverse proxy directly to the hardware device, meaning that if a user decided to enroll their device in this service, they would be able to access their management interface from anywhere in the world without having to have VPN access or be within some secure intranet at a randomly generated subdomain under the iBoot webpage website, rather. Another thing that made this a particularly attractive target to us is that all of the models, and there are about 20 of them for the US and international markets, use the exact same publicly available firmware image. So right off the bat, we were able to download it, unpack it, and have a look around. And although static analysis got us a long way, we really wanted to have the ability to interact with the device at the process level and really see what's going on, from memory and stuff like that. So that led us to full system emulation. And this wound up being a very powerful technique for us in the course of researching this product. And in fact, all of the vulnerabilities that we are going to be disclosing today were discovered and verified hand-wavely in this emulated environment. I should mention that eventually we did actually buy an iBoot PDU to make sure that they worked on the bare metal, but we already knew that that was almost a sure bet from the emulation. And so just for posterity's sake, I'm going to do a quick run through of how we were able to get that emulated device setup. So let's just run through it really quickly. So we decided to use Kimu. And given that there's an ARM chip on the device, we installed the full system emulator for ARM and grabbed a fresh 32-bit VM off of the Debian webpage. It was just hosted, already set up and configured on some of these personal file space. So that was easy enough. And then we got it spun up using the following arguments. You'll know this will appear in subsequent slides that we mapped port 80, which is what they're serving the website on to port 8080. Now, once we were inside the VM, we first of all pulled down a fresh firmware image, which turns out just to be a tar file and extracted it and then decompressed the root file system. This was the only component that was necessary to be able to spin up all of the core services on the device. We then went through the rigmarole of setting up the appropriate mount points in order to get this to work properly. That took a little while. And finally, cherooted into that root file system using the onboard bash instance. At that point, we tried to mimic the sequence of commands that are actually executed as the device is first booting up. Obviously, some of them didn't work. This is emulation. It's not a perfect science. But we were able to eventually run that RCS script and have all of the core services up and running. And I should also mention that there were a ton of them. We wound up targeting the webpage exclusively because that got us what we needed. But there were nearly 10, I believe, distinct attack vectors that we also could have looked at. But they all seemed to support the functionality available from the webpage anyway. So that's where we started. And just to prove it to you all that we got this to work, here's the login page running on localhost which made us very happy. And so now we're gonna talk about how we were able to get past that login page. But before we can understand the root cause of the following vulnerability, we need to go over briefly what the normal authentication process on this device looks like. So under normal circumstances, the client will send their username and a shoddily obfuscated password to the device and assuming that it matches what the device has saved in its database, this set cookie header will be returned. Setting, instructing the client to set a cookie called iBootPDU site off, which is just a URL encoded string that has two parameters. One is USR, which in this case, actually is an abbreviation for user. And an MD5 hash of the corresponding password. So for any subsequent request made to one of those privileged web pages, the client will include this cookie and the device will then verify that those credentials are valid and assuming that they are restricted content is returned. But we still need to zoom in a little bit further on what's going on here between steps three and four. So under normal circumstances, the client will issue their request, including the cookie and the PDU will query its own onboard postgres database, which contains all of the user credential information. So assuming that the credentials it finds in the cookie match what it has on the database, privileged content is returned no problem. However, in a malicious use case, and this is something of a spoiler, but I think that the 30,000 foot view here of what's happening is useful before we dive into the technical details. An attacker can supply a malicious cookie to the device and direct it to query not its own trusted database, but an arbitrary database at any IPv4 address of the attacker's choice. And assuming that that attacker has set up their rogue database correctly, then the passwords will match and that privileged content is returned. So before we get to looking at the root cause of the vulnerability, we have to do a quick review of the PHP function parster. I don't know about you, but I had never heard of it before. I'm not a PHP programmer, so I'm sure that this won't be review for everybody. So here's the function signature. It takes two parameters. The first is called string. This is a URL parameter string basically. Just key value pairs separated by ampersands. And then there's a second argument called results, which is just an associative array to store those key value pairs. However, in older versions of PHP, including the one that is used in the iBoot.PU product line to this day, you don't have to give that result parameter. And if you don't, then all of those key value pairs are instantiated as local variables in the current scope. So I'm sure I don't have to tell an audience like this that that's rather dangerous. And as such, there is a huge warning that appears on the PHP man page for this function that says, don't do this. Always put that result parameter in there. And in fact, we're gonna mandate that pretty soon. So problem solved, right? No. So this is that automatic login mechanism that I talked about between steps three and four in a previous slide. And this is the entirety of that file, so let's just go through it line by line. After doing a couple of checks to make sure that the cookie is actually there, it then drops it straight into parster without that result parameter, which means that all of these variables that I've boxed here in yellow can be user controlled if they are included in that malicious cookie, including the IP address of the database to which the device establishes a session. Just for the record, get new link is simply a wrapper for PG Connect, which is a library function for establishing a connection between a PHP server and a Postgres database. Next, we construct a SQL query, or the developers did rather, to grab the username or rather the password and the role associated with the provided user. And once that's run against the database of our choice, the resulting password is then MD5 hashed, which struck us as odd when we went to school. We were told that you are never supposed to store unhashed passwords under any circumstances, but two weeks their own and is compared against the hash that's provided in the cookie. And assuming that those match, which they should, if the attacker has set this up correctly, then the user is logged in with whatever privileges they gave themselves. Why not admin? So now let's pick apart the payload just a little bit. For those interested, I've included the URL encoded version up there at the top and also a breakdown of all of these different keys and values that are required to do this properly. So the IP of the database and the credentials for that database, those are arbitrary. I mean, they must match the attackers set up, but those can vary. And then the USR value has to be this hard coded user that was already included on the device and the hash just simply has to match the password for that user. So this was our first CVE, which is deserialization of untrusted data leading to authentication bypass. So now we're gonna demonstrate how we can use this to dump the entire contents of the database that exists on the device, including plain text passwords, emails that are used for alerts and that kind of thing. So normally if an administrator wanted to do this, they would go to the import export page on the management interface. They would select export as their action and then hit run. When they do this, under the hood, this export.sh script is executed, which goes through and does a select star on all of the tables in the devices on onboard database and stores them in CSV files with names corresponding to the table name. Once it's done this, it then tars them all up and gives that tar file, the file extension, pdudatun, which in context, we figured out means pdudata unencrypted because very shortly thereafter, this secure pdudat binary is run to encrypt that tar file. However, you'll notice that the unencrypted version is never deleted. So when the client goes to download their encrypted database dump, all they have to do is add UN to the file name that they want and they're able to get the unencrypted tar file back. As a matter of fact, this mechanism could be used to download any file in the temp directory, but that's another story. So now let's see this exploit in action. So we're executing this via the cloud interface, so we don't have to be adjacent on the network at this point. Now we're gonna generate that database dump and download it. So as you can see, this is just a normal unencrypted tar file containing a bunch of CSV files and now we can dump them and we get plain text user names, passwords, emails, the whole nine yards, including the credentials for emails that are used for automatic notifications and that kind of thing. So basically everything that the device has on it saved, we now have access to. So now I'm gonna turn this back over to Sam to tell us all about how we were able to pound this thing. All right, thanks, Jesse. So for one, yeah, we wanted to take it a little bit further as we always do as hackers. So I'm gonna start with a process that has worked for me very much in the past. So this is kind of my idea of how I triage a lot of these embedded systems for command injection opportunities here. The first thing I like to do is actually look for like custom binaries that the vendor is writing themselves and for the data probe, they were stored in the user bin folder and a lot of them had a D at the end, probably for daemon. So that is why I'm searching through the star.d and then running strings on each of those files. Then I'm searching like using just grep for shell scripts. And so you can see there is quite a few here. And then the next step I like to do is look for potentially injectable format strings here. So everything in red is fully command injectable. We have to verify that later. So like, but just from this initial triage, all of these look really promising. The yellow is injectable as well, but it's a numerical value which kind of goes only so far. And then there is that single green one there that is not susceptible to command injection. A single quotes in a shell program does not expand any variables or sub processes. So this was a good sign for us. And then the next step that I like to do when I'm trying to triage these command injection opportunities is now open up those binaries in a decompiler like IDA and look for calls to system to see how those format strings are being generated and then how they are being run. Sometimes people or developers will add sanitization and things like that. This is where you check for that. So you can see here that there is none, no, this whole update Linux SNMP v3 user function doesn't really have much sanitization. And then you kind of have to kind of imagine what values an attacker can control here. So if you can imagine updating your user, you can probably control the username and probably the password too. So the next step is to relate that back to like really validate that you actually do control those as malicious data. So looking at the add new user, you can see the username there as well as the SNMP v3 password. The last step, if you're doing a blind command injection, is to always try to keep it as simple as possible. Luckily enough, Jesse set up the emulator so I was able to run PS down there on the bottom, but sleep is always a really good step to actually figure out if your command injection is running properly. The webpage hangs for however long you told it to sleep for. That's probably because it's executing in the background. So this was the second CVE that we found on the PDU and it also had its caveats. So the username that we were able to inject into there was limited to 20 characters. And during that initial triaging stage, we realized that it's probably a database schema or something, because every time we'd pass in 21 or more characters, it would return this unknown database error. This is where the initial triaging and trying to dive into all of the devices components is really useful, is we remembered, we saw there was a pretty interesting endpoint really on in the stage that's this firmware upload endpoint. And the reason it stood out to us that we had to remember to use it potentially for this was that it was unauthenticated. So this is the entire PHP file, or yeah, file here. And the thing that really caught our eye was, up here on the top, it's taking post parameters as input and then directly writing them to this file in temp. So, and it will do this until it reaches an EOF, which is kind of a perfect script drop option with an unlimited character count really. So at this point, all we had to do is send whatever code we wanted to execute to this endpoint and then change our username to this kind of gross looking function here, but what it's really doing is just catting out everything in that file contents and then running them as shell commands. So this was under 20 characters and was able to run all those commands that we wanted to pass into that file in temp. So I'll go ahead and show this in action, it's kind of cool. The right side of the screen will be a Netcat listener and then the left is where we're gonna be executing the commands from. So we'll go ahead and start off that Netcat listener. On the left here, we actually are using that cloud connection because it was actually running at Jesse's house for this, but we're using the legit credentials that we just showed previously that we could dump and adding that malicious user and now you can see our Netcat is already connected. We can run things as root and really have full access to the Linux operating system on that PDU. So now what? Okay, we've hacked both of these devices. Let's zoom back out and kind of just re-envision our scenario here. So there are potentially two devices in the cloud now. So there's the cyber power, which is our initial idea of using it as a pivot point. However, there is that data probe cloud connection thing, but we'll kind of just ignore that for now. The attacker can now get access to either of those, but we'll just kind of focus on the cyber power for here and now can actually even get access to the operating system underneath that software. They can kind of hang out on that network, wait for a good time to use the connections set up in place to actually gain access to some of the devices in the data center or cage space. And now of course we can use the admin panel because we actually can bypass that authentication of the PDU to already just turn off power, do a DDoS or whatever. But as Jesse mentioned earlier, this is a perfect spot to be as an attacker, to pivot to other devices inside the data center. Now we have practically a Linux machine that we control inside of this restricted environment that clearly would never run any virus or any sort of detections really. And of course after that we cause havoc. So you can switch over, you can turn on and off power quite rapidly that is known to cause hardware issues. So really you can kind of take this as far as you want. I'll pass it back on over to Jesse to do some final takeaways, but yeah. So what are our takeaways here? What have we learned? Well, the first thing that stood out to us as we washed our hands of both of these products was that hard coded credentials are still everywhere. And this kind of makes sense from a developer's perspective, like if you're working with a Postgres database for example, which kind of require that admin username and password in the initial setup phase, it can be quite expeditious particularly if you're under a deadline to just hard code those credentials. But even if they don't constitute vulnerabilities in and of themselves because you've written some logic around them or something like that, they can be still leveraged in addition to other vulnerabilities to enhance the impact of an attacker's exploit. So they're still dangerous and from an attacker's perspective from the offensive point of view, it's always a good idea to check those database initialization scripts or to go through the binaries for interesting looking strings that might be some kind of special hard coded user and see if you can leverage those to enhance your exploit. Our second takeaway is that much to our delight we were able to find and achieve code execution through the results of our like first pass looking for low hanging fruit when we went after both of these different products. Like, as you can see, there was no unprecedented or particularly difficult exploitation techniques in play here, it was just command injections. So it's always worth it no matter what to go through those products and look for strings that might represent some kind of operating system level command, particularly if they have format strings, those percent S's, and to look for those process spawning function calls like your systems, your execs or execute command if you're in a Windowsy environment. The other thing that kind of surprised us and it was a very pleasant surprise, all things considered, is that research doesn't have to be expensive. We were able to download and set up the power panel enterprise, our DSIM, without having to ever enter any kind of license key or pay for anything other than the VM and which we hosted it. And similarly with the PDU, we were able to conduct end to end bone research just by downloading the publicly available firmware and then emulating it. So in that case, emulation turned out to really be our friend and is a nice thing to try, especially if you're hacking on a budget. Moreover, there's this tremendous discrepancy that we observed across these products and others between the criticality of these applications to business operations, let's say, and the quality of the software that backs them. So you might think that, given that these are the kinds of devices that are going to end up in data centers and trusted with the security of our information, that they might be a little bit more locked down and the developers might have adhered to slightly better secure design principles. But we find time and time again that this is simply not the case. So I guess our final takeaway is something of a call to action to all of the talent here in the room, which is to help us keep this industry accountable. So go for it, we won't take the violence from you. All right, so let's just close off by giving a huge thanks to a friend and a colleague who's sitting right here, Philippe Walharay. He was in this research with us from the start and made some huge contributions early on. And in fact, he's credited with, I don't know about most, probably, yeah, most, let's go with most of the CV's that we talked about in this talk. And he's just overall a great guy, so come find him, say hi, buy him a beer. We love you, Philippe. And we'll just finish off by also giving a shout out to Clarity's Team 82 who first turned us on to the iBoot PDU as a potentially valuable target. They wrote an interesting blog that tipped us off called Jumping Nat to shut down electric devices. Obviously they missed a spot, but nevertheless, a lot of great work, so well done Team 82. We should also mention that we reported all of these vulnerabilities in adherence with Trelex's responsible disclosure policy. We gave both vendors 90 days and we worked with them to make sure that patches were available before we went and gave the details of these exploits to a bunch of hackers. So you can check out our blog for some more information about the vulnerabilities, including the two that we had to gloss over just due to time constraints. That's going to be dropping in the next couple of days if it hasn't already. And I'll just close here by saying that this research is just part of a smaller or rather larger effort on behalf of the vulnerability research team at Trelex to investigate the security of data center products of all kinds. And we have a couple more disclosures that are still in that 90 day period that we'll be hoping to drop before the end of the year. So stay tuned for that. And well, comrades and friends, thank you very much for coming. We'll be hanging around afterward if you want to come say hi.