www.inversecos.com
Open in
urlscan Pro
2a00:1450:400e:802::2013
Public Scan
URL:
https://www.inversecos.com/2022/07/heap-overflows-on-ios-arm64-heap.html
Submission: On July 29 via manual from TR — Scanned from DE
Submission: On July 29 via manual from TR — Scanned from DE
Form analysis
1 forms found in the DOMhttps://www.inversecos.com/search
<form action="https://www.inversecos.com/search" target="_top">
<div class="search-input">
<input aria-label="Search this blog" autocomplete="off" name="q" placeholder="Search this blog" value="">
</div>
<input class="search-action flat-button" type="submit" value="Search">
</form>
Text Content
Skip to main content INVERSECOS HEAP OVERFLOWS ON IOS ARM64: HEAP GROOMING, USE-AFTER-FREE (PART 3) * Get link * Facebook * Twitter * Pinterest * Email * Other Apps July 12, 2022 Welcome back to part 3 of my iOS arm64 exploitation series! If you’ve missed the blogs in the series, check them out below ^_^ Part 1: How to Reverse Engineer and Patch an iOS Application for Beginners Part 2: Guide to Reversing and Exploiting iOS binaries: ARM64 ROP Chains If you’re more of a visual learner – I have filmed a YouTube video on this that you can check out! The YouTube video does not go into the same level of depth as this blog post will, so just keep that in mind. INTRODUCTION We’ve gone through iOS hooking, buffer overflows and simple ROP chains on ARM64. Now it’s time to talk about heap overflows and exploiting use-after-free (UAF) bugs. The goal of this blog is to show you how a UAF bug can be exploited and turned into something “malicious”. I will be walking you through step-by-step the following things: * How to identify a UAF bug * How to statically analyse the binary to figure out how to perform the exploitation * Heap overflow logic * Heap grooming * Full exploitation As always, we will be using open-source tools to perform this and I have compiled, signed, and uploaded the exercise binary that we will use for this exercise. I have also uploaded the source code for those of you that want to read it. This is all available for you to download on my Github: Download exercise binary “moneymachine” from GitHub here This blog has been broken down into five parts: * High level walkthrough of the steps * Introduction to the exercise binary * Static analysis of the binary using Radare2 * ARM64 heap overflow * Resources HIGH-LEVEL STEPS These are the high-level steps we will take during this exercise, and I will explain each one in detail. If detail isn’t your kinda thing, then just peep my YouTube video: 1. Upload the binary to your jailbroken iOS device via SFTP to the /var/mobile directory. I am running a jailbroken iOS 14 device called “honeypot” 2. Find the UAF vulnerability by playing around with the program 3. Statically analyse the binary using R2 to locate any meaningful functions that we can manipulate 4. Set up a remote debug session on the iOS device using LLDB 5. Debug the binary and set breakpoints after memory allocation to fetch the heap address where the objects will be allocated to 6. Perform heap grooming by populating areas of the heap until all the free lists are emptied and the only “free gap” to write to is the initial freed object on the heap 7. Perform the heap overflow 8. Invoke a function call to trigger the payload INTRODUCTION TO THE EXERCISE BINARY This binary is called “moneymachine” and it’s a MACH-O 64-bit binary. It was inspired by the internet and all my weird friends who grew up playing Runscape! Lol. The name of the binary is a reference to the 100 gecs iconic meme song “money machine”. Anyway, when you download the binary and run the binary, there are 6 option to choose from (as pictured below). The goal of the exercise is to exploit a heap overflow and perform heap grooming until you can buy the legendary item! There is an embedded use-after-free vulnerability coded into this binary. Please note, no security controls need to be disabled for this exploit to work. ;) When you select [2], the program will call ‘malloc’ and allocate memory on the heap for your quest (in this instance, Goblin diplomacy). The “quest” is a struct – an object which stores the name of the quest along with a function pointer to a function which lists all the available quests [3]. The call to [5] will invoke the ‘free’ function which will free the object allocated on the heap. However, this object has not been nulled meaning the data is still residing on the heap – which is why, when you call [3] after the object is freed, it will still return all the available quests. The goal here is to go from a broke traveller to a rich traveller. And then after we exploit the moneymachine, we will become rich enough to be the owner of the largest and most magnificent sword in the world. To do this, you must perform a heap overflow, heap groom, and identify a secret function we need to overwrite the function pointer on the heap with. STATIC ANALYSIS USING R2 AND LLDB Let’s look at the binary and perform some static analysis UwU 1. Examine all the functions within the program To do this you can use Hopper, Radare2 (https://github.com/radareorg/radare2) – whatever diassembler you want to use. I am going to use radare2 to perform this step. All you need to do is to run the following commands: * r2 <binaryname> * aaa – to trigger r2 to analyse the flags, function calls, bytes etc * afl – lists all the functions From the screenshot below you can see some standard C functions and three non-standard functions highlighted in purple. 2. Look at buyItems function to see what it does The goal of this exercise is to figure out how you can afford to buy the legendary item – so based on the name of this function, we should probably prioritise it for analysis. Hopefully it might help us understand the logic behind how to buy items within this binary. To examine this function type in: * s sym._buyItems * pdf Straight away, in the code we can see comparison happening leading to two jumps. Let me break down the assembly into plain English: * First, we notice there is a variable called “sym._money”, we can guess variable may be storing how much gold we have * The value of “sym._money” is stored in the w8 register * The function moves the value of 999999 into w9 register (as highlighted in purple). This is represented as 0XF423F in hex. * There is a comparison being done between w9 and w8 (comparing our current money with the value of 999999) * The program branches to two different locations depending on if the amount of money we have is greater than or equal to 999999 (b.ge), otherwise it jumps somewhere else We don’t really need to analyse the rest of the code to understand logically why this is useful. It’s likely at this point that because we are broke with 0 gold, we will not be able to buy the legendary item. It’s also likely that the legendary item costs 999999. I pulled the binary into Hopper (as it does a better job of showing strings than r2 visually) to show you where the function branches to based on the comparison. The first location is if the comparison fails and we have less than 999999 gold – it will print “you do not have enough money”. The second location shows you what happens if you do have 999999 or more gold. It prints “item acquired”. Now with this knowledge, it’s immediately clear we need to find a way to get more money to exploit this program. 3. Analyse the makeItRain function Next, let’s look at the makeItRain function to figure out what it does. As you can see in the picture below – once again after the function prologue, it interacts with the “money” variable (sym._money). * Stores the value of sym._money inside the w8 register * Stores the value of 0xF4240 in w10 register which corresponds to the value “1000,000” * Adds the value from w10 register to the w8 register * Prints something From this we can deduce that this function increases the value of “money” by 1,000,000. 4. Analyse other functions Looking at the other functions called within the program we can see references to these functions: * malloc – something is allocating memory on the heap * free – something is being freed on the heap * fread/fopen – something is being read from a file 5. Find the use-after-free bug When we run the program, we notice something interesting. When we call [3] for available quests before allocating a new quest [2], a segmentation fault happens. A segmentation fault doesn’t occur after we get a new quest [2]. However, after we free the quest with option [5], and then we call [3] available quests, the data is still referenced. This is the premise of a use-after-free bug where the data is still resident on the heap and that memory address is still being referenced by another function. If we look at the source code, we can see below that the freeing of the quest object on the heap does not include nulling the data out! It’s this bug which causes the use-after-free bug. HEAP OVERFLOW WITH HEAP GROOMING Now that we have statically analysed the binary, we have an idea of how we should proceed with the exploitation: * Allocate a new quest on the heap with option [2] * Free the new object on the heap [5] * Read data from a file by calling [4] to import items from a file * Use the data from the file to overwrite the original quest heap object * Overwrite the function call to listQuests() on the heap with the address of makeItRain() * Trigger the use-after-free by calling [3] available quests * See if the exploit was successful by calling [1] to buy legendary items To perform these steps, we need to gather some information and ensure a few things: * Get the heap address where the quest is allocated to * Get the heap address where option [4] is writing the file contents to * Ensure that the two heap addresses are the same, otherwise perform heap grooming 1. Remotely connect to your iOS where the binary is running with LLDB On your iOS device, make sure to have two terminal sessions open, one which is running the binary, and another to start a debugserver session attaching it to the running process. Pass into debugserver the IP address of the workstation you’ll use to perform the remote analysis On your workstation, open LLDB and connect to the running process. 2. Disassemble the main function The first thing we are going to do is to analyse the main function. The purpose of analysing the main function is so we can get an idea of what it is doing and work out where we should set some breakpoints. To do this you just type the command: * disass -n main Please note all your addresses will be different to mine :) 3. Set breakpoints for the purpose of working out where we are writing to on the heap The heap address where malloc allocates to will be pushed into the x0 register in ARM64 right after the function call to malloc. Therefore, by breaking right after the call to malloc, and by inspecting the registers, you will be able to pull the heap address that we are writing to ^_^ Therefore, at this stage, we will scroll through the main function and copy down the addresses where we will set breakpoints at. The first breakpoint happens early in the program (likely where the call to [2] New quest is done). The second malloc is later in the main function right after the contents of a file ‘items.txt’ is read and then stored onto the heap. We are also going to set a breakpoint right after the call to the “free” function. This is so we can double check that this UAF exists. If there is a UAF bug then the data on the heap will still remain after the call to free as it won’t be nulled. To set the breakpoints, just run the following commands: 4. Hit the first breakpoint and gather the address of the heap from the first malloc As the program execution is currently paused, we need to continue the process and then select [2] to allocate a new quest. This should immediately then hit our first breakpoint at the first malloc: Now, we need to examine the register and pull the address of the heap. This can be done by typing “register read”. As you can see below the heap address where our quest “Goblin Diplomacy” will be allocated to will reside at the address “0x0000000104b06ce0”. Looking at the heap address right now, you will see there’s not much sitting there on the heap. This will be important later as we compare what happens when we get data written to the heap. 5. Free the heap allocation by calling [5] Continue the process execution by typing “process continue” and then call option [5] to free the allocated data on the heap. 6. Check the data on the heap Pause execution by typing “process interrupt” and then observe what is written to the heap. As you can see below there has been data populated in the highlighted purple region. As expected, the data written there corresponds to “Goblin Diplomacy” in hexademical followed by the address of the listQuests() function at 0x104b06d00. The important thing to note here is, even though the heap has been freed, the data is still resident here instead of being nulled! This is the premise of the bug. Just to really demonstrate my point, the values on the heap correlate exactly to “Goblin Diplomacy” in hex but in little endian format :) 7. Prepare payload to overwrite the heap In order for us to prepare the payload, we will need to put data into a “items.txt” file before we invoke a call to option [4] to read items from a file. Let’s use this as an opportunity to calculate the offset where we need to overwrite the function pointer address with the makeItRain() address. After piping all the data into a “items.txt” file. I then SFTP’d it into the same directory as the binary on the iOS device. 8. Get the payload heap address and check it’s the same as the first heap address Now let’s trigger the payload and see where this new data will be written to on the heap. We do this by calling option [4]. This will hit our second malloc breakpoint. We will do the same step of calling “register read” to pull the new heap address off the x0 register. This heap address is 0x0000000102906080 which is different from the first heap address of 0x0000000104b06ce0. 9. Heap grooming or heap feng shui technique On later versions of iOS, even if two objects being allocated on the heap are the same size, the second object may not be allocated to the same location as the first freed object. This is due to how the heap manager manages free space on the heap. A great explanation on how this works is on Azeria Labs blog (https://azeria-labs.com/grooming-the-ios-kernel-heap/). How this works is, on the heap, there might be several gaps where the new malloc’d object will be written to. Our goal here is to keep filling in these gaps with data to increase the chance that our data will be written to the attacker freed area on the heap. To do this, you just keep spraying the heap and fill all the free gaps with objects until our object is written into the desired heap section. In the picture below, this is a *VERY* rough representation of our current heap state. I simplified this so it’s easier to understand. Basically, we have free gaps and our freed quest object is sitting on the heap. However, our items.txt was written to another freed gap on the heap, at a different address. Therefore, to perform the heap groom, we need to fill out the heap until only freed area in the zone which can accommodate the size of the malloc’d items.txt object is the original freed quest object address. Therefore, in our program example, we will just keep calling the [4] import items call to malloc until we get our items.txt allocated to the only gap in the zone left – the same address as the freed quest object. This program is a more simplistic example of this as I coded it so that the two objects are the same size. 10. Call [4] import items again The number of times you may have to call [4] will vary, but you need to continue the process and keep calling it and checking the x0 register until we hit the same address on the heap as the original object at 0x0000000104b06ce0. As you can see on the second iteration of the program, we have had our second malloc set to the same address - 0x0000000104b06ce0. At this point, we will hit ‘process continue’ to allow the heap to populate. As you can see from the screenshot below, we have overwritten the heap with the hex representation of “AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFF”. Highlighted in red, is the hex of “EEEEEEEE”. This is the location of where “listQuests()” resided on the original heap when we allocated the quest data. This means when we edit our payload, we need to replace this with the address of the “makeItRain()” function. FULL EXPLOITATION Now that we know we need to replace the EEEEEEEE in our payload with the address of the makeItRain() function. We are ready to perform the full exploit. Let’s get it! Step 1: Rerun the binary We are going to start a fresh debug of the running binary. So just load up the binary again and connect to it with your remote workstation where you will be performing the exploitation. Step 2: Repeat steps 2-4 in the heap overflow section Once again, we need to set breakpoints at the address right after the two calls to malloc so we can ensure that we are writing to the same heap address. For the actual exploitation you can ignore the third breakpoint set after the “free” function call. If the heap address is different, just remember you may need to heap groom, I have rarely ever seen it hit the same address straight away. Step 3: Get the runtime address of the makeItRain() function We need to change the payload to replace EEEEEEEE with the address of the makeItRain function at runtime. Therefore we need to disassemble this function and get the entry address which is 0x1028637bc. To set the breakpoint you just need to run: * br s -a 0x1028637bc Step 4: Replace the payload Currently our payload looks like this: \x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42\x43\x43\x43\x43\x43\x43\x43\x43\x44\x44\x44\x44\x44\x44\x44\x44\x45\x45\x45\x45\x45\x45\x45\x45\x46\x46\x46\x46\x46\x46\x46\x46 We need to replace the \x45\x45\x45\x45\x45\x45\x45\x45 section with the little endian version of the address of makeItRain 0x1028637bc. This turns the payload into this: \x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42\x43\x43\x43\x43\x43\x43\x43\x43\x44\x44\x44\x44\x44\x44\x44\x44\xbc\x37\x86\x02\x01\x00\x00\x00\x46\x46\x46\x46\x46\x46\x46\x46 Step 5: Read from items.txt Before you read from the file make sure you have allocated a new quest [2] and freed it [5]. Then do a call to [4] import items checking that the heap address is the same. If not, then you need to heap spray until it is. Step 6: Check the heap and the payload on the heap I like to just interrupt the process and ensure that the address is written properly to the heap. You do this by running: * process interrupt * x/64 0x0000000102a04510 As you can see from the screenshot below we have successfully overwritten the function call area of the heap with our makeItRain() function. Step 7: Make it rain baby! Now it’s time to trigger the exploit. To do this you just need to call the [3] available quests function and it will jump to the makeItRain() address. As you can see below, this is successful! Now all there is to do is to try and get our legendary item UwU. As you can see below, this is a success! Heap overflow, UAF abuse with heap groom complete! Other Resources I noticed there are not many resources specifically dedicated to arm64. There are a few on arm32, but most of the exploitation write-ups are focused on x86. I recommend for further study you take a look at the following resources below T_T Azeria Labs: https://azeria-labs.com/heap-overflows-and-the-ios-kernel-heap/ HighAltitudeHacks: https://highaltitudehacks.com/2020/09/06/arm64-reversing-and-exploitation-part-2-use-after-free/ Billy Ellis: https://www.youtube.com/watch?v=L8Ya7fBgEzU&ab_channel=BillyEllis LiveOverflow (Note this is on x86): https://www.youtube.com/watch?v=TfJrU95q1J4&ab_channel=LiveOverflow arm64 heap overflow heap feng shui arm64 heap grooming arm64 heap overflow ios ios uaf exploit use after free ios exploitation * Get link * Facebook * Twitter * Pinterest * Email * Other Apps COMMENTS POST A COMMENT POPULAR POSTS FROM THIS BLOG FORENSIC ANALYSIS OF ANYDESK LOGS February 10, 2021 Most threat actors during ransomware incidents utilise some type of remote access tools - one of them being AnyDesk. This is a free remote access tool that threat actors download onto hosts to access them easily and also for bidirectional file transfer. There are two locations for where AnyDesk logs are stored on the Windows file system: %programdata%\AnyDesk\ad_svc.trace %appdata%\Anydesk\ad.trace The AnyDesk logs can be found under the appdata located within each users' directory where the tool has been installed. Forensic analysis of these logs reveal interesting pieces of information inside the "ad.trace" log: Remote IP where the actor connected from File transfer activity Locating the Remote IP Connecting to AnyDesk Inside the "ad.trace" log you can grep for the following term "External address" and this should reveal the following line pasted below. I have redacted the IP for privacy's sake: info 2021-02-04 23:25:10.500 lsvc 9988 Read more OFFICE365 ATTACKS: BYPASSING MFA, ACHIEVING PERSISTENCE AND MORE - PART I September 16, 2021 APTs are actively attacking Office 365 (O365) – finding mechanisms to bypass MFA and to impersonate users regardless of whether you reset their passwords. When I was looking through the Mitre mapping of O365 attacks , I noticed that it didn’t include many methods of intrusion and actions on objectives that can occur with O365. In conversations with several clients, I couldn’t help but notice that there’s still a heavy focus on “endpoint” style attacks and not much resource / thought put into attacks that can occur in the cloud. Attacking O365 gives an attacker many benefits… it allows an attacker to impersonate users, alter MFA settings, register malicious devices, access Teams messages, download sensitive emails, access SharePoint, OneDrive, register malicious applications and various other actions that could allow them to maintain persistence in your environment. This blog post explores the various ways O365 can be attacked. I will be writing a Part II follow up that describes the me Read more BACKDOOR OFFICE 365 AND ACTIVE DIRECTORY - GOLDEN SAML September 02, 2021 Backdoors can bypass all MFA requirements put in place by an organisation. Earlier this year, I worked an engagement with an APT group that had a keen interest on the client’s Office 365 environment, where this group found a way to bypass authentication controls to access the environment. Given that most clients either have a hybrid authentication model set-up or are fully in the cloud – I think it’s important that most blue teams / defenders / hunters are aware of the various techniques threat actors are using against Azure AD. Compromise of the AD FS server token-signing certificate could result in access to the Azure/Office365 environment by the attacker. By default, this certificate is valid for a year and will allow an attacker to log into Azure/Office365 as any user within AD regardless of any password resets and MFA. The implication of this, is that the attacker maintains persistence and has a means to re-enter into the environment, escaping detection. This blog post will cover Read more Powered by Blogger REPORT ABUSE MY BOOK * How to get a job in cybersecurity earning over six figures : Zero to Cyber Hero inversecos Visit profile LINA LAU I'm a lead incident responder and security researcher. If you'd like to get in touch with me, hit me up on twitter @inversecos SOCIAL * Twitter * YouTube * LinkedIn * Tiktok SEARCH BLOG ARCHIVE * July 20222 * June 20223 * May 20222 * April 20222 * March 20221 * January 20221 * December 20211 * November 20211 * October 20213 * September 20212 * May 20211 * February 20211 * April 20201 * November 20191 * March 20181 * October 20172 * June 20172 Show more Show less Diese Website verwendet Cookies von Google, um Dienste anzubieten und Zugriffe zu analysieren. Deine IP-Adresse und dein User-Agent werden zusammen mit Messwerten zur Leistung und Sicherheit für Google freigegeben. So können Nutzungsstatistiken generiert, Missbrauchsfälle erkannt und behoben und die Qualität des Dienstes gewährleistet werden.Weitere InformationenOk