Cybersecurity Notes
MathematicsCryptography
  • Cybersecurity Notes
  • Binary Exploitation
    • Stack
      • Introduction
      • ret2win
      • De Bruijn Sequences
      • Shellcode
      • NOPs
      • 32- vs 64-bit
      • No eXecute
      • Return-Oriented Programming
        • Calling Conventions
        • Gadgets
        • Exploiting Calling Conventions
        • ret2libc
        • Stack Alignment
      • Format String Bug
      • Stack Canaries
      • PIE
        • Pwntools, PIE and ROP
        • PIE Bypass with Given Leak
        • PIE Bypass
      • ASLR
        • ASLR Bypass with Given Leak
        • PLT and GOT
        • ret2plt ASLR bypass
      • GOT Overwrite
        • Exploiting a GOT overwrite
      • RELRO
      • Reliable Shellcode
        • ROP and Shellcode
        • Using RSP
        • ret2reg
          • Using ret2reg
      • One Gadgets and Malloc Hook
      • Syscalls
        • Exploitation with Syscalls
        • Sigreturn-Oriented Programming (SROP)
          • Using SROP
      • ret2dlresolve
        • Exploitation
      • ret2csu
        • Exploitation
        • CSU Hardening
      • Exploiting over Sockets
        • Exploit
        • Socat
      • Forking Processes
      • Stack Pivoting
        • Exploitation
          • pop rsp
          • leave
    • Heap
      • Introduction to the Heap
      • Chunks
      • Freeing Chunks and the Bins
        • Operations of the Fastbin
        • Operations of the Other Bins
      • Malloc State
      • malloc_consolidate()
      • Heap Overflow
        • heap0
        • heap1
      • Use-After-Free
      • Double-Free
        • Double-Free Protections
        • Double-Free Exploit
      • Unlink Exploit
      • The Tcache
        • Tcache: calloc()
        • Tcache Poisoning
      • Tcache Keys
      • Safe Linking
    • Kernel
      • Introduction
      • Writing a Char Module
        • An Interactive Char Driver
        • Interactivity with IOCTL
      • A Basic Kernel Interaction Challenge
      • Compiling, Customising and booting the Kernel
      • Double-Fetch
        • Double-Fetch without Sleep
      • The Ultimate Aim of Kernel Exploitation - Process Credentials
      • Kernel ROP - ret2usr
      • Debugging a Kernel Module
      • SMEP
        • Kernel ROP - Disabling SMEP
        • Kernel ROP - Privilege Escalation in Kernel Space
      • SMAP
      • modprobe_path
      • KASLR
      • KPTI
    • Browser Exploitation
      • *CTF 2019 - oob-v8
        • The Challenge
      • picoCTF 2021 - Kit Engine
      • picoCTF 2021 - Download Horsepower
  • Reverse Engineering
    • Strings in C++
    • C++ Decompilation Tricks
    • Reverse Engineering ARM
  • Blockchain
    • An Introduction to Blockchain
  • Smart Contracts and Solidity
  • Hosting a Testnet and Deploying a Contract
  • Interacting with Python
  • Writeups
    • Hack The Box
      • Linux Machines
        • Easy
          • Traceback
        • Medium
          • Magic
          • UpDown
        • Hard
          • Intense
      • Challenges
        • Web
          • Looking Glass
          • Sanitize
          • Baby Auth
          • Baby Website Rick
        • Pwn
          • Dream Diary: Chapter 1
            • Unlink Exploit
            • Chunk Overlap
          • Ropme
    • picoGym
      • Cryptography
        • Mod 26
        • Mind Your Ps and Qs
        • Easy Peasy
        • The Numbers
        • New Caesar
        • Mini RSA
        • Dachshund Attacks
        • No Padding, No Problem
        • Easy1
        • 13
        • Caesar
        • Pixelated
        • Basic-Mod1
        • Basic-Mod2
        • Credstuff
        • morse-code
        • rail-fence
        • Substitution0
        • Substitution1
        • Substitution2
        • Transposition-Trial
        • Vigenere
        • HideToSee
    • CTFs
      • Fword CTF 2020
        • Binary Exploitation
          • Molotov
        • Reversing
          • XO
      • X-MAS CTF 2020
        • Pwn
          • Do I Know You?
          • Naughty
        • Web
          • PHP Master
      • HTB CyberSanta 2021
        • Crypto
          • Common Mistake
          • Missing Reindeer
          • Xmas Spirit
          • Meet Me Halfway
  • Miscellaneous
    • pwntools
      • Introduction
      • Processes and Communication
      • Logging and Context
      • Packing
      • ELF
      • ROP
    • scanf Bypasses
    • Challenges in Containers
    • Using Z3
    • Cross-Compiling for arm32
