Skip to main content

Exercises on software security

2022-2021 DEMO Exam exercise 3 (6 points)

Assume that:

  • The C standard library is loaded at a known address during every execution of the program, and that the address of the function system() is 0xf4d0e2d3.
  • Environment variables are located in the highest addresses.
  • The program is compiled for the x86 architecture (32 bit) and for an environment that adopts the usual cdecl calling convention. Furthermore, assume that no compiler-level or OS-level mitigations against the exploitation of memory corruption errors are present (unless specified otherwise).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef struct {
  char base[8];
  int r;
  char buf[64];
  char *str_p;
  char canary[4];
} data_t;

void guess(int num, char *str, data_t *data) {

  snprintf(data->buf, num, str);

  if (strncmp(data->buf, "backdoor", 8) == 0){
    scanf("%8s", data->str_p);

    if (num == data->r){
      system("/bin/sh\0");
    }
  }
  if (strcmp(data->canary, "XXX") != 0)
  	abort();
}

int main(int argc, char** argv) {
  int num;
  data_t data;

  srand(time(NULL));
  num = atoi(argv[1]);

  data.r = rand();
  strcpy(data.canary, "XXX");
  data.str_p = data.base;

  guess(atoi(argv[1]), argv[2], &data);
}
  1. [1 point] The program is affected by typical buffer overflow and format string vulnerabilities. Complete the following table, focusing on a vulnerability per row.
Vulnerability Line Modify the line to solve the detected vulnerability
Buffer Overflow
Format String
  1. [2 points] 2. Focus only on the stack-based buffer overflow(s) you found. Write an exploit for this vulnerability that must execute the following shellcode, composed of 16 bytes, which opens a shell: 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90.

    1. Describe all the steps and assumptions required for the successful exploitation of the vulnerability. 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 and/or environment variables, if any).
    2. 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 vulnerable line during the program exploitation showing:
      • Direction of growth and high-low addresses;
      • The name of each allocated variable;
      • The content of relevant registers (i.e., EBP, ESP);
      • The functions stack frames.
      • Show also the content of the caller frame.
  2. [2 points] Focus only on the format string vulnerability you found. Assume that you were able to find this working exploit to execute a piece of shellcode saved in an environment variable. \xb6\x06\x3a\x44\xb8\x06\x3a\x44%26543c%4$hn%9529c%5$hn. Clearly detail all the components of the format string exploit:

    • The decimal components of the address of the environment variable containing your shellcode (i.e., what to write)
    • The address of the saved return address (i.e., the address where we want to write)
    • The displacement on the stack of your format string.
  3. [1 point] Consider ONLY the “Non-executable stack (NX)” mitigation technique. A friend of yours suggests that there is an alternative way to exploit the vulnerability/ies you found to spawn a privileged shell in the program without executing any shellcode or calling library functions. If it is possible, please explain all the steps and assumptions required for a successful exploitation of the vulnerabilities detected. Focus on one vulnerability at a time. 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 and/or environment variables, if any). If it is not effective, please explain why.

Question 1

Consider the C program below, which is affected by a typical buffer overflow vulnerability.

#include <stdio.h>
#include <stdlib.h>
#include <string.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();
}

Assume that the program runs on the usual IA-32 architecture (32-bits), with the usual “cdecl” calling convention. Also assume that the program is compiled without any mitigation against exploitation (ASLR is off, stack is executable, and stack canary is not present).

Draw the stack layout when the program is executing the instruction at line 7, showing:

  1. Direction of growth and high-low addresses.
  2. The name of each allocated variable.
  3. 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).

Solution

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.

Solution

The function must return, this is the reason why buf must start with "Knight_King!". A is ESP + 3*4.

If address space layout randomization (ASLR) is active, is the exploit you just wrote still working without modifications? Why?

Solution

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.

If the stack is made non executable (i.e., NX, W^X), is the exploit you just wrote still working without modifications? If not, propose an alternative solution to exploit the program.

Solution

No, we can use ret to libc technique in order to execute the system function in the libc and obtain a shell.

Question 2

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?
Solution

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.

  • How would you fix BlaBlaStack in order to protect from local attackers?
Solution

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.

Question 2b

Consider the following assembly code

  • Describe in detail what the assembly code does and the name of the technique that is being implemented.
  • Describe the weakness in this implementation.
  • Describe, in common words, how would you fix the vulnerability.
function_prologue:
	pushl $0x0000d00d
	pushl %ebp
	mov %esp, %ebp
	subl $4, %esp
    
function_foo:
	(functionbody)
    
function_epilogue:
  movl %ebp, %esp
  popl %ebp
  cmpl 0x0000d00d,(%esp)
  jne function_bar
  addl $4, %esp
  ret
  
function_bar:
	(functionbody)
Solution

The assembly code implements a static canary. It pushes 0x0000d00d in the stack in the prologue and it compare if the value is still there in the epilogue.

The implementation is vulnerable because the hardcoded value can be leaked reversing the binary and used in the exploit.

A correctly implemented canary: 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.

Question 3