• Aucun résultat trouvé

Sécurité des logiciels

N/A
N/A
Protected

Academic year: 2022

Partager "Sécurité des logiciels"

Copied!
56
0
0

Texte intégral

(1)

Sécurité des logiciels

Compilation hardening

Samuel Thibault <samuel.thibault@u-bordeaux.fr>

CC-BY-NC-SA

(2)

2

GOT overwriting

(3)

Calling a library function?

#include <stdio.h>

int main(void) { puts("foo");

return 0;

}

How does this actually work?

(4)

4

Calling a library function?

...extern int puts(const char *s);

...int main(void) { puts("foo");

return 0;

}

(5)

Calling a library function?

...extern int puts(const char *s);

...int main(void) { puts("foo");

return 0;

}

gcc test.c -o test.o -c ; objdump -d test.o [...]

10: e8 00 00 00 00 callq 10 <main+0x10>

I.e. leaves a “hole”, a “relocation”: no idea what it should be yet

(6)

6

Calling a library function?

...extern int puts(const char *s);

...int main(void) { puts("foo");

return 0;

}

gcc test.o -o test ; objdump -d test [...]

1040: e8 eb fe ff ff callq 1030 <puts@plt>

“Filled” the hole

The thing is: we don’t know where libc will be in memory!

(7)

Calling a library function?

Disassembly of section .plt :

<main>

1040: e8 eb fe ff ff callq 1030 <puts@plt>

Disassembly of section .plt :

<puts@plt>:

1030: ff 25 e2 2f 00 00 jmpq *0x2fe2(%rip)

# 4018 <puts@GLIBC_2.2.5>

1036: 68 00 00 00 00 pushq $0x0

103b: e9 e0 ff ff ff jmpq 1020 <.plt>

Disassembly of section .got.plt : 4018: 36 10 00 00 00 00 00

(8)

8

Calling a library function?

.text r-x main .plt r-x

puts@plt .plt

.got.plt rw-

R_X86_64_JUMP_SLOT puts@GLIBC_2.2.5 .text r-x

puts

(9)

9

Calling a library function?

.text r-x main .plt r-x

puts@plt .got.plt rw-

R_X86_64_JUMP_SLOT puts@GLIBC_2.2.5 .text r-x

puts

.plt

(10)

10

Calling a library function?

.text r-x main .plt r-x

puts@plt .got.plt r--

R_X86_64_JUMP_SLOT puts@GLIBC_2.2.5 .text r-x

puts

.plt

(11)

Calling a library function?

Library calls through GOT

By default, function names resolved lazily

By default, GOT writable

→ attack target

→ making it read-only after program load

-Wl,-z,relro -Wl,-z,now

One example of build-time fortification option

Possibly use prelink

(12)

12

Fortifying the build

(13)

Fortifying the build

Checks in the generated code

Checks in libc

Guard areas

Strengthened linking

Strengthened memory layout

More or less execution-time cost

But considered worth the price

(14)

14

Fortifying the build

Memory layout

(15)

Memory layout

ASLR!

Nowadays, all areas at random locations

Large holes between regions

Requires PIE options for text -fPIE -pie

(Already by default nowadays)

Non-executable stack

-Wl,-z,noexecstack

(Already by default nowadays)

Control-related data in read-only regions

-Wl,-z,relro -Wl,-z,now

Also use const as much as possible

e.g. for structures containing methods pointers

(16)

16

Memory layout

Structures containing methods pointers

Common in large C programs

Use const!

Quite common in C++ programs

Object virtual methods!

→ Attack targets

-fvtable-verify=std

Verifies the target makes sense for the object

More generally, all indirect calls / jumps

-fcf-protect=branch

Verifies the target makes sense

Hardware support being added by Intel:

CET (Control-Flow Enforcement Technology)

All branch targets marked with ENDBR

(17)

Fortifying the build

Stack protection

(18)

18

Stack protection

Stack-based buffer overflow

ret@

(19)

canary

Stack protection

Stack-based buffer overflow Adding a canary

Overwritten as well

Checked before ret instruction

Ideally random (and per-thread), or

0x000d0aff

Contains a ‘\0’

Contains a ‘\r’ + ‘\n’

Contains ~’\0’

ret@

(20)

20

Stack protection

Stack clashing

What happens if stack grows too much?

heap

(21)

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

heap guard

(22)

22

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

heap guard

(23)

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(24)

24

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(25)

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(26)

26

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(27)

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(28)

28

Stack protection

Stack clashing

What happens if stack grows too much?

Putting a stack guard to prevent clash

But if really large allocation, could step over it

Make the compiler allocate precautiously

-fstack-clash-protection

heap guard

(29)

Stack protection

Control-Flow Protection

Basic issue: we are not returning where we are supposed to Also remember Return-Oriented Programming

Picking up gadgets from libc

addl $12,%esp ret

Basically, erratic control flow

(30)

30

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

(31)

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

(32)

32

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

(33)

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

(34)

34

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

Check equality on ret

(35)

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

Check equality on ret

(36)

36

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

Check equality on ret

(37)