Powered by GitBook
On this page
  • The PLT and GOT
  • How is this useful for binary exploitation?
  • Exploiting an Arbitrary Read
  • ret2plt
  • %s format string
  • Summary

Was this helpful?

Export as PDF
  1. Binary Exploitation
  2. Stack
  3. ASLR

PLT and GOT

Bypassing ASLR

Last updated 4 years ago

Was this helpful?

The PLT and GOT are sections within an ELF file that deal with a large portion of the dynamic linking. Dynamically linked binaries are more common than statically linked binary in CTFs. The purpose of dynamic linking is that binaries do not have to carry all the code necessary to run within them - this reduces their size substantially. Instead, they rely on system libraries (especially libc, the C standard library) to provide the bulk of the fucntionality. For example, each ELF file will not carry their own version of puts compiled within it - it will instead dynamically link to the puts of the system it is on. As well as smaller binary sizes, this also means the user can continually upgrade their libraries, instead of having to redownload all the binaries every time a new version comes out.

So when it's on a new system, it replaces function calls with hardcoded addresses?

Not quite.

The problem with this approach is it requires libc to have a constant base address, i.e. be loaded in the same area of memory every time it's run, but remember that exists. Hence the need for dynamic linking. Due to the way ASLR works, these addresses need to be resolved every time the binary is run. Enter the PLT and GOT.

The PLT and GOT

The PLT (Procedure Linkage Table) and GOT (Global Offset Table) work together to perform the linking.

When you call puts() in C and compile it as an ELF executable, it is not actually puts() - instead, it gets compiled as puts@plt. Check it out in GDB:

Why does it do that?

Well, as we said, it doesn't know where puts actually is - so it jumps to the PLT entry of puts instead. From here, puts@plt does some very specific things:

  • If there is a GOT entry for puts, it jumps to the address stored there.

  • If there isn't a GOT entry, it will resolve it and jump there.

The GOT is a massive table of addresses; these addresses are the actual locations in memory of the libc functions. puts@got, for example, will contain the address of puts in memory. When the PLT gets called, it reads the GOT address and redirects execution there. If the address is empty, it coordinates with the ld.so (also called the dynamic linker/loader) to get the function address and stores it in the GOT.

How is this useful for binary exploitation?

Well, there are two key takeaways from the above explanation:

  • Calling the PLT address of a function is equivalent to calling the function itself

  • The GOT address contains addresses of functions in libc, and the GOT is within the binary.

The use of the first point is clear - if we have a PLT entry for a desirable libc function, for example system, we can just redirect execution to its PLT entry and it will be the equivalent of calling system directly; no need to jump into libc.

The second point is less obvious, but debatably even more important. As the GOT is part of the binary, it will always be a constant offset away from the base. Therefore, if PIE is disabled or you somehow leak the binary base, you know the exact address that contains a libc function's address. If you perhaps have an arbitrary read, it's trivial to leak the real address of the libc function and therefore bypass ASLR.

Exploiting an Arbitrary Read

There are two main ways that I (personally) exploit an arbitrary read. Note that these approaches will cause not only the GOT entry to be return but everything else until a null byte is reached as well, due to strings in C being null-terminated; make sure you only take the required number of bytes.

ret2plt

A ret2plt is a common technique that involves calling puts@plt and passing the GOT entry of puts as a parameter. This causes puts to print out its own address in libc. You then set the return address to the function you are exploiting in order to call it again and enable you to

# 32-bit ret2plt
payload = flat(
    b'A' * padding,
    elf.plt['puts'],
    elf.symbols['main'],
    elf.got['puts']
)

# 64-bit
payload = flat(
    b'A' * padding,
    POP_RDI,
    elf.got['puts']
    elf.plt['puts'],
    elf.symbols['main']
)

flat() packs all the values you give it with p32() and p64() (depending on context) and concatenates them, meaning you don't have to write the packing functions out all the time

%s format string

This has the same general theory but is useful when you have limited stack space or a ROP chain would alter the stack in such a way to complicate future payloads, for example when stack pivoting.

payload = p32(elf.got['puts'])      # p64() if 64-bit
payload += b'|'
payload += b'%3$s'                  # The third parameter points at the start of the buffer


# this part is only relevant if you need to call the function again

payload = payload.ljust(40, b'A')   # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])

# Send it off...

p.recvuntil(b'|')                   # This is not required
puts_leak = u32(p.recv(4))          # 4 bytes because it's 32-bit

Summary

  • The PLT and GOT do the bulk of static linking

  • The PLT resolves actual locations in libc of functions you use and stores them in the GOT

    • Next time that function is called, it jumps to the GOT and resumes execution there

  • Calling function@plt is equivalent to calling the function itself

  • An arbitrary read enables you to read the GOT and thus bypass ASLR by calculating libc base

ASLR