2025年湾区杯网络安全大赛初赛

  1. 2025年湾区杯网络安全大赛初赛
    1. hardtest
    2. strangeApp
    3. minigame
    4. checkwebshell

2025年湾区杯网络安全大赛初赛

hardtest

IDA 打开反编译,逻辑很清晰,就是两块加密,第一个输入一个伪随机数没什么用

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  unsigned int seed; // eax
  unsigned __int64 v5; // rax
  void *v6; // rsp
  unsigned __int64 v7; // rax
  void *v8; // rsp
  __int64 encFlag1[4]; // [rsp+8h] [rbp-F0h] BYREF
  char v10; // [rsp+29h] [rbp-CFh] BYREF
  char v11; // [rsp+2Ah] [rbp-CEh]
  char v12; // [rsp+2Bh] [rbp-CDh]
  int j; // [rsp+2Ch] [rbp-CCh]
  int i; // [rsp+30h] [rbp-C8h]
  int flag_len; // [rsp+34h] [rbp-C4h]
  __int64 v16; // [rsp+38h] [rbp-C0h]
  __int64 *p_encFlag1; // [rsp+40h] [rbp-B8h]
  __int64 v18; // [rsp+48h] [rbp-B0h]
  __int64 *p_encFlag1_1; // [rsp+50h] [rbp-A8h]
  char flag[104]; // [rsp+58h] [rbp-A0h] BYREF
  unsigned __int64 v21; // [rsp+C0h] [rbp-38h]

  v21 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  seed = time(0LL);
  srand(seed);
  v12 = rand() % 255 + 1;
  printf("input your number(1-255): ");
  if ( __isoc99_scanf("%d", &v10) == 1 && v12 == v10 )
  {
    while ( getchar() != 10 )
      ;
    printf("flag: ");
    fgets(flag, 100, stdin);
    flag[strcspn(flag, "\n")] = 0;
    flag_len = strlen(flag);
    v16 = flag_len - 1LL;
    encFlag1[2] = flag_len;
    encFlag1[3] = 0LL;
    encFlag1[0] = flag_len;
    encFlag1[1] = 0LL;
    v5 = 16 * ((flag_len + 15LL) / 0x10uLL);
    while ( encFlag1 != (encFlag1 - (v5 & 0xFFFFFFFFFFFFF000LL)) )
      ;
    v6 = alloca(v5 & 0xFFF);
    if ( (v5 & 0xFFF) != 0 )
      *(&encFlag1[-1] + (v5 & 0xFFF)) = *(&encFlag1[-1] + (v5 & 0xFFF));
    p_encFlag1 = encFlag1;
    crypto1(flag, encFlag1);
    v18 = flag_len - 1LL;
    v7 = 16 * ((flag_len + 15LL) / 0x10uLL);
    while ( encFlag1 != (encFlag1 - (v7 & 0xFFFFFFFFFFFFF000LL)) )
      ;
    v8 = alloca(v7 & 0xFFF);
    if ( (v7 & 0xFFF) != 0 )
      *(&encFlag1[-1] + (v7 & 0xFFF)) = *(&encFlag1[-1] + (v7 & 0xFFF));
    p_encFlag1_1 = encFlag1;
    for ( i = 0; i < flag_len; ++i )
      *(p_encFlag1_1 + i) = crypto2(*(p_encFlag1 + i));
    v11 = 1;
    for ( j = 0; j < flag_len; ++j )
    {
      if ( *(p_encFlag1_1 + j) != enc[j] )
      {
        v11 = 0;
        break;
      }
    }
    if ( v11 )
      puts("right");
    return 0LL;
  }
  else
  {
    puts("error");
    return 1LL;
  }
}

image-20250908110301375

image-20250908110312387

直接抄下来,跑破就完事了

exp 如下

# Encrypted data from address 0x2120
encrypted_data = [
    0x97, 0xd5, 0x60, 0x43, 0xb4, 0x10, 0x43, 0x73, 0x0f, 0xda, 0x43, 0xcd,
    0xd3, 0xe8, 0x73, 0x4a, 0x94, 0xc3, 0xcd, 0x71, 0xbd, 0xdc, 0x97, 0x1a
]

