← All talks

Certpinning, OpenSSL and Memory Patching

BSides Joburg · 202434:58340 viewsPublished 2024-08Watch on YouTube ↗
Speakers
Tags
CategoryTechnical
StyleTalk
About this talk
This is a technical and theoretical talk on an alternative approach to bypassing certificate pinning by using Frida to change values in memory. It will cover my research on certificate pinning over the last few months, mainly within an Android mobile context. This approach differs from the usual approach of using function hooking by being more difficult, less practical and far less reliable. This is a novel technique for bypassing a security control, rather than being a vulnerability. The following section will be covered by the talk: - Introduction to what certificate pinning is. - The different methods typically employed to implement certificate pinning. - How certificate pinning is typically bypassed. - Using memory patching to bypass certpinning. - Future research and understanding where OpenSSL fits in. (Hint: everywhere) Follow BSides Joburg: Web: https://www.bsidesjoburg.co.za Twitter / X: https://www.x.com/BSidesJoburg LinkedIn: https://www.linkedin.com/company/bsides-joburg/ Masterdon: https://infosec.exchange/@bsidesjoburg
Show transcript [en]

[Music] everyone um think we can start so today I'll be talking about my journey into researching SSL pinning um the last few months um this has mostly been focused on trying to find a way investigating how we can potentially bypass a Sal Penning as well as other measures um from a perspective where we don't necessarily know what's going on in the application maybe it's a native application um maybe there's a lot of reflective loading or such um involved and in general just to get a better understanding of how the TLs stack on a mobile um application works um for This research I specifically focused on an Android environment though some of this is also directly transferable to iOS so

firstly um just an introduction uh we're going to run through the normal ways you typically do SSL pinning uh the typical bypasses we use for those uh then we'll move on to how memory patching works and why I thought that might be a potential uh approach to do and then the future work um that I'm planning to do from here and the many more questions uh that I got after only barely got getting my initial ones um answered so in terms of who I am some of you might have heard of me on not um I work for orange Tri defense I'm also a staff member on hack South and a organizer for bides Kel so just before we start um it is

them I don't consider certificate pending or the lack of certificate pinning as a security vulnerability it's rather a more defense in depth measure rather than a vulnerability the lack of it um and in our case we assume you already have direct access to the device so this approach does not constitute a vulnerability per se or new bypass that can actively be used in in an attack or such but rather just to Aid reverse engineering um and maybe malware analysis or such so firstly what is certificate pinning um it's basically the act of using some token for verifying that the certificate you are getting from this server is what you expect it to be um this is typically done

when you want to further measure other than verifying the normal certificate chain um and once again it so it serves effectively the purpose of providing additional protection so let's say a certificate Authority is compromised um or some of the other measures to verify the chain U fails then um there's some typical nuances uh that that are important here with certificate pinning many times what is referred to as certificate pinning isn't actually certificate pinning so host name validation your chain validation the trust store uh certificate validation all of those can involve certificate Penning uh but many times it's not actually certificate pinning that's taking place there's just other verifications and it might appear that you're not getting traffic um

because it's certificate pinning but in technicality it's not now in terms of issues with implementing SSL pinning um con and Andre showed us nicely how not to do that and the many other issues that that can occur when you try to implement certificate pinning and how that can break all the normal other protections that are usually in place so just a rough rough um introduction this is effectively the handshake that takes place with THS it's not too important um all we need to know here is the is that the server is going to send us a certificate chain um the client's to verify that and then the actual connections encryp the connection is going to be established uh here we

can have a or here we have an overview of the Javas skare socket extension this is just the different libraries that are used to construct itals connection um most of them are not really uh that important we're going to look at the trust managers uh as well as the SSL context um but most of what I looked at is not within the Java environment because I wanted to try and get a more generic approach that applies across different programming languages and implementations now in terms of the typical implementations for certificate pinning at least the ones I've seen in my experience um it's typically done through a hash or it can be do done through a full certificate pinning but

