
Hello. Hello everybody. Good afternoon. Welcome. Hope you guys got in the mid-after afternoon nap. Welcome to Bides Las Vegas uh proving grounds. This talk is titled an awakened wakeup a novel PHP object injection technique to bypass wake up function and it's presented by Hiroi Matsukuma right here. And uh right before we begin we got a few announcements. We'd like to thank our sponsors, especially our diamond sponsors, Adobe and Iikido, and our gold sponsors, Drop Zone AI and Run Zero. It's their support along with our other sponsors, donors, and volunteers that make this event possible. These talks are being streamed live and as a courtesy to our speakers and audience, we ask that you check to make sure your
cell phones are set to silent. So, this is your opportunity to set your phones to silent if you already haven't. And if you have a question, you would be using the audience microphone that I'm holding right now uh to ask it because the people on YouTube can also hear you. Just raise your hands and I'll bring the mic to you. Um as a reminder, the Bside's Las Vegas photo policy prohibits taking pictures without the explicit permission of the people involved. So, please do not raise your phone to take pictures. I would appreciate that dearly. These talks are all being recorded and will be available on YouTube in the future. With that, let's get started. Please welcome your
speaker. >> Yeah. Hi. Thank you. >> Uh first, uh all of you can take a photo and uh so hi everyone. Today I'd like to share new wake up bypass technique. Uh let's start with a quick quiz. Uh so here's a question. Which payload would give us share access in this code? If you've seen PHP object injection before, this should feel familiar. Uh if not, don't worry. I'll explain the concept of PHP object injection attack here. Um and today's technique itself is very simple too. So option one or option two. Yeah, that's right. Um the answer is option two. It's a classic PHP object injection attack. So uh but the next example doesn't work the same way here. wake up towards
uh exception drawing unserialize. This is where a wake up bypass becomes necessary. Oops. Uh that said a nonPHP bug made this bypass possible like this. Um, the approach relies on an unknown bug that allows a regular object to be disguised as serializable. But since civilizable will be removed in PHP9, another approach will be required. So oops sorry. So uh what should we do starting with PHP9 and beyond? The solution I'll present today is a technique called an awakened wake up. So quick self intro. Um I'm the I'm the tech lead of the reverse engineering group at cyber defense institute in Japan. Uh I enjoy finding simple solutions for uh challenging problems. So okay before we dive into the main
topic let's briefly go over the technical background. Um, PHP has built-in feature for saving the state of objects and restoring them later. This is civilization. Uh, internally it's used in places we don't usually see. For example, in the builtin session support or in caching features such as APCU. Um developers can also use it free with through the civilized and unsealized functions. Um but the PHP manual itself warns not to pass untrusted user input to unsealized function. Uh such misuse of univilized is known as PHP object injection vulnerability or POI for short. Um, by tampering with serialized data, attackers can control the properties of the objects that get restored. For example, uh, by changing a property value to order the username.
Oops. Uh, strange behavior. lines. Sorry.
Yeah. And this this page. Sorry. Um and by tampering with civilized data, attackers can control the properties of objects that get restored. For example, by changing properties value to alter the username here and uh they can escalate privileges like yeah this is adine and it's not limited to changing values. attacker can even change the data type of a property entirely like this uh from class food to int. Yeah. uh in POI uh properly oriented programming or POP for short is a technique that chains method invocations by co crafting object properties to achieve attacker controlled effect. uh it's kind of code wheels attack where each gadget is a class and the entire chain is formed by carefully crafted
objects. Uh in PHP object injection PHPGC is a well-known exploitation tool. It collects gadget chains from popular PHP products. [snorts] uh in most cases a gadget chain is triggered by a magic method. These three are important in this talk. Uh first uh construct and destruct uh constructor and destructor um as each name suggests and wake up gets invoked automatically during thisization. So we'll start by looking at how wake up is used in real world PHP applications to prevent an expected dualization then to understand why this mitigation isn't enough. We'll briefly explore a non bypass technique that still works today. So wake up app was originally designed to restore states not to preserve during civilization. Typical use cases include
uh res reestablishing data connections and restoring transient states such as open file handlers or cached data. Uh so at least uh originally wake up was never about security but over time some PHP frameworks and libraries have repurposed wake up method as a safeguard against PHP object injection attacks. In practice, they implement wake up in classes that might otherwise be abused as pop gadgets. For example, by throwing exceptions or by overwriting properties with safe values before any harmful behavior can occur. Um, still such a mitigation is not foolproof. Several bypass techniques have been reported and some continue to be effective even in modern PHP. So one powerful technique involved disguising a normal object as civilizable. But as mentioned earlier um
it will no longer work starting from PHP9. Uh another approach involved exporting references and it has been successfully used in gadget chains from PHPGC uh targeting LA and that the advantage is that it is not affected by PHP bug fixes but it fails against wake up implementations that simply throw exceptions. All of this points to the need for a more general technique, one that doesn't rely on PHP bugs and can bypass wake up app entirely. So um so now let's look at my technique that entirely bypasses wake up invocation without reing on any PHP bugs and the mitigation relies on the fact that wake up is automatically invoked when an object is dualized but wake up is never triggered during
classes instantiation with noob. With that in mind, let's consider a way to instantiate gadget class dynamically with any class name we control. So, uh now let's look at another vulnerability class that enables this behavior. Arbitrary object instantiation or AOI. It happens when an application takes a class name from user input and dynamically instantiates it without proper validation. Uh this can even allow passing arbitrary arguments uh making it as dangerous as PHP object injection. And though considered a classic bug, it was still shows up in modern PHP products like GP uh GLPI AOB account manager. Yeah. uh recent CVS and of course from a developer perspective if user in were always validated it would be safe
right and dynamic instantiation can be seen as a primitive a basic capability we can rely on in an attack vulnerabilities have been patched many times but dynam Dynamic instantiation itself is a common PHP feature. So this AI primitive may still be lurking in modern code bases. So an awakening an awakened wake up is a technique that incorporates an AOI gadget a class providing the AOI primitive into pop gadget chain. So let's take a quick look at how an AI gadget works. Uh here's a class called target uh shown earlier. Yeah. Uh it's protected by a wake up method. So this realizing it will fail and we can't use this gadget directory in a pop chain.
Here's another class AI in its destruct method. It uses the name properly to dynamically instantiate another class as shown in the code. If we set name target, it creates a target instance without triggering wake up. Uh when destroyed, the target objects [snorts] distract once. It's so simple. So but the question is is this technique actually practical in real world applications. So uh from here we'll show that an awakened wake up is not just theorical but a practical technique. To do that we'll use a case study reviving garc1 gadget chain inside the nails flow. So let's quickly review the Gazer RC1 chain and see how it was broken by the wake up as POI mitigation. Uh Gazer RC1 is a gadget chain included
in PHP GGC. It used only pop gadget chain gadgets from Gazo, a popular PHP library for um HTTP requests, but it only works in specific versions. Let's look at how it worked in version 6.3.2. Oh, sorry. And this chain takes two arguments uh a function and a parameter to attribute OCE. It uses them to build a hand stack object and then combines that with the string resolve in an array. uh that away is wrapped once more with the key cloth and passed to the fn streaming constructor which initializes its internal properties from it. So uh the important parts are fn close property in the fn stream object and tree properties in the hand stack object
handler stack and cast. Uh let's now look at how these are used during execution. uh when when a fn stream object created through PHP object injection goes out of scope uh its destructor runs and calls call user funk that function takes an array with an object and a method name and here it end uh ends up calling the resolve method on a handraw stack. So if we control the cast handler and stack properly, we can invoke any function with a single argument. The single argument is prev. Uh for example, calling system with a command string. Yeah, it's useful. But this is uh this no longer works. Wake up of fn stream the initial stage of the chain now
throws an exception. So the original gazer LC1 chain is dead. So before jumping into the revival of Gazer LC1, let's first take a moment to explain what nails flow is and the reason why I chose it as the case study. So for this case study, we'll be looking at NF version 9.0.2. Flow is a PHP web framework and I chose it because this technique was discovered during post engagement research after a pentest overflow based application. The gadgets used here come from flow itself gaz PS7 uh doctrine or m a well-known object related mapper in PHP uh to find a gadgets we can search a code base for dynamic instantiation points. PHP has some patterns for
creating objects without hard coding the class name. So tools like grab with reject can be used. Oh sorry uh can be used using this approach. I found a usable ai gadget in nails pro specifically in doctrine or So here's the EO AOI gadget I found in that version of doctrine OM. Um it takes three arguments all of which can be controlled. I'll explain later how this is wired into the pop chain. So here is the flow RC1 gadget chain. essentially a reincarnation of the original gazer LC1 adapted to nails flow. Uh it involves uh five gadgets. So the execution flow is a bit long. I I'll skip over some of details. One important point to notice
in the fn stream part uh in in uh instead of using the new keyword for instantiation, it's now just a string here. So here is the structure with just the key ports highlighted but yeah many many highlighted. The AOA gadget uh tree worker chain iterator has two arrays workers holding the string gather HTTP PS7 FN string for instantiation. this one um and the query mapping the key uh clause. So with with that in mind, let's move on the key parts of flow RC1's execution flow. Um let's assume a dualized object is being destroyed. It's destructor simply triggered a the flash method inside flash for each loop iterates over the message properties. So here comes the EI gadget to revoke a
chain iterator. uh during the for each iteration we saw uh earlier uh its current method runs like magic method which calls offset get with the first key from the workers array after confirming the offset exists um the ai primitive is executed so the constructor of fn streaming dynamically creates It's fn clause properly from an array that uses close as the key op key uh will leverage for code execution. Uh when the fn stream object is destroyed it's destructor is triggered. Yeah this is so uh it's it's uh it's not enough time. So uh I skipped the details here but that's how the chain finally reaches code execution. So uh uh these hund stack steps don't add
anything new uh so I'll skip over them. Yeah this one to end uh sorry uh quick uh quickly. So live demo. So uh this is the target uh target application. Um yeah. And uh 1 2 3 4 5 and this is the length field. So 1 uh 5 + 5 = 10. Yeah, it seems good. And uh can you see it? Yeah. So, uh this is uh Gazer LC1 system ID. Uh this execute uh system function with uh parameter id command and this is all to h. So, uh, copy to clipboard. Oops. So, and this one. Oops.
Sorry. We send and uh this is the post request and edit and resend. Yeah, maybe uh there it's uh not uh it's difficult to see. Oops. Oh, so
sorry. We wrote um post and we send and
uh this one is uh ops. copy uh copy I missed copy so yeah it's uh it should be abnormal case but I uh the the time is not enough so uh I only the succeeded case so uh sorry And yeah, this is it. [applause] >> Oops, it's not good work. Yeah. And uh sorry clo for pentesters consider using AOI gadget to bypass wake up when exporting POI for PHP developers. Uh don't use uh PHP serialization. Use JSON or validate data with HMAK as we recommended in the PHP manual. And for aspiring hackers, uh share what you discover in your work. Uh the community is eager to learn from you. Yeah. And resources. And thank you for
listening. And huge shout out to besides staffs and mtor. Thank you. [applause] Any question? Okay.