第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解

admin 2025年4月29日16:45:58评论0 views字数 6613阅读22分2秒阅读模式

经过激烈角逐,第二届 "长城杯" 信息安全铁人三项赛(防护赛)总决赛圆满落幕!作为行业参与者,我们禾信智安的奉天安全团队在赛后第一时间整理并公布逆向题解题思路!

Time_Capsule

这个ELF文件后缀被改成了.zip,先删除后缀然后使用ExePeinfo查壳发现存在UPX壳

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解尝试用UPX脱壳工具脱壳发现提示没有检测到有UPX壳,这是因为区段名被修改了

第二届“长城杯”信息安全铁人三项赛(防护赛)总决赛-逆向题解我们可以看到原本的UPX被替换成了QQQ,我们将所有的QQQ替换成UPX

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解可以发现此时已经脱壳成功了第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解

放进IDA里分析一下由于程序没有符号我大致分析了一下代码恢复了一些函数符号如下,首先进行反调试如果检测到调试直接退出否则提示用户输入并且判断长度是否为24以及flag开头是不是flag{,最后我们的输入和32、37循环xor后进行比较

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解EXP

enc = [ 0x46, 0x49, 0x41, 0x42, 0x5B, 0x40, 0x4E, 0x4F, 0x4F, 0x5C,  0x7F, 0x57, 0x13, 0x53, 0x13, 0x57, 0x53, 0x40, 0x7F, 0x17,  0x10, 0x11, 0x19, 0x58]key = [32,37]for i in range(len(enc)):    enc[i] ^= key[i % 2]print(bytes(enc).decode())

icrypt

描述:安全研究员Alice的电脑被植入了一个神秘的ELF加密程序,她发现所有文件都被该程序加密成.icrypt格式且无法打开。程序运行后会立即自毁,所幸她在内存中捕获了加密后的文件flag.jpg.icrypt和加密程序icrypt的副本。已知该程序采用分组加密,你能逆向加密逻辑,从flag.jpg.icrypt中还原出被隐藏的图片吗?

题目没有符号大致分析一下首先这里是判断命令行参数个数是否为2,如果不为2就提示用户输入要加密的路径

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解这一段首先路径进行拷贝到v9中,然后判断这个路径是一个文件还是目录,sub_407FB4函数里面是加密的KEY和IV存放到了v7数组中,最后调用sub_407BD2函数进行加密

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解整个红框里面的函数的作用就是读取文件内容到v3数组中,然后将内容和IV、key传入进行加密

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解这个加密函数会判断是128、192还是256并且还会填充为16的倍数,很明显的AES-CBC模式的加密

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解

继续往下分析直到sub_4074FA函数加密后才对AES-CBC加密后的结果进一步操作了

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解通过比对密文的前后差异发现就是对AES加密后的结果的前八字节倒叙了

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解EXP

from Crypto.Cipher import AES  import binascii  with open(f"C:UsersZhuanZDesktopicryptflag.jpg.icrypt","rb") as f:  data = f.read()  enc = b""key = bytes([0x7C, 0x32, 0x41, 0x45, 0x23, 0x26, 0x58, 0x3B, 0x48, 0x22,  0x36, 0x29, 0x26, 0x22, 0x75, 0x73])  iv = bytes([0x37, 0x7A, 0x33, 0x48, 0x2F, 0x75, 0x3B, 0x5D, 0x5D, 0x76,  0x72, 0x6B, 0x65, 0x63, 0x24, 0x3F])  for i in range(0,len(data),16):  line = data[i:i+16]  enc += line[:8][::-1] + line[8:]  a = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  res = a.decrypt(enc)  with open("1.jpg","wb") as f1:  f1.write(res)

vm_challenge

一个C++实现的简单的VM,首先提示用户输入flag,再将一些输入存储再V21数组

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解
fig:

创建一个int类型的vector后将v21数组里面的内容拷贝进去后,循环将opcode以及操作数push进一个vector中

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解
fig:

调用run实现虚拟机加密输入

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解
fig:

通过调试整个加密流程为读取输入的每一个字节和之前的操作数66进行异或后再和之前v21数组里面的值进行比较

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解
fig:

EXP

v21 = [0] * 18  v21[0] = 0x24  v21[1] = 0x2E  v21[0] = 0x24  v21[1] = 0x2E  v21[2] = 35  v21[3] = 37  v21[4] = 57  v21[5] = 52  v21[6] = 47  v21[7] = 29  v21[8] = 48  v21[9] = 39  v21[10] = 52  v21[11] = 39  v21[12] = 48  v21[13] = 49  v21[14] = 43  v21[15] = 44  v21[16] = 37  v21[17] = 63  for i in range(len(v21)):  print(chr(v21[i] ^ 0x42),end="")

CrackMe

描述 :这程序怎么不对劲,沙箱机制(seccomp)造成的扰动,找到真正需要逆向的地方

主程序是一个DES加密,但是发现解密不出查看题目描述发现这里原来不是真正需要逆向的地方

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解

查看init发现有三个函数

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第一个函数没用,第二个函数进行了SMC解密

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第三个函数是禁止所有未允许的系统调用,允许了一些程序所要使用的系统调用函数如read write mmap等,并且进行了反调试。

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解使用IDA Python手动解密一下SMC

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解得到真正的主逻辑,提示用户输入后比较输入长度是否为32第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解调用AES加密后进行比较

第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解通过分析代码可以发现这是一个白盒AES加密第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解根据程序修改白盒AES的源码通过调试提取出TyiBoxes和TBoxes得到缺陷数据构造出来的密文

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <string.h>#include <stdlib.h>#include <time.h>#define ROTL8(x, shift) ((u8) ((x) << (shift)) | ((x) >> (8 - (shift))))typedef unsigned char u8;typedef unsigned int u32;u8 DFA = 0;u8 xorTable[9][96][16][16];u32 TyiBoxes[9][16][256];unsigned char TBoxes[16][256];unsigned int mixBijOut[9][16][256];void GetxorTable() {for (int i = 0; i < 9; i++) {for (int j = 0; j < 96; j++) {for (int x = 0; x < 16; x++) { //2的4次方=16for (int y = 0; y < 16; y++) {                    xorTable[i][j][x][y] = x ^ y;                }            }        }    }}void shiftRows(u8 state[16]) {    u8 out[16];    int shiftTab[16] = { 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 };for (int i = 0; i < 16; i++) {        out[i] = state[shiftTab[i]];    }    memcpy(state, out, sizeof(out));}void AES_128_encrypt(unsigned char ciphertext[16], unsigned char plaintext[16], int white) {    u8 input[16] = { 0 };    u8 output[16] = { 0 };    memcpy(input, plaintext, 16);    u32 a, b, c, d, aa, bb, cc, dd;for (int i = 0; i < 9; i++) {        // DFA Attackif (white != -1 && i == 8) {            input[white] = 11;        }        shiftRows(input);for (int j = 0; j < 4; j++) {            a = TyiBoxes[i][4 * j + 0][input[4 * j + 0]];            b = TyiBoxes[i][4 * j + 1][input[4 * j + 1]];            c = TyiBoxes[i][4 * j + 2][input[4 * j + 2]];            d = TyiBoxes[i][4 * j + 3][input[4 * j + 3]];            aa = xorTable[i][24 * j + 0][(a >> 28) & 0xf][(b >> 28) & 0xf];            bb = xorTable[i][24 * j + 1][(c >> 28) & 0xf][(d >> 28) & 0xf];            cc = xorTable[i][24 * j + 2][(a >> 24) & 0xf][(b >> 24) & 0xf];            dd = xorTable[i][24 * j + 3][(c >> 24) & 0xf][(d >> 24) & 0xf];            input[4 * j + 0] = (xorTable[i][24 * j + 4][aa][bb] << 4) | xorTable[i][24 * j + 5][cc][dd];            aa = xorTable[i][24 * j + 6][(a >> 20) & 0xf][(b >> 20) & 0xf];            bb = xorTable[i][24 * j + 7][(c >> 20) & 0xf][(d >> 20) & 0xf];            cc = xorTable[i][24 * j + 8][(a >> 16) & 0xf][(b >> 16) & 0xf];            dd = xorTable[i][24 * j + 9][(c >> 16) & 0xf][(d >> 16) & 0xf];            input[4 * j + 1] = (xorTable[i][24 * j + 10][aa][bb] << 4) | xorTable[i][24 * j + 11][cc][dd];            aa = xorTable[i][24 * j + 12][(a >> 12) & 0xf][(b >> 12) & 0xf];            bb = xorTable[i][24 * j + 13][(c >> 12) & 0xf][(d >> 12) & 0xf];            cc = xorTable[i][24 * j + 14][(a >> 8) & 0xf][(b >> 8) & 0xf];            dd = xorTable[i][24 * j + 15][(c >> 8) & 0xf][(d >> 8) & 0xf];            input[4 * j + 2] = (xorTable[i][24 * j + 16][aa][bb] << 4) | xorTable[i][24 * j + 17][cc][dd];            aa = xorTable[i][24 * j + 18][(a >> 4) & 0xf][(b >> 4) & 0xf];            bb = xorTable[i][24 * j + 19][(c >> 4) & 0xf][(d >> 4) & 0xf];            cc = xorTable[i][24 * j + 20][(a >> 0) & 0xf][(b >> 0) & 0xf];            dd = xorTable[i][24 * j + 21][(c >> 0) & 0xf][(d >> 0) & 0xf];            input[4 * j + 3] = (xorTable[i][24 * j + 22][aa][bb] << 4) | xorTable[i][24 * j + 23][cc][dd];        }    }    shiftRows(input);for (int j = 0; j < 16; j++) {        input[j] = TBoxes[j][input[j]];    }for (int i = 0; i < 16; i++)        output[i] = input[i];    memcpy(ciphertext, output, 16);}void wpadBoxes() {    const char* PATH1 = "TBoxes";    FILE* fp = fopen(PATH1, "rb");    fread(TyiBoxes, sizeof(TyiBoxes), 1, fp);    fclose(fp);    const char* PATH2 = "mixBijOut";    fp = fopen(PATH2, "rb");    fread(TBoxes, sizeof(TBoxes), 1, fp);    fclose(fp);    const char* PATH3 = "TBoxes";    fp = fopen(PATH3, "rb");    fread(mixBijOut, sizeof(mixBijOut), 1, fp);    fclose(fp);}int main() {    srand(time(0));    GetxorTable();    wpadBoxes();for (int i = -1; i < 16; ++i) {        DFA = i != 0;        char flag[16] = { 0 };        memset(flag, 0x11, 16);        unsigned char ciphertext[16] = { 0 };        AES_128_encrypt(ciphertext, (unsigned char *)flag, i);for (int i = 0; i < 16; ++i) {printf("%02X", ciphertext[i]);        }        puts("");    }return 0;}

使用缺陷数据构造的密文求出k10,从而得出主密钥

import phoenixAESdata = """E976EFF0A00EBAA7B531632909A3D25F3F76EFF0A00EBA04B531CA290908D25FE976EFC8A00E2CA7B5C86329DAA3D25FE97676F0A023BAA7F331632909A3D28EE93FEFF0B80EBAA7B53163E909A3965FE9B3EFF0460EBAA7B531630B09A3F45F0A76EFF0A00EBA27B531F42909FAD25FE976EF13A00EB8A7B5606329DEA3D25FE976BBF0A077BAA75A31632909A3D2C0E97696F0A080BAA76431632909A3D265E9B8EFF0140EBAA7B531635409A36E5FD276EFF0A00EBA84B531C02909DED25FE976EFABA00EAEA7B5566329DFA3D25FE976EF9CA00E54A7B5AA632944A3D25FE976A3F0A02BBAA78331632909A3D215E930EFF07A0EBAA7B531631809A34F5F7576EFF0A00EBA3AB531B0290984D25F"""with open('crackfile''w') as fp:    fp.write(data)phoenixAES.crack_file('crackfile', [], True, False, verbose=0)from aeskeyschedule import *base_key = reverse_key_schedule(bytes.fromhex('195DCE39EC1CA57F35584891CB6378DE'),10)print(base_key.hex())

得出密钥为16个x01,正常AES求解

enc = b""enc_list = [0xCB8B76E4F2BD9924,0x8032310BC994A2E2,0x333172B6DF852A61,0x2F3A3E003C36088A]key =b"x01" * 16for i in range(4):    enc += enc_list[i].to_bytes(8,"little")a = AES.new(key=key,mode=AES.MODE_ECB)print(a.decrypt(enc))

原文始发于微信公众号(奉天安全团队):第二届“长城杯”信息安全铁人三项赛(防护赛)总决赛-逆向题解

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月29日16:45:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   第二届长城杯信息安全铁人三项赛(防护赛)总决赛-逆向题解https://cn-sec.com/archives/4015840.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息