<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kernel on bitfriends' blog</title><link>https://b17fr13nds.github.io/tags/kernel/</link><description>Recent content in Kernel on bitfriends' blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 03 Jul 2026 23:22:28 +0700</lastBuildDate><atom:link href="https://b17fr13nds.github.io/tags/kernel/index.xml" rel="self" type="application/rss+xml"/><item><title>Reviving modprobe_path technique (again)</title><link>https://b17fr13nds.github.io/posts/reviving_modprobe/</link><pubDate>Fri, 03 Jul 2026 23:22:28 +0700</pubDate><guid>https://b17fr13nds.github.io/posts/reviving_modprobe/</guid><description>&lt;h1 id="overview"&gt;
 Overview
 &lt;a class="heading-link" href="#overview"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;modprobe_path&lt;/code&gt; technique is a widely known Linux kernel exploitation primitive that can be used to turn an arbitrary write primitive into LPE.&lt;/p&gt;
&lt;h3 id="tldr"&gt;
 TL;DR
 &lt;a class="heading-link" href="#tldr"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;modprobe_path&lt;/code&gt; is a string that specifies the name of the modprobe executable in the Linux kernel. This program is responsible for adding and removing loadable kernel modules.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;CONFIG_STATIC_USERMODEHELPER&lt;/code&gt; is disabled &lt;code&gt;modprobe_path&lt;/code&gt;is R/W, this means that if we have an arbitrary write primitive and a KASLR leak, we can change it to a controlled executable file path.
