We are working on our own custom command and control protocol. Can
you identify any hidden features in the service? We also included a
packet capture of some old sessions so you can learn how it works.
我们正在开发自己的自定义命令与控制协议。您能发现该服务中有哪些隐藏功能吗?我们还提供了一些旧会话的数据包捕获文件,以便您了解其工作原理。
PCAP Investigation with
Scapy
The first step was to examine the provided packet capture
(custom_protocol_log.pcap) to understand the communication
pattern. I used scapy to extract and decode raw data from
the TCP streams.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from scapy.all import *from scapy.layers.inet import TCPPCAP_FILE = "custom_protocol_log.pcap" def print_hex (pcap_path ): packets = rdpcap(pcap_path) for pkt in packets: if TCP in pkt and pkt.haslayer(Raw): raw = pkt[Raw].load try : print (raw.hex ()) except Exception as e: print (f"[-] Error: {e} " ) if __name__ == "__main__" : print_hex(PCAP_FILE)
Protocol Reversal
By analyzing the hex data from the traffic between
172.17.0.1 and 172.17.0.2, a clear pattern
emerged:
1 2 3 b925afc1 00 31 00 30 00 323430323435313235 b925afc1 00 32 00 30 00 323032383630353038 b925afc1 00 33 00 32 00 33383232383038323633
The protocol structure appears to be:
[Session ID] [Null] [Counter] [Null] [Command] [Null] [Checksum]
Session ID : A 4-byte identifier (e.g.,
b925afc1).
Counter : Increments with each request.
Command : Hex-encoded numbers (e.g., 30
for 0, 31 for 1, 32
for 2).
Checksum : A CRC32 calculation of the preceding
bytes, where the result is converted to a decimal string and then
hex-encoded.
Checksum Verification
Using Python to verify the CRC32 logic:
1 2 3 4 5 6 7 8 9 10 11 12 import zlibdef calc_custom_crc_hex (hex_data: str ) -> str : data_bytes = bytes .fromhex(hex_data) crc_val = zlib.crc32(data_bytes) return str (crc_val).encode().hex () base_hex = "b925afc100310030" print (f"Payload: {base_hex} " )print (f"Custom CRC Hex: {calc_custom_crc_hex(base_hex)} " )
Solution
Exploit Script
I developed a brute-force script using pwntools to
iterate through potential commands (0-14) and find the one
that triggers the flag response.
wtf why not 0-15
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 import zlibfrom pwn import *HOST = "35f9359cc67c7983.247ctf.com" PORT = 50385 context.log_level = "info" def calc_custom_crc_hex (hex_data: str ) -> str : data_bytes = bytes .fromhex(hex_data) crc_val = zlib.crc32(data_bytes) return str (crc_val).encode().hex () def solve (): sep = "00" counter = "31" commands = [f"3{hex (i)[2 :]} " for i in range (15 )] for cmd in commands: try : conn = remote(HOST, PORT, timeout=5 ) session_id = conn.recvline(drop=True ).decode(errors="replace" ) log.info(f"Session ID: {session_id} | Testing Command: {cmd} " ) base_hex = f"{session_id} {sep} {counter} {sep} {cmd} " crc_hex = calc_custom_crc_hex(base_hex) payload = f"{base_hex} {sep} {crc_hex} " conn.sendline(payload.encode()) raw_response = conn.recvall(timeout=3 ).decode(errors="replace" ) try : decoded_response = bytes .fromhex(raw_response).decode(errors="replace" ) if "247CTF" in decoded_response: log.success(f"Flag found: {decoded_response} " ) conn.close() return except ValueError: log.warning(f"Failed to decode hex response: {raw_response} " ) print ("-" * 40 ) if __name__ == "__main__" : solve()
Execution Output
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 [*] Starting brute-force with commands: ['30' , '31' , '32' , '33' , '34' , '35' , '36' , '37' , '38' , '39' , '3a' , '3b' , '3c' , '3d' , '3e' ] [+] Opening connection to 35f9359cc67c7983.247ctf.com on port 50385: Done [*] Session ID: 9b2832a1 [+] Receiving all data: Done (54B) [*] Closed connection to 35f9359cc67c7983.247ctf.com port 50385 [*] Response: �(2�\x001\x00notroot \x003738085711 ---------------------------------------- [*] Connection closed. [+] Opening connection to 35f9359cc67c7983.247ctf.com on port 50385: Done [*] Session ID: 3907e672 [+] Receiving all data: Done (152B) [*] Closed connection to 35f9359cc67c7983.247ctf.com port 50385 [*] Response: 9\x07�r\x001\x00uid=1000(notroot) gid=1000(notroot) groups =1000(notroot) \x003051696603 ---------------------------------------- [*] Connection closed. [+] Opening connection to 35f9359cc67c7983.247ctf.com on port 50385: Done [*] Session ID: edd0a465 [+] Receiving all data: Done (96B) [*] Closed connection to 35f9359cc67c7983.247ctf.com port 50385 [*] Response: �Фe\x001\x00Sun Mar 1 06:57:51 UTC 2026 \x003480231763 ---------------------------------------- [*] Connection closed. [+] Opening connection to 35f9359cc67c7983.247ctf.com on port 50385: Done [*] Session ID: 705136bc [+] Receiving all data: Done (446B) [*] Closed connection to 35f9359cc67c7983.247ctf.com port 50385 [*] Response: pQ6�\x001\x00 total used free shared buff/cache available Mem: 7973384 1587756 3913000 2636 2472628 6135804 Swap: 2097148 0 2097148 \x002165499562 ---------------------------------------- [*] Connection closed. [+] Opening connection to 35f9359cc67c7983.247ctf.com on port 50385: Done [*] Session ID: d0f8fe01 [+] Receiving all data: Done (118B) [*] Closed connection to 35f9359cc67c7983.247ctf.com port 50385 [*] Response: ���\x01\x001\x00247CTF{e5df2a6497c8733e8dc4679d856591af}\x001655731160 [+] Flag found: ���\x01\x001\x00247CTF{e5df2a6497c8733e8dc4679d856591af}\x001655731160 [*] Connection closed. [Process exited 0]
Flag
247CTF{e5df2a6497c8733e8dc4679d856591af}