Misc Ciallo_Encrypt Challenge
我的第一个项目终于上线了,上线前我加密了一个小秘密,应该不会被发现吧…… My first project has finally gone live. Before going live, I encrypted a little secret that shouldn’t have been discovered, right
Hint:
admin账号邮箱为qq邮箱。(数字@qq.com)例子:12345@qq.com The email for the admin account is a QQ email (<number>@qq.com) Example: 12345@qq.com
Solution 首先在日志(/logs)发现部分代码在远程仓库,5qC45b+D5Luj56CB5oiR5bey5bCG5YW25pS+6L+b5LqGZm9ya+eahOengeS6uuS7k+W6k+mHjA== base64解码得到 核心代码我已将其放进了fork的私人仓库里
因此直接搜索页面底部的 Yu2ul0ver 发现项目 https://github.com/Yu2ul0ver/Ciallo_Encrypt0r
查看 commit 记录发现后台的账号密码是 email:md5(Ciallo_Encrypt0r)
md5(Ciallo_Encrypt0r) = f42e16b836b22e83fd3818b603c75dc6这点不必多说
账号的获取方式是非预期解法:
首先在公告看到账号是qq邮箱:
接着在之前找到的 commit 记录可以发现是 Uh5ih2 提交的,这个id很眼熟,在两周前刚结束的 2025年“羊城杯”网络安全大赛 的题目 你也是旮旯给木大师? 中见到过,这题是一道内存取证题,且出题人当时开着 QQ
巧的是我还没删除当时的内存镜像,因此打开当时题目的镜像搜索 @qq.com
这里找到的 3517508570@qq.com 就是登录邮箱
预期解法是在 想请教师傅点问题 · Issue #1 · Yu2ul0ver/Ciallo_Encrypt0r 找到 QQ 号 3517508570
登录后台在最早的一条记录找到密文
1 Ci@110 一(2 ・ω< )⌒★ Cia11o~(∠°ω< )⌒★ Cial10一(2 ・ω< )⌒★ Cia1lo~(2 ・ω< )⌒★ Ciallo一(∠・w< )⌒★ Cial10~(∠・ω< )⌒★ Cial10~(∠°ω< )⌒★ Ci@110 ~(2 ・ω< )⌒★ Cia110一(∠・ω< )⌒★ Cia11o~(2 ・ω< )⌒★ Ciall0一(∠・w< )⌒★ Cia110~(2 ・ω< )⌒★ Ciallo一(2 ・ω< )⌒★ Cia11o~(2 ・ω< )⌒★ Ci@110 一(∠°ω< )⌒★ Ci@1lo 一(∠・w< )⌒★ Cia110一(∠°ω< )⌒★ Cia11o~(2 ・ω< )⌒★ Cia1lo一(∠・w< )⌒★ Cia1lo一(∠・ω< )⌒★ Ciallo~(∠°ω< )⌒★ Cial10一(∠・ω< )⌒★ Ciallo~(∠・w< )⌒★ Cial10一(2 ・ω< )⌒★ Cial10~(2 ・ω< )⌒★ Cia1lo~(2 ・ω< )⌒★ Ciall0~(∠・ω< )⌒★ Cial10一(∠・w< )⌒★ Ci@110 ~(∠・ω< )⌒★ Cia110~(2 ・ω< )⌒★ Cia1l0~(∠・ω< )⌒★ Ciall0~(∠・ω< )⌒★ Ciallo~(∠・w< )⌒★ Cial10一(∠・ω< )⌒★ Ciallo一(∠°ω< )⌒★ Cia1l0~(∠・w< )⌒★ Cia110~(∠°ω< )⌒★ Ci@110 ~(2 ・ω< )⌒★ Cial10一(∠・w< )⌒★ Ciall0一(∠・ω< )⌒★ Cia1l0一(∠・ω< )⌒★ Cial10~(∠°ω< )⌒★ Ci@110 一(∠・ω< )⌒★ Cia1lo一(∠・ω< )⌒★ Ci@1lo ~(∠・w< )⌒★ Cia11o~(∠・ω< )⌒★ Cia1lo一(∠・ω< )⌒★ Ciallo~(2 ・ω< )⌒★ Ciallo~(2 ・ω< )⌒★ Cial10~(2 ・ω< )⌒★ Cia1l0一(∠・ω< )⌒★ Cia1lo一(∠・w< )⌒★ Ciallo~(∠°ω< )⌒★ Cia1l0一(∠・ω< )⌒★ Cia11o~(2 ・ω< )⌒★ Ci@1lo ~(∠・w< )⌒★ Cial1o~(∠°ω< )⌒★ Cia110~(2 ・ω< )⌒★ Cial10~(∠°ω< )⌒★ Ciall0一(∠°ω< )⌒★ Cial10一(∠°ω< )⌒★ Cia110一(∠・ω< )⌒★ Cia110一(∠・w< )⌒★ Cia1l0一(2 ・ω< )⌒★
时间(北京时间):2025-10-17 22:27:17
在前面找到的仓库中发现加密函数是这样导入的:
1 from encrypt import ciallo_encrypt
然而搜遍了整个仓库都没找到这个库,此时想起前面base64解码得到的 核心代码我已将其放进了fork的私人仓库里
根据 ThTsOd 师傅找到的文章 https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650927888&idx=3&sn=68fcbe5bc86381f18d171c3aa0fa16f1 了解到可以通过爆破 Commit Hash 访问已删除 fork 存储库的数据,编写脚本进行爆破(修改自 ThTsOd 师傅提供的脚本),考虑到耗时过长,我们平均分成四份进行爆破,最终在最后一份里爆破得到结果,以下是当时的爆破代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import requestsfrom multiprocessing import Poolfrom tqdm import tqdmimport timeimport randomRETRY_COUNT = 0x10 def process_url (current ): retry = 0 while (retry < RETRY_COUNT): try : url = "https://github.com/Yu2ul0ver/Ciallo_Encrypt0r/commit/%04x" % current result = requests.get(url) if result.status_code == 429 : print (" %04x" % current, "SLOW DOWN! Rate limited." ) time.sleep(random.randint(10 , 30 )) elif result.status_code != 404 : print (f" Found: {url} Status: {result.status_code} " ) break else : break except requests.exceptions.RequestException as e: retry += 1 time.sleep(1 ) if retry >= RETRY_COUNT: print (" %04x" % current, "FAILED after multiple retries." ) return 0 if __name__ == '__main__' : num_processes = 8 start_range = 0xc000 end_range = 0x10000 total_to_process = end_range - start_range print (f"Starting brute-force from {start_range:04x} to {end_range-1 :04x} ..." ) try : with Pool(processes=num_processes) as pool: with tqdm(total=total_to_process, desc="Processing Commits" ) as pbar: for _ in pool.imap_unordered(process_url, range (start_range, end_range)): pbar.update(1 ) except KeyboardInterrupt: print ("\nUser interrupted, shutting down..." ) finally : print ("\nProcess finished." )
爆破得到的结果:https://github.com/Yu2ul0ver/Ciallo_Encrypt0r/commit/e58e
赛后找到了这篇 blog CFOR Exploit - Recovering Deleted and Private Github Commits ,进而发现了这个 exp SorceryIE/cfor_exploit: Exploit script for the CFOR vulnerability using Github’s GraphQL API
得到 encrypt.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 from Crypto.Cipher import AESfrom Crypto.Util.Padding import padimport hashlibimport base64def ciallo_encrypt (input ,ts_str ): key = hashlib.md5(ts_str.encode()).digest() cipher = AES.new(key, AES.MODE_ECB) ciphertext = cipher.encrypt(pad(input .encode(), AES.block_size)) enc_b64 = base64.b64encode(ciphertext).decode() utf8_bytes = enc_b64.encode("utf-8" ) binary = '' .join(format (b, '08b' ) for b in utf8_bytes) sum = '' data = [binary[i:i + 8 ] for i in range (0 , len (binary), 8 )] for i in range (0 , len (data)): cia = 'Ciallo~(∠・ω<)⌒★' if data[i][0 ] == '0' : cia = cia else : cia = cia[:1 ] + '1' + cia[2 :] if data[i][1 ] == '0' : cia = cia[:2 ] + '@' + cia[3 :] else : cia = cia if data[i][2 ] == '0' : cia = cia elif data[i][2 ] == '1' : cia = cia[:3 ] + '1' + cia[4 :] if data[i][3 ] == '0' : cia = cia elif data[i][3 ] == '1' : cia = cia[:4 ] + '1' + cia[5 :] if data[i][4 ] == '0' : cia = cia[:5 ] + '0' + cia[6 :] elif data[i][4 ] == '1' : cia = cia if data[i][5 ] == '0' : cia = cia elif data[i][5 ] == '1' : cia = cia[:6 ] + '一' + cia[7 :] if data[i][6 :8 ] == '00' : cia = cia[:9 ] + '°' + cia[10 :] elif data[i][6 :8 ] == '01' : cia = cia elif data[i][6 :8 ] == '10' : cia = cia[:8 ] + '2' + cia[9 :] elif data[i][6 :8 ] == '11' : cia = cia[:10 ] + 'w' + cia[11 :] sum += cia + ' ' return sum
根据加密函数编写解密脚本即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 from Crypto.Cipher import AESfrom Crypto.Util.Padding import unpad, pad import hashlibimport base64import datetimedef ciallo_decrypt (encrypted_ciallo, ts_str ): """ Decrypts the 'Ciallo' encoded string back to the original text. :param encrypted_ciallo: The output string from ciallo_encrypt. :param ts_str: The same timestamp string used for encryption. :return: The original decrypted string. """ cia_parts = encrypted_ciallo.split(' ' ) binary_string = '' for cia in cia_parts: if not cia: continue bits = ['' ] * 8 bits[0 ] = '1' if cia[1 ] == '1' else '0' bits[1 ] = '0' if cia[2 ] == '@' else '1' bits[2 ] = '1' if cia[3 ] == '1' else '0' bits[3 ] = '1' if cia[4 ] == '1' else '0' bits[4 ] = '0' if cia[5 ] == '0' else '1' bits[5 ] = '1' if cia[6 ] == '一' else '0' if cia[9 ] == '°' : bits[6 :8 ] = ['0' , '0' ] elif cia[8 ] == '2' : bits[6 :8 ] = ['1' , '0' ] elif cia[10 ] == 'w' : bits[6 :8 ] = ['1' , '1' ] else : bits[6 :8 ] = ['0' , '1' ] binary_string += '' .join(bits) utf8_bytes = bytes ([int (binary_string[i:i + 8 ], 2 ) for i in range (0 , len (binary_string), 8 )]) enc_b64 = utf8_bytes.decode('utf-8' ) ciphertext = base64.b64decode(enc_b64) key = hashlib.md5(ts_str.encode()).digest() cipher = AES.new(key, AES.MODE_ECB) decrypted_padded_bytes = cipher.decrypt(ciphertext) try : original_bytes = unpad(decrypted_padded_bytes, AES.block_size) except ValueError as e: raise ValueError(f"Unpadding failed. The key (from ts_str) or ciphertext may be incorrect. Error: {e} " ) original_text = original_bytes.decode('utf-8' ) return original_text if __name__ == "__main__" : time_str = "2025-10-17 22:27:17" dt_object = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S" ) timestamp = str (int (dt_object.timestamp())) encrypted_data = "Ci@110一(2・ω<)⌒★ Cia11o~(∠°ω<)⌒★ Cial10一(2・ω<)⌒★ Cia1lo~(2・ω<)⌒★ Ciallo一(∠・w<)⌒★ Cial10~(∠・ω<)⌒★ Cial10~(∠°ω<)⌒★ Ci@110~(2・ω<)⌒★ Cia110一(∠・ω<)⌒★ Cia11o~(2・ω<)⌒★ Ciall0一(∠・w<)⌒★ Cia110~(2・ω<)⌒★ Ciallo一(2・ω<)⌒★ Cia11o~(2・ω<)⌒★ Ci@110一(∠°ω<)⌒★ Ci@1lo一(∠・w<)⌒★ Cia110一(∠°ω<)⌒★ Cia11o~(2・ω<)⌒★ Cia1lo一(∠・w<)⌒★ Cia1lo一(∠・ω<)⌒★ Ciallo~(∠°ω<)⌒★ Cial10一(∠・ω<)⌒★ Ciallo~(∠・w<)⌒★ Cial10一(2・ω<)⌒★ Cial10~(2・ω<)⌒★ Cia1lo~(2・ω<)⌒★ Ciall0~(∠・ω<)⌒★ Cial10一(∠・w<)⌒★ Ci@110~(∠・ω<)⌒★ Cia110~(2・ω<)⌒★ Cia1l0~(∠・ω<)⌒★ Ciall0~(∠・ω<)⌒★ Ciallo~(∠・w<)⌒★ Cial10一(∠・ω<)⌒★ Ciallo一(∠°ω<)⌒★ Cia1l0~(∠・w<)⌒★ Cia110~(∠°ω<)⌒★ Ci@110~(2・ω<)⌒★ Cial10一(∠・w<)⌒★ Ciall0一(∠・ω<)⌒★ Cia1l0一(∠・ω<)⌒★ Cial10~(∠°ω<)⌒★ Ci@110一(∠・ω<)⌒★ Cia1lo一(∠・ω<)⌒★ Ci@1lo~(∠・w<)⌒★ Cia11o~(∠・ω<)⌒★ Cia1lo一(∠・ω<)⌒★ Ciallo~(2・ω<)⌒★ Ciallo~(2・ω<)⌒★ Cial10~(2・ω<)⌒★ Cia1l0一(∠・ω<)⌒★ Cia1lo一(∠・w<)⌒★ Ciallo~(∠°ω<)⌒★ Cia1l0一(∠・ω<)⌒★ Cia11o~(2・ω<)⌒★ Ci@1lo~(∠・w<)⌒★ Cial1o~(∠°ω<)⌒★ Cia110~(2・ω<)⌒★ Cial10~(∠°ω<)⌒★ Ciall0一(∠°ω<)⌒★ Cial10一(∠°ω<)⌒★ Cia110一(∠・ω<)⌒★ Cia110一(∠・w<)⌒★ Cia1l0一(2・ω<)⌒★ " decrypted_data = ciallo_decrypt(encrypted_data, timestamp) print (decrypted_data)
FLAG 1 flag{9f08699d-1b6c-471e-9ed0-86dbf3ee8074}
低空经济网络安全 The Hidden Link Challenge
我们截获了一个名为“MAV1”的恐怖组织发出的无人机遥测下行数据。capture.pcap中的数据流量看起来很正常,是吗? We’ve intercepted a drone’s telemetry downlink from a terrorist group called “MAV1”. The traffic in capture.pcap appears to be normal, or is it?
Solution 根据流量特征,结合题目描述 “MAV1” 不难发现该流量为 MAVLink v1 协议通信
MAVLink v1 消息结构是:
[FE (Start)] [Len] [Seq] [SysID] [CompID] [MsgID] [Payload...] [Checksum (2 bytes)]
直接搜索字符串 “flag”
不难发现flag由 [SysID] [CompID] [MsgID] [Payload]组成,发现此时的序列号 [Seq] 为 00,自然而然想看 01 是什么样的,因此搜索十六进制 fe0401(fe 是固定的起始符,04 是固定的长度,01 就是序列号):
发现 {dr0,符合前面的猜想,因此以此类推继续搜索后面的序列号,也就是继续搜索十六进制 fe0402,fe0403,fe0404…
最后全部连起来就能得到 flag 了
FLAG 1 flag{dr0n3_fl1ght_c0ntr0ll3r_h4ck3d}