-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
buffer-overflow-control-flow: Add the first focused adversarial mission
- Loading branch information
1 parent
202aa3d
commit 7ddac3b
Showing
5 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,50 @@ | ||
# Exploiting a buffer overflow to manipulate control flow | ||
|
||
The objective of this mission is to demonstrate arbitrary code execution | ||
through a control-flow attack, despite CHERI protections. You will attack three | ||
different versions of the program: | ||
|
||
1. A baseline RISC-V compilation, to establish that the vulnerability is | ||
exploitable without any CHERI protections. | ||
|
||
2. A baseline CHERI-RISC-V compilation, offering strong spacial safety between | ||
heap allocations, including accounting for imprecision in the bounds of large | ||
capabilities. | ||
|
||
3. A weakened CHERI-RISC-V compilation, reflecting what would occur if a memory | ||
allocator failed to pad allocations to account for capability bounds | ||
imprecision. | ||
|
||
The success condition for an exploit, given attacker-provided input overflowing | ||
a buffer, is to modify control flow in the program such that the `success` | ||
function is executed. | ||
|
||
1. Compile `buffer-overflow.c` and `btpalloc.c` together with a RISC-V target | ||
and exploit the binary to execute the `success` function. | ||
|
||
**buffer-overflow.c** | ||
```C | ||
{{#include buffer-overflow.c}} | ||
``` | ||
2. Recompile with a CHERI-RISC-V target, attempt to exploit the binary and, if | ||
it cannot be exploited, explain why. | ||
3. Recompile with a CHERI-RISC-V target but this time adding | ||
`-DCHERI_NO_ALIGN_PAD`, attempt to exploit the binary and, if it cannot be | ||
exploited, explain why. | ||
**btpalloc.c** | ||
```C | ||
{{#include btpalloc.c}} | ||
``` | ||
|
||
## Support code | ||
|
||
**btpalloc.h** | ||
```C | ||
{{#include btpalloc.h}} | ||
``` | ||
**main-asserts.inc** | ||
```C | ||
{{#include main-asserts.inc}} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016 | ||
* Copyright (c) 2020 Jessica Clarke | ||
*/ | ||
#include "btpalloc.h" | ||
|
||
#include <assert.h> | ||
#include <stddef.h> | ||
|
||
#include <sys/mman.h> | ||
|
||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
#include <cheriintrin.h> | ||
#endif | ||
|
||
static void *btpmem; | ||
static size_t btpsize; | ||
|
||
static void | ||
btpinit(void) | ||
{ | ||
btpsize = 0x100000; | ||
btpmem = mmap(NULL, btpsize, PROT_READ | PROT_WRITE, | ||
MAP_PRIVATE | MAP_ANON, -1, 0); | ||
assert(btpmem != MAP_FAILED); | ||
} | ||
|
||
void * | ||
btpmalloc(size_t size) | ||
{ | ||
void *alloc; | ||
size_t allocsize; | ||
|
||
if (btpmem == NULL) | ||
btpinit(); | ||
|
||
alloc = btpmem; | ||
/* RISC-V ABIs require 16-byte alignment */ | ||
allocsize = __builtin_align_up(size, 16); | ||
|
||
#if defined(__CHERI_PURE_CAPABILITY__) && !defined(CHERI_NO_ALIGN_PAD) | ||
allocsize = cheri_representable_length(allocsize); | ||
alloc = __builtin_align_up(alloc, | ||
~cheri_representable_alignment_mask(allocsize) + 1); | ||
allocsize += (char *)alloc - (char *)btpmem; | ||
#endif | ||
|
||
if (allocsize > btpsize) | ||
return (NULL); | ||
|
||
btpmem = (char *)btpmem + allocsize; | ||
btpsize -= allocsize; | ||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
alloc = cheri_bounds_set(alloc, size); | ||
#endif | ||
return (alloc); | ||
} | ||
|
||
void | ||
btpfree(void *ptr) | ||
{ | ||
(void)ptr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016 | ||
* Copyright (c) 2020 Jessica Clarke | ||
*/ | ||
#include <stddef.h> | ||
|
||
void *btpmalloc(size_t size); | ||
void btpfree(void *ptr); |
73 changes: 73 additions & 0 deletions
73
src/missions/buffer-overflow-control-flow/buffer-overflow.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016 | ||
* Copyright (c) 2020 Jessica Clarke | ||
*/ | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
#include "btpalloc.h" | ||
|
||
void | ||
success(void) | ||
{ | ||
puts("Exploit successful!"); | ||
} | ||
|
||
void | ||
failure(void) | ||
{ | ||
puts("Exploit unsuccessful!"); | ||
} | ||
|
||
static uint16_t | ||
ipv4_checksum(uint16_t *buf, size_t words) | ||
{ | ||
uint16_t *p; | ||
uint_fast32_t sum; | ||
|
||
sum = 0; | ||
for (p = buf; words > 0; --words, ++p) { | ||
sum += *p; | ||
if (sum > 0xffff) | ||
sum -= 0xffff; | ||
} | ||
|
||
return (~sum & 0xffff); | ||
} | ||
|
||
#include "main-asserts.inc" | ||
|
||
int | ||
main(void) | ||
{ | ||
int ch; | ||
char *buf, *p; | ||
uint16_t sum; | ||
void (**fptr)(void); | ||
|
||
buf = btpmalloc(25000); | ||
fptr = btpmalloc(sizeof(*fptr)); | ||
|
||
main_asserts(buf, fptr); | ||
|
||
*fptr = &failure; | ||
|
||
p = buf; | ||
while ((ch = getchar()) != EOF) | ||
*p++ = (char)ch; | ||
|
||
if ((uintptr_t)p & 1) | ||
*p++ = '\0'; | ||
|
||
sum = ipv4_checksum((uint16_t *)buf, (p - buf) / 2); | ||
printf("Checksum: 0x%04x\n", sum); | ||
|
||
btpfree(buf); | ||
|
||
(**fptr)(); | ||
|
||
btpfree(fptr); | ||
|
||
return (0); | ||
} |
45 changes: 45 additions & 0 deletions
45
src/missions/buffer-overflow-control-flow/main-asserts.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016 | ||
* Copyright (c) 2020 Jessica Clarke | ||
*/ | ||
#include <assert.h> | ||
#include <stdint.h> | ||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
#include <cheriintrin.h> | ||
#endif | ||
|
||
static void | ||
main_asserts(void *buf, void *fptr) | ||
{ | ||
uintptr_t ubuf = (uintptr_t)buf; | ||
uintptr_t ufptr = (uintptr_t)fptr; | ||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
ptraddr_t ubuf_top; | ||
#endif | ||
|
||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
ubuf_top = cheri_base_get(ubuf) + cheri_length_get(ubuf); | ||
#endif | ||
|
||
#if defined(__CHERI_PURE_CAPABILITY__) && !defined(CHERI_NO_ALIGN_PAD) | ||
/* | ||
* For the normal pure-capability case, `buf`'s allocation should be | ||
* adequately padded to ensure precise capability bounds and `fptr` | ||
* should be adjacent. | ||
*/ | ||
assert(ubuf_top == ufptr); | ||
#else | ||
/* | ||
* Otherwise `fptr` should be 8 bytes (not 0 due to malloc's alignment | ||
* requirements) after the end of `buf`. | ||
*/ | ||
assert(ubuf + 25008 == ufptr); | ||
#ifdef __CHERI_PURE_CAPABILITY__ | ||
/* | ||
* For pure-capability code this should result in the bounds of the | ||
* large `buf` allocation including all of `fptr`. | ||
*/ | ||
assert(ubuf_top >= ufptr + sizeof(void *)); | ||
#endif | ||
#endif | ||
} |