Sbox = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01,
  0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
  0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4,
  0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
  0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7,
  0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
  0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E,
  0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
  0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
  0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
  0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
  0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
  0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C,
  0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
  0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A,
  0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
  0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3,
  0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
  0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A,
  0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
  0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E,
  0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
  0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9,
  0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
  0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99,
  0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]


def rotate_left(value, shift):
    return ((value << shift) | (value >> (8 - shift))) & 0xFF

def rotate_right(value, shift):
    return ((value >> shift) | (value << (8 - shift))) & 0xFF

def sub_1313(v4):
    index = 255
    v2 = 1
    while index:
        if (index & 1) != 0:
            v2 = v4 * v2 % 257
        v4 = v4 * v4 % 257
        index >>= 1
    return v2

enc1 = [0] * len(encrypted_data)

for i in range(len(encrypted_data)):
    for char in range(32, 128):
        temp = char
        enc1[i] = rotate_left(char, (i % 7) + 1)

        v1 = rotate_left(enc1[i] ^ 0x5A, 3)
        v3 = sub_1313((16 * ((3 * (v1 >> 4)) & 0xF)) | (5 * (v1 & 0xF)) & 0xF)
        if encrypted_data[i] == Sbox[rotate_right(v3, 2)]:
            print(chr(temp), end="")
            break# Encrypted data from address 0x2120
encrypted_data = [
    0x97, 0xd5, 0x60, 0x43, 0xb4, 0x10, 0x43, 0x73, 0x0f, 0xda, 0x43, 0xcd,
    0xd3, 0xe8, 0x73, 0x4a, 0x94, 0xc3, 0xcd, 0x71, 0xbd, 0xdc, 0x97, 0x1a
]

Sbox = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01,
  0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
  0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4,
  0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
  0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7,
  0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
  0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E,
  0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
  0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
  0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
  0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
  0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
  0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C,
  0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
  0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A,
  0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
  0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3,
  0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
  0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A,
  0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
  0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E,
  0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
  0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9,
  0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
  0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99,
  0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]


def rotate_left(value, shift):
    return ((value << shift) | (value >> (8 - shift))) & 0xFF

def rotate_right(value, shift):
    return ((value >> shift) | (value << (8 - shift))) & 0xFF

def sub_1313(v4):
    index = 255
    v2 = 1
    while index:
        if (index & 1) != 0:
            v2 = v4 * v2 % 257
        v4 = v4 * v4 % 257
        index >>= 1
    return v2

enc1 = [0] * len(encrypted_data)

for i in range(len(encrypted_data)):
    for char in range(32, 128):
        temp = char
        enc1[i] = rotate_left(char, (i % 7) + 1)

        v1 = rotate_left(enc1[i] ^ 0x5A, 3)
        v3 = sub_1313((16 * ((3 * (v1 >> 4)) & 0xF)) | (5 * (v1 & 0xF)) & 0xF)
        if encrypted_data[i] == Sbox[rotate_right(v3, 2)]:
            print(chr(temp), end="")
            break

flag{Bl@st1ng_1s_a_g00d_Way!!}

strangeApp

有点唐的,app 运行不起来,后来在公司试了不少测试机,并且还得插卡,Java 层有检测,然后跑起来,
image-20250908134916238

并用 frida-dexdump 脱壳,
image-20250908135016759

第一个就是关键的 dex 文件,JADX 打开,如果报 checksum 有问题,那么就在首选项把下面这个选项关掉,或者写个脚本修复一下
image-20250908135119346

关掉之后,就可以正常打开了

package com.swdd.strangeapp;

