前言

Tnze yyds,距离比赛结束还有 30 秒不到的时间解出了最后一道题
逆向的那道 arm64 Linux Kernel 题有师傅解出来的话请告诉我,不甚感激。

CTF

关注公众号“云演”,有手就行

EZ_Checkin

直接打开什么都没有,通过 Dirsearch 扫出来一个 index.php~,访问查看代码:

Almighty 师傅说除了 param2 和 param3 是双 MD5 碰撞之外,其余所有的均可以数组绕过。

所以构造 Payload 如下:
http://2dd44ae4.yunyansec.com/index.php?param1=0e251288019&param2=aabg7XSs&param3=iv2Cn&param4[]=a&param5[]=b

由于平台关闭了忘记截图,所以没有 Flag 截图了

Give me Num

nc 上去,测试了一下发现:

所以你可以随便输入 2536 个数,第二轮的时候把第一次给的数输进去就行。

用 pwntools 或者别的东西来写,只要满足第二轮输入的数字和第一次相同即可。这里安利一下稻子同学的 Pwntools Golang 版本:

package main

import (
    "fmt"
    "sync"
    "github.com/Tnze/pwn/v2"
)

func main() {
    p := pwn.Remote("129.226.4.186:7000")
    for i := 0; i < 17; i++ {
        p.ReadLine()
    }
    var table sync.Map
    var num int
    go func() {
        var guess int
        for i := 0; i < 2538; i++ {
            if v, ok := table.Load(i % 2536); ok {
                guess = v.(int)
            } else {
                guess = 0
            }
            _, err := p.Writer.Write([]byte(fmt.Sprintf("%d\n", guess)))
            if err != nil {
                fmt.Printf("Write data error: %v\n", err)
                return
            }
        }
    }()
    for i := 0; ; i++ {
        str, err := p.BufReader.ReadBytes('\n')
        if err != nil {
            fmt.Printf("ReadLine error: %v\n", err)
            fmt.Println(string(str))
            return
        }
        if _, err := fmt.Sscanf(string(str), "please enter num:%d", &num); err != nil {
            fmt.Println(str, err)
            break
        }
        if num < 500 {
            fmt.Printf("[%06d] %d\n", i, num)
        }
        if num == 4 {
            break
        }
        table.Store(i%2536, num)
    }
    fmt.Println("start interactive mode")
    p.Interactive()
}

执行完毕之后,对方返回了一个 RSA 的问题:

cipher1=pow(m,e,n):
0x10652cdfaa84742a301254ad38685682db0723ead4a9696a391186333d2e18f1b1205385f3658c27818bcfb0bdb8b84f17b26ef267f93d08b9eef9791a7ce8ad98d4d0393b0df6696d9568caa712e5a2645ed74f758b378fd7f6f37e70248e46cd814d8b03da3287cea21a3f42a371adb565L
cipher2=pow(m+1,e,n):
0x10652cdfaa84742a301254ad38685682db0723ead4a9696a391186333d2e18f1b1205385f3660717240e2fd0a5b4a66b71329cab62c2cf4d5f3a706aeefd13c05993ce41f119bff6039327bd36bee9a01181bd366d4118ce3d8ce118dc84a3eb7e5497fa611a2c7c4811fa835faf4c1925f8L
N:
86556158206673268412999351099391537818771292689555971866425305353742222745803154706209551717854578357455003375422313884956087927511235887012764481212450066610311227919903117972157504258058310749942009463761100652057157343578534551749795505001379235681472026344861535746921918227188061252683055822118537612609
E: 3

典型的小公钥指数攻击,C 直接开 3 次幂就是明文,Payload 如下:

N = 86556158206673268412999351099391537818771292689555971866425305353742222745803154706209551717854578357455003375422313884956087927511235887012764481212450066610311227919903117972157504258058310749942009463761100652057157343578534551749795505001379235681472026344861535746921918227188061252683055822118537612
c2 = 0x10652cdfaa84742a301254ad38685682db0723ead4a9696a391186333d2e18f1b1205385f3660717240e2fd0a5b4a66b71329cab62c2cf4d5f3a706aeefd13c05993ce41f119bff6039327bd36bee9a01181bd366d4118ce3d8ce118dc84a3eb7e5497fa611a2c7c4811fa835faf4c1925f8
c1 = 0x10652cdfaa84742a301254ad38685682db0723ead4a9696a391186333d2e18f1b1205385f3658c27818bcfb0bdb8b84f17b26ef267f93d08b9eef9791a7ce8ad98d4d0393b0df6696d9568caa712e5a2645ed74f758b378fd7f6f37e70248e46cd814d8b03da3287cea21a3f42a371adb565
e = 3

import gmpy
import libnum

i = 0
while 1:
    if (gmpy.root(c1 + i * N, 3)[1] == 1):
        print(gmpy.root(c1 + i * N, 3))
        break
    i = i + 1

print(libnum.n2s(13040004482825757166149747768424026334639325666603913967492907164094589547731068248503236733))

得到 Flag:

EzCrack

APK 解压后,dex 文件丢进 JEB 反编译得到:

decrypt 函数都给你写好了,那就直接用呗:

package online.jdao;

import java.security.Key;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Main {
    private static String KEY = "QWERTYUIOPWE1235QWERTYUIOPWE1235";
    private static String SUCCESS_KEY = "5bCP5LyZLOW+iOS8mOengOWViu+8jOasoui/juadpeWbm+WPtuiNieWuieWFqOW3peS9nA==";

    public static String calculate(String arg6) {
        int v0 = arg6.length();
        char[] v1 = new char[v0];
        int v2;
        for (v2 = 0; v2 < v0; ++v2) {
            int v3 = v2 % 2 == 0 ? arg6.charAt(v2) ^ v2 + 37 : arg6.charAt(v2);
            v1[v2] = ((char) v3);
        }
        return new String(v1);
    }
    public static byte[] decrypt(String arg4, byte[] arg5) throws Exception {
        SecretKeySpec v0 = new SecretKeySpec(new SecretKeySpec(arg4.getBytes(), "AES").getEncoded(), "AES");
        Cipher v4 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v4.init(2, ((Key) v0), new IvParameterSpec("seclover12343234".getBytes()));
        return v4.doFinal(arg5);
    }
    public static byte[] encrypt(String arg4, byte[] arg5) throws Exception {
        SecretKeySpec v0 = new SecretKeySpec(new SecretKeySpec(arg4.getBytes(), "AES").getEncoded(), "AES");
        Cipher v4 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v4.init(1, ((Key) v0), new IvParameterSpec("seclover12343234".getBytes()));
        return v4.doFinal(arg5);
    }
    public static void main(String[] args) throws Exception {
        byte[] result = decrypt(KEY, Base64.getDecoder().decode("lLuyQzc5qO740MJhff6vF/dnvBHm0Bod2GPNRBknn/Y="));
        System.out.println(calculate(new String(result)));
    }
}