If we now find a way to make the kernel run modprobe for us, it will run our executable with root privileges, thus achieving LPE.&lt;/p&gt;</description></item><item><title>heap_master - n1ctf 2024</title><link>https://b17fr13nds.github.io/posts/n1ctf_heap_master/</link><pubDate>Thu, 09 Jan 2025 15:59:10 +0100</pubDate><guid>https://b17fr13nds.github.io/posts/n1ctf_heap_master/</guid><description>&lt;p&gt;Heap_master was a kernel pwn challenge from n1ctf. I didn&amp;rsquo;t play the ctf, allthough the
challenge seemed nice to upsolve. Let&amp;rsquo;s get started&lt;/p&gt;
&lt;p&gt;For the environment, we were given a Linux &lt;code&gt;6.1.110&lt;/code&gt; image as well as a config file. Before
looking at the config file, the fact that we have an nsjail environment. In our case, this
means a bunch of disabled syscalls, no setuid binaries, and only few useful files in &lt;code&gt;/dev&lt;/code&gt;
and &lt;code&gt;/proc&lt;/code&gt; directories. The goal is hereby not only to get root, but also escape the nsjail
to read &lt;code&gt;flag.txt&lt;/code&gt;. We need to take this into account when creating our exploit.&lt;/p&gt;</description></item><item><title>physler - BRICS CTF 2024</title><link>https://b17fr13nds.github.io/posts/brics_physler/</link><pubDate>Sun, 20 Oct 2024 12:18:45 +0200</pubDate><guid>https://b17fr13nds.github.io/posts/brics_physler/</guid><description>&lt;p&gt;Physler was another challenge from BRICS CTF that I solved.
We basically got a kernel module that has two ioctl requests defined:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;case&lt;/span&gt; &lt;span style="color:#79c0ff;font-weight:bold"&gt;IOCTL_MAP_PHYS_ADDR&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#d2a8ff;font-weight:bold"&gt;copy_from_user&lt;/span&gt;(&lt;span style="color:#ff7b72;font-weight:bold"&gt;&amp;amp;&lt;/span&gt;_map, (&lt;span style="color:#ff7b72"&gt;void&lt;/span&gt;&lt;span style="color:#ff7b72;font-weight:bold"&gt;*&lt;/span&gt;)arg, &lt;span style="color:#ff7b72"&gt;sizeof&lt;/span&gt;(_map))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;return&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-&lt;/span&gt;EFAULT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (mem)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d2a8ff;font-weight:bold"&gt;iounmap&lt;/span&gt;(mem);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mem &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#d2a8ff;font-weight:bold"&gt;ioremap&lt;/span&gt;(_map.phys_addr, _map.size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#ff7b72;font-weight:bold"&gt;!&lt;/span&gt;mem) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;return&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-&lt;/span&gt;EFAULT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;case&lt;/span&gt; &lt;span style="color:#79c0ff;font-weight:bold"&gt;IOCTL_WRITE_PHYS_MEM&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#ff7b72;font-weight:bold"&gt;!&lt;/span&gt;mem)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;return&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-&lt;/span&gt;EFAULT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#d2a8ff;font-weight:bold"&gt;copy_from_user&lt;/span&gt;(&lt;span style="color:#ff7b72;font-weight:bold"&gt;&amp;amp;&lt;/span&gt;_write, (&lt;span style="color:#ff7b72"&gt;void&lt;/span&gt;&lt;span style="color:#ff7b72;font-weight:bold"&gt;*&lt;/span&gt;)arg, &lt;span style="color:#ff7b72"&gt;sizeof&lt;/span&gt;(_write))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;return&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-&lt;/span&gt;EFAULT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; _write.size;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (size &lt;span style="color:#ff7b72;font-weight:bold"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;sizeof&lt;/span&gt;(kernel_buffer))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;sizeof&lt;/span&gt;(kernel_buffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#d2a8ff;font-weight:bold"&gt;copy_from_user&lt;/span&gt;(kernel_buffer, (&lt;span style="color:#ff7b72"&gt;char&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;*&lt;/span&gt;)_write.in_data, size))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;return&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-&lt;/span&gt;EFAULT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d2a8ff;font-weight:bold"&gt;memcpy_toio&lt;/span&gt;(mem, kernel_buffer, size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ff7b72"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This essentially lets us map any physical address and write arbitrary data to it - all as normal user
since this also bypasses all virtual access protections for pages/memory regions, we can overwrite
kernel code. To get the physical kernel base, we can read &lt;code&gt;/proc/iomem&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>My own kernel fuzzer - lxfuzz</title><link>https://b17fr13nds.github.io/posts/kernel_fuzzer_lxfuzz/</link><pubDate>Sat, 07 Sep 2024 18:11:00 +0200</pubDate><guid>https://b17fr13nds.github.io/posts/kernel_fuzzer_lxfuzz/</guid><description>&lt;p&gt;My long-term project is writing a kernel fuzzer named lxfuzz. It is a coverage-guided fuzzer for the linux kernel. I chose that project for some reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To learn about fuzzing, its mechanisms etc. in general&lt;/li&gt;
&lt;li&gt;To learn more about the linux kernel, especially&lt;/li&gt;
&lt;li&gt;To improve my C++ skills :) (the language used for lxfuzz)&lt;/li&gt;
&lt;li&gt;Profit (finding CVEs)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under the hood it&amp;rsquo;s using qemu to run the kernel and KCOV for coverage collection.
The project is still work-in-progress and developed gradually.
Current features are:&lt;/p&gt;</description></item><item><title>Exploiting the kernel - CVE-2022-24122</title><link>https://b17fr13nds.github.io/posts/kernel_exploit_cve-2022-24122/</link><pubDate>Sun, 12 Mar 2023 17:47:13 +0200</pubDate><guid>https://b17fr13nds.github.io/posts/kernel_exploit_cve-2022-24122/</guid><description>&lt;p&gt;For the first time I exploited the kernel in real life.
I used the bug &lt;a href="https://www.cvedetails.com/cve/CVE-2022-24122/" class="external-link" target="_blank" rel="noopener"&gt;CVE-2022-24122&lt;/a&gt;, which allowed a use-after-free due to bad use of &lt;code&gt;refcount&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The exploit itself requires a KASLR leak to prevent an oops during the process,
as well as access to user namespaces. It is not really reliable, needs many tries :D&lt;/p&gt;
&lt;p&gt;To get root I corrupted the SLUB freelist and wrote to &lt;code&gt;modprobe_path&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The exploit code can be found on &lt;a href="https://github.com/b17fr13nds/kernel-exploits/tree/main/CVE-2022-24122" class="external-link" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt; or in the following:&lt;/p&gt;</description></item></channel></rss>