Class11 cs230s23
Class11 cs230s23
Machine-Level Programming V:
Advanced
Spring, 2023
00007FFFFFFFFFFF
Shared
Stack (= 247–1)
Libraries
00007FFFF0000000
Runtime stack (8MB limit) Stack
E. g., local variables 8MB
Heap
Dynamically allocated as needed
When call malloc(), calloc(), new()
Data
Statically allocated data
E.g., global vars, static vars, string constants
int global = 0;
int main ()
{
void *phuge1, *psmall2, *phuge3, *psmall4;
int local = 0;
phuge1 = malloc(1L << 28); /* 256 MB */
psmall2 = malloc(1L << 8); /* 256 B */
phuge3 = malloc(1L << 32); /* 4 GB */
psmall4 = malloc(1L << 8); /* 256 B */ Heap
/* Some print statements ... */
} Data
Text
Where does everything go?
not drawn to scale
x86-64 Example Addresses Shared
address range ~247 Libraries
Stack
local 0x00007ffe4d3be87c
phuge1 0x00007f7262a1e010
phuge3 0x00007f7162a1d010
psmall4 0x000000008359d120 Heap
psmall2 0x000000008359d010
big_array 0x0000000080601060
huge_array 0x0000000000601060
main() 0x000000000040060c
useless() 0x0000000000400590
Heap
00007FFFFFFFFFFF
Shared
int recurse(int x) { Libraries
int a[1<<15]; // 4*2^15 = 128 KiB
Stack
printf("x = %d. a at %p\n", x, a);
a[0] = (1<<14)-1; 8MB
a[a[0]] = x-1;
if (a[a[0]] == 0)
return -1;
return recurse(a[a[0]]) - 1;
}
double fun(int i) {
volatile struct_t s;
s.d = 3.14;
s.a[i] = 1073741824; /* Possibly out of bounds */
return s.d;
}
??? 8
Explanation: Critical State 7
Critical State 6
Critical State 5
Critical State 4
d7 ... d4 3 Location accessed by
fun(i)
d3 ... d0 2
struct_t
a[1] 1
a[0] 0
Such problems are a BIG deal
Generally called a “buffer overflow”
when exceeding the memory size allocated for an array
void call_echo() {
echo();
}
unix>./bufdemo-nsp
Type a string:01234567890123456789012
01234567890123456789012
unix>./bufdemo-nsp
Type a string:012345678901234567890123
012345678901234567890123
Segmentation Fault
Buffer Overflow Disassembly
echo:
000000000040069c <echo>:
40069c: 48 83 ec 18 sub $0x18,%rsp
4006a0: 48 89 e7 mov %rsp,%rdi
4006a3: e8 a5 ff ff ff callq 40064d <gets@plt>
4006a8: 48 89 e7 mov %rsp,%rdi
4006ab: e8 50 fe ff ff callq 400500 <puts@plt>
4006b0: 48 83 c4 18 add $0x18,%rsp
4006b4: c3 retq
call_echo:
4006b5: 48 83 ec 08 sub $0x8,%rsp
4006b9: b8 00 00 00 00 mov $0x0,%eax
4006be: e8 d9 ff ff ff callq 40069c <echo>
4006c3: 48 83 c4 08 add $0x8,%rsp
4006c7: c3 retq
Buffer Overflow Disassembly
echo:
000000000040069c <echo>:
40069c: 48 83 ec 18 sub $0x18,%rsp
4006a0: 48 89 e7 mov %rsp,%rdi
4006a3: e8 a5 ff ff ff callq 40064d <gets@plt>
4006a8: 48 89 e7 mov %rsp,%rdi
4006ab: e8 50 fe ff ff callq 400500 <puts@plt>
4006b0: 48 83 c4 18 add $0x18,%rsp
4006b4: c3 retq
call_echo:
4006b5: 48 83 ec 08 sub $0x8,%rsp
4006b9: b8 00 00 00 00 mov $0x0,%eax
4006be: e8 d9 ff ff ff callq 40069c <echo>
4006c3: 48 83 c4 08 add $0x8,%rsp
4006c7: c3 retq
Buffer Overflow Stack Example
Before call to gets
Stack Frame
for call_echo
/* Echo Line */
Return Address void echo()
(8 bytes) {
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
20 bytes unused }
echo:
subq $0x18, %rsp
movq %rsp, %rdi
call gets
. . .
Buffer Overflow Stack Example
Before call to gets
void echo() echo:
Stack Frame { subq $0x18, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
. . . . . .
00 00 Address
Return 00 00 }
00 (8
40bytes)
06 c3
call_echo:
. . .
20 bytes unused 4006be: callq 4006cf <echo>
4006c3: add $0x8,%rsp
. . .
[3] [2] [1] [0] buf %rsp
Buffer Overflow Stack Example #1
After call to gets
void echo() echo:
Stack Frame { subq $0x18, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
. . . . . .
00 00 Address
Return 00 00 }
00 (8
40bytes)
06 c3
00 32 31 30 call_echo:
39 38 37 36 . . .
35 34 unused
20 bytes 33 32 4006be: callq 4006cf <echo>
31 30 39 38 4006c3: add $0x8,%rsp
37 36 35 34 . . .
33 32 31 30 buf %rsp
unix>./bufdemo-nsp
Type a string:01234567890123456789012
01234567890123456789012
“01234567890123456789012\0”
Overflowed buffer, but did not corrupt state
Buffer Overflow Stack Example #2
After call to gets
void echo() echo:
Stack Frame { subq $0x18, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
. . . . . .
00 00 Address
Return 00 00 }
00 (8
40bytes)
06 00
33 32 31 30 call_echo:
39 38 37 36 . . .
35 34 unused
20 bytes 33 32 4006be: callq 4006cf <echo>
31 30 39 38 4006c3: add $0x8,%rsp
37 36 35 34 . . .
33 32 31 30 buf %rsp
unix>./bufdemo-nsp
Type a string:012345678901234567890123
012345678901234567890123
Segmentation fault
00 07 00
FF
00 Address
Return 00
00 40
FF (8 06
AB c8
FFbytes) 80 %rsp Target Code
33 32 31 30
void smash() {
39 38 37 36
printf("I've been smashed!\n");
35 34 unused
20 bytes 33 32 exit(0);
31 30 39 38 }
37 36 35 34
33 32 31 30 00000000004006c8 <smash>:
4006c8: 48 83 ec 08
Attack String (Hex)
30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33
c8 06 40 00 00 00 00 00
Performing Stack Smash
linux> cat smash-hex.txt
30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 c8 06 40 00 00 00 00 00
linux> cat smash-hex.txt | ./hexify | ./bufdemo-nsp
Type a string:012345678901234567890123?@
I've been smashed!
30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33
c8 06 40 00 00 00 00 00
Code Injection Attacks
Stack after call to gets()
void P(){
P stack frame
Q(); return
... address
} A BB
A
rsp
…
void P(){ rsp
Q(); BB
A
rsp
...
} pad
rip
ret ret exploit
int Q() { Shared code
rip
char buf[64]; Libraries
gets(buf); // A->B
...
return ...;
} Heap
Data
rip
rip Text
What To Do About Buffer Overflow Attacks
Avoid overflow vulnerabilities
GCC Implementation
-fstack-protector
Now the default (disabled earlier)
unix>./bufdemo-sp
Type a string:0123456
0123456
unix>./bufdemo-sp
Type a string:012345678
*** stack smashing detected ***
Protected Buffer Disassembly
echo:
Aside: %fs:0x28
40072f: sub $0x18,%rsp • Read from memory using
400733: mov %fs:0x28,%rax
40073c: mov %rax,0x8(%rsp) segmented addressing
400741: xor %eax,%eax • Segment is read-only
400743: mov %rsp,%rdi • Value generated randomly
400746: callq 4006e0 <gets@plt> every time program runs
40074b: mov %rsp,%rdi
40074e: callq 400570 <puts@plt>
400753: mov 0x8(%rsp),%rax
400758: xor %fs:0x28,%rax
400761: je 400768 <echo+0x39>
400763: callq 400580 <__stack_chk_fail@plt>
400768: add $0x18,%rsp
40076c: retq
Setting Up Canary
Before call to gets
/* Echo Line */
Stack Frame void echo()
for call_echo {
char buf[4]; /* Way too small! */
gets(buf);
Return Address puts(buf);
(8 bytes) }
20 bytes unused
Canary
(8 bytes)