most typically it's just a hash um either sh 56 show one or md5 of the public certificate of the U that's of one of the public certificates in the certificate chain um here's another example from a reverse engineer application where the where it uses a full public um certificate um and it just loads that from the resources so in this case it's it's far easier to just uh patch the actual application or maybe um patch where when it reads the file from from the file system so I didn't bother too much in terms of these certificates and it becomes quite a bit of a race condition when you tried to uh replace these certificates just because of the

size now just a very rough overview of how a certificate chain looks uh we have a certificate Authority that we're starting with we have maybe one or more intermediate certificates and then we have our leave certificate that that's that's it and that's most that's basically what we that what's important to us now in actuality it looks more like this where we have for example our um isrg root X1 root certificate a all3 intermediate certificate and then the lease certificate which is a wild card certificate in this case for bad SSL and at the bottom right you'll see the public key value there 0 B9 fa um and that is the RO hex value for that now if

you take the from the previous slides if you check that hash that sha 56 hash there that's actually just B 64 encoded if you decco um you're going to get the same value moving on um I used this specific application SSL pinning demo that I got of GitHub just for demonstration purposes it provides a mer of different SSL pinning methods as well as certificate transparency um for this talk I won't be considering certificate transparency as that's not really SSL pinning it's a bit of a different method of validating the certificate itself then um the typical bypasses that we use uh when we're talking about an instrumentation perspective and not from an attacker perspective where we want to

um actually compromise the communication uh we're assuming we have full control over the device already typically things like fedo used or or patching the IPA or the or the APK application for example modifying the network security config uh or removing the the the hardcoded hashes there and then of course objection so why memory patching I mean we already have existing ways to bypass SSL pinning why just another one um well because I wanted to find a more difficult method method uh to to basically accomplish the same thing less reliably because apparently I had too much fun in life um yeah um but more specifically strings are quite easy to find in memory um when they're not encrypted or such they have

a set length especially because we're dealing here with a hash they have predetermined length that don't really change so we didn't really need to make a string either longer or shorter in which case if we had to that do that it would become quite a bit more complicated because if you're dealing with a framework like Java or other programming languages it's a more complex data structure not like C which just a null Terminator so we'd also have to override the length of the string which things get quite a bit complicated when we assume we it's a black box and we don't know what's going on there um issues that we that we might have if

this was not the case especially in terms of java is the Java's Primitives are IM mutable which means they you once it's created the actual value in memory it it doesn't get changed so if you have a string in Java and you change that string uh from the variable a new memory addes gets allocated and the new value assigned there what this means for us is if we want to check a specific variable across two points in time that's not really possible with Java because the original one is going to still the original memory value is still going to have the same value and even if we change that it's not going to affect what the actual value is reflected

within the code um because a new memory address has been assigned to that but because we're dealing with effectively constants here none of this is a problem we have static um strings that have a set length they're stored directly and they never change so we don't have to deal with any of these problems so when we're dealing from a blackbox um one thing that becomes important um is knowing what the application actually connects to uh if we're not looking at the source code we don't know what server is being used so how on Earth are we going to figure out what the string is in the first place to patch with memory like we wouldn't know um now one approach we

could use is doing DNS resolution maybe forcing the phone to use a DNS server that we own uh we could potentially do some other attacks with that as well but using that we can figure out what um what servers the device is trying to connect to another option um that let's say the device is using IP addresses directly for some reason we could also just look the raw sockets um on the Android device um and I'm specifically referring to the raw sockets not Java because if we have other Frameworks such as jav such dot which is employed by flatter you're not going to see that because it already has its own implementation of TLS and doesn't use

the Java jss stack so we can hook the on socket level to get the uh server that's being connected to now now that we have the server addes how do we go about figuring out what the actual hash is that's being Pinn that we want to uh find um because currently once again we're dealing with a black box here so the first thing you can go about is just using this op SSL command it might look complicated it's fairly simple um as you can see there it's connecting to es 384b ssl.com that's just a domain in this example all this is doing is pulling the certificate chain using open SSL and orc is just being used to dump that into

