Mitigating Memory Safety Vulnerabilities
CS 161 Fall 2023 - Lecture 5
Computer Science 161
Next: Memory Safety Mitigations
2
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
3
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
4
Computer Science 161
Using Memory-Safe Languages
5
Textbook Chapter 4.1
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
6
Computer Science 161
Memory-Safe Languages
7
Computer Science 161
Why Use Non-Memory-Safe Languages?
8
Computer Science 161
The Cited Reason: The Myth of Performance
9
Computer Science 161
The Cited Reason: The Myth of Performance
10
Computer Science 161
The Real Reason: Legacy
11
Computer Science 161
Example of Legacy Code: iPhones
12
Computer Science 161
Writing Memory-Safe Code
13
Textbook Chapter 4.2
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
14
Computer Science 161
Writing Memory-Safe Code
15
Computer Science 161
Writing Memory-Safe Code
16
Computer Science 161
Building Secure Software
17
Textbook Chapter 4.3
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
18
Computer Science 161
Approaches for Building Secure Software/Systems
19
Computer Science 161
Approaches for Building Secure Software/Systems
20
Computer Science 161
Testing for Software Security Issues
21
Computer Science 161
Working Towards Secure Systems
22
Computer Science 161
Exploit Mitigations
23
Textbook Chapter 4.4
Computer Science 161
Today: Defending Against Memory Safety Vulnerabilities
24
Computer Science 161
Exploit Mitigations
25
Computer Science 161
Recall: Putting Together an Attack
26
Computer Science 161
Recall: Putting Together an Attack
We can defend against memory safety vulnerabilities by making each of these steps more difficult (or impossible)!
27
Computer Science 161
Mitigation: Non-Executable Pages
28
Textbook Chapter 4.5 & 4.6 & 4.7
Computer Science 161
Recall: Putting Together an Attack
We can defend against memory safety vulnerabilities by making each of these steps more difficult (or impossible)!
29
Computer Science 161
Non-Executable Pages
30
Computer Science 161
Subverting Non-Executable Pages
31
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
32
char cmd[] = "rm -rf /";
system(cmd);
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
33
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of main | |||
SFP of main | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name | |||
&name (arg to gets) |
Exploit:
'A' * 24� + [address of system]
+ 'B' * 4
+ [address of "rm -rf /"]
+ "rm -rf /"
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
34
ESP
... | ... | ... | ... |
... | ... | ... | ... |
'\0' | ... | ... | ... |
'r' | 'f' | ' ' | '/' |
'r' | 'm' | ' ' | '-' |
[address of "rm -rf /"] | |||
'B' | 'B' | 'B' | 'B' |
[address of system] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
Exploit:
'A' * 24� + [address of system]
+ 'B' * 4
+ [address of "rm -rf /"]
+ "rm -rf /"
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
35
ESP
... | ... | ... | ... |
... | ... | ... | ... |
'\0' | ... | ... | ... |
'r' | 'f' | ' ' | '/' |
'r' | 'm' | ' ' | '-' |
[address of "rm -rf /"] | |||
'B' | 'B' | 'B' | 'B' |
[address of system] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
36
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
ESP
... | ... | ... | ... |
... | ... | ... | ... |
'\0' | ... | ... | ... |
'r' | 'f' | ' ' | '/' |
'r' | 'm' | ' ' | '-' |
[address of "rm -rf /"] | |||
'B' | 'B' | 'B' | 'B' |
[address of system] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
EIP
EBP
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
37
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
ESP
... | ... | ... | ... |
... | ... | ... | ... |
'\0' | ... | ... | ... |
'r' | 'f' | ' ' | '/' |
'r' | 'm' | ' ' | '-' |
[address of "rm -rf /"] | |||
'B' | 'B' | 'B' | 'B' |
[address of system] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
EIP
EBP
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: Return-to-libc
38
system:
...
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
ESP
... | ... | ... | ... |
... | ... | ... | ... |
'\0' | ... | ... | ... |
'r' | 'f' | ' ' | '/' |
'r' | 'm' | ' ' | '-' |
[address of "rm -rf /"] | |||
'B' | 'B' | 'B' | 'B' |
[address of system] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
EIP
EBP
We jumped into the system function, and it expects the first argument to be 4 bytes above the ESP: "rm -rf /"!
int system(char *command);
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: ROP
39
Computer Science 161
Subverting Non-Executable Pages: ROP
Example: Let’s say our shellcode involves the following sequence:
movl $1, %eax�xorl %eax, %ebx
The following is present in memory:
foo:� ...�<foo+7> addl $4, %esp�<foo+10> xorl %eax, %ebx�<foo+12> ret��bar:� ...�<bar+22> andl $1, %edx�<bar+25> movl $1, %eax�<bar+30> ret
How can we chain returns to run the code sequence we want?
40
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of main | |||
SFP of main | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name | |||
&name (arg to gets) |
Computer Science 161
Subverting Non-Executable Pages: ROP
Example: Let’s say our shellcode involves the following sequence:
movl $1, %eax�xorl %eax, %ebx
The following is present in memory:
foo:� ...�<foo+7> addl $4, %esp�<foo+10> xorl %eax, %ebx�<foo+12> ret��bar:� ...�<bar+22> andl $1, %edx�<bar+25> movl $1, %eax�<bar+30> ret
How can we chain returns to run the code sequence we want?
41
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of main | |||
SFP of main | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name | |||
&name (arg to gets) |
If we jump 25 bytes after the start of bar then 10 bytes after the start of foo, we get the result we want!
Computer Science 161
Subverting Non-Executable Pages: ROP
42
EBP
ESP
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of main | |||
SFP of main | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
name | |||
name | |||
name | |||
name | |||
name | |||
&name (arg to gets) |
Exploit:
'A' * 24� + [address of <bar+25>]
+ [address of <foo+10>]
+ ... (more chains)
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
Computer Science 161
Subverting Non-Executable Pages: ROP
43
ESP
Exploit:
'A' * 24� + [address of <bar+25>]
+ [address of <foo+10>]
+ ... (more chains)
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
EBP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
Computer Science 161
Subverting Non-Executable Pages: ROP
44
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
ESP
EBP
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
Computer Science 161
Subverting Non-Executable Pages: ROP
45
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
ESP
EBP
Computer Science 161
Subverting Non-Executable Pages: ROP
46
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
EBP
ESP
Computer Science 161
Subverting Non-Executable Pages: ROP
47
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
EBP
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
ESP
Computer Science 161
Subverting Non-Executable Pages: ROP
48
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
EBP
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
ESP
Computer Science 161
Subverting Non-Executable Pages: ROP
49
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
ESP
EBP
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
Computer Science 161
Subverting Non-Executable Pages: ROP
50
foo:
addl $4, %esp
xorl %eax, %ebx
ret
bar:
...
andl $1, %edx
movl $1, %eax
ret
vulnerable:
...
call gets� addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
main:
...
call vulnerable
...
EIP
void vulnerable(void) {
char name[20];
gets(name);
}
int main(void) {
vulnerable();
return 0;
}
ESP
EBP
The ret instruction always pops off the bottom of the stack, so execution continues based on the chain of addresses!
... | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of ........] | |||
[address of <foo+10>] | |||
[address of <bar+25>] | |||
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
'A' | 'A' | 'A' | 'A' |
&name (arg to gets) |
Computer Science 161
Subverting Non-Executable Pages: ROP
51
Computer Science 161
Mitigation: Stack Canaries
52
Textbook Chapter 4.8 & 4.9
Computer Science 161
Recall: Putting Together an Attack
We can defend against memory safety vulnerabilities by making each of these steps more difficult (or impossible)!
53
Computer Science 161
Analogy: Canary in a Coal Mine
54
Computer Science 161
Stack Canaries
55
Computer Science 161
Stack Canaries: Properties
56
Computer Science 161
Stack Canaries
57
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of vulnerable | |||
SFP of vulnerable | |||
🐦🐦🐦 canary 🐦🐦🐦 | |||
name | |||
name | |||
name | |||
name | |||
name |
vulnerable:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl ($CANARY_ADDR), %eax # Load canary
movl %eax, -4(%ebp) # Save on stack
...
movl -4(%ebp), %eax # Load stack value
cmpl %eax, ($CANARY_ADDR) # Compare to canary and...
jne canary_failed # ... crash if not equal
movl %ebp, %esp
popl %ebp
ret
void vulnerable(void) {
char name[20];
gets(name);
}
Because the write starts at name, the attacker has to overwrite the canary before the RIP or SFP!
Note: 20 bytes for name + 4 bytes for canary (32-bit architecture)
Computer Science 161
Stack Canaries: Efficiency
58
Computer Science 161
Subverting Stack Canaries
59
Computer Science 161
Subverting Stack Canaries: Leaking the Canary
60
Computer Science 161
Subverting Stack Canaries: Bypassing the Canary
61
Computer Science 161
Subverting Stack Canaries: Guessing the Canary
62
Computer Science 161
Subverting Stack Canaries: Guessing the Canary
63
Computer Science 161
Mitigation: Pointer Authentication
64
Textbook Chapter 4.10
Computer Science 161
Recall: Putting Together an Attack
We can defend against memory safety vulnerabilities by making each of these steps more difficult (or impossible)!
65
Computer Science 161
Reminder: 32-Bit and 64-Bit Processors
66
Computer Science 161
Pointer Authentication
67
Computer Science 161
Pointer Authentication: Properties of the PAC
68
Computer Science 161
Subverting Pointer Authentication
69
Computer Science 161
Defenses Against Pointer Reuse
70
Computer Science 161
Pointer Authentication on ARM
71
Computer Science 161
Mitigation: Address Space Layout Randomization (ASLR)
72
Textbook Chapter 4.11 & 4.12
Computer Science 161
Recall: Putting Together an Attack
We can defend against memory safety vulnerabilities by making each of these steps more difficult (or impossible)!
73
Computer Science 161
Recall: x86 Memory Layout
74
Higher addresses
Lower addresses
Stack |
|
Heap |
Data |
Code |
Grows upwards
In theory, x86 memory layout looks like this...
Grows downwards
Computer Science 161
Recall: x86 Memory Layout
75
Higher addresses
Lower addresses
Stack |
|
Heap |
Data |
Code |
Grows downwards
Grows upwards
In theory, x86 memory layout looks like this...
Higher addresses
Lower addresses
Unused |
Stack |
Unused |
Heap |
Unused |
Data |
Unused |
Code |
Unused |
...but in practice, it usually looks like this (mostly empty)!
Computer Science 161
Recall: x86 Memory Layout
76
Higher addresses
Lower addresses
|
Stack |
|
Heap |
|
Data |
|
Code |
|
Idea: Put each segment of memory in a different location each time the program is run
|
Heap |
|
Data |
|
Code |
|
Stack |
|
Computer Science 161
Address Space Layout Randomization
77
Computer Science 161
ASLR: Efficiency
78
Computer Science 161
Subverting ASLR
79
Computer Science 161
Relative Addresses
80
void vulnerable(char *dest) {
// Format string vulnerability
printf(dest);
}
int main(void) {
int secret = 42;� char buf[20];
fgets(buf, 20, stdin);
vulnerable(buf);
}
... | ... | ... | ... |
... | ... | ... | ... |
... | ... | ... | ... |
RIP of main | |||
SFP of main | |||
secret = 42 | |||
buf | |||
buf | |||
buf | |||
buf | |||
buf | |||
dest (arg to vulnerable) | |||
RIP of vulnerable | |||
SFP of vulnerable | |||
format (arg to printf) |
We know that the SFP is a pointer to the stack. How would you print the value of the SFP?
secret is 4 bytes below where the SFP points, so its address is 0xbfff0404!
Input:
'%x'
If the output is bfff0408 what is the address of secret?
Computer Science 161
Combining Mitigations
81
Textbook Chapter 4.13
Computer Science 161
Combining Mitigations
82
Computer Science 161
Combining Mitigations
83
Computer Science 161
Enabling Mitigations
84
Computer Science 161
Enabling Mitigations: CISCO
85
Computer Science 161
Enabling Mitigations: Internet of Things
Takeaway: Many (most?) IoT devices don’t enable basic mitigations
86
Qualys Security Blog | |
CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit) | |
Animesh Jain | January 26, 2021 |
The Qualys Research Team has discovered a heap overflow vulnerability in sudo, a near-ubiquitous utility available on major Unix-like operating systems. Any unprivileged user can gain root privileges on a vulnerable host using a default sudo configuration by exploiting this vulnerability. |
Computer Science 161
Summary: Memory Safety Mitigations
87
Computer Science 161
Summary: Memory Safety Mitigations
88
Computer Science 161
Summary: Memory Safety Mitigations
89
Computer Science 161