{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
The Global Offset Table (GOT) is a mechanism used in dynamically linked binaries to manage the addresses of external functions. Since these addresses are not known until runtime (due to dynamic linking), the GOT provides a way to dynamically update the addresses of these external symbols once they are resolved.
Each entry in the GOT corresponds to a symbol in the external libraries that the binary may call. When a function is first called, its actual address is resolved by the dynamic linker and stored in the GOT. Subsequent calls to the same function use the address stored in the GOT, thus avoiding the overhead of resolving the address again.
The Procedure Linkage Table (PLT) works closely with the GOT and serves as a trampoline to handle calls to external functions. When a binary calls an external function for the first time, control is passed to an entry in the PLT associated with that function. This PLT entry is responsible for invoking the dynamic linker to resolve the function's address if it has not already been resolved. After the address is resolved, it is stored in the GOT.
Therefore, GOT entries are used directly once the address of an external function or variable is resolved. PLT entries are used to facilitate the initial resolution of these addresses via the dynamic linker.
Get the address to the GOT table with: objdump -s -j .got ./exec
Observe how after loading the executable in GEF you can see the functions that are in the GOT: gef➤ x/20x 0xADDR_GOT
Using GEF you can start a debugging session and execute got
to see the got table:
In a binary the GOT has the addresses to the functions or to the PLT section that will load the function address. The goal of this arbitrary write is to override a GOT entry of a function that is going to be executed later with the address of the PLT of the system
function for example.
Ideally, you will override the GOT of a function that is going to be called with parameters controlled by you (so you will be able to control the parameters sent to the system function).
If system
isn't used by the binary, the system function won't have an entry in the PLT. In this scenario, you will need to leak first the address of the system
function and then overwrite the GOT to point to this address.
You can see the PLT addresses with objdump -j .plt -d ./vuln_binary
The GOT of libc is usually compiled with partial RELRO, making it a nice target for this supposing it's possible to figure out its address (ASLR).
Common functions of the libc are going to call other internal functions whose GOT could be overwritten in order to get code execution.
Find more information about this technique here.
In heap exploitation CTFs it's common to be able to control the content of chunks and at some point even overwrite the GOT table. A simple trick to get RCE if one gadgets aren't available is to overwrite the free
GOT address to point to system
and to write inside a chunk "/bin/sh"
. This way when this chunk is freed, it'll execute system("/bin/sh")
.
Another common technique is to overwrite the strlen
GOT address to point to system
, so if this function is called with user input it's posisble to pass the string "/bin/sh"
and get a shell.
Moreover, if puts
is used with user input, it's possible to overwrite the strlen
GOT address to point to system
and pass the string "/bin/sh"
to get a shell because puts
will call strlen
with the user input.
{% content-ref url="../rop-return-oriented-programing/ret2lib/one-gadget.md" %} one-gadget.md {% endcontent-ref %}
A common way to obtain RCE from a heap vulnerability is to abuse a fastbin so it's possible to add the part of the GOT table into the fast bin, so whenever that chunk is allocated it'll be possible to overwrite the pointer of a function, usually free
.
Then, pointing free
to system
and freeing a chunk where was written /bin/sh\x00
will execute a shell.
It's possible to find an example here.
The Full RELRO protection is meant to protect agains this kind of technique by resolving all the addresses of the functions when the binary is started and making the GOT table read only after it:
{% content-ref url="../common-binary-protections-and-bypasses/relro.md" %} relro.md {% endcontent-ref %}
- https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite
- https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.