Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write a simple C arbitrary code execution exploit on ARM Cortex-M3?

I'm trying to write a proof of concept in C that demonstrates code execution from a memory buffer in the stack on an ARM Cortex-M3. This will be useful to demonstrate that using the ARM MPU correctly can prevent such an attack. I figured a quick and dirty way to get some code into the stack is to copy it from a regular function and then use a goto to jump to it like so:

static void loopit(void)
{
    printf("loopit\n");
    while (1);
}

void attack(void)
{
    uint8_t buffer[64] __attribute__((aligned(4)));
    memcpy(buffer, loopit, sizeof(buffer));
    goto *((void *) (int) buffer);
}

I would expect that when I call the attack function it will copy code into the stack, jumps to it, print the message and go into an infinite loop. However instead I get an exception with the following values in the fault registers:

HFSR = 0x40000000
CFSR = 0x00020000
PSR  = 0x60000000

This seems to be the INVSTATE bit in the UFSR which indicates "illegal use of the EPSR", which I read is usually due to the BX instruction attempting to jump to an address with the LSB set to 0 which the processor interprets as a function with non-Thumb code in it, but Cortex-M processors only allow Thumb code. I see that the memcpy is being given an odd address for the loopit function since I assume the compiler is ORing the real memory address with 1. So the fix I would think would be to rewrite my attack function like so:

void attack(void)
{
    uint8_t buffer[64] __attribute__((aligned(4)));
    memcpy(buffer, ((int) loopit) & ~1, sizeof(buffer));
    goto *((void *) ((int) buffer) | 1);
}

However after doing that I get a different exception with fault registers:

HFSR = 0x40000000
CFSR = 0x00080000
PSR  = 0x81000000

This doesn't seem to make any sense the UFSR bit 3 set means "the processor has attempted to access a coprocessor". Looking at the PC this time it appears the jump succeeded which is great but then something went off the rails and the CPU appears to be executing strange instructions and not going into the infinite loop. I tried turning off interrupts before the goto and commenting out the printf as well but no luck. Any clue what is going wrong and how to make it work?

like image 233
satur9nine Avatar asked Nov 07 '22 14:11

satur9nine


1 Answers

Sorry for abusing the answer form, I have adapted your code a little and it blinks a LED right from the stack:

void (*_delay_ms)(uint32_t) = delay_ms;

static void loopit(void)
{
    while (1)
    {
        GPIOC->ODR ^= 1 << 13;
        _delay_ms(125);
    }
}

void attack(void)
{
    volatile uint8_t buffer[64] __attribute__((aligned(4)));
    memcpy(buffer, (void *)((uint32_t) loopit & ~1), sizeof(buffer));
    goto *(void *)((uint32_t) buffer | 1);
}

I wonder how soon I get complaints about UB.

like image 170
A.K. Avatar answered Nov 15 '22 04:11

A.K.