You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

缓冲区溢出漏洞利用练习求助:输入9字符无法覆盖变量以绕过用户名验证的问题排查

Hey there! Let's figure out why your initial 9-character input didn't work, and walk through how to successfully bypass the username check.

First, let's break down the key issues you might be hitting, then fix them step by step:

1. Your Compilation Environment Might Be Blocking the Overflow

Modern compilers enable stack protection mechanisms by default (like stack canaries) that detect buffer overflows and crash the program before you can overwrite the allow variable. For this exercise, you need to disable these protections to make the overflow possible.

Compile your code with these flags to turn off security features and disable optimizations (which can reorder variables or store them in registers):

gcc -g -fno-stack-protector -z execstack -O0 vuln.c -o vuln
  • -g: Adds debug info to help inspect variables later
  • -fno-stack-protector: Disables stack canaries that block overflows
  • -z execstack: Disables the "no-execution stack" restriction (not strictly needed here, but common in exploit exercises)
  • -O0: Turns off all optimizations to keep variables in the stack in their code-defined order

2. You Need to Confirm the Exact Offset Between username and allow

Just because you defined username[8] before allow doesn't guarantee they're immediately adjacent in memory. Compilers might add padding bytes for alignment, or even reorder variables in some cases.

Use GDB to find their addresses:

  1. Start GDB with your compiled binary: gdb ./vuln
  2. Set a breakpoint at the start of main: break main
  3. Run the program: run
  4. Print the addresses of both variables:
    p &username
    p &allow
    
    For example, if you get:
    $1 = (char (*)[8]) 0xffffd060
    $2 = (int *) 0xffffd068
    
    The offset between username and allow is 8 bytes (since 0xffffd068 - 0xffffd060 = 8). That means username takes exactly 8 bytes, and allow starts right after it.

3. The gets() Function Adds a Null Terminator—This Is Likely Your Mistake!

gets() reads input until it hits a newline, then replaces that newline with a null byte (\0) at the end of the input. So if you entered 9 characters and pressed enter:

  • The first 8 fill the username buffer
  • The 9th character goes into the first byte of allow
  • Then gets() writes a \0 into the second byte of allow

But even with that, allow would be a non-zero value (since its first byte is non-zero), which should trigger the Success message—unless your compiler had protections enabled (which we fixed in step 1).

4. Construct the Correct Input

Let's use the offset we found (8 bytes) to craft input that sets allow to a non-zero value:

  • If the offset is 8: Enter 8 arbitrary characters + 1 non-zero character, then press enter. For example, use printf to pipe this input directly (typing control characters in the terminal can be tricky):

    printf 'AAAAAAAA\x01\n' | ./vuln
    

    This will:

    • Fill username with 8 'A's
    • Write \x01 to the first byte of allow
    • The \n triggers gets() to stop reading, and it appends a \0 to the second byte of allow

    Since allow is an int (4 bytes), its value becomes 0x00000001 (on little-endian systems like x86), which is non-zero—so the if (allow) condition passes, and you'll see "Success".

What If the Offset Is Larger?

If GDB shows a bigger offset (like 12 bytes, due to padding), you'll need to fill the username buffer, the padding bytes, then write to allow. For example, if offset is 12:

printf 'AAAAAAAAAAAA\x01\n' | ./vuln

The first 12 characters fill username and padding, then \x01 overwrites the first byte of allow.


内容的提问来源于stack exchange,提问作者Gilad Tayeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 15:47:29