three or however long the chain is pem files that's all effectively do just pull the certificate chain and then we have another one here that basically goes for each of those certificate uh files it takes them and then on the fourth line there you'll see it calculates the shot to 56 digest and then it just pipes it into uh or converts it to Bay 64 you can also just do that with a B 64 command and similarly you can use this for all the other different formats sha one uh md5 just to get all the different hatches this is just an example um now if we look at the bottom there we will see the basics the four encoded

versions of them and that last one may or may not be familiar or look familiar so that is actually the hash that was used in the slides at the beginning for the certificate pinning um I have already seen that hash way too many times now if we move over to a or or implementation here um this is just an example F script uh to now do the actual patching if we look at the top there we firstly begin with the SHA 256 hash of our burp certificate because in this case we're using burp as intercepting proxy this is arbitrary you can obviously use whatever you want and we just need the actual certificates hash you can calculate this once again

using the same op SSL commands that I showed in the previous slides so okay now we have the shot 256 hash we have the list of hashes um from the website so if we go back one okay this is not going back if you go back one we have on the the hex there the three hex lines those are the same ones we have in this script just the the first part of them because we don't really need to look for the full one they're fairly unique strings um and then once we have that um we basically find the areas in memory that we have read write access to in this case just the specific first one uh

depending on the application where the logic lies this is going to differ it might not be in the main module of the application uh this command uh I believe is probably just going to fetch the main module so just as you can see at the end there that that zero index I just uh fetches the first index that's returned so that's going to be the main module of the application and we have read write access to that um in this case and then we're just going to Loop over all the the full certificate the array that contains um the certificate hashes um and this is now of our Target server this is the ones we pulled and

then for each of those we're going to use the memory. scan command of feda um to locate that hash within memory we're searching from the module. base um a size of module size and then obviously looking for the the those hex values within the RAM memory of the device and once it finds those we just override the bites of those with our certificate hatch now this is a bit of a example implementation the the it it's probably going to not work in a lot of cases um this only works for example when you're looking or when the server is the device is trying to put a single hash um because what this is effectively going

to do is it's overriding all the hashes within the chain so if two hashes are checked uh this is obviously going to fail because we're just overriding all of them with the same

value then moving on so this is what that typically looks once we executed once again on the right side we have the uh certificate pinning example application um just to rund down effectively of what that does so the first two there the unpen request and the unpen web request those are as they say the unpen request just the context in which they make the request differs the second and third one relies on the um security config file uh the XML file within the application um both a sh 256 H as well as the full certificate hash um of the certificate uh the reason I didn't bypass those um is because the the data structure they use is slightly

different um and I didn't really care too much because they are as I said they're using the network security config which is a very easily accessible file it's not encrypted we know where it is so it's not really of importance or any practicality um to overh these when you can just modify that plain text file and then we have the third one there which which uses the okay HTTP pin requests we have volley which uses a um a bit of a additional logic to validate the full certificate chain um this does uh verification both on Java side as well as the native libraries of open op SSL and such that are used on Android I'll get to more specifics later on and

then a lot of the the next ones use certificate transparency uh CT as noted there so we don't really care of them and then we have What's called the raw custom pin request so this has a this just opens a raw SSL socket gets the certificates of the server and validates them against this hash now it's interesting this is considered as the most difficult to bypass but because we're using a fundamentally different approach to attack this in quotes um we don't have that problem because we're not trying to hook functions here or known libraries or whe we're attacking it from a memory perspective and assuming we know nothing about the application then moving on um while I

was at this um also as Leon uh reminded Us in his talk last year I I thought I I I both needed a framework for this um and I had already programmed a lot of the scripts and such that I need to search for things in memory and replace them um I thought like I'm might as well add this to one of the tools I'm using um constantly just to make my life easier and then why not also submit that so other people can also find Value in there because I mean the work's already been done at this point so getting over to op SSL um op SSL I found is employed very very vastly it is used by