import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/* loaded from: C:\Users\16219\Desktop\strangeapp\classes.dex */
public class MainActivity extends AppCompatActivity {
    private static final byte[] TARGET = {118, 17, 7, 124, -99, 51, 23, -123, -78, 23, -53, 1, 42, 109, -77, 5, -87, 10, -77, 106, 78, 100, 123, -118, -47, 31, 19, 56, 115, -105, -11, -38, -18, -72, 12, 42, 17, 55, -121, -44, 119, -41, 87, 118, 95, -76, -84, 69};

    public static String a(String algo) {
        if (algo == null || algo.isEmpty()) {
            return algo;
        }
        char first = algo.charAt(0);
        char changed = (char) (first ^ 5);
        return changed + algo.substring(1);
    }

    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText flag = (EditText) findViewById(R.id.inputText);
        Button checkButton = (Button) findViewById(R.id.checkButton);
        checkButton.setOnClickListener(new View.OnClickListener() { // from class: com.swdd.strangeapp.MainActivity$$ExternalSyntheticLambda0
            @Override // android.view.View.OnClickListener
            public final void onClick(View view) {
                this.f$0.m160lambda$onCreate$0$comswddstrangeappMainActivity(flag, view);
            }
        });
    }

    /* renamed from: lambda$onCreate$0$com-swdd-strangeapp-MainActivity */
    /* synthetic */ void m160lambda$onCreate$0$comswddstrangeappMainActivity(EditText inputText, View v) {
        String input = inputText.getText().toString();
        try {
            byte[] encrypted = aa(input);
            if (compareBytes(encrypted, TARGET)) {
                showDialog("Good");
            } else {
                showDialog("NO");
            }
        } catch (Exception e) {
            showDialog("加密失败: " + e.getMessage());
        }
    }

    private byte[] aa(String input) throws Exception {
        Key secretKey = new SecretKeySpec("1234567891123456".getBytes(StandardCharsets.UTF_8), a("DES"));
        IvParameterSpec iv = new IvParameterSpec("1234567891123456".getBytes(StandardCharsets.UTF_8));
        Cipher cipher = Cipher.getInstance(a("DES/CBC/PKCS5Padding"));
        cipher.init(1, secretKey, iv);
        return cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
    }

    private boolean compareBytes(byte[] a, byte[] b) {
        if (a == null || b == null || a.length != b.length) {
            return false;
        }
        for (int i = 0; i < a.length; i++) {
            if (a[i] != b[i]) {
                return false;
            }
        }
        return true;
    }

    private void showDialog(String msg) {
        new AlertDialog.Builder(this).setMessage(msg).setPositiveButton("OK", (DialogInterface.OnClickListener) null).show();
    }
}

就是一个 AES 加密,DES 以字符串的形式传到 a 方法,然后首字母进行异或一下,就是 AES,赛博厨子一把梭
image-20250908135635406

minigame

小程序逆向,给的附件中没有文件后缀,加一下就可以了
然后使用这个项目解包,biggerstar/wedecode: 全自动化,微信小程序 wxapkg 包 源代码还原工具, 线上代码安全审计

image-20250908145753540

check逻辑就在 wasm 文件里,ghidra 装插件就可以直接反编译了
image-20250908145902993

就是一个 xor,直接一把梭
image-20250908145918957

后面补个 大括号
flag{fae0b27c451c728867a567e8c1bb4e53}

checkwebshell

进流量包搜索flag:

image-20250908145512982

看到709包有明显的flag脚本内容,直接追踪HTTP流并下载为1.php

