Exercises Flashcards
include <stdio.h></stdio.h>
Consider the C program below, which is affected by a typical buffer overflow vulnerability.
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln() {
char buf[32];
<— Here —>
scanf(“%s”, buf);
if (strncmp(buf, “Knight_King!”, 12) !=
0) {
abort();
}
int main(int argc, char** argv) {
vuln();
}
Draw the stack layout when the program is executing the instruction at line 7, showing:
a. Direction of growth and high-low addresses.
b. The name of each allocated variable.
c. The boundaries of frame of the function frames (main and vuln).
Show also the content of the caller frame (you can ignore the environment variables, just focus on what matters for the vulnerability and its exploitation).
(Low Addresses)
buf[0-3]
…
buf[28-31]
EBP (vuln)
EIP
…
EBP (main)
(High Addresses)
Main Frame: EBP (main) - EIP
Vuln Frame: EBP (vuln) - End
include <stdio.h></stdio.h>
Consider the C program below, which is affected by a typical buffer overflow vulnerability.
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln() {
char buf[32];
<— Here —>
scanf(“%s”, buf);
if (strncmp(buf, “Knight_King!”, 12) !=
0) {
abort();
}
int main(int argc, char** argv) {
vuln();
}
Write an exploit for the buffer overflow vulnerability in the above program. Your exploit should execute the following simple shellcode, composed only by 4 instructions (4 bytes): 0x12 0x34 0x56 0x78.
Write clearly all the steps and assumptions you need for the exploitation, and show the stack layout right after the execution of the scanf() during the program exploitation.
(Low Addresses)
buf[0-3] => “Knig”
buf[4-7] => “ht_k”
buf[8-11] => “ing!”
buf[12-15] => NOP Sled
… => NOP Sled
buf[28-31] => 0x12 0x34 0x56 0x58
EBP (vuln) => Not Relevant
EIP => Pointer to around the start of the NOP sled interval
…
EBP (main)
(High Addresses)
include <stdio.h></stdio.h>
Consider the C program below, which is affected by a typical buffer overflow vulnerability.
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln() {
char buf[32];
<— Here —>
scanf(“%s”, buf);
if (strncmp(buf, “Knight_King!”, 12) !=
0) {
abort();
}
int main(int argc, char** argv) {
vuln();
}
If address space layout randomization (ASLR) is active, is the average exploit still work without modifications? Why?
No, because the address of the stack would be randomized for every execution, and we must have to have a leak in order to exploit it successfully.
include <stdio.h></stdio.h>
Consider the C program below, which is affected by a typical buffer overflow vulnerability.
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln() {
char buf[32];
<— Here —>
scanf(“%s”, buf);
if (strncmp(buf, “Knight_King!”, 12) !=
0) {
abort();
}
int main(int argc, char** argv) {
vuln();
}
If the stack is made non executable (i.e., NX, W^X), is the average exploit still working without modifications? If not, propose an alternative solution to exploit the program.
No, we can use ret to libc technique in order to execute the system function in the libc and obtain a shell. In order to do that, we change the value of B and let it point to the address of system.
BlaBlaStack is a new stack protection mechanism that is designed to protect against local attackers (e.g., users that can have a shell and launch binaries).
BlaBlaStack works by inserting instructions in the prologue that push a value to the stack. This value is generated at compile time and is hardcoded in the binary.
Then, during the epilogue, this value is popped from the stack and an appropriate instruction compares it with the hardcoded, expected one.
In case of match, the program goes on, otherwise it is aborted.
● Why this mechanism does not provide proper protection against stack overflows?
● How would you fix BlaBlaStack in order to protect from local attackers?
This is a compiler based protection mechanism, it is a variant of the stack canary mechanism seen in class. The attacker can read the binary, for example using a disassembler, obtain the hardcoded value and include it as part of the exploit.
Instead of hardcoding the canary value, the instructions in the prologue should generate a random value and push it on a general purpose register. During the epilogue, the register is used to compare the valued popped from the stack.
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) {
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
Draw the stack layout when the program is executing the instruction at line 12, showing:
a. Direction of growth and high-low addresses;
b. The name of each allocated variable;
c. The boundaries of frame of the function frames (main and vuln).
Show also the content of the caller frame (you can ignore the environment variables, just focus on what matters for the vulnerability and its exploitation).
(Low Addresses)
buf[0-3]
…
buf[15-12]
tmp[3-0]
…
tmp[15-12]
sparrow
EBP (vuln)
EIP
n
…
EBP (main)
(High Addresses)
Main Frame: EBP (main) - EIP
Vuln Frame: EBP (vuln) - buf[0-3]
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) {
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
The program is affected by a buffer overflow vulnerability. Complete the following table.
Vulnerability: Buffer Overflow
Line(s):
Motivation:
Vulnerability: Buffer Overflow
Line(s): scanf(“%s”, s.tmp)
Motivation: buffer where there is no boundness for the insertion
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) { This
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
The underlined lines of code (indicated by “This”) attempt to mitigate the exploitation of the buffer overflow vulnerability you just found.
a. Shortly describe what is the implemented technique, and how it works in general.
b. Describe the weaknesses in this specific implementation, and how you would fix them.
a. The underlined code implements a stack canary as a mitigation against stack-based buffer overflows. When writing past the end of a stack-allocated buffer, one would overwrite the variable x before overwriting the saved EIP. Before returning from the function, the content of the variable x is checked against the original value: if they differs, a buffer overflow is detected and the program aborts without returning from the function (i.e., without triggering the exploit).
b. In this case, the stack canary is a static value (0xBAAAAAAD): if the binary is available, it is enough to retrieve this value by reverse engineering the program; then, during the exploitation it is enough to overwrite the stack canary with this (known) value. To fix this issue, the stack canary should be randomized at the program startup and placed in a register.
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) { This
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
Write an exploit for the buffer overflow vulnerability in the above program to execute the following simple shellcode, composed only by 4 instructions (4 bytes): 0x51 0x52 0x5a 0x5b. Make sure that you show how the exploit will appear in the process memory with respect to the stack layout right before and after the execution of the detected vulnerable line during the program exploitation. Ensure you include all of the steps of the exploit, ensuring that the program and the exploit execute successfully. Include also any assumption on how you must call the program (e.g., the values for the command-line arguments required to trigger the exploit correctly, environment variables).
(Low Addresses)
buf[0-3]
…
buf[15-12] =>
tmp[3-0]
…
tmp[15-12] => 0x51 0x52 0x5a 0x5b
sparrow =>
EBP (vuln) => Not Relevant
EIP
n
…
EBP (main)
(High Addresses)
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) {
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
Write an exploit for the buffer overflow vulnerability in the above program to execute the following simple shellcode, composed only by 4 instructions (4 bytes): 0x51 0x52 0x5a 0x5b. Make sure that you show how the exploit will appear in the process memory with respect to the stack layout right before and after the execution of the detected vulnerable line during the program exploitation. Ensure you include all of the steps of the exploit, ensuring that the program and the exploit execute successfully. Include also any assumption on how you must call the program (e.g., the values for the command-line arguments required to trigger the exploit correctly, environment variables).
buf[0-3] => H4CK
… => Irrelevant
buf[15-12] => Irrelevant
tmp[0-3] => Nop Sled
… => Nop Sled
tmp[15-12] => 0x51 0x52 0x5a 0x5b
sparrow => 0xBAAAAAAD
Base vuln => Irrelevant
EIP => tmp[0-3]
N
…
Base Main
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) {
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
Let’s assume that the C standard library is loaded at a known address during every execution of the program, and that the (exact) address of the function system() is 0xf7e38da0. Explain how you can exploit the buffer overflow vulnerability to launch the program /bin/secret.
We write ni tmp het string /bin/secret, and we overwrite the saved EIP with the address of system. We then overwrite 8 bytes more for the system) EIP (to exit) and for the pointer ot - Yso that, when
jumping into the system) function, this pointer will be where system ) expects the parameter and will complete the execution.
buf[0-3] => H4CK
… => (not relevant)
buf[15-12] => (not relevant)
… not relevant
tmp[7-4] => /bin => Add Y
tmp[11-8] => /sec
tmp[15-12] => ret\0
OxAD OxAA 0xAA 0xBA
(not relevant)
Oxf7e38da0
exit
~ Addr Y
If the ASLR is enabled what is randomized
Both the stack and the shared libraries are randomized
include <stdio.h></stdio.h>
Consider the C program below:
#include <stdlib.h>
#include <string.h></string.h></stdlib.h>
void vuln(int n) {
struct {
char buf[16];
char tmp[16];
int sparrow = 0xBAAAAAAD;
} s;
if (n > 0 && n < 16) {
fgets(s.buf,n,stdin);
if(strncmp(s.buf, “H4CK”, 4) != 0 &&
s.buf[14] != “X”) {
abort();
}
scanf(“%s”, s.tmp);
if(s.sparrow != 0xBAAAAAAD) {
printf(“Goodbye!\n”);
abort();
}
}
}
int main(int argc, char** argv) {
vuln(argc);
return 0;
}
Assume now that the program is compiled without any mitigation against exploitation (the address space layout is not randomized, the stack is executable, and there are no stack canaries). Propose the simplest modification to the C code provided (i.e., patch) that solves the buffer overflow vulnerability detected, motivating your answer.
scanf(“%15s”, s.tmp); fgets(s.tmp,15,stdin);
See the code in the picture 1 in the Comp Sec album
Assuming that the program is compiled and run for the usual IA-32 architecture (32-bits), with the usual cdecl calling convention, draw the stack layout just before the execution of line 11 showing:
● Direction of growth and high-low addresses;
● The name of each allocated variable;
● The boundaries of the function stack frames (main and guess)
Show also the content of the caller frame (you can ignore the environment variables: just focus on what matters for the exploitation of typical memory corruption vulnerabilities).
Assume that the program has been properly invoked with a single command line argument.
See the picture 1S in the Comp Sec album
See the picture 1 in the Comp Sec album
The program is affected by a typical buffer overflow and a format string vulnerability. Which line each happen and why
See picture 2S in the Comp Sec album
See the picture 1 in the Comp Sec album
Assume that the program is compiled and run with no mitigation against exploitation of memory corruption vulnerabilities (no canary, executable stack, environment with no ASLR active).
Focus on the buffer overflow vulnerability. Write an exploit for the buffer overflow vulnerability in the above program to execute the following simple shellcode, composed only by 4 instructions (4 bytes): 0x58 0x5b 0x5a 0xc3.
Make sure that you show how the exploit will appear in the process memory with respect to the stack layout right before and after the execution of the detected vulnerable line during the program exploitation.
Ensure you include all of the steps of the exploit, ensuring that the program and the exploit execute successfully. Include also any assumption on how you must call the program (e.g., the values for the command-line arguments required to trigger the exploit correctly).
See the picture 3S in the Comp Sec album
See code in the picture 1 in the Comp Sec album
Now focus on the format string vulnerability you identified. We want to exploit this vulnerability to overwrite the saved EIP with the address of the environment variable $EGG that contain your executable shellcode. Assuming we know that:
● The address of $EGG (i.e., what to write) is 0x44674234 (0x4467(hex) = 17511(dec), 0x4234(hex) = 16948(dec))
● The target address of the EIP (i.e., the address where we want to write ) is 0x42414515
● The displacement on the stack of your format string is equal to 7
write an exploit for the format string vulnerability to execute the shellcode in the environment variable EGG.
Write the exploit clearly, detailing all the components of the format string, and detailing all the steps that lead to a successful exploitation.
The command line argument is directly fed as a format string to snprintf, and the format string itself is on the stack with a given displacement: we just need to construct a standard format string exploit.
- We need to write 0x44674234 to 0x42414515(<tgt>)
- 0x4467 > 0x4234 -> we write 0x4234 first
The value of the command line argument will have the form <tgt><tgt+2>%<N1>c%<pos>$hn%<N2>c%<pos+1>$hn
where</N2></pos></N1></tgt></tgt>
<tgt> = 0x42414515
<tgt+2> = 0x42414517
<pos> = 7
<N1> = dec(0x4234) - 8 (bytes already written) = 16948 - 8 = 16940
<N2> = dec(0x4467) - 16948 (bytes already written) = 17511 - 16948 = 563 thus the final string is
\x15\x45\x41\x42\x17\x45\x41\x42%16940c%7$hn%563c%8$hn
</N2></N1></pos></tgt>
See the code in the picture 1 in the Comp Sec album
Now consider that the program is compiled enabling the exploit mitigation technique known as stack canary. Assume that the compiler and the runtime correctly implement this technique with a random value changed at every program execution. Are the two exploits you wrote still working without modifications? Why? If not working modify the exploit so that it works reliably in this setting (i.e., enabled stack canaries). Please describe precisely how you would modify the above exploit, and any further assumption you need to make it work. If your exploit needs to perform multiple iteration of any loop, please describe what you would write to the standard input at every iteration of the loop(s). If the exploit is working without modification, please describe precisely why the vulnerability is still exploitable.
First exploit
No. the first exploit would overwrite the stack canary (placed in the stack before the return address). The code placed by the compiler in the function epilogue would detect the canary overwrite and abort the execution of the program without jumping to the saved return address, and without executing the attacker’s shellcode. We need to make the program perform two iterations of the loop.
First iteration: write an argv[1] that starts with ‘_’ (e.g., ‘_dbg!\n’) and ‘DEBUG’ at line 16; the code at lines 17-21 will print n words from the stack. Assuming that n is sufficiently high to print also the word containing the stack canary (or, if the attacker controls the command line arguments, passing a sufficiently high n), this would leak the stack canary value for that specific execution of the program.
Then, as strncmp(s.buf, “DEBUG”, 5) == 0 , the do…while loop will not exit.
Second iteration: at this point, we know the value of the stack canary (read during the first loop iteration). We write to stdin (i.e., we put in the buffer) the same exploit I wrote at point 2, changing it slightly so that the stack canary gets overwritten by the value leaked during the first iteration. Also, we need to ensure that strncmp(s.buf, “DEBUG”, 5) == 1 so that the loop ends, the function returns, and the shellcode is executed.
Second exploit
Yes, the second exploit still work without modification