Machine-Level Programming V - Advanced Topics

Class: CSCE-312


Notes:

Today

Memory Layout

x86-64 Linux Memory Layout

Pasted image 20251023125029.png300

Memory Allocation Example

char big_array[1L<<24];  /* 16 MB */
char huge_array[1L<<31]; /*  2 GB */

int global = 0;

int useless() { return 0; }

int main ()
{
    void *p1, *p2, *p3, *p4;
    int local = 0;
    p1 = malloc(1L << 28); /* 256 MB */
    p2 = malloc(1L << 8);  /* 256  B */
    p3 = malloc(1L << 32); /*   4 GB */
    p4 = malloc(1L << 8);  /* 256  B */
 /* Some print statements ... */
}

Where does everything go?

Pasted image 20251023131056.png75

x86-64 Example Addresses

_address range ~2^47_
Pasted image 20251023133812.png500

Buffer Overflow

Recall: Memory Referencing Bug Example

typedef struct {
  int a[2];
  double d;
} struct_t;

double fun(int i) {
  volatile struct_t s;
  s.d = 3.14;
  s.a[i] = 1073741824; /* Possibly out of bounds */
  return s.d;
}
fun(0)  ➙	3.14
fun(1)  ➙	3.14
fun(2)  ➙	3.1399998664856
fun(3)  ➙	2.00000061035156
fun(4)  ➙	3.14
fun(6)  ➙	Segmentation fault

Pasted image 20251023135202.png500

Such problems are a BIG deal

String Library Code

Implementation of Unix function gets()

/* Get string from stdin */
char *gets(char *dest)
{
    
	int c = getchar();
    char *p = dest;
    while (c != EOF && c != '\n') {
        *p++ = c;
        c = getchar();
    }
    *p = '\0';
    return dest;
}

Similar problems with other library functions

Vulnerable Buffer Code

/* Echo Line */  
void echo()  
{  
    char buf[4];  /* Way too small! */  
    gets(buf);  
    puts(buf);  
}
void call_echo() {
    echo();
}

Pasted image 20251023135950.png350

Buffer Overflow Disassembly

Pasted image 20251023161809.png550

Buffer Overflow Stack

C code:

/* Echo Line */  
void echo()  
{  
    char buf[4];  /* Way too small! */  
    gets(buf);  
    puts(buf);  
}

Assembly code:

echo:
  subq  $24, %rsp
  movq  %rsp, %rdi
  call  gets
  . . .

Pasted image 20251023162041.png250

Buffer Overflow Example

Pasted image 20251028131153.png500

Buffer Overflow Example #1

Pasted image 20251028131217.png500

Buffer Overflow Example #2

Pasted image 20251028131405.png500

Buffer Overflow Example #3

Pasted image 20251028131430.png500

Buffer Overflow Example #3 Explained

Pasted image 20251028131539.png450

Code Injection Attacks

Pasted image 20251028131726.png500

Notes:

Exploits Based on Buffer Overflows

Example: the original Internet worm (1988)

Notes:

Example 2: IM War

Aside: Worms and Viruses

Ok, what to do about buffer overflow attacks

1. Avoid Overflow Vulnerabilities in Code (!)

/* Echo Line */  
void echo()  
{  
    char buf[4];  /* Way too small! */  
    fgets(buf, 4, stdin);  
    puts(buf);  
}

2. System-Level Protections can help (Randomized offsets)

Pasted image 20251028133618.png150

2. System-Level Protections can help (Nonexecutable code segments)

Pasted image 20251028133929.png300

3. Stack Canaries can help

Protected Buffer Disassembly (skip)

echo:

  40072f:	sub    $0x18,%rsp
  400733:	mov    %fs:0x28,%rax
  40073c:	mov    %rax,0x8(%rsp)
  400741:	xor    %eax,%eax
  400743:	mov    %rsp,%rdi
  400746:	callq  4006e0 <gets>
  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

C code:

/* Echo Line */  
void echo()  
{  
    char buf[4];  /* Way too small! */  
    gets(buf);  
    puts(buf);  
}

Assembly code:

echo:
	. . .
	movq	%fs:40, %rax  # Get canary
	movq	%rax, 8(%rsp) # Place on stack
	xorl	%eax, %eax    # Erase canary
	. . .

Pasted image 20251028134456.png200

Checking Canary

Assembly code:

echo:
	. . .
	movq	8(%rsp), %rax     # Retrieve from stack
	xorq	%fs:40, %rax      # Compare to canary
	je	    .L6               # If same, OK
	call	__stack_chk_fail  # FAIL
.L6:        . . .

Input: 0123456

Pasted image 20251103201253.png200

Return-Oriented Programming Attacks

Notes:

Why ROP defeats NX but not always other defenses

Gadget Example #1

Pasted image 20251028134635.png550

Gadget Example #2

Pasted image 20251103203338.png575

ROP Execution

Pasted image 20251103203614.png500

Unions

"Like structs, except that all the elements occupy the same space"

Union Allocation

Pasted image 20251028135101.png600

Using Union to Access Bit Patterns

Pasted image 20251028135350.png550

Byte Ordering Revisited

Byte Ordering Example

union {
      unsigned char c[8];
      unsigned short s[4];
      unsigned int i[2];
      unsigned long l[1];
    } dw;

Pasted image 20251028135625.png475

Print function:

int j;
for (j = 0; j < 8; j++)
    dw.c[j] = 0xf0 + j;

printf("Characters 0-7 ==  [0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x]\n",
    dw.c[0], dw.c[1], dw.c[2], dw.c[3],
    dw.c[4], dw.c[5], dw.c[6], dw.c[7]);

printf("Shorts 0-3 == [0x%x,0x%x,0x%x,0x%x]\n",
    dw.s[0], dw.s[1], dw.s[2], dw.s[3]);

printf("Ints 0-1 == [0x%x,0x%x]\n",
    dw.i[0], dw.i[1]);

printf("Long 0 == [0x%lx]\n",
    dw.l[0]);

Byte Ordering on IA32 (Little Endian)

Little Endian
Pasted image 20251103210713.png425
Output:

Characters 0-7 == [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7]
Shorts     0-3 == [0xf1f0,0xf3f2,0xf5f4,0xf7f6]
Ints       0-1 == [0xf3f2f1f0,0xf7f6f5f4]
Long       0   == [0xf3f2f1f0]

Byte Ordering on Sun (Big Endian)

Big Endian
Pasted image 20251103210845.png425
Output:

Characters 0-7 == [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7]
Shorts     0-3 == [0xf0f1,0xf2f3,0xf4f5,0xf6f7]
Ints       0-1 == [0xf0f1f2f3,0xf4f5f6f7]
Long       0   == [0xf0f1f2f3]

Byte Ordering on x86-64 (Little Endian 64-bit)

Little Endian
Pasted image 20251103210944.png425
Output:

Characters 0-7 == [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7]
Shorts     0-3 == [0xf1f0,0xf3f2,0xf5f4,0xf7f6]
Ints       0-1 == [0xf3f2f1f0,0xf7f6f5f4]
Long       0   == [0xf7f6f5f4f3f2f1f0]

Summary of Compound Types in C