一些比赛(1)

PolarCTF网络安全2025春季个人挑战赛

1.签到题

关注公众号发送flagflag

题目提示是双写,,呃呃谁知道在这里双写,出题人在群里被群嘲了

2.find

附件是xlsx文件,打开注意到有的格子加粗了,有的没有,官方wp说直接联想到二维码。。额可能老手的经验吧,然后ctrl+h替换加粗的格子为黑色,不过我不是这么做的

众所周知,xlsx和doc都是压缩包,改成zip,解压出sheet1.xml

审计代码,写脚本将sheetdata里提到的s=2的单元格填充成黑色

不知道为什么代码只能把格子涂成白色。。。改了一下,在 s=”2″ 的单元格填入数字 111

import xml.etree.ElementTree as ET
from openpyxl import load_workbook

# 读取 XML 文件
try:
    with open('cg1.txt', 'r', encoding='utf-8') as f:
        xml_string = f.read()
except FileNotFoundError:
    print("错误:找不到 sheet.xml 文件,请确保文件存在。")
    exit()

# 解析 XML
root = ET.fromstring(xml_string)

# 定义命名空间
ns = {'ns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'}

# 查找 <sheetData> 中的所有 <c> 元素并提取 r 和 s 属性
sheet_data = root.find('.//ns:sheetData', namespaces=ns)
if sheet_data is not None:
    cells = sheet_data.findall('.//ns:c', namespaces=ns)
    cell_data = [(cell.get('r'), cell.get('s')) for cell in cells if cell.get('r') and cell.get('s')]
else:
    print("错误:XML 中未找到 sheetData 元素。")
    exit()

# 打开 Excel 文件
try:
    wb = load_workbook('flag.xlsx')
except FileNotFoundError:
    print("错误:找不到 flag.xlsx 文件,请确保文件存在。")
    exit()

ws = wb.active  # 使用活动工作表

# 根据 s 属性填充单元格
for ref, s_value in cell_data:
    if s_value == "2":
        ws[ref].value = 111  # 在 s="2" 的单元格填入数字 111
    # s="1" 的单元格保持原样,不做操作

# 保存修改后的文件
wb.save('flag_modified.xlsx')
print("已完成修改,输出文件保存为 flag_modified.xlsx")

然后打开flag_modified.xlsx,要么用ctrl+h,要么用条件格式,总之换成黑色,调整宽高就得到二维码了,扫码得flag

参考:GKCTF 2021]excel 骚操作_excel 隐写 ctf-CSDN博客

——————————————————————————————————————————————

GHCTF新生赛

mybrave

参考:ZIP已知明文攻击深入利用 – FreeBuf网络安全行业门户

注意到压缩包使用的储存方法是Store,加密算法是ZipCrypto,加密的文件是png图片。

拿到秘钥后97d30dcc 173b15a8 6e0e7455解密,得到一张图片,010查看文件尾:

从54到结尾是base64,解码得到flag

知识点:

明文攻击并不需要得知其中完整的一个文件,知道至少 12 个字节的已知明文的话就可能可以使用明文攻击(其中8字节需要连续,需要知道已知字节的偏移)。

使用这类明文攻击要求压缩包的压缩方式是

ZipCrypto:Store或ZipCrypto:Deflate。

PNG图片的前 16 个字节基本是固定的。

——————————————————————————————————————————————

2025“红明谷”杯

1.异常行为溯源

附件是pcap,是访问日志,要找攻击者的攻击ip,题目说攻击者先低密度尝试然后再攻击

看到很多base64

考虑将数据包负载数据导出来解base64,得到JSON格式的数据保存到txt,发现还有一层base64

import base64
from scapy.all import rdpcap


def extract_packet_data(pcap_file):
    # 读取 PCAP 文件
    packets = rdpcap(pcap_file)
    data_list = []

    # 遍历每个数据包
    for packet in packets:
        # 检查数据包是否包含数据负载
        if packet.haslayer('Raw'):
            # 提取数据负载
            data = packet['Raw'].load
            data_list.append(data)

    return data_list


def base64_decode_and_save(data_list, output_file):
    with open(output_file, 'wb') as f:
        for data in data_list:
            try:
                # 尝试进行 Base64 解码
                decoded_data = base64.b64decode(data)
                # 将解码后的数据写入文件
                f.write(decoded_data)
                f.write(b'\r\n')
            except base64.binascii.Error:
                print(f"数据 {data} 不是有效的 Base64 编码,跳过。")


# 替换为你的 PCAP 文件路径
pcap_file = 'network_traffic.pcap'
# 替换为你想保存的输出文件路径
output_file = 'decoded1.txt'

# 提取数据包数据
packet_data = extract_packet_data(pcap_file)
# 进行 Base64 解码并保存到文件
base64_decode_and_save(packet_data, output_file)

再写个脚本解base64

import base64
import json
def process_file(input_file_path, output_file_path):
    with open(input_file_path, 'r', encoding='utf-8',errors='ignore') as input_file, open(output_file_path, 'w', encoding='utf-8') as output_file:
        for line in input_file:
            line = line.strip()  # 去除行首尾的空白字符(如换行符)
            try:
                # 解析 JSON 数据
                data = json.loads(line)
                # 获取 msg 字段的值
                msg = data.get('msg')
                if msg:
                    # 对 msg 进行 Base64 解码
                    decoded_msg = base64.b64decode(msg).decode('utf-8')
                    # 将处理后的数据重新组装为 JSON 格式并写入输出文件
                    data['msg'] = decoded_msg
                    output_file.write(json.dumps(data) + '\n')
                else:
                    output_file.write(line + '\n')  # 如果没有 msg 字段,原样写入
            except json.JSONDecodeError:
                output_file.write(line + '\n')  # 如果不是有效的 JSON 格式,原样写入
            except base64.binascii.Error:
                output_file.write(line + '\n')  # 如果 msg 不是有效的 Base64 编码,原样写入


