【2023春节】解题领红包 WP

查看 140|回复 10
作者:十一七   
【2023春节】解题领红包
Windows 初级题 1/23
cpp逆向,简单移位
bytearray([i >> 2 for i in [0x00000198, 0x000001B0, 0x00000184, 0x0000019C, 0x000001EC, 0x000000D4, 0x000000C8, 0x00000140, 0x000001BC, 0x00000128, 0x000001A4, 0x00000194, 0x000000C8, 0x000000C0, 0x000000C8, 0x000000CC, 0x00000120, 0x00000184, 0x000001C0, 0x000001C0, 0x000001E4, 0x00000138, 0x00000194, 0x000001DC, 0x00000164, 0x00000194, 0x00000184, 0x000001C8, 0x000001F4]])
Android  初级题 1/24
Java逆向,简单位操作
bytearray([i - 2 for i in b"hnci}|jwfclkczkppkcpmwckng\x7f"])
Android  初级题 1/25
frida hook
objection -g com.zj.wuaipojie2023_1 explore
android hooking watch class_method com.zj.wuaipojie2023_1.C.cipher --dump-return


image-20230125130126360.png (201.38 KB, 下载次数: 0)
下载附件
2023-2-5 09:47 上传

Windows  中级题 1/26
魔改upx,oep定位,dump&fix,关闭ASLR。
MFC程序,SEH异常处理,调用结构类似以下:
void DivException(int a1, int a2, int* a3) {
    __try {
        *a3 = a1 / a2;
    }
    __except (GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) { }
}
void DbgBrk() {
    __try {
        DebugBreak();
    }
    __except (GetExceptionCode() == EXCEPTION_BREAKPOINT) {
        getUSER32BaseAddr(); // +0x2410
    }
}
int entry() {
    __try {
        RaiseException(1u, 0, 0, 0);
    }
    __except (filterLoadApiTable() /* +0x2DC0 */) {
        DbgBrk(); // +0x2FC0
    }
    __finally {
        DivException(1, 0, 0); // +0x2D80
    }
    divZero(); // +0x2FF0
    return 0;
}
这里注意到了divZero并没有对应注册SEH。
而是在_tmainCRTStartup初始化程序时,调用SetUnhandledExceptionFilter注册了UEH,具体位置在偏移0x100B上。
同时,由于SetUnhandledExceptionFilter内部调用了ntdll!NtQueryInformationProcess检测调试器,在这里结合divZero实现了反调试。
将call divZero patch 为call TopLevelExceptionFilter 完成反反调试
流程分析中的几个点:
通过PEB获取USER32.dll基址,进而拿到函数表。
API表位于偏移0x17C90


image-20230126172208874.png (793.02 KB, 下载次数: 0)
下载附件
2023-2-5 09:47 上传

存储解密字符串表指针位于0x17D30,内容为宽字符形式


image-20230126172450919.png (533.03 KB, 下载次数: 0)
下载附件
2023-2-5 09:47 上传

