Get the executable here
- Add a hook at the end of the
pick_number
function. - You can save your hook at
some_space
function. - The hook that you add must print the return value of
pick_number
function. - Then, give this number as an input to the program in order to reveal the flag.
- Do not edit any other part of the program or try to reverse decrypt function.
Lets try to run the application, a.out
.
root@hammerhead:/data/local/tmp # ./a.out
Enter number: 123
wrong number :(
So it looks like we need to hook the function pick_number
and get the number to solve this challenge.
Before we start writing the hook, we need to know where to hook?
The instruction says to:
Add a hook at the end of the pick_number function.
Lets open up the binary in IDA for static analysis and find the address of the end of the pick_number
function.
We can see that the end of the pick_number
function lies around the address 0x000009D0
.
We can also see that the instruction at that address is POP {R11, PC}
. Remember this, we will be referring to this later.
Lets ensure that is the right address by using gdb
to perform dynamic analysis.
We will be using gdbserver
in our android and debug the binary a.out
remotely using our gdb-multiarch
client on our host.
In our android, lets feed the program some random number
root@hammerhead:/data/local/tmp # ./gdbserver localhost:6666 a.out 1234
Process a.out created; pid = 12547
Listening on port 6666
In our host, we need to port forward port 6666 first.
┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ adb forward tcp:6666 tcp:6666
┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ gdb-multiarch
gef➤ target remote localhost:6666
Remote debugging using localhost:6666
warning: Architecture rejected target-supplied description
Reading /data/local/tmp/a.out from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /data/local/tmp/a.out from remote target...
Reading symbols from target:/data/local/tmp/a.out...
Reading /system/bin/linker from remote target...
Reading /system/bin/linker from remote target...
Reading symbols from target:/system/bin/linker...
gef➤
We have connected to our binary a.out
.
Lets print the address of pick_number
.
gef➤ p &pick_number
$1 = (<text variable, no debug info> *) 0x2a000980 <pick_number>
IDA said that the end of the pick_number
function is at 0x000009D0
while GDB says it starts at 0x2a000980
.
From this we can deduce that the end of the pick_number
function is at 0x2A0009D0
.
Lets verify it by printing out the instruction at that address.
gef➤ x/i 0x2a0009d0
0x2a0009d0 <pick_number+80>: pop {r11, pc}
This is what IDA showed as well, so this is the right address.
We are going to overwrite this instruction with a branch
instruction. We want to branch to our shellcode.
The tips for this exercise was to put our shellcode at
You can save your hook at
some_space
function.
Thus, we need to find out the address of some_space
function. Lets do this using GDB
as well.
gef➤ p &some_space
$1 = (<text variable, no debug info> *) 0x2a0009e4 <some_space>
Great, so we know the place to put our shell code is at 0x2a0009e4
.
We also, as stated previously, want to put a jump instruction to our shell code therefore replacing 0x2a0009d0 <pick_number+80>: pop {r11, pc}
.
So in general, our hooking shell code is gonna look like.
Shellcode Header
1) branch to shellcode
Shellcode
2) Save registers that we going to use
3) Create a file to save return value from pick_number
4) Write the return value to the file
5) Close the file
ShellCode Footer
6) Pop back the registers that were previously saved
7) Write the original instruction that was replaced, pop {r11, pc}
8) Jump back to the original function
Our hook.s
looks like
.data
shellcodeHeader:
//Place at 0x2A0009D0
b shellcode
comeBackHereAfterEverything:
.text
//Place at 0x2A0009E4
shellcode:
push {r1, r2}
push {r0} //R0 Contains the number
//Create file
mov r7, #8 //creat syscall
mov r1, #1 //write permission
adr r0, file_name
svc #0
push {r0} //contains the FD
//WRITE
mov r7, #4 //write syscall
mov r2, #4 //4 bytes
add r1, sp, #4 //buff
svc #0 // call write
//CLOSE
pop {r0} //pops the fd
mov r7, #6
svc #0
Override:
pop {r0}
pop {r1, r2}
//original instruction
pop {r11, pc}
b comeBackHereAfterEverything
file_name: .asciz "answer"
Thus we will save the number into a file called answer
.
We can't just compile it now. We need as linker script to tell the linker which section of the code goes to which part of the memory.
Our .data
section is going to be at address 0x2A0009D0
.
Our .text
section is going to be at address 0x2A0009E4
.
The linker script, linker_script.ld
thus looks like
SECTIONS
{
. = 0x2A0009D0;
.data : { *(.data) }
. = 0x2A0009E4;
.text : { *(.text) }
}
Lets compile it. To make it easier, I created my commands into a shellscript file.
┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ vim commands.sh
export ndk=/home/razali/Downloads/android-ndk-r21e/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin
$ndk/as hook.s -o hook.o
$ndk/ld hook.o -T linker_script.ld -o hook
$ndk/objcopy -O binary --only-section=.data hook branch.bin
$ndk/objcopy -O binary --only-section=.text hook shellcode.bin
echo "==============XXD OUTPUT OF BRANCH======================"
echo "==============PUT IT AT 0x2A0009D0 =========================="
xxd branch.bin
echo "==============XXD OUTPUT OF Shellcode======================"
echo "==============PUT IT AT 0x2A0009E4 =========================="
xxd shellcode.bin
──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ ./commands.sh
==============XXD OUTPUT OF BRANCH======================
==============PUT IT AT 0x2A0009D0 ==========================
00000000: 0f00 00ea ....
==============XXD OUTPUT OF Shellcode======================
==============PUT IT AT 0x2A0009E4 ==========================
00000000: 0600 2de9 0400 2de5 0870 a0e3 0110 a0e3 ..-...-..p......
00000010: 3000 8fe2 0000 00ef 0400 2de5 0470 a0e3 0.........-..p..
00000020: 0420 a0e3 0410 8de2 0000 00ef 0400 9de4 . ..............
00000030: 0670 a0e3 0000 00ef 0400 9de4 0600 bde8 .p..............
00000040: 0088 bde8 ddff ffea 616e 7377 6572 0000 ........answer..
Now its time to patch our program. We are going to input all the above bytes at their respective addresses.
Open a.out
using IDA
.
Press the hotkey, g
, which opens up the Jump to Address
prompt.
Put the address 0x000009D0
or 9d0
for short, and it will take you to the address where we want to put our branch.bin
.
Click on Edit
> Patch program
> Change Byte
.
The xxd output suggested us to patch the bytes to 0F 00 00 EA
. But it seemed like it did not hit the shellcode location properly. I adjusted it slightly to 03 00 00 EA
and it worked, as you can see from the image above. It points to the some_space
function directly.
Next, go to the some_space
function and patched the bytes to the xxd output of shellcode.bin
.
Once done, we are going to apply the patches to the file.
Next, we will push the patched program to our android device.
──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ adb push a.out /data/local/tmp
a.out: 1 file pushed. 0.2 MB/s (44552 bytes in 0.185s)
I will then launch a.out
root@hammerhead:/data/local/tmp # chmod +x a.out
root@hammerhead:/data/local/tmp # ./a.out
Enter number:
a.out
will have now picked a number and store it in our file answer
.
From my host , i will use adb to cat
out the file..
──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ adb shell "su -c cat /data/local/tmp/answer" > answer
┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/inlineFunctionHooking]
└─$ xxd answer
00000000: 807f 6cfc
Great, now this is probably a signed integer in little-endian format. I went online to convert it.
The website I went to was here.
Then I got the flag.
root@hammerhead:/data/local/tmp # ./a.out
Enter number: 4234968960
You did it!
The flag is: "peter_pan"
Top comments (0)