From 503f0561d555841820977373f9ff2b3c7d1b6b71 Mon Sep 17 00:00:00 2001 From: Tharre Date: Sun, 19 Jan 2020 22:33:05 +0100 Subject: [PATCH] Add tharre/seccon19.md --- writeups/tharre/seccon19.md | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 writeups/tharre/seccon19.md diff --git a/writeups/tharre/seccon19.md b/writeups/tharre/seccon19.md new file mode 100644 index 0000000..24f38b5 --- /dev/null +++ b/writeups/tharre/seccon19.md @@ -0,0 +1,80 @@ +# SECCON 2019 Online CTF - pwn one + +## Overview + +This was probably the hardest challange I've done during the course, besides +engine which was unsolvable anyway. It starts relatively simple, it's a pwn +challange and you get a binary, `one_ef36d5ef6169aeda65259f627f282930b93cf6e5` +and `libc-2.27.so_18292bd12d37bfaf58e8dded9db7f1f5da1192cb`. When running the +binary you're presented with four options, add, show, delete a memo or exit the +program. + +## Find the vulnerability + +After playing around with it a bit you find a bug rather quickly, adding a memo +and then deleting it twice produces a double free: + +``` +free(): double free detected in tcache 2 +[1] 43966 abort (core dumped) ./one_ef36d5ef6169aeda65259f627f282930b93cf6e5 +``` + +This alone would not really be exploitable, however this was run directly on my +updated Arch Linux machine which was running `glibc-2.30`. Since there was +suspiciously also a `libc-2.27.so` included in the challange it was rather +obvious that it was meant to only be exploitable with that or older versions. +And indeed if you google `glibc 2.27 double free` you get tons of results +describing exploitation methods related to tcache double-free. + +## Trying to build an exploit + +So we know what vulnerability we want to exploit and there's tons of additional +material available describing similar exploits so this should be easy right? + +Well, not so fast. First of all we need to actually run the binary with +`libc-2.27`. I tried for quite a bit to actually run the thing on my machine +directly with commands like `LD_LIBRARY_PATH=$(pwd) ./ld-linux-x86-64.so.2 +./one_ef36d5ef6169aeda65259f627f282930b93cf6e5` but couldn't get it to work in a +timely fashion, so I just settled on working in a Ubuntu 18.04 docker container +after reading `cluosh` hint that they use the same libc version. + +The next difficulty was actually applying what I've read about tcache's freelist +to write to arbitrary addresses in memory. The details of how this works are +quite complicated, I probably don't understand them fully myself either, but the +gist of it is that you can trick glibc into returning a pointer to a memory +region that was never part of the original heap region that glibc uses and that +we can control. This happens because after a double free there's a loop in the +tcache freelist, the linked-list that holds available memory chunks, which +causes the chunk we recieve from `malloc()` to not be removed from the freelist. +We can then write to this address by adding a memo, where the first 8 byte will +override the next pointer, which we can point to any memory region we want. Now +we just need to do force two more allocations, one to reach our crafted `next` +pointer and one to actually get back our target pointer. + +So to write value to an arbitrary pointer `ptr`, we just do `add -> add(ptr) -> +add -> add(value)`. + +## ASLR makes everything hard + +This is were I ultimately got stuck. So we can write to arbitrary memory +locations, how do we actually turn this into a shell? As `cluosh` also noted on +mattermost, we can't override GOT entries since the binary is full-relro, so +probably the easiest way to exploit this is by overriding glibc hooks, +especially `__free_hook`. And indeed with ASLR turned off and a debugger (and +some fiddling) attached to get the memory address of `__free_hook` I managed to +successfully override the hook. + +With ASLR turned on not so much. I did manage to find a information leak by +doing `add -> add -> delete -> delete -> show`, however I ultimately failed to +do anything useful with the address I leaked. Even worse, leaking the address +made the rest of the exploit fail. The reason for this is actually rather +obvious in hindsight, adding a memo twice meant that the tcache was getting +messed up. Just doing `add -> delete -> delete -> delete -> delete -> show` +would've been better. + +Looking at writeups from other people, the rest would actually have been doable +as well, I really just failed at properly determining the offset to the libc +base address. + +I spend around 35h on this challange, most of it after the original challange +already ended though since SECCONs timeframe was so short. -- 2.43.0