<?php
class SM4 {
    const ENCRYPT = 1;
    private $sk;
    private static $FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
    private static $CK = [
        0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
        0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
        0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
        0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
        0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
        0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
        0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
        0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
    ];
    private static $SboxTable = [
        0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
        0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
        0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
        0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
        0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
        0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
        0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x0D, 0x2D, 0xEC,
        0x84, 0x9B, 0x1E, 0x87, 0xE0, 0x3E, 0xB5, 0x66, 0x48, 0x02, 0x6C, 0xBB, 0xBB, 0x32, 0x83, 0x27,
        0x9E, 0x01, 0x8D, 0x53, 0x9B, 0x64, 0x7B, 0x6B, 0x6A, 0x6C, 0xEC, 0xBB, 0xC4, 0x94, 0x3B, 0x0C,
        0x76, 0xD2, 0x09, 0xAA, 0x16, 0x15, 0x3D, 0x2D, 0x0A, 0xFD, 0xE4, 0xB7, 0x37, 0x63, 0x28, 0xDD,
        0x7C, 0xEA, 0x97, 0x8C, 0x6D, 0xC7, 0xF2, 0x3E, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7,
        0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x36, 0x24, 0x07, 0x82, 0xFA, 0x54, 0x5B, 0x40,
        0x8F, 0xED, 0x1F, 0xDA, 0x93, 0x80, 0xF9, 0x61, 0x1C, 0x70, 0xC3, 0x85, 0x95, 0xA9, 0x79, 0x08,
        0x46, 0x29, 0x02, 0x3B, 0x4D, 0x83, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x1A, 0x47, 0x5C, 0x0D, 0xEA,
        0x9E, 0xCB, 0x55, 0x20, 0x15, 0x8A, 0x9A, 0xCB, 0x43, 0x0C, 0xF0, 0x0B, 0x40, 0x58, 0x00, 0x8F,
        0xEB, 0xBE, 0x3D, 0xC2, 0x9F, 0x51, 0xFA, 0x13, 0x3B, 0x0D, 0x90, 0x5B, 0x6E, 0x45, 0x59, 0x33
    ];

    public function __construct($key) {
        $this->setKey($key);
    }
    public function setKey($key) {
        if (strlen($key) != 16) {
            throw new Exception("SM4");
        }
        $key = $this->strToIntArray($key);
        $k = array_merge($key, [0, 0, 0, 0]);
        for ($i = 0; $i < 4; $i++) {
            $k[$i] ^= self::$FK[$i];
        }
        for ($i = 0; $i < 32; $i++) {
            $k[$i + 4] = $k[$i] ^ $this->CKF($k[$i + 1], $k[$i + 2], $k[$i + 3], self::$CK[$i]);
            $this->sk[$i] = $k[$i + 4];
        }
    }
    public function encrypt($plaintext) {
        $len = strlen($plaintext);
        $padding = 16 - ($len % 16);
        $plaintext .= str_repeat(chr($padding), $padding);
        $ciphertext = '';
        for ($i = 0; $i < strlen($plaintext); $i += 16) {
            $block = substr($plaintext, $i, 16);
            $ciphertext .= $this->cryptBlock($block, self::ENCRYPT);
        }
        return $ciphertext;
    }
    private function cryptBlock($block, $mode) {
        $x = $this->strToIntArray($block);

        for ($i = 0; $i < 32; $i++) {
            $roundKey = $this->sk[$i];
            $x[4] = $x[0] ^ $this->F($x[1], $x[2], $x[3], $roundKey);
            array_shift($x);
        }
        $x = array_reverse($x);
        return $this->intArrayToStr($x);
    }
    private function F($x1, $x2, $x3, $rk) {
        return $this->T($x1 ^ $x2 ^ $x3 ^ $rk);
    }
    private function CKF($a, $b, $c, $ck) {
        return $a ^ $this->T($b ^ $c ^ $ck);
    }
    private function T($x) {
        return $this->L($this->S($x));
    }
    private function S($x) {
        $result = 0;
        for ($i = 0; $i < 4; $i++) {
            $byte = ($x >> (24 - $i * 8)) & 0xFF;
            $result |= self::$SboxTable[$byte] << (24 - $i * 8);
        }
        return $result;
    }
    private function L($x) {
        return $x ^ $this->rotl($x, 2) ^ $this->rotl($x, 10) ^ $this->rotl($x, 18) ^ $this->rotl($x, 24);
    }
    private function rotl($x, $n) {
        return (($x << $n) & 0xFFFFFFFF) | (($x >> (32 - $n)) & 0xFFFFFFFF);
    }
    private function strToIntArray($str) {
        $result = [];
        for ($i = 0; $i < 4; $i++) {
            $offset = $i * 4;
            $result[$i] =
                (ord($str[$offset]) << 24) |
                (ord($str[$offset + 1]) << 16) |
                (ord($str[$offset + 2]) << 8) |
                ord($str[$offset + 3]);
        }
        return $result;
    }
    private function intArrayToStr($array) {
        $str = '';
        foreach ($array as $int) {
            $str .= chr(($int >> 24) & 0xFF);
            $str .= chr(($int >> 16) & 0xFF);
            $str .= chr(($int >> 8) & 0xFF);
            $str .= chr($int & 0xFF);
        }
        return $str;
    }
}
try {
    $key = "a8a58b78f41eeb6a";
    $sm4 = new SM4($key);
    $plaintext = "flag";
    $ciphertext = $sm4->encrypt($plaintext);
    echo  base64_encode($ciphertext) ; //VCWBIdzfjm45EmYFWcqXX0VpQeZPeI6Qqyjsv31yuPTDC80lhFlaJY2R3TintdQu
} catch (Exception $e) {
    echo $e->getMessage() ;
}
?>

复制脚本给GPT,并且提示词:

帮我写一个这个解密脚本,从base64_encode($ciphertext)还原到plaintext,输出的base64是VCWBIdzfjm45EmYFWcqXX0VpQeZPeI6Qqyjsv31yuPTDC80lhFlaJY2R3TintdQu。直接给我逆向脚本就可以了

解密脚本:

<?php
class SM4 {
    const ENCRYPT = 1;
    const DECRYPT = 0;
    private $sk;
    private static $FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
    private static $CK = [
        0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
        0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
        0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
        0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
        0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
        0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
        0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
        0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
    ];
    private static $SboxTable = [
        0xD6,0x90,0xE9,0xFE,0xCC,0xE1,0x3D,0xB7,0x16,0xB6,0x14,0xC2,0x28,0xFB,0x2C,0x05,
        0x2B,0x67,0x9A,0x76,0x2A,0xBE,0x04,0xC3,0xAA,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
        0x9C,0x42,0x50,0xF4,0x91,0xEF,0x98,0x7A,0x33,0x54,0x0B,0x43,0xED,0xCF,0xAC,0x62,
        0xE4,0xB3,0x1C,0xA9,0xC9,0x08,0xE8,0x95,0x80,0xDF,0x94,0xFA,0x75,0x8F,0x3F,0xA6,
        0x47,0x07,0xA7,0xFC,0xF3,0x73,0x17,0xBA,0x83,0x59,0x3C,0x19,0xE6,0x85,0x4F,0xA8,
        0x68,0x6B,0x81,0xB2,0x71,0x64,0xDA,0x8B,0xF8,0xEB,0x0F,0x4B,0x70,0x56,0x9D,0x35,
        0x1E,0x24,0x0E,0x5E,0x63,0x58,0xD1,0xA2,0x25,0x22,0x7C,0x3B,0x01,0x0D,0x2D,0xEC,
        0x84,0x9B,0x1E,0x87,0xE0,0x3E,0xB5,0x66,0x48,0x02,0x6C,0xBB,0xBB,0x32,0x83,0x27,
        0x9E,0x01,0x8D,0x53,0x9B,0x64,0x7B,0x6B,0x6A,0x6C,0xEC,0xBB,0xC4,0x94,0x3B,0x0C,
        0x76,0xD2,0x09,0xAA,0x16,0x15,0x3D,0x2D,0x0A,0xFD,0xE4,0xB7,0x37,0x63,0x28,0xDD,
        0x7C,0xEA,0x97,0x8C,0x6D,0xC7,0xF2,0x3E,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,
        0x62,0x0E,0xAA,0x18,0xBE,0x1B,0xFC,0x56,0x36,0x24,0x07,0x82,0xFA,0x54,0x5B,0x40,
        0x8F,0xED,0x1F,0xDA,0x93,0x80,0xF9,0x61,0x1C,0x70,0xC3,0x85,0x95,0xA9,0x79,0x08,
        0x46,0x29,0x02,0x3B,0x4D,0x83,0x3A,0x0A,0x49,0x06,0x24,0x1A,0x47,0x5C,0x0D,0xEA,
        0x9E,0xCB,0x55,0x20,0x15,0x8A,0x9A,0xCB,0x43,0x0C,0xF0,0x0B,0x40,0x58,0x00,0x8F,
        0xEB,0xBE,0x3D,0xC2,0x9F,0x51,0xFA,0x13,0x3B,0x0D,0x90,0x5B,0x6E,0x45,0x59,0x33
    ];

    public function __construct($key) {
        $this->setKey($key);
    }
    public function setKey($key) {
        if (strlen($key) != 16) throw new Exception("SM4");
        $key = $this->strToIntArray($key);
        $k = array_merge($key, [0,0,0,0]);
        for ($i=0;$i<4;$i++) $k[$i] ^= self::$FK[$i];
        for ($i=0;$i<32;$i++) {
            $k[$i+4] = $k[$i] ^ $this->CKF($k[$i+1], $k[$i+2], $k[$i+3], self::$CK[$i]);
            $this->sk[$i] = $k[$i+4];
        }
    }
    public function decrypt($ciphertext) {
        $plaintext = '';
        for ($i=0; $i<strlen($ciphertext); $i+=16) {
            $block = substr($ciphertext, $i, 16);
            $plaintext .= $this->cryptBlock($block, self::DECRYPT);
        }
        // 去掉 PKCS#7 填充
        $pad = ord(substr($plaintext, -1));
        return substr($plaintext, 0, -$pad);
    }
    private function cryptBlock($block, $mode) {
        $x = $this->strToIntArray($block);
        for ($i=0; $i<32; $i++) {
            $rk = $this->sk[$mode==self::ENCRYPT ? $i : (31-$i)];
            $x[4] = $x[0] ^ $this->F($x[1], $x[2], $x[3], $rk);
            array_shift($x);
        }
        $x = array_reverse($x);
        return $this->intArrayToStr($x);
    }
    private function F($x1,$x2,$x3,$rk){return $this->T($x1^$x2^$x3^$rk);}
    private function CKF($a,$b,$c,$ck){return $a ^ $this->T($b^$c^$ck);}
    private function T($x){return $this->L($this->S($x));}
    private function S($x){
        $r=0;
        for($i=0;$i<4;$i++){
            $b=($x>>(24-$i*8))&0xFF;
            $r|=self::$SboxTable[$b]<<(24-$i*8);
        }
        return $r;
    }
    private function L($x){return $x ^ $this->rotl($x,2)^$this->rotl($x,10)^$this->rotl($x,18)^$this->rotl($x,24);}
    private function rotl($x,$n){return (($x<<$n)&0xFFFFFFFF)|(($x>>(32-$n))&0xFFFFFFFF);}
    private function strToIntArray($str){
        $res=[];
        for($i=0;$i<4;$i++){
            $o=$i*4;
            $res[$i]=(ord($str[$o])<<24)|(ord($str[$o+1])<<16)|(ord($str[$o+2])<<8)|ord($str[$o+3]);
        }
        return $res;
    }
    private function intArrayToStr($arr){
        $s='';
        foreach($arr as $int){
            $s.=chr(($int>>24)&0xFF).chr(($int>>16)&0xFF).chr(($int>>8)&0xFF).chr($int&0xFF);
        }
        return $s;
    }
}

try {
    $key = "a8a58b78f41eeb6a";
    $sm4 = new SM4($key);
    $cipher_b64 = "VCWBIdzfjm45EmYFWcqXX0VpQeZPeI6Qqyjsv31yuPTDC80lhFlaJY2R3TintdQu";
    $cipher_raw = base64_decode($cipher_b64);
    $plaintext = $sm4->decrypt($cipher_raw);
    echo $plaintext; // 输出: flag
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

获得flag:

image-20250908145659124


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1621925986@qq.com

💰

×

Help us with donation