# 替换为你的输入文件路径
input_file_path = 'decoded1.txt'
# 替换为你的输出文件路径
output_file_path = 'decoded2.txt'

process_file(input_file_path, output_file_path)

看到ip了,再统计一下出现次数

import json
from collections import defaultdict

def count_ips(input_file_path, output_file_path):
    ip_count = defaultdict(int)

    with open(input_file_path, 'r', encoding='utf-8') as input_file:
        for line in input_file:
            line = line.strip()
            try:
                # 解析 JSON 数据
                data = json.loads(line)
                # 获取 msg 字段的值
                msg = data.get('msg')
                if msg:
                    # 提取 IP 地址(假设 IP 是 msg 字段中第一个出现的格式为 x.x.x.x 的部分)
                    # 这里简单地按空格分割,取第一个元素作为 IP
                    ip = msg.split()[0]
                    ip_count[ip] += 1
            except json.JSONDecodeError:
                continue  # 跳过无效的 JSON 格式行

    # 筛选出出现次数大于等于 4 次的 IP,并按出现次数从大到小排序
    filtered_ip_count = {ip: count for ip, count in ip_count.items() if count >= 4}
    sorted_ip_count = sorted(filtered_ip_count.items(), key=lambda x: x[1], reverse=True)

    # 将统计结果写入输出文件
    with open(output_file_path, 'w', encoding='utf-8') as output_file:
        for ip, count in sorted_ip_count:
            output_file.write(f"{ip}: {count}\n")

    print("统计完成,结果已保存到", output_file_path)

# 替换为你的输入文件路径
input_file_path = 'decoded2.txt'
# 替换为你的输出文件路径
output_file_path = 'ip_count.txt'

count_ips(input_file_path, output_file_path)


———————————————————————————————————

2.数据校验

写脚本校验数据

import csv
import hashlib
import base64
import re
from ecdsa import VerifyingKey, BadSignatureError
import os

# 计算字符串的 32 位小写 MD5 值
def md5_hex(s):
    return hashlib.md5(s.encode()).hexdigest()

# 加载 ECDSA 公钥
def load_public_key(serial_number):
    pem_file = os.path.join("ecdsa-key", f"{serial_number}.pem")
    with open(pem_file, "rb") as f:
        pem_data = f.read()
    return VerifyingKey.from_pem(pem_data)

# 定义密码格式的正则表达式:只允许大写字母、小写字母和数字
password_pattern = re.compile(r'^[A-Za-z0-9]+$')

# 定义 IP 地址格式的正则表达式
ip_pattern = re.compile(r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$')

# 校验 IP 地址格式
def is_valid_ip(ip):
    match = ip_pattern.match(ip)
    if not match:
        return False
    for part in match.groups():
        num = int(part)
        if not (0 <= num <= 255):
            return False
    return True

# 用于存储不合规的序列号
invalid_serials = []

# 读取并处理 CSV 文件
with open('data.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        sn = row['Serial_Number']
        username = row['UserName']
        username_check = row['UserName_Check']
        password = row['Password']
        password_check = row['Password_Check']
        ip = row['IP']
        signature = row['Signature']

        # 校验 1:UserName 是否以 "User-" 开头
        username_valid = username.startswith('User-')

        # 校验 2:UserName 的 MD5 是否匹配
        username_md5_valid = md5_hex(username) == username_check

        # 校验 3:Password 是否只包含允许的字符
        password_valid = bool(password_pattern.match(password))

        # 校验 4:Password 的 MD5 是否匹配
        password_md5_valid = md5_hex(password) == password_check

        # 校验 5:IP 地址格式是否正确
        ip_valid = is_valid_ip(ip)

        # 校验 6:验证 ECDSA 签名
        signature_valid = False
        try:
            vk = load_public_key(sn)  # 加载对应公钥
            sig = base64.b64decode(signature)  # 解码签名
            vk.verify(sig, username.encode(), hashfunc=hashlib.sha1)  # 使用 SHA-1 哈希验证签名
            signature_valid = True
        except (base64.binascii.Error, BadSignatureError, Exception):
            signature_valid = False

        # 如果任一校验失败,记录该序列号
        if not (username_valid and username_md5_valid and password_valid and password_md5_valid and ip_valid and signature_valid):
            invalid_serials.append(sn)

# 将序列号转换为整数并按从小到大排序
invalid_serials = [int(sn) for sn in invalid_serials]
sorted_invalid = sorted(invalid_serials)  # 默认升序排序

# 用下划线连接排序后的序列号
joined = '_'.join(map(str, sorted_invalid))

# 计算连接字符串的 MD5 值
flag_md5 = md5_hex(joined)

# 打印用 _ 连接的不合规序列号
print("Invalid Serial Numbers (joined):", joined)

# 生成并输出 flag
flag = f'flag{{{flag_md5}}}'
print(flag)

3个ecdsa不对,2个ip不对

暂无评论

发送评论 编辑评论


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