 Hi there. Thanks very much, welcome to the talk. I'm not very good at intros, and I always talk under different pseudonyms, so I'm just going to tell you some facts about myself to hopefully make you trust what I'm about to tell you. I've been mainly working in embedded systems slash enterprise perimeter for a few years. Sometimes as a consultant, sometimes as a researcher, sometimes in education. I've published research into Microsoft, Cisco, Netgear stuff, all kinds of different software over the years. I spoke here a few years ago about cellular hotspots and things like that. My main interest is just reverse engineering, so we might go off on a bit of a tangent here in some of these. I'm going to have to speed through some of this because I've got a lot to talk about, and this is one of the bits I'm going to speed through. If you don't know what PBX is, a PBX is a private branch exchange emphasis on the private. Before these private branch exchanges, everything went through public branch exchanges for telephone calls. The problem was when businesses wanted to make calls to each other internally, the calls had to go through a public exchange, so it cost them money, so they moved the branch exchanges indoors. These first early PBX systems were for classic phones, and then VoIP started becoming more cheaper and more popular, so digital PBX started popping up, starting off as hardware and then slowly over time becoming implemented purely in software. Then, as time went on communication styles started morphing again, so PBX started morphing into something that people start to call unified communication servers today, which is for like video, text and all kinds of other kinds of communication, so this is more like modern chat based contemporary stuff, but I'll use the term PBX more here, because the servers and the software that I'm talking about is more like PBX servers, they're not really unified communication servers, although they do function in the way that unified communication servers claim to as well. This kind of stuff shows up in enterprise environments where they like to do things like on-prem, and there's a lot of different stuff in the PBX slash UC space, so probably the most fundamental will be like the SIP switching telephony software, something like asterisk or free switch for example, this is like the bare bones telephone exchange functionality, then there's other products which show up which use these phone exchange cores and then provide easier UI configuration, so for example free PBX is basically just like a UI configuration wrapper for asterisk, and SIP XCOM is basically a UI configuration wrapper for free switch, and then on top of that they'll bolt a whole bunch of other stuff on text and video chat to make it a bit more UC like asterisk. There's a few big like PBX systems, free PBX and 3CX are probably the biggest, and then there's SIP XCOM as well. There's about 10,000 to 19,000 free PBX web interfaces I could see on showdown the other day, about 250,000 3CX ones. There's not so many SIP XCOM ones, but it has been around for quite a long time, so it's still working into. PBX servers are due to the complexity and all the kinds of services that you find on them, they can have a really big attack surface as well, so they'll have things like the SIP, like telephone exchange core, they'll have proprietary services like the inter-asterisk exchange protocol, which you find an asterisk. There's things like MGCP, RTSP, XMPP, MySQL, DNS, all kinds of stuff you'll find on these servers, so there's a lot to look into. There's also these like web management interfaces, which are the core of a lot of these things, so as I said before, free PBX is basically just a web UI that allows you to configure all of these extra services plus asterisk and things like that. All of these servers also require authentication user accounts, so post authentication stuff is also on the table for this kind of research, so the attack surface is really, really broad. I'm going to talk about two different servers today. The first one will be SIPXCOM and the other one will be free PBX. I there's a caveat to it, which is that I found these bugs through sort of less structured research, so despite the massive attack surface, I only managed to sort of really touch the surface of what actually is on these servers, but what I found I think is quite interesting. So the first bug is an RCE chain in SIPXCOM, so SIPXCOM is mainly written in Java. It's all open source, all on GitHub. It ships with this optional XMPP server called SIPX OpenFire. The name is based on Ignite OpenFire, but the bugs don't actually affect Ignite OpenFire. It's a quite complex SIPX OpenFire is quite complex integration with other like SIPX components, so it's not a totally standalone XMPP server. It sort of integrates with the whole SIPX ecosystem. Within SIPX OpenFire there's a message interceptor called default message packet interceptor, and every message that's sent through the XMPP server is checked by this interceptor to see if it starts with a string that they call directives internally. So these directives are at call, at conf, and at xfer. If the message starts in one of these directives, then that message is handed off to some other SIPX component, so this is part of the whole integration. The issues sort of affect a couple of the directives, but I'm just going to follow the at call one just for the simplicity here. So every message is intercepted and then passed to a function called process chat message, where it's checked for directives. If it starts with at call, then the rest of the message is passed to the map arbitrary name to SIP endpoint function, and then the result of that is passed to send rest request. So we can just follow this flow really quickly. Map arbitrary name to SIP endpoint just checks for usernames in the string and basically just returns back the string wholesale as we want it. As we give it without doing anything to it if it doesn't find a valid username. Build rest call command takes the whole string that we've passed in the string. It can catch it directly into a URL string and then returns it, and there's no check or filtering on it at all. And then that whole URL string is passed to send rest request, which just can catch it directly into a curl command string. And this curl command string just gets passed directly to runtime.exec. There's a to do note above this function saying, suggesting that they know this isn't really the ideal to implement this functionality, but it's been there since about 2010 according to the githistory, so 13 years of not doing anything about it. The conventional wisdom of this would say that this is just arbitrary command execution, but that's not actually really true. Runtime.exec doesn't quite work like that. There's an assumption that runtime.exec for some reason behaves like system p open, which is not true at all, so all the kind of classic code execution payloads that we might want to use for this will always fail. Just to give a quick run down of how runtime.exec works, we'll just follow the source. If you pass a normal string directly to runtime.exec, the first overload we hit is the one that just takes a single string. This passes it to another exact overload which takes three arguments, the first of which is a string. That overload takes the string and passes it to a string tokeniser and then just pushes that into a string array which passes it to another exact overload which takes three arguments and then arrays its first argument and then this overload passes the string array to process builder and creates the process using .start, so we've got this array of strings passed to process builder. Process builder takes the first element in the array and checks its executability and then the array gets passed to process .start, which just in our case because we're running on Linux creates a unix process. The first element of the array is the executable argument to the unix process. Regardless of what we actually inject into this command string, we're always going to be running curl, so there's no way around it. So it is we don't have direct command execution but we do, we can kind of use this to our advantage so we can't control the executable it's always going to be curl but we can pass arbitrary arguments to curl. So the next question is what arguments can we pass to create a useful primitive there? Before we figure that out we have to look at how the command string is actually laid out on what we control, so we can't control the arguments at the beginning because they are hard coded but as long as we pass a string that contains spaces we can put whatever arguments we want later into the command. So for example we can download files within the same curl command by just adding an extra dash x get argument and specifying just a file to output to with the OFLAG. So it's a pretty useful primitive we can force the server to download files from anywhere and save them and CipexOpenFile runs as the daemon user so we can only really write where the daemon user can write that's the only real limitation on it. We can also read files from the server so we can use the dflag to read a file on the server then send it over to wherever we specify so an injection like this one tells the first x dash x post request to output the result of the request to some temp file and then tells curl to read the password file using the dflag and then send it over to an IP address. So we can both read and write files using this curl argument injection so they're quite interesting and good primitives but it doesn't quite get us to code execution directly. But there is one more bug which is quite useful in this case. The OpenFile service file for CipexOpenFile is installed with daemon daemon privileges in the init.d directory so with our right primitive we can overwrite this file which will execute as root whenever the service is restarted. So we can chain those things together and we overwrite the OpenFile init file using the curl file download primitive and then replace it with an almost identical file with just a command exact payload on it. We wait for the service to be restarted or force it to restart using the web interface and then we just get a root shell. So it's a fun bug chain just by sending XMPP messages from one user to another you can overwrite files and then eventually get a root shell from this server. There's a full rundown of the exploit on setlist that I sent over in March that you can have a look at. CipexOpenFile is maintained by a company called CoreDial who just never responded to anything that I've said so I sent them emails for a while I first reported in November they didn't reply I kept on sending emails for a while they didn't reply to any of them I kept sending them tweets and they just kept on untagging themselves from tweets so I consider that a kind of vendor response of active indifference and so these are just bugs that are still in the latest version of CipexCom and I guess we'll stay there for a while it looks like CipexCom might be dead I'm not entirely sure so yeah, CoreDial gets half a star for their vendor response very bad experience don't work with them ok, the next bugs are all in freePBX so freePBX is maintained by Sangoma is based on asterisk for the telephone side of things there's a web interface loads of free and paid modules that you can sort of strap on to it and according to their website they run a bug bounty program so they say they want to work with security researchers that they want to fix everything within 60 days so that all looks really nice and of course at this point I'm really looking forward to the professional disclosure process with lots of communication and very happy outcomes for everyone involved CipexCom is pretty straightforward it's just straightforward open source Java, freePBX is a bit more complicated so it's mainly written in PHP which is nice a lot of the core code is open source to some extent there's a freePBX core bit that's free and the code for that's all in the freePBX bitbuck here there's a few free plugins which come bundled with freePBX which you can't find the source for for some reason and then Sangoma also sells licenses for some other plugins and none of those plugins are open source either so there's a lot of functionality where the code just isn't public despite the fact that freePBX is touted as something like an open source pbx server it's mainly written in PHP and it's shipped mainly as a Linux VM so whoever has access to the VM could read the PHP files so obviously to avoid leaking code for the non open source components they've used something called IonCube so IonCube is a PHP source code obfuscation solution the IonCube compiler compiles down PHP to Zen bytecode essentially and stores it in its proprietary IonCube format and then at runtime the PHP process loads the IonCube module which decompiles the PHP before running it so it's a massive oversimplification of actually what IonCube is doing but it's essentially what it does it's a lot like things like Zengard and Source Guardian there's some really nice previous research into IonCube by these guys that I've mentioned here but it's from quite a few years ago so some of the information is still relevant some of it's a little bit updated the point of IonCube is just to create as much hassle as possible for people like us so anyone who wants to have a look at the source code it will cause us to spend a lot of time trying to get access to the source or maybe just give up entirely and the point is also to make money like they sell a license for like $200, $229 there's no free or open source deobfuscators available I'm not entirely sure why I assume it's because IonCube are litigious I'm not entirely sure how legal it is or how legal it would be to offer a deobfuscator for free but regardless because there's nothing free out there there's this grey market for deobfuscation tools that exists out there so you can find these deobfuscations as a service and people trying to sell things on telegram and very dodgy looking YouTube videos that show nothing in particular happening with very big price tags so I spent a bit of time playing with these during the process of looking at the free PBX code I did actually I had a look at some of the I did get some useful code out of out of some of them but it's a bit of a grey area regardless I spent quite a lot of time looking at the deobfuscation process so I'm going to share a little bit of that today as well in the case of free PBX they're using the R&Q loader for PHP 7.4 which is version 10.4.5 the loader PHP module is an SO that's just under 1.4 megabytes it's part of the free PBX VM image so you can just dump it straight out of there it hooks a Zen compile file and Zen execute X functions in the main PHP process what it does very basically at the beginning is just check for magic bytes at the start of every PHP file that comes in if it finds them it will try to deobfuscate it and run it, if it doesn't find it it just passes the files just directly back to the PHP Zen VM if it does find the bytes then it will it goes on this sort of chaotic journey so the whole loader is a complete chaotic mess you have to really follow a lot of things going along it doesn't just deobfuscate the Zen byte code and just pass it back to the main PHP Zen VM it actually ships a whole modified Zen VM within itself and every opcode is executed within the loader itself nothing ever goes back to the main PHP process so the whole extension is really really big and you can waste a lot of time in it I'm just going to share a few little bits and pieces that I that I noticed while I was working on it the loader is kind of obfuscated so all the strings or the useful strings within an x-word with this static x-word key so obviously when you're trying to reverse engineer it being able to see the strings is very beneficial as part of the process so I wrote a gridra script which you can download here to help you do that you do need to you do need to put the x-word key into it for the specific loader although I think it might be static among different versions but I have to see and once all the strings are deobfuscated it makes it very obvious as you can probably see and maybe see in these little images here where the Zen VM code is just copied and pasted you just see the exact same strings from the Zen VM except weirdly obfuscated within the loader itself so it makes it a bit easier to see which bits are just Zen VM and which bits are actually IonCube there's also a bunch of other weird little stuff in there, there's something called IonCube24 which is end point security for PHP or something, I'm not entirely sure what it does but it just registers lots of IC24 underscore PHP functions in there knowing that there's something that isn't really relevant in there as useful as well it means we can just sort of cut through the fat a little bit it registers a bunch of underscore IonCube PHP functions as well but it also registers these other strange functions that looks like with names like some sort of mash the keyboard each of these functions takes two arguments one of just is a pointer and the other is a kind of checksum which is just that same pointer exord with this with this number if you don't give it the right arguments it will just send you some really sinister threats it will say things like a rat who knows that a cat's tail invites destruction and do good reap good, do evil, reap evil and things like that which isn't very isn't very nice but if you give it the right arguments it will do something I never actually figured out exactly what it was doing but it seems like some kind of debug functionality and there maybe it would be a fun thing to look at another day so once all of this is sort of sifted through and we've cut through a lot of the fat the way to start de-office gating this stuff is to hook some strategic points in the unpacking process and you can dump the opcodes in this sort of proprietary way that they've stored them you might be able to see here with these these very strange looking strings but it stores the variable names it stores the function names like everything is retrievable from within the compiled IonCube format whatever it is anyway it's a whole hassle and it's a whole thing to talk about another day but it's elaborate and complicated and you have to spend a lot of time in it I'll talk about it probably another day and maybe talk to legal professionals about why this kind of stuff isn't in public anyway at the moment anyway we have de-office gated code why does FreePBX use this obfice gated code in the first place? I'm not entirely sure I think it has something to do with the license model so they've got all these paid modules and the paid modules check for licenses before they run but since it's all PHP if the code wasn't obfice gated somehow then maybe people would modify the code and then bypass the license checks but it does sort of serve a licensing purpose maybe the only problem with this logic is that once you've de-office gated this stuff you can just replace these obfice gated files with the de-office gated ones and FreePBX won't notice and you can comment out the code it doesn't check for integrity or anything like that it does check for integrity on other files that aren't obfice gated which is also very strange so they've decided to do obfice gation instead of integrity checking which I don't really understand maybe you get a sense by now I think obfice gation is really silly anyway so let's look at some bugs the first one is in the de-phone API component this is part of the core functionality of FreePBX but the code is still obfice gated for some reason there's a lot of functionality within this but it does require authentication which is handled by this function called de-off de-off contains this subtle if condition which checks if the password is just the word login in the abstract this seems like a weird decision but I think it's because they've designed this API to be a this component to be an API for the Digium or other Sangoma like VoIP phones so these devices aren't expected to have their own credentials so this is a kind of concession in the authentication process for these particular devices to be able to authenticate but it does essentially mean that it's an authentication bypass to pass the logic of this authentication function or two of the things you need is the MAC address of a registered phone VoIP device and this hard coded password login there's also one more check which is the user agent header so you just have to modify the user agent header to look like you're coming from a Digium or Sangoma phone but the whole auth bypass is just sending a packet that makes it look like you're a VoIP device you basically authenticate with just a MAC address and maybe I don't need to tell this audience but MAC addresses are not particularly unique Digium MAC addresses also have this 24-bit prefix so you can find the MAC addresses just by sniffing on the network and then print it on the back of the VoIP devices inside a building or if you're really desperate you could try to brute force the last 24 bits of the MAC address 2 to the power of 24 seconds is like 27 weeks so if you sent a request every second for 27 weeks you'd be able to figure out at least one of the Digium devices on the network and so we have this kind of authentication bypass and we can chain it with this other bug also in the DeFone API the DeFone API handles all these different methods that are specified in this request method field in a JSON post request and so the pbx.users.currentCalls.stopRecordingMethod is one that's vulnerable here so let's have a look so the channel ID function the channel ID value from the JSON request just into a PHP exec function there's no attempt at input filtering or checking anything it's just a very pure classic command injection in PHP in this software in 2023 I'm sorry it's not more interesting than that I'm sorry it's not more complex bug it's just I mean it's fun in the fact that it's just very very classic and very very simple command injection so that's an authentication bypass to ask you chain in free pbx there's another few issues as well this one's another authentication issue in free pbx where they have this admin interface that I tried to avoid finding bugs in because if you actually have admin privileges you can just create a skeleton module and just install it yourself and then you're just running code so it didn't seem like a proper boundary but they do have this other functionality that allows normal users to authenticate the admin interface but they don't get administrative rights I think this is maybe just for monitoring or creating these like lower privileged accounts with this limited functionality they get to see some like module output when they log in and they can be granted access to specific modules and stuff but they're explicitly not given full administration rights but actually it means nothing because anyone who can authenticate to the admin interface has full admin privileges on pretty much anything it's only enforced in the UI so there's no separation between these lower privileged and admin roles in the admin web interface and so we can use this to exploit another vulnerability which is in the API module which any of these non-admin users of the admin interface can access this is part of the core free pvx so this isn't actually obfuscated at all this is just in the bit bucket just in the open source core if we send a request with the command generate docs we hit this like generate documentation function it takes two arguments which we also specify in the request that we're sending it the most obvious issue is that if you can see the code here the host argument is just concated into a string which is passed directly to a process so again this is just a very very bog standard command injection vulnerability the only thing that actually needs to be taken into account when you're exploiting this is the host value needs to actually resolve somewhere so the command injection payload has to start with a valid URL to an actual server that will actually respond but we can just spin up a server and do that so the host will point somewhere like attacker.com slash command injection and then return some valid access token and all the checks will be passed and the command will be run but also because the access token itself that's retrieved is concated into a string we can also just spin up a server that just returns command injections as access tokens and we don't even have to send the command injection as part of the payload we just send a host and we've got a server that's just returning command injection payloads as access tokens so this makes it also quite a fun a fun way to exploit this bug and then finally there's one more little DOS that I found reported to Sangoma it's in another endpoint called UCP which is the user control panel this is accessible to every user by default it's just a UI for normal user functions so making calls managing phone books and extensions and stuff like that it's meant to be for everybody in the UCP PMS module any user can send a request with the command parameter woo del and then this woo del value gets used to create a path which is just passed directly to unlink so we can pass a path traversal string and unlink anything that we want on the server it runs with asterisk user privileges so anything owned by asterisk you can delete on the server so it's a kind of way for any user to delete files useful asterisk files off the server the disclosure the disclosure process with Sangoma was pretty pretty bad as well the response was really lukewarm I sent them a disclosure at the start of May and then they replied a few days later sort of asking about the ion cube stuff and then they never then I sent a few updates and request for information and they never replied and then I chased them with some tweets for a while and I did eventually get a response saying patch some stuff but without telling me or helping me to with version numbers or anything like this so this was about a month ago they I replied to that email from them with a whole bunch of questions and tried to get some other information out of them and they just haven't replied at all so again nothing coming back from Sangoma it was a really annoying situation especially considering they have this big page saying that they really want to work with security researchers and they really want to try and fix vulnerabilities as quickly as possible and that's also why none of these issues have CVs related to them at all and the one email they did send back to me they said that they were going to apply for a CVE for the issues so it might just be that they've decided to apply for one CVE and bundle all of these issues under one CVE which is helpful and useful for all the defenders and customers out there so yeah I sent in these emails they never replied to me I did have a look at the patch for the API bug that I mentioned here and it looks like the patch is now good so I would have also been very happy to tell them that if they'd emailed me back Sangoma gets two stars because they sent me two emails for their vendor response and so I'm going to show oh no how do I do this so this is yesterday I'm not sure why there we go this is the most updated version of FreePBX as you can see here I've taken the session token from the low privilege user and I am sending the patch bypass for the API exploit here and getting a shell back so obviously still issues in FreePBX today I mean I did write a kind of summary for this the PBX systems are meant to be pretty robust they're meant to handle all the communications in these on-prem situations people use them because they want to do things on-prem they want to trust what's happening with their data but the threat model is quite complicated these servers they give different permissions to all kinds of different users there's all kinds of different objects trying to connect to them there's such a massive threat model for them that they're very very difficult to secure the user accounts are often acquired as well many employees will have some kind of phone or chat access many devices need their own accounts and the privilege models are also sort of all over the place as well this extra functionality that they keep on adding to make it more like you see like or voice chat and video chat and things like this text chat and data transfers and stuff is probably an interesting place to start if anyone wants to start looking at these kinds of servers and adding XMPP servers to internal enterprise environments in 2023 seems silly but maybe there's situations where it's called for another take away is there's just command injection bugs in PBX servers in 2023 and loads of them so have fun also trying to look for them also bugs in open source can just sit there for years so the Cipex open fire bug has been sitting there for 13 years and nobody's done anything about it and also Sangoma are really really disappointing to work with they say they wanted to work with researchers they said they had this whole bug bounty program they said they made all these big claims and then they didn't reply to any of my emails so don't trust tenders and also Cod Office Gation is stupid it's fun to try and break it we should all try and break it more this is exactly the kind of place where people should be trying to mess around with that kind of stuff and yeah thank you it's going under here's my email address if you want to contact me yeah thanks