羊城杯2024 Writeup

Misc

hiden

题目附件有一个wav文件,初步查看发现没有异常,所以从60=()+().txt文件入手。通过编码识别出为ROT47,根据感觉或者文件名可以知道还需要进行ROT13或者Caesar偏移13都可以,解码后得到wav加密代码,写出解密代码。

import wave  

with wave.open("hiden.wav", "rb") as f:  
    attrib = f.getparams()  
    wav_data = bytearray(f.readframes(-1))  

extracted_data = []  

for i in range(0, len(wav_data), 4):  
    if i < len(wav_data):  
        extracted_data.append(wav_data[i])  

extracted_bytes = bytes(extracted_data)  

if len(extracted_bytes) >= 3:  
    length_prefix = int.from_bytes(extracted_bytes[:3], 'little')  
    text_data = extracted_bytes[3:3+length_prefix]  
    flag_text = text_data.decode('utf-8')  
    print(flag_text)  
else:  
    print("Wrong")

得到flag

ok,now you find me,so the flag give you

DASCTF{12jkl-456m78-90n1234}

Check in

首先在附件压缩包中发现一串base,解码得到一串字符串

5unVpeVXGvjFah      base58---->
Welcome2GZ

txt文件是流量包的十六进制,先导出为流量包,但是发现流量包损坏,这里用在线网站或者NetA都可以进行修复。打开压缩包发现很多SMB流量,并且原先的txt中存在空格和\x00,初步分析止步于此。

后面放出了hint,txt存在第二层面纱,重新对txt文档进行分析,先将txt文档以utf-8编码打开并保存,一开始考虑的是零宽,但是未解出。尝试wbStego4open,输入密码得到一个txt文件,查询后发现是tls.log文件。

这里可以使用Wireshark,在菜单栏中找到编辑,并在Protocols中找到tls,并导入log文件

image-20240828191121731

导入后在流33发现post传的flag.gif,将gif导出

image-20240828191221184

提取GIF帧间隔

['30', '230', '30', '230', '30', '230', '30', '230', '30', '230', '30', '230', '230', '230', '230', '230', '30', '30', '230', '230', '30', '30', '30', '30', '30', '230', '230', '230', '30', '230', '230', '230', '30', '230', '30', '30', '230', '230', '230', '30', '30', '230', '30', '230', '230', '230', '230', '230', '30', '30', '230', '230', '30', '30', '30', '230', '30', '230', '30', '230', '30', '230', '30', '30']

发现只有30和230两种,分别转化为0和1,再转为字符,得到flag

0101010101011111001100000111011101001110010111110011000101010100
U_0wN_1T

1z_misc

题目和hint如下

天地玄黄,宇宙洪荒;日月盈昃,辰宿列张;万物芸芸,息息相关;是以十二岁而行二十八宿,其间奥妙,待探寻,显真章。
若女可为11,可为1124......觜可为91,亦可为725......如此往复,周而复始。
祈解其秘:[43,101,55,16,16,1017,28,812,824,43,55,226,101,55,55,415,1017,1027,28,28,617,824,28,812,1027,16,101,16,55,1027,1017,28,16]

hint:十二支藏二十八星宿,细看二者关联,数字不一定只是数字本身~

这里我们先看十二地支和二十八星宿图结合图片来解释原理

image-20240828192817531

数字由两部分组成:

前半部分代表的是十二地支偏移量,从子开始为1,顺时针计数。

后半部分代表的是二十八星宿偏移量,从相应地支最右边开始为1,逆时针计数。

明白这个过后就能理解为什么女可为11,可为1124,觜可为91,亦可为725了。对密文进行解密:

[心,胃,心,奎,奎,心,奎,心,胃,心,心,心,胃,心,心,胃,心,奎,奎,奎,奎,胃,奎,心,奎,奎,胃,奎,心,奎,心,奎,奎]

可以发现里面只有心,胃,奎,分别转为0,1,2

010220201000100102222120221202022

观察发现只有1可能作为分隔符,在线网站解码会显示错误,这里用CyberChef,得到压缩包密码

image-20240828215150595

E@SI1Y!

解压得到一个未命名文件和hint.jpg,图片为天琴座(lyra),参考 ISCC2024的一道题目通过lyra进行解码,未命名文件修改后缀名为flag.lyra

这里试了很多办法也没能配置好环境,解题思路和ISCC的大体相似,将得到的wav进行语音转文字得到社会主义核心价值观编码,进行解码得到flag


 miaoro

附件为一个流量包,通过分析发现流量包的数据流中存在zip文件

