Don't like this style? Click here to change it! blue.css
Here's our target problem:
This one is compiled with no to canary but yes to PIE. So we can smash but we can't predict main addresses.
OK no big deal they leak main
. But there is not a win function and our job is to decide what to do with our instruction pointer.
PLT == Procedure Linkage Table is a
section of memory just before main
that is R-X (readable and executable just like the main instructions).
When you call a function in PLT (e.g. sym.imp.printf or sym.imp.exit or anything the comes in stdlib.h
)
the instruction pointer goes to the correct spot in PLT which does this:
First PLT istruction immediately jumps to the address written in the GOT == Global Offset Table. GOT is a RW- (readable and writable) section of memory that is PIE impacted (meaning if no-PIE you can predict it and with PIE you can find it if you can find .main) containing the addresses for imported library functions.
The general concept is that we can know (in no-PIE land) where PLT AND GOT live, we can use addresses in PLT to call functions that program is using, we can use addresses in the GOT to leak glibc addresses AND if we can write to the GOT we have our second viable method to control the instruction pointer: overwrite the GOT address which should be printf (or whatever) and the next time something prints it calls our function instead
The addresses written in the GOT are not the final addresses when the binary is made, they can't be, the binary is a text book and these addresses for library functions are like today's stock prices.
So the first addresses written in the GOT are actually instructions in the PLT which call the LINKER. The Linker does some weird graph theory stuff to lookup the latest version of the glibc address. That new address gets WRITTEN BACK TO THE GOT! This means the next time you would have linked instead you go straight to the library function instead. This is Lazy Linking and it saves a ton of CPU time by not having to do crazy graph theory stuff at every library function call.
Let's compile this and look at the addresses: