StarrySky 发表于 2025-8-26 14:51

SekaiCTF 2025 Sekai Bank WriteUp

本帖最后由 StarrySky 于 2025-8-26 15:01 编辑

参加了一下国际比赛以下是我的解题思路
打开NP管理器反编译APK
@POST("flag")
    Call<String> getFlag(@Body FlagRequest flagRequest)
找到获取Flag的方法com.sekai.bank.network.ApiService.getFlag
转到FlagRequestpublic class FlagRequest {
    private boolean unmask_flag;

    public FlagRequest(boolean z) {
      this.unmask_flag = z;
    }

    public boolean getUnmaskFlag() {
      return this.unmask_flag;
    }

    public void setUnmaskFlag(boolean z) {
      this.unmask_flag = z;
    }
}
从这里分析的值,我们可以伪造一个POST请求来得到Flag
抓包先登录,通过ProxyPin抓包看看请求体发现有一个X-Signature继续打开NP管理器搜索X-Signature字符串public Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      try {
            chain = chain.proceed(request.newBuilder().header("X-Signature", generateSignature(request)).build());
            return chain;
      } catch (Exception e) {
            Log.e("SekaiBank-API", "Failed to generate signature: " + e.getMessage());
            return chain.proceed(request);
      }
    }

可以看到一个generateSignature方法,定位进去看看private String generateSignature(Request request) throws IOException, GeneralSecurityException {
      Throwable e;
      String str = request.method() + "/api".concat(getEndpointPath(request)) + getRequestBodyAsString(request);
      SekaiApplication instance = SekaiApplication.getInstance();
      PackageManager packageManager = instance.getPackageManager();
      String packageName = instance.getPackageName();
      try {
            Signature[] apkContentsSigners;
            if (VERSION.SDK_INT >= 28) {
                PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 134217728);
                SigningInfo signingInfo = packageInfo.signingInfo;
                apkContentsSigners = signingInfo != null ? signingInfo.hasMultipleSigners() ? signingInfo.getApkContentsSigners() : signingInfo.getSigningCertificateHistory() : packageInfo.signatures;
            } else {
                apkContentsSigners = packageManager.getPackageInfo(packageName, 64).signatures;
            }
            if (apkContentsSigners == null || apkContentsSigners.length <= 0) {
                throw new GeneralSecurityException("No app signature found");
            }
            MessageDigest instance2 = MessageDigest.getInstance("SHA-256");
            for (Signature toByteArray : apkContentsSigners) {
                instance2.update(toByteArray.toByteArray());
            }
            return calculateHMAC(str, instance2.digest());
      } catch (NameNotFoundException e2) {
            e = e2;
            throw new GeneralSecurityException("Unable to extract app signature", e);
      } catch (NoSuchAlgorithmException e3) {
            e = e3;
            throw new GeneralSecurityException("Unable to extract app signature", e);
      }
    }

可以看到str字符串,是由getEndpointPath和getRequestBodyAsString拼接得到的String str = request.method() + "/api".concat(getEndpointPath(request)) + getRequestBodyAsString(request); SekaiApplication instance = SekaiApplication.getInstance();分析完开始HOOK这里的HOOK我采用的朋友开发的LuahookcalculateHMAC方法看看第一个参数str



参数是POST/api/auth/login{"password":"114514","username":"114514"}那就简单了,直接HookgetEndpointPath和getRequestBodyAsString方法hook("com.sekai.bank.network.ApiClient$SignatureInterceptor",
lpparam.classLoader,
"getEndpointPath",
"okhttp3.Request",
function(it)

end,
function(it)
it.result="/flag"
end)

hook("com.sekai.bank.network.ApiClient$SignatureInterceptor",
lpparam.classLoader,
"getRequestBodyAsString",
"okhttp3.Request",
function(it)
end,
function(it)
it.result=[[{"unmask_flag":true}]]
end)

de]接着我们直接登录,然后他就会自动计算X-Signature,然后拿ProxyPin重写请求就行了
拿到flag**** Hidden Message *****









lies 发表于 2025-8-26 16:07

谢谢分享!

JuStkK 发表于 2025-8-26 17:55

看看大哥的思路

tingwei3 发表于 2025-8-26 22:54

支持大佬的分享

52bug 发表于 2025-8-27 00:32

{:6_219:}学习

美好映像 发表于 2025-8-29 07:13

进来学习时大佬原创

提笔只两行 发表于 2025-9-7 09:13

过来看看

高高小舟 发表于 2025-9-7 11:23

学习一下
页: [1]
查看完整版本: SekaiCTF 2025 Sekai Bank WriteUp