Stack protection

Control-Flow Protection Shadow stack

Replicates return addresses

Somewhere else in address space

Check equality on ret

Hardware support being added by Intel:

CET (Control-Flow Enforcement Technology)

Shadow stacks only writable by call/ret instructions

(38)

38

Fortifying the build

_FORTIFY_SOURCE

(39)

_FORTIFY_SOURCE

-O2 -D_FORTIFY_SOURCE=1 (or 2)

Includes various additional compile-time or run-time checks

Array bounds

Parameters

Unused error result

And more!

(40)

40

_FORTIFY_SOURCE

int main(void) { char s[10];

read(STDIN_FILENO, s, 11);

}

For read, s is just a char *, and it is told it is 11-bytes big.

But compiler knows better!

And libc headers can benefit from it

__builtin_object_size(s, 0) returns 10 abbreviated __bos(s)

(41)

_FORTIFY_SOURCE

In the libc headers static inline

ssize_t read(int fd, void *buf, size_t n) { return __read_chk(fd, buf, n, __bos(buf));

}

__read_chk can then check that n ≤ __bos(s)

(42)

42

_FORTIFY_SOURCE

In the libc headers, even better:

static inline

ssize_t read(int fd, void *buf, size_t n) { if (!__builtin_constant_p(n))

return __read_chk(fd, buf, n, __bos(buf));

if (n > __bos(buf))

return __read_chk_warn(fd, buf, n, __bos(buf));

return __read_alias(fd, buf, n);

}

__read_chk_warn wears a compile-time warning

(43)

_FORTIFY_SOURCE

int main(void) { char s[10];

strcpy(s, "Hello, world!");

}

Similar check for overflow

(44)

44

_FORTIFY_SOURCE

int main(void) { int fd;

fd = open("test.txt", O_RDONLY);

...

}

(45)

_FORTIFY_SOURCE

int main(void) { int fd;

fd = open("test.txt", O_RDWR|O_CREAT);

...

}

(46)

46

_FORTIFY_SOURCE

int main(void) { int fd;

fd = open("test.txt", O_RDWR|O_CREAT, 0600);

...

}

Check for missing parameter

(47)

_FORTIFY_SOURCE

int main(int argc, char *argv[]) { char *s;

asprintf(&s, "Hello, %s!\n", argv[1]);

...

}

Warn about unused result

(48)

48

_FORTIFY_SOURCE

int myfunc(const char *s) { printf(s);

...

}

As discussed last week, bad idea.

But perhaps s really is a static constant string?

How to know?

(49)

Fortifying the build

[almtu]san

(50)

50

[almtu]san

Address / Leak / Memory / Thread / Undefined SANitizer

In-compiler additions

Small-ish checks

Not negligible overhead! (can be 2x - 3x!)

Very useful for debugging, Continuous Integration

(51)

51

[almtu]san

Address / Leak SANitizer

use-after-free

free(s); printf("%s\n", s);

double-free

free(s); free(s);

memory leaks

/* No free :) */

use-after-return

int *f(void) { int a;

return &a;

}

use-after-scope

int *p;

{ int a; p = &a; } printf("%d\n", *p);

(52)

52

[almtu]san

Address / Leak SANitizer

heap/stack/global buffer overflow

Keeps track of set of valid addresses

Knows exactly where variables & arrays are!

Checks address on each pointer dereference

(53)

[almtu]san

Memory SANitizer (LLVM-specific for now)

Keeps track of set of initialized addresses

Checks it on each pointer dereference for read

(54)

54

[almtu]san

Thread SANitizer

Looks out for

Race conditions

Lock ordering conflicts

(55)

[almtu]san

Undefined SANitizer

Looks out for undefined behavior (see previous course)

Integer overflow

Undefined integer shifts

...

(56)

56

Cheat sheet

(bold options: now by default in Debian’s dpkg-buildflags)

-Wall -Wextra -Wformat -Werror=format-security

-fPIE -pie

-Wl,-z,relro -Wl,-z,now

-Wl,-z,noexecstack

-fstack-protector-strong

-fstack-clash-protection

-D_FORTIFY_SOURCE=2 -O2

-fvtable-verify=std

-fcf-protection=full

Use hardening-check to check your binaries For debugging,

-fsanitize=address (or leak, or memory, or thread, or undefined, or several at the same time)

Références

Documents relatifs

HAL is a multi-disciplinary open access archive for the deposit and dissemination of sci- entific research documents, whether they are pub- lished or not. The documents may come

La victime est logguée sur un site bancaire site-bancaire.com mais visite également dʼautres sites web dans le même temps dont celui du pirate. Une popup est

– Step 2: The server receive the message and reply by sending back the minimal string and part of the process memory;. – Step 3: The client get the string back

Programs have their own uid, inherited from uid of parent, except when the program is

● Disassemble functions objdump -d test. ● Disassemble everything objdump

Pieces from Emmanuel Fleury

● Local variable (aka automatic variable): a variable whose scope is not getting outside of the function. ● Parameters (aka arguments): Data set by the caller for the

But shell code can lookup the random value ... The game never