粗略分析,疑似check两处:0x2110和0x2A50
tea算法两处
  • tea encrypt 0x1D70
  • tea decrypt 0x26E0

    懒虫方案
    猜能省大量时间(
    frida hook俩函数,修改返回值 & 打表
    发现只有修改0x2A50函数返回值为4时,弹出Success,逻辑部分简单描述如下
    [ol]

  • 十六进制转字符数组

  • tea解密

  • 与明文对比
    [/ol]
    调试拿到明文


    image-20230126172026214.png (240.09 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:48 上传

    frida hook拿到k和delta
    const addr = Module.findBaseAddress("【2023春节】解题领红包之五_dump_SCY.exe");
    function buf2hex(buffer) {
        return [...new Uint8Array(buffer)]
            .map(x => '0x'+x.toString(16).padStart(2, '0').toUpperCase())
            .join(' ');
    }
    Interceptor.attach(addr.add(0x26e0), {
        onEnter: function (args) {
            console.log("[+] onEnter");
            console.log("[+]     v: " + buf2hex(args[0].readByteArray(8)));
            console.log("[+]     k: " + buf2hex(args[1].readByteArray(16)));
            console.log("[+] delta: " + args[2]);
            console.log("[+]   sum: " + args[3]);
        },
        onLeave: function (retval) {
            console.log("[+] retval: " + retval);
        }
    });
    跑一遍标准tea,转成十六进制拿到flag
    void tea_encrypt(uint32_t*a1, uint32_t *a2, uint32_t a3, uint32_t a4)
    {
      unsigned int v5; // [rsp+0h] [rbp-28h]
      unsigned int v6; // [rsp+4h] [rbp-24h]
      unsigned int i; // [rsp+8h] [rbp-20h]
      v5 = *a1;
      v6 = a1[1];
      for ( i = 0; i > 5)) ^ (a4 + v6) ^ (*a2 + 16 * v6);
        v6 += (a2[3] + (v5 >> 5)) ^ (a4 + v5) ^ (a2[2] + 16 * v5);
      }
      *a1 = v5;
      a1[1] = v6;
    }
    int main() {
        char inp[] = "flag{!!!_HAPPY_NEW_YEAR_2023!!!}";
        auto *v = (uint32_t*) inp;
        uint32_t k[4] = {0x8C7BD7F8, 0x18F7AFF0, 0xA57387E8, 0x31EF5FE0};
        uint32_t delta = 0x8c7bd7f7;
        uint32_t sum = 0x8f7afee0;
        for (int i = 0; i
    正常方案
    程序调用DialogBoxParamW创建对话框,0x11D0为DialogFunc
    WM_INITDIALOG初始化窗口
    单击按钮,首先执行WM_CREATE处内容


    image-20230127024220104.png (227.12 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:49 上传

    分析0x2110部分看似进行了tea encrypt并进行了check,实际上只是混淆视听,其真正的用途是传递sum
    而后调用PostMessageW执行WM_CUT部分,此时lParam即为sum


    image-20230127020542360.png (442.8 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:50 上传

    进入default分支,v6恒为0,能看到真正的check在0x2A50处


    image-20230127025355079.png (376.99 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:50 上传

    check算法主要是根据uid,计算delta,以及k,而后tea解密,大致算法如下
    v11 = 0x11111111;
    for ( i = 0; i = 0; delta = 2 * delta + 9 )
        ;
      for ( n = 0; n
    附keygen
    from ctypes import c_int32
    import struct
    def calc_delta(uid):
        i = c_int32(uid - 1)
        while i.value >= 0:
            i.value = 2 * i.value + 9
        return i.value & 0xffffffff
    def calc_key(delta):
        k = [0] * 4
        for i in range(4):
            k = (i + 1) * (delta + 1)
            k &= 0xffffffff
        return k
    def tea_encrypt(v, k, delta):
        v0, v1 = v
        k0, k1, k2, k3 = k
        sums = 0
        for i in range(32):
            sums += delta
            sums &= 0xffffffff
            v0 += ((v1 > 5) + k1)
            v0 &= 0xffffffff
            v1 += ((v0 > 5) + k3)
            v1 &= 0xffffffff
        return v0, v1
    def keygen(uid):
        FLAG = struct.unpack('
    Android 中级题 1/27
    ndk逆向,java层没啥用
    流程完全没有串起来,需要脑洞
    根据符号猜作者意图:找到RealKey解密assets/aes.png
    算法为AES-128-ECB PKSC7 padding
    JNI注册了函数get_RealKey,结尾调用的strcmp上有个不明显的hint:thisiskey,其意为执行getRealKey的算法得到RealKey
    k = b'|wfkuqokj4548366'
    xmmword_3030 = [0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE, 0xFB, 0xFE]
    v5 = [(i + j) & 0xff for i, j in zip(k, xmmword_3030)]
    real = bytearray(v5)
    print(real) # bytearray(b'wuaipojie2023114')
    AES解出图片
    import base64
    from Crypto.Cipher import AES
    def pad(s):
        return s + (16 - len(s) % 16) * chr(16 - len(s) % 16)
    def unpad(s):
        return s[:-ord(s[len(s) - 1:])]
    cipherText = open('com.zj.wuaipojie2023_2/assets/aes.png', 'rb').read()
    cipherText = base64.urlsafe_b64decode(cipherText)
    ctx = AES.new(key=b'wuaipojie2023114', mode=AES.MODE_ECB)
    dec = unpad(ctx.decrypt(cipherText))
    pic = bytearray.fromhex(dec.decode('utf-8'))
    with open('aes.dec.png', 'wb') as f:
        f.write(pic)
    然后misc行为:文件末尾塞了一个png图片


    image-20230127181701066.png (492.85 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:50 上传

    扫码得到flag
    Android 高级题 1/28
    ndk逆向,JNI动态注册checkSn,ollvm sub fla bcf拉满,流程混淆的稀碎
    我选择摆烂unidbg trace
    贴个片段
        public static void main(String[] args) {
            emulator = AndroidEmulatorBuilder.for64Bit().setRootDir(new File("target/rootfs")).setProcessName("com.zj.wuaipojie2023_2").build();
            Memory memory = emulator.getMemory();
            memory.setLibraryResolver(new AndroidResolver(23));
            Logger.getLogger("com.github.unidbg.linux.ARM32SyscallHandler").setLevel(Level.DEBUG);
            Logger.getLogger("com.github.unidbg.unix.UnixSyscallHandler").setLevel(Level.DEBUG);
            Logger.getLogger("com.github.unidbg.AbstractEmulator").setLevel(Level.DEBUG);
            Logger.getLogger("com.github.unidbg.linux.android.dvm.DalvikVM").setLevel(Level.DEBUG);
            Logger.getLogger("com.github.unidbg.linux.android.dvm.BaseVM").setLevel(Level.DEBUG);
            Logger.getLogger("com.github.unidbg.linux.android.dvm").setLevel(Level.DEBUG);
            vm = emulator.createDalvikVM();
            vm.setVerbose(true);
            new AndroidModule(emulator, vm).register(memory);
            DalvikModule dm = vm.loadLibrary(new File("lib52pojie.so"), false);
            vm.setJni(new MyJni());
            dm.callJNI_OnLoad(emulator);
            module = dm.getModule();
    //        PrintStream printStream = null;
    //        try {
    //            printStream = new PrintStream(new FileOutputStream("log.txt"));
    //        } catch (FileNotFoundException e) {
    //            throw new RuntimeException(e);
    //        }
    //
    //        emulator.traceCode().setRedirect(printStream);
            String uid = "01150835";
            String flag = "MWYxODIxOThmYWFmM2ZlYjYxM2Q5ZDVlZTExMzg4MTM=";
            List list = new ArrayList();
            list.add(vm.getJNIEnv());
            list.add(0);
            list.add(vm.addLocalObject(new StringObject(vm, uid)));
            list.add(vm.addLocalObject(new StringObject(vm, flag)));
            Debugger dbg = emulator.attach();
    //        dbg.addBreakPoint(0x4001064c);
            Number number = module.callFunction(emulator, 0xe830, list.toArray());
            System.out.println("result: " + number.intValue());
        }
    分析下jni注册,checkSn偏移E830


    image-20230129023347169.png (166.96 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:50 上传

    调用一次checkSn大概86w行,ida+trace日志+unidbg调试分析
    改变同一位置字节、不同位置字节
    对比两者trace差异,简单贴几个关键偏移
    0x184B8 -> md5_transform
    0x1B32C -> 0x17834 -> md5(const uint8_t* uid)
    0x1ECD8 -> zuc_F(pzuc_context context)
    0x1D454 -> zuc_init(pzuc_context context, const uint8_t* key, const uint8_t* iv)
    0x10668 -> md5_hexdigests(uid) xor zuc_encrypt(base64_decode(flag)) == 0
    md5、base64为标准算法
    zuc算法为流加密,参考代码 https://github.com/zhiyuan-lin/zuc/blob/master/c/zuc.c
    key与时间戳相关,iv来自偏移4D22B,具体组成如下
    char key[16]={};
    char iv[16]={};
    char buf[6]={};
    int t = timestamp/20000000; // 0x185f69b0a37 / 20000000 == 83743
    sprintf(buf, "%d", t);
    memcpy(key, 0x4D220, 0xA); // 0x3d,0x99,0x40,0x0e,0x05,0x50,0x7c,0x81,0x2e,0x3f
    memcpy(key+0xA, buf, 0x5); // 0x38,0x33,0x37,0x34,0x35,0x00
    memcpy(iv, 0x4D22B, 0x5); // 0xf2,0x3d,0xa0,0x96,0x02,0x2b,0x26,0x63,0xe1,0x5f,0xc1,0x28,0x6a,0x33,0x70,0x25

    流加密,即crypt(crypt(inp)) == inp

    直接偷懒
    uid、flag输入格式
    uid # 8位,不足补0
    flag = base64.b64encode(md5(uid).hexdigest()) # 44 bytes after base64 encode
    unidbg跑起来dump
            final byte[] res = new byte[32];
        final int[] i = {0};
        dbg.addBreakPoint(0x40010668, new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator emulator, long address) {
                res[i[0]++] = (byte) emulator.getContext().getLongByReg(Arm64Const.UC_ARM64_REG_X15);
                return true;
            }
        });
    然后转成base64,输回去就成了


    1674931854061-1674932177792-6.jpg (383.12 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:51 上传

    至于keygen,分析这一坨太费时间,略
    Web 初/中/高
    应该改名misc+web+古典crypto套娃题
    直接挂个草稿吧(不完全)
    2023challenge.52pojie.cn adg dns重定向 52pojie.cn


    image-20230201172951629.png (128.76 KB, 下载次数: 0)
    下载附件
    2023-2-5 09:51 上传

    flag1
    放视频
    flag1{52pojiehappynewyear}
    ----------------------------------------------------------------------------
    flag2
    视频二维码
    https://2023challenge.52pojie.cn/?flag=flag2{878a48f2}
    flag2{878a48f2}
    ----------------------------------------------------------------------------
    flag3
    视频右下角水印 iodj3(06i95dig) 凯撒 offset 3
    flag3(06f95afd)
    ----------------------------------------------------------------------------
    ----------------------------------------------------------------------------
    flag5
    morse code
    flag5{eait}
    ----------------------------------------------------------------------------
    flag6
    flag6{590124}
    视频开头 拨号盘
    https://blog.xhyeax.com/2019/02/03/friend-ctf/
    ---------------------------------------------------------------------------
    flag7
    网页 二进制
    flag7{5d06be63}
    ----------------------------------------------------------------------------
    flag8
    音频频谱
    flag8{c394d7}
    ----------------------------------------------------------------------------
    flag9
    倒着放音频
    flag9{21c5f8}
    ----------------------------------------------------------------------------
    ----------------------------------------------------------------------------
    flag11
    网页下方brainfuck
    flag11{63418de7}
    ----------------------------------------------------------------------------
    flagA
    curl "https://2023challenge.52pojie.cn/?uid=1150835" \
      -H "X-52PoJie-Uid: 1150835" \
      -v
    ----------------------------------------------------------------------------
    flagB
    dns解析
    dig 2023challenge.52pojie.cn @8.8.8.8 -t txt
    2023challenge.52pojie.cn. 600        IN        TXT        "\"_52pojie_2023_happy_new_year=flagB{substr(md5(uid+\\\"_happy_new_year_\\\"+floor(timestamp/600)),0,8)}\""
    ----------------------------------------------------------------------------
    flagC
    jwt伪造
    eyJ1aWQiOiIxMTUwODM1Iiwicm9sZSI6ImFkbWluIn0
    curl 'https://2023challenge.52pojie.cn/home' \
      -H 'Cookie: 2023_challenge_jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiIxMTUwODM1Iiwicm9sZSI6ImFkbWluIn0.U2Yd0PGhcJq_D0QAicnA8xTb1menooqWBaLCt65y1Cw' \
      -v
    END
    最后吐槽一下,其他不说,Android能不能换个花样,去年也是ollvm

    难度不够ollvm来凑(

    Refer
  • https://www.anquanke.com/post/id/208404
  • https://learn.microsoft.com/en-us/windows/win32/api/
  • https://github.com/zhiyuan-lin/zuc
  • https://blog.xhyeax.com/2019/02/03/friend-ctf/

    下载次数, 下载附件

  • 十一七
    OP
      


    侃遍天下无二人 发表于 2023-2-6 10:54
    一看到大量的trace就头疼,不知道从哪找起差异,大佬可以录个视频演示下吗,安卓高级题这里是不是相当于做 ...

    视频大概率是不会录的(
    简单写几个分析trace的技巧:
      控制变量法,trace两遍对比差异
      跟踪输入数据在寄存器/堆、栈之间的传递
      指令运行、函数调用的次数
    这里并不是爆破,只是将zuc加密后结果作为输入又执行了一遍zuc加密,得到的就是flag(流加密的特性)通俗的解释就是负负得正。
    Light紫星   

    安卓高级题太难了,大佬厉害
    kobeLau   

    过来支持一下
    lvbuqing   

    ?????2023啥时候出的春节红包题啊!根本没有刷到啊,我丢啊,从除夕就开始关注的,现在直接出的答案?
    qcz00622   

    太屌了,一个没看懂
    nitian0963   

    太厉害了,新手学习中....
    webfly   

    基本上看不懂,膜拜
    xuebinboy   

    只能膜拜,默默学习吧
    jackyyue_cn   

    初级还能搞搞 中高级还得不断学习
    您需要登录后才可以回帖 登录 | 立即注册