This is my writeup for the Deep Six forensics challenge from the US Navy Cyber Competition Team 2019 assessment.
Challenge Description
Another one with really no story behind it…just find the flag. Flag will be in the format: CCT{flag}
Challenge Summary
This challenge started with a USB packet capture, where a zip file was extracted using tshark
. An in-depth inspection of this pcapng
file revealed covert communication through the ICMP protocol, decrypted with information from OSINT research related to the movie “The Net.” Next, Cryptcat communications were spotted and decrypted using a password found via OSINT. Lastly, a ROT-13 encoded and reversed string was statically analyzed in a captured x64 ELF binary, leading to the discovery of the flag.
Extract pcapng
file From USB Capture
Running a hex dump on the file, I see the magic bytes for a zip file, with a file named pcap_chal.pcap
inside:
xxd pcap1_v2.pcapng | head -n 50
Opening the packet capture in Wireshark, it appears the file was transferred via the USB protocol:
Extract the zip file using the following bash script
# Extract hexedecimal usb data from the packet capture
tshark -r pcap1_v2.pcapng -Y 'usb.capdata' -T fields -e usb.capdata > raw
# Convert the hexedecimal output to raw bytes that binwalk can understand
xxd -r -p raw raw.bin
# Carve the zip file from the raw data
binwalk --dd='.*' raw.bin
Unzip the file from the directory created by binwalk:
Discover Covert ICMP Communication Channel
Open pcap_chal.pcap
in Wireshark, and view the Protocol Hierarchy
Statistics —> Protocol Hierarchy:
There were an unusually large amount of ICMP packets. Let’s filter by ICMP, and view these packets:
Every once in a while, there is a ICMP packet sent with no response, and a packet length not equal to 98. It appears the ICMP protocol’s data field is being used as a covert communication channel:
Lets extract all of their conversations with tshark
tshark -r pcap_chal.pcap -Y 'icmp && frame.len != 98' -T fields -e data
Decode the hex in CyberChef to view their communications:
It seems there was a file transferred over the network with cryptcat
.
After some quick OSINT, I discover the character and location in the messages are from the movie The Net
. In the movie, Angela Bennett finds a password in Delvin’s wallet. It seems we need to decrypt the cryptcat
communications using the password BER5348833
Extract Binary from .pcap
with cryptcat
First, extract all the cryptcat
packets from the .pcap
file, and convert it to raw bytes:
# Note, the messages say to use the "metasploit port"; by default, meterpreter sessions listen on port 4444.
tshark -r pcap_chal.pcap -Y 'tcp.dstport==4444' -T fields -e data | tr -d '\n' | xxd -r -p > bytes
Set up the cryptcat
listener on your primary machine:
# This machine: 192.168.19.131
sudo apt install cryptcat
cryptcat -l -k BER5348833 -p 4444 > unencrypted_cryptcat
Copy the bytes
binary file to another system on the same subnet as your primary box, and send the file to port 4444 with netcat
# This machine: 192.168.19.132
netcat 192.168.19.131 4444 < bytes
It appears we have a x64 ELF binary. Time to open up IDA.
Discover and Decode the Flag Using Static Analysis
Let’s view the main function:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
size_t v4; // rax
char v6; // [rsp+17h] [rbp-A9h]
int i; // [rsp+18h] [rbp-A8h]
int j; // [rsp+18h] [rbp-A8h]
int v9; // [rsp+1Ch] [rbp-A4h]
int v10; // [rsp+24h] [rbp-9Ch]
char *ptr; // [rsp+28h] [rbp-98h]
char *ptra; // [rsp+28h] [rbp-98h]
char *ptrb; // [rsp+28h] [rbp-98h]
char *buf; // [rsp+38h] [rbp-88h]
char *v15; // [rsp+40h] [rbp-80h]
char *dest; // [rsp+48h] [rbp-78h]
char s[48]; // [rsp+50h] [rbp-70h] BYREF
char src[56]; // [rsp+80h] [rbp-40h] BYREF
unsigned __int64 v19; // [rsp+B8h] [rbp-8h]
v19 = __readfsqword(0x28u);
strcpy(s, "gf1j7_n_r6_bg_g0t_f4u_re3ug_qe@m1j_c@pc_n_f'3u");
buf = (char *)calloc(1uLL, 0x10uLL);
v15 = (char *)sub_5568F1038279();
if ( (int)sub_5568F10382A8((__int64)v15, "irc.cct", 0x1A0Bu) < 0 )
{
printf("ERROR %s\n", *((const char **)v15 + 4));
exit(*((_DWORD *)v15 + 6));
}
inet_ntop(2, v15 + 8, buf, 0x10u);
if ( !buf )
{
puts("Failed to get ip");
exit(*((_DWORD *)v15 + 6));
}
printf("Found the server at %s\n", buf);
free(buf);
if ( (int)sub_5568F10383CC(v15) < 0 )
{
printf("ERROR %s\n", *((const char **)v15 + 4));
exit(*((_DWORD *)v15 + 6));
}
puts("Connected to my server!");
sleep(5u);
ptr = (char *)sub_5568F10384A2(v15);
if ( ptr )
printf("%s", ptr + 8);
sub_5568F1038437((__int64)v15, "CAP LS 302\r\n", 0xCuLL);
sub_5568F1038437((__int64)v15, "USER cct2019 cct2019 irc.cct :realname\r\n", 0x28uLL);
sub_5568F1038437((__int64)v15, "NICK cct\r\n", 0xAuLL);
if ( ptr )
free(ptr);
ptra = (char *)sub_5568F10384A2(v15);
if ( ptra )
printf("%s", ptra + 8);
sub_5568F1038437((__int64)v15, "JOIN #flag\r\n", 0xCuLL);
if ( ptra )
free(ptra);
ptrb = (char *)sub_5568F10384A2(v15);
if ( ptrb )
printf("%s", ptrb + 8);
v10 = strlen(s);
v9 = v10 - 1;
for ( i = 0; i < v10; ++i )
{
v6 = s[i];
if ( (v6 <= 64 || v6 > 77) && (v6 <= 96 || v6 > 109) )
{
if ( v6 > 77 && v6 <= 90 || v6 > 109 && v6 <= 122 )
s[i] = v6 - 13;
}
else
{
s[i] = v6 + 13;
}
}
for ( j = 0; j < v10; ++j )
src[j] = s[v9--];
src[j] = 0;
v3 = strlen(src);
dest = (char *)calloc(1uLL, v3 + 22);
strcat(dest, "PRIVMSG #flag :CCT{");
strcat(dest, src);
*(_DWORD *)&dest[strlen(dest)] = 658813;
v4 = strlen(dest);
sub_5568F1038437((__int64)v15, dest, v4);
free(dest);
while ( *((_DWORD *)v15 + 6) != -1 )
{
if ( ptrb )
free(ptrb);
ptrb = (char *)sub_5568F10384A2(v15);
}
puts(*((const char **)v15 + 4));
if ( ptrb )
free(ptrb);
close(*(_DWORD *)v15);
free(v15);
return 0LL;
}
On line 22, it appears we have a encoded flag saved to the s
variable:
strcpy(s, "gf1j7_n_r6_bg_g0t_f4u_re3ug_qe@m1j_c@pc_n_f'3u");
It looks ROT-13 encoded:
v10 = strlen(s);
v9 = v10 - 1;
for (i = 0; i < v10; ++i) {
v6 = s[i];
if ((v6 <= 64 || v6 > 77) && (v6 <= 96 || v6 > 109)) {
if (v6 > 77 && v6 <= 90 || v6 > 109 && v6 <= 122)
s[i] = v6 - 13;
} else {
s[i] = v6 + 13;
}
}
Then reversed:
for ( j = 0; j < v10; ++j )
src[j] = s[v9--];
The following C code decodes and prints the flag:
solve.c
#include <stdio.h>
#include <string.h>
int main() {
char s[100];
char src[100];
int v10, v9, i, v6, j;
strcpy(s, "gf1j7_n_r6_bg_g0t_f4u_re3ug_qe@m1j_c@pc_n_f'3u");
v10 = strlen(s);
v9 = v10 - 1;
for (i = 0; i < v10; ++i) {
v6 = s[i];
if ((v6 <= 64 || v6 > 77) && (v6 <= 96 || v6 > 109)) {
if (v6 > 77 && v6 <= 90 || v6 > 109 && v6 <= 122)
s[i] = v6 - 13;
}
else {
s[i] = v6 + 13;
}
}
for ( j = 0; j < v10; ++j ) {
src[j] = s[v9--];
}
printf("ROT-13 decoded string: %s\n", s);
printf("Reversed string: %s\n", src);
return 0;
}
Compile and run the code to reveal the flag:
gcc solve.c -o solve
./solve
Flag: CCT{h3's_a_pc@p_w1z@rd_th3re_h4s_g0t_to_6e_a_7w1st}