a lot of different Frameworks um not directly but indirectly so even Android uses as a default it's um it's it's TS manager is op SSL sort of um so by default it uses conscript now conscript is a uh Java Library created by Google and conscript is makes um calls to boring SSL which is a c um library now it does that through the Java native interface and then the boring SSL library is a fork of open SSL which through which half of its calls still rely on open SSL so the core Point here is the logic or the base base data structure that that is used here is the same across a lot of different

platforms now for interest sake I also looked at dot um which is used by flutter and this also use that also uses boring SSL although doesn't use conscript which once again uses op SSL so theoretically if we can understand the data structure that's in use by open SSL um we can find that in memory patch that um and um yeah byp pass that simple right yeah um so starting off uh I hooked up a the buer and started looking through the Java functions in this case this is deep within conscript um I learned a lot of interesting things here so here you'll see the M context variable that looks like a weird long integer um that's

actually a long value because Java doesn't have pointers so that's actually a pointer value to the C data structure uh that they're storing in a long within Java why because all of the open SSL functions that make modifications or that take data you need to pass the M context value or the CTX as it's called in the cworld value to those functions for it able to be able to retrieve that because all of them are static so if we start looking at um the data structures within c um it looks something like this so this is specifically destruct that M context points to there's a whole lot of values there luckily fortunately for us we only

care about the first one in this case firstly to Def find this which is the certificate info because if it was any of the other ones the lookup gets a bit more complicated because once again we're dealing in the context of memory here so we're working in offsets all of these are raw memory that we have to look at and this doesn't work so that points to um this data structure which has quite a few different values and then that ASN one integer um is a custom length that structure that they use for all Primitives as well and then within this I discovered specifically um what we care about is the publicy also sorry just to step back to give some

more context um a lot of it checks in terms of validation on Java conp all of those let's say they do um name validation or uh date validity um checking and such all of those typically um get the values from the C structure um through calling the openl or conscript functions they don't actually store the vales the values within the Java world even though the certificate is initially requested within the Java World transferred storen C so they can have or or they can get those values but in most cases they don't a lot of the libraries um such as okay HTTP or such those have or trust kit have extra checks they trust kit for

example stores it in an asn1 data structure and it compares the full ASN data structure asn1 data structure of the two certificates both the one it it knows is is true and the one provided by the server to validate whether they are the same so that gets complicated um we're not going to go into that um that's just to give context why I'm specifically looking into the seawall because then if I change the date values of of validity year in the seawall that also affects the checks done in Java without having to hook or override or in fact worry about how any of those checks look at least theoretically then coming back to this in this case we're just looking for the

public key um if we go first uh and we look now in memory how does that look uh on the left side we still have that x509 info struct uh and you'll see highlighted in color the the different values of that and then um using Freda we can see how those look within actual memory and then from that we can start to perhaps override or mess with these values now going back to openl um we'll see that x509 public keyy is another pointer to another struct you see a pattern here now we have another struct for the public key and that contains another value values with a lot of more offsets to What's called the P key

value and that goes to this truct which has a lot of generic um values to store a lot of different um certificates because if you step back one one uh moment this is x509 data structure this is not um specific to the public key um this data structure is not specific to the public key this data structure within op SSL is designed to store any type of of um certificate so private Keys public Keys um in in all different formats so it has a lot of other values as well and to be frank to this day uh I still have no idea what's going on there because there's a lot of recursion going on there um and once

again yeah as you can see there the two important ones there is is the a stack of x509 attributes which stores the actual attributes such as the date values the names and all of those of uh the data structure so at this point um yeah I took back a a step a few steps back um because it's it's kind of becoming an infinite recursion almost here and at any point in this process if you are a single bit off you completely lost and you're not going to realize that until you get to the last value and try to read that and if it's an integer you might get a string uh and really not know what's going on so for now I'm

