LOADING

加载过慢请开启缓存 浏览器默认开启

强网杯青少年赛选拔赛re Writeup

原题提取码:95lk

EnterGame

一个chacha20加密,尝试用脚本解密不过好像不行,不知道是哪里的问题,可能是我密钥找错了。chacha20本质就是一个异或,我们可以把密文写入加密一次就可以得到原文。

image-20250113235605760

下断点在加密入口处,提取密文注意点进去把密文全部提取,一共有48字节“5E 13 AA D3 87 75 2B 7A 1B 16 04 A3 49 7E 1D D26B 5D 58 40 5E 44 63 59 48 51 0D 54 5E 58 55 58 AD 82 AF DC E7 AB 58 5D CE C1 FD F7 FF 7F 00 00”。我们再次动调,输入48字节数据作为输入,然后再次在加密入口处断点,修改input的值。

image-20250114000006845

用ida自带的chage byte就可以每十六字节进行修改。在比较的位置下一个断点继续运行查看s1的值就可以得到flag。

image-20250114000519077

image-20250114001301768

Flip_over

看java层主逻辑在validateAndEncrypt()函数里,在so文件里找到这个函数,大概逻辑的是取flagflag这个字符串作为密钥把”a4c3f8927d9b8e6d6e483fa2cd0193b0a6e2f19c8b47d5a8f3c7a91e8d4b9f67”先进行RC4加密再进行DES_ECB加密,最后再与0x21和密后的数据进行异或后,与密文比较。解密时提取数据,把异或逆一下,直接用赛博厨师解密。

值得注意的是,我字自己了一个脚本用于获取异或的数据,然后我发现当c语言输出到01 00这类只有一位的十六进制数时,会省略掉前面的0,在用这一大串密钥异或时默认是两位一字节,如果没有前面的0,那么密钥就是错误的,所以我们要把0添加进去。如下面的注释。或者我们在输出十六进制数据时用空格隔开,这在赛博厨师里时不影响的。还有一种解决方案就是用”%.2x”的格式输出,指定输出2个十六进制数。

#include <stdio.h>

unsigned char data[] = { 0x59,0x15,0xc1,0x3f,0x40,0x9a,0x7a,0xe7,0xa6,0x8b,0xb6,0xe3,0xee,0x0d,0x19,0x6d,0xb7,
0x6d,0xca,0xe6,0xda,0x5f,0x0d,0x4b,0xd6,0x0a,0xb2,0xde,0xad,0xaa,0x95,0xeb,0x85,0xb7,0x77,0xc3,0x10,0xbb,0xcf,
0xce,0xf7,0xd2,0x22,0xc9,0xc4,0xf9,0xfc,0xfb,0xab,0x32,0xea,0x31,0x81,0x55,0xaf,0x79,0x52,0x8e,0x80,0xaf,0xc3,
0x18,0x60,0x50,0xf1,0xd8,0x40,0xbb,0xfc,0x1b,0x89,0xa6 };//赛博厨师解密的数据.

int main() {
   unsigned long long a[] = { 0xF462D91A7981581E, 0x780001A9A6A79EE3,0x47141FC8F3C62DA6, 0xAFD0BEA1CBF14F95,0x89DDAB508133AF93,0x8EE2 };
   unsigned char result[42];
   for (int i = 0; i < 42; i++) {
       printf("%x,", *((unsigned char*)a + i));
       result[i] = *((unsigned char*)a + i) ^ 0x21 ^ data[i];
   }
   for (int i = 0; i < 42; i++) {
       printf("%c", *((unsigned char*)result + i));
   }

   //1e5881791ad962f4e39ea7a6a9 1 0 78a62dc6f3c81f1447954ff1cba1bed0af93af338150abdd89e28e  //输出结果
   //1e5881791ad962f4e39ea7a6a9 01 00 78a62dc6f3c81f1447954ff1cba1bed0af93af338150abdd89e28e  //异或要用到的结果
}