1 of 29

Binary Exploitation

Cyber Academy S23

2 of 29

Announcements

  • Cyber Lab: Aaron Yoo’s Talk
    • Thursday 7-9 pm ~ Boelter 4760
  • LiveOverflow Talk
    • Saturday 11 am ~ Zoom & E4 63-129
  • Cyber Lab: Sanjana Sarda’s Talk
    • Monday 6-8 pm ~ Kerckhoff 133
  • PBR Practice: Joint Practice w. Batman’s Kitchen (University of Washington’s CTF Team)
    • Tuesdays 6-8 pm ~ Ackerman Union 3517
  • Cyber Academy: Software Verification
    • Wednesdays 6-8 pm ~ MATH SCI 5200

3 of 29

✨Social Engineering Time ✨

  • Icebreaker
    • What is a simple dance that you are bad at? :D

4 of 29

Binary Exploitation Review

5 of 29

Review: The Stack

  • The stack is a LIFO (Last In, First Out) data structure that is used to store/allocate local variables created by a function.
    • Automatically allocated and deallocated by compiler
  • The stack pointer (%rsp) contains the lowest stack address (the “top” element)
    • Grow and shrink stack!

6 of 29

Review: How is the stack organized? (x86-64)

  • On x86-64 machines, memory is allocated on the stack in stack frames.
    • Stack frames are big chunks of memory
      • Each stack frame represents one function call
      • Contains:
        • Return address
        • Local variables (if can’t keep in registers)
        • Saved register context (return address)
  • Allow for recursion + procedure calls!

7 of 29

ROP: Overwriting the Return Address

Return address

0x0000000000601234

Data (orig rbp value)

0x0000000000401234

Input data

0x0000000000000000

Input data

0x0000000000000000

Stack frame:

func0:

pushq %rbp

movq %rsp, %rbp

subq $16, %rsp

...read unlimited input into (%rsp)...

addq $16, %rsp

popq %rbp

ret

User input: aaaaaaaaaaaaaaaaaaaaaaaaabcdefgh

(32 a’s)

rsp

Stack is expanded downwards

(towards lower address values)

Lower memory addresses

Higher memory addresses

8 of 29

ROP: Overwriting the Return Address

Return address

0x6867666564636261

Data (orig rbp value)

0x6161616161616161

Input data

0x6161616161616161

Input data

0x6161616161616161

Stack frame:

func0:

pushq %rbp

movq %rsp, %rbp

subq $16, %rsp

...read unlimited input into (%rsp)...

addq $16, %rsp

popq %rbp

ret

User input: aaaaaaaaaaaaaaaaaaaaaaaaabcdefgh

(32 a’s)

rsp

Stack is expanded downwards

(towards lower address values)

Data is written into the stack upwards (towards higher address values)

Lower memory addresses

Higher memory addresses

9 of 29

ROP: Overwriting the Return Address

Return address

0x6867666564636261

Data (orig rbp value)

0x6161616161616161

Input data

0x6161616161616161

Input data

0x6161616161616161

Stack frame:

func0:

pushq %rbp

movq %rsp, %rbp

subq $16, %rsp

...read unlimited input into (%rsp)...

addq $16, %rsp

popq %rbp

ret

User input: aaaaaaaaaaaaaaaaaaaaaaaaabcdefgh

(32 a’s)

rsp

Stack is expanded downwards

(towards lower address values)

Data is written into the stack upwards (towards higher address values)

Lower memory addresses

Higher memory addresses

At the end of the function, it will “return” to the address 0x6867666564636261 and execute instructions there, a number that we control!

10 of 29

ROP: Overwriting the Return Address

  • Note: Watch out for little endian!
    • Lowest byte position in little endian address value = first byte entered into input
    • Highest byte position = last byte entered into input
  • Example:
    • Input: aaaaaaaa12345678
    • Memory:
      • 61 61 61 61 61 61 61 61 31 32 33 34 35 36 37 38

Lower memory addresses - Higher memory addresses

    • Interpreted address to return to (starting 8 bytes in):
      • 0x3837363534333231

11 of 29

Review: Code Injection

  • Every region of memory has permissions just like files
  • These permissions are read, write, execute
  • If memory is both writable and executable, you can write then execute raw machine code, even jumping to other functions using ret!
  • This is commonly known as shellcode
  • Due to how input is read, shellcode should avoid using newlines

12 of 29

Review: Jumping to injected shellcode

  • Write code in the stack, then overwrite the return address to jump to your injected code!

13 of 29

Review: Jumping to injected shellcode

  • Where to jump to make sure to hit your code? NOP sleds!
  • nop is “no op”, or does nothing
    • Opcode 0x90
  • Spam a bunch of nops so that as long as your return address is somewhere in the vicinity of your code area, your shellcode is still run!
    • Stack pointers are almost always in the same general address space

14 of 29

Exploit Mitigation: NX

  • The NX (No eXecute) bit (also referred to as W^X bit) exists on all modern systems
  • If set (the default), no pages will be writable and executable
  • This stops code injection from working
  • It can still work if mmap or mprotect is called to explicitly allocate a wx page

15 of 29

Automating Exploitation: pwntools

  • Python library specialized for binary exploitation
  • Can do IO along with a lot of other quality of life
  • pip3 install pwntools

16 of 29

IO Example with pwntools

17 of 29

Quality of Life: ELF Loading and Endianness

18 of 29

Assembling Shellcode

  • Also Intel syntax (reverse argument order, no % or $ signs, no size suffixes, 8(%rdi, %rsi, 2) is written [rdi+rsi*2+8])

19 of 29

Demo Time!

20 of 29

Review: ROP Chains

  • What if you chained together multiple return addresses?
  • Create custom logic by chaining "gadgets"
  • Gadgets should end in a ret in order to move onto the next one
  • Can use pop gadgets to control registers

21 of 29

Finding Gadgets

  • Gadgets must be in an executable segment
  • They must be at a known address
  • Usually located in the program code itself
  • Can be inside another instruction!

22 of 29

Exploit Mitigation: ASLR

  • Address Space Layout Randomization
  • Kernel-level mitigation
  • The stack, heap, and libraries (e.g. libc) will all be put at random addresses
  • If PIE is enabled, code and data segments will also be randomized
  • ASLR+PIE makes it so you have to get an address leak before doing a ROP attack

23 of 29

Useful Tool: ASREPL

  • If you don't mind Intel syntax, use https://asrepl.jonpalmisc.com
  • Can assemble and disassemble x86
  • Useful for both shellcoding and finding gadgets

24 of 29

Useful GEF Commands: vmmap

  • Lists memory regions and the permissions on them
  • rwx pages can be used to inject shellcode!

25 of 29

checksec

  • Allows you to check which mitigations there are!
  • Since ASLR is kernel-level, it won't show up here
  • ASLR is almost always enabled

26 of 29

info frame

  • Gives info about the current stack frame
  • Can give you the address of the saved rip/rbp

27 of 29

deref

  • Prints a prettier view of a memory address
  • Defaults to $rsp, but can be given an argument
  • Useful for inspecting ropchains

28 of 29

Challenges!!!

29 of 29

Check out our linktree:

linktr.ee/uclacyber