pausing this um but the idea for me still is to try and find um known values such as the certificate uh version and such and trying to build up the data structure within memory and then to be able to replace that full public key certificate um then just as summary um what we've done so far and what we have seen so we know if we have have a blackbox application we can establish the server that it connects to we can get the hashes or public key uh keys that are possibly or likely used for pinning um they keep in mind they can obviously the developer can obviously use some kind of custom hashing algorithm and you're not going to be

able to get that uh likely unless you reverse engineer the application so there's a lot of caveats here but I think the base concept here is just that we have a potential different approach um to patch certificate pinning because all the base necessary information that we need um we have available or can get without looking at the core or the the the without reverse engineering the application itself and I believe this creates a a bit of a different attack Vector um especially for reverse engineering applications not just for the um not specifically for SSL pinning but for a lot of other checks that rely on fixed length strings um through so that we can patch them rather than

having to hook the functions now because we are working within memory here there's a lot of difficulties and caveats um I have managed to crash my host machine uh quite a few times through this process which theoretically should not be possible because I'm making memory changes within a virtual machine or or Android virtual device so that theoretically shouldn't be influencing my my host machine which might be worth investigating in itself but yeah throughout this process I've had a lot of crashes um because of the memory changes that I make and that's thank [Applause] you any

questions oh uh I I forgot something very important here I'm not done sorry so I can actually show um just a demo of how this actually works so there we have our example application I am just going to uh kill it and then if I'm on the right screen we're going to start up objection just loading our custom plugin in this case um and then we're starting the application here hopefully y it'll start correctly we're going to resume it yes there's the application so this virtual device is just um set up to uh proxy through burp using the virtual device settings uh if we go over and this is nice because we don't have to make any changes in the device

itself so that's just piping through to BP which is running in the background now in this case if we make unpend requests those are hopefully going to go through uh but once we go into any of these pend request as expected um they are going to fail so what we can do now is we can go back to objection um we can then if I click use uh the script that basically just implements the open SSL commands um as we showed as I showed earlier uh and that's that is going to so this one is going to just pull the certificate hashes both the rule and the Bas 64 encoded of the certificate chain um and

then this one is going to provide us with the uh hash of our burp certificate and then we can in this case we can oh I there's also a command to replace all of them though in this case I'm just going to use the other command as I showed earlier to replace the hash within memory so this one only does one specific one at a time um because it's only two it doesn't really Mato so all we're doing here is we're taking the hash um from the second one the Bas 641 we're searching for that and we're replacing that with our burp hash so as you can see I found 13 matches um within memory

and that is also partly due to how Java loads it into different places but only one of those two are actually one or two of those are actually important going back to the application is if we make that same request now hopefully all the thumbs that is going to Su go [Applause] through and if we go back to B we'll see those two requests going through um and the responses

so yeah that's it any questions on this

one yes work on a how's it will he work on a physical device uh yes this works precisely the same on the physical device I don't want to have one to demo with um but the only reason I'm using a here is because um of it's it's more repeatable um and I currently have a lot of other stuff on my physical device um that makes it harder to test with but yes it works exactly the same on a physical device once again in this case I'm just using Freda so you'd either use a Freda server on the on a rout device or just patching the application um with either objection or manually with a Fredo Gadget so the gadget is it needs

to be rooted no it doesn't need to be rooted you can use the the you either patch the application um with with objection or Freda on a non-rooted device or if you have a rout device you can use 3. server okay

cool I don't see any other questions oh there's one back there it's a bit hard to see from here um hi um just the the silly one um those memory Replacements that you're doing is that just in the memory space of the the hooked application so it's not in the whole uh memory space of the device yes so that's a good question um in this case it's only within even a specific part of the application um the applic the application itself loads a lot of different libraries and such such as conscript and such um but in this case I'm only patching within the main application though of course you can patch within within the full context of

the application or if you're on a routed device you can also patch in the full context of the the entire device very cool

thanks I think that's all thanks [Applause]