image-20240828200901078

先from dumphex将十六进制整理出来,再进行reverse,得到zip

image-20240828201044927

导出发现需要密码,并且压缩包内的只是flag2,说明还有flag1。

分析流量包发现shiro特征,直接用最后一个流的值,key是1234567890abcdef,算法是CBC,AES解密后得到flag1

image-20240828201801957

DASCTF{B916CFEB-C40F-45D6-A7BC-

flag2需要密码进行解压,我们在zip流附近开始查找,在流10的GWHT中找到密码

image-20240828202135462

image-20240828202158144

echo Th15_11111111s_pP@sssssw000rd!!!>pass.txt

解压后得到一张jpg图片,发现可能宽度不对,crc检验证实了想法,在010中进行修改

image-20240828202538684

得到完整的图(猫猫可爱捏(●'◡'●)

image-20240828202613736

搜索发现猫猫字体对应的字母表

image-20240828202712036

对应解码得到flag

EBOFDELQDIAA}

综上所述

DASCTF{B916CFEB-C40F-45D6-A7BC-EBOFDELQDIAA}

不一样的数据库_2

附件为一个加密的压缩包,打开010在末尾发现信息

image-20240828203115002

进行爆破,先尝试纯数字,得到密码

image-20240828203205350

解压后得到一个残缺二维码和kdbx文件,先对二维码补全进行解码,得到以下信息

NRF@WQUKTQ12345&WWWF@WWWFX#WWQXNWXNU

但是后面尝试后发现是不对的,根据题目描述需要注意文件名13.jpg,所以进行ROT13,得到正确的密码

AES@JDHXGD12345&JJJS@JJJSK#JJDKAJKAH

kdbx文件使用KeePass打开,在文件中发现AES密文和key

image-20240828204229503

解码得到flag

Snipaste_2024-08-27_21-58-04

DASCTF[snsnndjahenanheanjjskk12235)

so much

附件为一个ad1磁盘文件,010查看末尾发现信息

image-20240828204804181

将文件名进行base64解码也能得到信息

c2hpZnQh    --->base64
shift!

结合得到的信息可以找到正确的key

!@#$%^&

在FTK Imager中挂载磁盘文件,并提取内容,总共发现345个crypto文件,并且关注修改日期可以发现末尾只为19和20。并且345可以被8整除,这里我们对照时间进行01转化,并将二进制转成字符串

image-20240828205337573

import os
list = ['']*344
i = 0
for j in range(344):
    list[j] = os.path.getmtime(str(j)+'.crypto')
flag = ''

for i in range(344):
    if(str(list[i]) == '1628151585.73009'):
        flag += '0'
    else:
        flag += '1'

tmp = ''
for k in range(len(flag)):
    tmp += flag[k]
    if len(tmp) == 8:
        print(chr(int(tmp,2)),end='')
        tmp = ''

# the_key_is_700229c053b4ebbcf1a3cc37c389c4fa

得到key,使用

Encrypto对创建时间不同的两个文件进行解密,分别得到一半flag,组合得到最终flag

DASCTF{85235bd803c2a0662b771396bce9968f}

数据安全

data-analy1

import pandas as pd
import re

patterns = {
    '编号': re.compile(r'^([1-9]\d{0,3}|10005)$'),
    '手机号码': re.compile(r'^(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)[0-9]{8}$'),
    '身份证号': re.compile(r'^\d{17}[\dX]$'),
    '姓名': re.compile(r'^[\u4e00-\u9fa5]+$'),
    '密码': re.compile(r'^[a-f0-9]{32}$'),
    '性别': re.compile(r'^(男|女)$'),
    '出生日期': re.compile(r'^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])$'),
    '用户名': re.compile(r'^[0-9A-Za-z]+$')
}

def classify_value(value):
    if isinstance(value, str):
        for col, pattern in patterns.items():
            if pattern.match(value):
                if col == '姓名' and value in ['男', '女']:
                    continue
                return col, value
    return None, None

def process_row(row):
    result = {col: '' for col in ordered_columns}
    for value in row:
        col, val = classify_value(value)
        if col:
            result[col] = val
    return pd.Series(result)

input_csv = 'person_data.csv'
df = pd.read_csv(input_csv, header=None)

ordered_columns = ['编号', '用户名', '密码', '姓名', '性别', '出生日期', '身份证号', '手机号码']

new_df = df.apply(process_row, axis=1)

new_df = new_df.reindex(columns=ordered_columns)
new_df.fillna('', inplace=True)

output_csv = 'data.csv'
new_df.to_csv(output_csv, index=False)

print(f"数据已恢复并保存到 {output_csv}"

导出的csv有一丢丢小问题,但是检测能过就没修了


data-analy2

通过流量包提取出信息,先将信息整理正csv格式的文件

import csv
import json

def read_data_from_txt(txt_file):
    with open(txt_file, 'r', encoding='utf-8') as file:
        lines = file.readlines()
        data = [json.loads(line.strip()) for line in lines]
    return data

def write_data_to_csv(data, csv_file):
    with open(csv_file, mode='w', newline='', encoding='utf-8') as file:
        writer = csv.DictWriter(file, fieldnames=["username", "name", "sex", "birth", "idcard", "phone"])
        writer.writeheader()
        writer.writerows(data)

txt_file = 'data.txt'
csv_file = 'data.csv'

data = read_data_from_txt(txt_file)
write_data_to_csv(data, csv_file)

print(f'数据已保存到 {csv_file}')

再根据题目要求整理出需要的信息

import pandas as pd
import re

VALID_PREFIXES = {
    '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'
}

def validate_username(username):
    return bool(re.match(r'^[a-zA-Z0-9]+$', username))

def validate_name(name):
    return bool(re.match(r'^[\u4e00-\u9fff]+$', name))

def validate_sex(sex, idcard):
    if sex not in ['男', '女']:
        return False
    gender_digit = int(idcard[-2])
    expected_sex = '男' if gender_digit % 2 == 1 else '女'
    return sex == expected_sex

def validate_birth(birth, idcard):
    birth = str(birth)
    if not re.match(r'^\d{8}$', birth):
        return False
    idcard_birth = idcard[6:14]
    return birth == idcard_birth

def validate_idcard(idcard):
    if len(idcard) != 18 or not re.match(r'^\d{17}(\d|X)$', idcard):
        return False

    weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    check_code = '10X98765432'

    weighted_sum = sum(int(idcard[i]) * weights[i] for i in range(17))
    remainder = weighted_sum % 11
    expected_check_digit = check_code[remainder]

    return idcard[-1] == expected_check_digit

def validate_phone(phone):
    prefix = phone[:3]
    return prefix in VALID_PREFIXES

df = pd.read_csv('data.csv', skiprows=1, header=None, names=['username', 'name', 'sex', 'birth', 'idcard', 'phone'])

invalid_records = []

for index, row in df.iterrows():
    username = str(row['username']).strip()
    name = str(row['name']).strip()
    sex = str(row['sex']).strip()
    birth = str(row['birth']).strip()
    idcard = str(row['idcard']).strip()
    phone = str(row['phone']).strip()

    valid_username = validate_username(username)
    valid_name = validate_name(name)
    valid_sex = validate_sex(sex, idcard)
    valid_birth = validate_birth(birth, idcard)
    valid_idcard = validate_idcard(idcard)
    valid_phone = validate_phone(phone)

    if not (valid_username and valid_name and valid_sex and valid_birth and valid_idcard and valid_phone):
        invalid_records.append(row)

invalid_df = pd.DataFrame(invalid_records)
invalid_df.to_csv('wrong.csv', index=False)

data-analy3

解压后发现用户信息存储在error.log中,先对error.log进行提取处理

import csv

input_log_file = 'error.log'
output_csv_file = 'output.csv'

EXCLUDED_FIELDS = ['\xe6\x82\xa8\xe8\xbe\x93\xe5\x85\xa5\xe7\x9a\x84\xe7\x94\xa8\xe6\x88\xb7\xe5\x90\x8d\xe4\xb8\x8d\xe5\xad\x98\xe5\x9c\xa8\xef\xbc\x81']

def extract_username_password(lines):
    extracted_lines = []
    total_lines = len(lines)

    for i in range(total_lines):
        line = lines[i]
        if 'username' in line:
            start_index = line.find('username')
            extracted_line = line[start_index:].strip()

            seventh_line_index = i + 6
            if seventh_line_index < total_lines:
                seventh_line = lines[seventh_line_index].strip()

                if any(field in seventh_line for field in EXCLUDED_FIELDS):
                    continue

                keyword = "(data-HEAP): "
                if keyword in seventh_line:
                    try:
                        password_content = seventh_line.split(keyword, 1)[1].strip()
                        if ": " in password_content:
                            password_content = password_content.split(": ", 1)[1].strip()
                            password_content = password_content.replace('\\n', '')
                            extracted_line += '&password=' + password_content
                            extracted_lines.append(extracted_line)
                    except IndexError:
                        continue

    return extracted_lines

with open(input_log_file, 'r') as log_file:
    lines = log_file.readlines()

extracted_lines = extract_username_password(lines)

with open(output_csv_file, 'w', newline='') as csv_file:
    csv_writer = csv.writer(csv_file)
    for extracted_line in extracted_lines:
        csv_writer.writerow([extracted_line])

print(f"提取的内容已保存到 {output_csv_file}")

再针对name的url编码,以及特定列顺序进行整理

import csv
import urllib.parse

def process_data(input_file, output_file):
    data_list = []

    with open(input_file, 'r') as infile:
        for line in infile:
            params = line.strip().split('&')
            data_dict = {}
            for param in params:
                key, value = param.split('=')
                if key == 'name':
                    value = urllib.parse.unquote(value)
                data_dict[key] = value

            data_list.append({
                'username': data_dict.get('username', ''),
                'password': data_dict.get('password', ''),
                'name': data_dict.get('name', ''),
                'idcard': data_dict.get('idcard', ''),
                'phone': data_dict.get('phone', '')
            })

    with open(output_file, 'w', newline='', encoding='utf-8') as outfile:
        writer = csv.DictWriter(outfile, fieldnames=['username', 'password', 'name', 'idcard', 'phone'])
        writer.writeheader()
        writer.writerows(data_list)

input_file = 'output.csv'
output_file = 'sorted_data.csv'
process_data(input_file, output_file)

筛选出符合要求的数据

import pandas as pd
import re

VALID_PREFIXES = {
    '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'
}

def validate_username(username):
    return bool(re.match(r'^[a-zA-Z0-9]+$', username))

def validate_name(name):
    return bool(re.match(r'^[\u4e00-\u9fff]+$', name))

def validate_idcard(idcard):
    if len(idcard) != 18 or not re.match(r'^\d{17}(\d|X)$', idcard):
        return False

    weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    check_code = '10X98765432'

    weighted_sum = sum(int(idcard[i]) * weights[i] for i in range(17))
    remainder = weighted_sum % 11
    expected_check_digit = check_code[remainder]

    return idcard[-1] == expected_check_digit

def validate_phone(phone):
    prefix = phone[:3]
    return prefix in VALID_PREFIXES

df = pd.read_csv('sorted_data.csv', skiprows=1, header=None, names=['username', 'password','name', 'idcard', 'phone'])

invalid_records = []

for index, row in df.iterrows():
    username = str(row['username']).strip()
    name = str(row['name']).strip()
    idcard = str(row['idcard']).strip()
    phone = str(row['phone']).strip()

    valid_username = validate_username(username)
    valid_name = validate_name(name)
    valid_idcard = validate_idcard(idcard)
    valid_phone = validate_phone(phone)

    if (valid_username and valid_name and valid_idcard and valid_phone):
        invalid_records.append(row)

invalid_df = pd.DataFrame(invalid_records)
invalid_df.to_csv('right.csv', index=False)

最后进行脱敏处理

import csv
import hashlib

def md5_hash(text):
    return hashlib.md5(text.encode('utf-8')).hexdigest()

def mask_username(username):
    if len(username) <= 2:
        return username[0] + '*'
    return username[0] + '*' * (len(username) - 2) + username[-1]

def mask_password(password):
    return md5_hash(password)

def mask_name(name):
    if len(name) == 2:
        return name[0] + '*'
    elif len(name) >= 3:
        return name[0] + '*' * (len(name) - 2) + name[-1]
    return name

def mask_idcard(idcard):
    if len(idcard) == 18:
        return '*' * 6 + idcard[6:10] + '*' * 8
    return idcard

def mask_phone(phone):
    if len(phone) == 11:
        return phone[:3] + '****' + phone[-4:]
    return phone

def process_data(input_file, output_file):
    data_list = []

    with open(input_file, 'r', encoding='utf-8') as infile:
        reader = csv.DictReader(infile)
        for row in reader:
            processed_data = {
                'username': mask_username(row['username']),
                'password': mask_password(row['password']),
                'name': mask_name(row['name']),
                'idcard': mask_idcard(row['idcard']),
                'phone': mask_phone(row['phone'])
            }
            data_list.append(processed_data)

    with open(output_file, 'w', newline='', encoding='utf-8') as outfile:
        fieldnames = ['username', 'password', 'name', 'idcard', 'phone']
        writer = csv.DictWriter(outfile, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(data_list)

input_file = 'right.csv'
output_file = 'end.csv'
process_data(input_file, output_file)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