简体   繁体   中英

Why didn't printf print out the string in this buffer overflow?

I'm learning buffer overflow. I wrote a small C program:

#include<stdio.h>
#include<string.h>
void vuln();
void win();
void main(int argc, char *argv[]){
        vuln();

}
void win (){
        printf("Pwned!!");
}
void vuln(){
        char buffer[256];
        printf("Enter a string: ");
        scanf(" %s", buffer);
}

Disassembly of the vuln function:

gef➤  disas vuln
Dump of assembler code for function vuln:
   0x0000555555555179 <+0>:     push   rbp
   0x000055555555517a <+1>:     mov    rbp,rsp
   0x000055555555517d <+4>:     sub    rsp,0x100
   0x0000555555555184 <+11>:    lea    rdi,[rip+0xe81]        # 0x55555555600c
   0x000055555555518b <+18>:    mov    eax,0x0
   0x0000555555555190 <+23>:    call   0x555555555030 <printf@plt>
   0x0000555555555195 <+28>:    lea    rax,[rbp-0x100]
   0x000055555555519c <+35>:    mov    rsi,rax
   0x000055555555519f <+38>:    lea    rdi,[rip+0xe77]        # 0x55555555601d
   0x00005555555551a6 <+45>:    mov    eax,0x0
   0x00005555555551ab <+50>:    call   0x555555555040 <__isoc99_scanf@plt>
   0x00005555555551b0 <+55>:    nop
   0x00005555555551b1 <+56>:    leave  
   0x00005555555551b2 <+57>:    ret    
End of assembler dump.

I managed to jump to win by using the payload:

>>> payload = "A"264 + p64(0x0000555555555161)

The problem is that it didn't print out the string in the function win . All I get was segmentation fault. Here's what I get:

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffe158 in ?? ()
[ Legend: Modified register | Code | Heap | Stack | String ]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x7               
$rbx   : 0x0               
$rcx   : 0x0               
$rdx   : 0x0               
$rsp   : 0x00007fffffffe068  →  0x0000000200000000
$rbp   : 0x4141414141414141 ("AAAAAAAA"?)
$rsi   : 0x656e7750        
$rdi   : 0x00005555555592a0  →  "Pwned!! string: "
$rip   : 0x00007fffffffe158  →  0x00007fffffffe436  →  "/media/sf_Code/asm/vuln"
$r8    : 0x00007ffff7fb9500  →  0x00007ffff7fb9500  →  [loop detected]
$r9    : 0x7               
$r10   : 0x0000555555556004  →  0x00212164656e7750 ("Pwned!!"?)
$r11   : 0x246             
$r12   : 0x0000555555555060  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffe150  →  0x0000000000000002
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero carry PARITY ADJUST sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffe068│+0x0000: 0x0000000200000000   ← $rsp
0x00007fffffffe070│+0x0008: 0x00005555555551c0  →  <__libc_csu_init+0> push r15
0x00007fffffffe078│+0x0010: 0x00007ffff7e1ebbb  →  <__libc_start_main+235> mov edi, eax
0x00007fffffffe080│+0x0018: 0x0000000000000000
0x00007fffffffe088│+0x0020: 0x00007fffffffe158  →  0x00007fffffffe436  →  "/media/sf_Code/asm/vuln"
0x00007fffffffe090│+0x0028: 0x0000000200100000
0x00007fffffffe098│+0x0030: 0x0000555555555145  →  <main+0> push rbp
0x00007fffffffe0a0│+0x0038: 0x0000000000000000
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x7fffffffe152                  add    BYTE PTR [rax], al
   0x7fffffffe154                  add    BYTE PTR [rax], al
   0x7fffffffe156                  add    BYTE PTR [rax], al
 → 0x7fffffffe158                  ss     in  al, 0xff
   0x7fffffffe15b                  (bad)  
   0x7fffffffe15c                  (bad)  
   0x7fffffffe15d                  jg     0x7fffffffe15f
   0x7fffffffe15f                  add    BYTE PTR [rsi-0x1c], cl
   0x7fffffffe162                  (bad)  
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "vuln", stopped 0x7fffffffe158 in ?? (), reason: SIGSEGV
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7fffffffe158 → ss in  al, 0xff

How is that the printf didn't print out the string?

stdout defaults to line-buffered, and the string doesn't end with a newline. If you changed it to puts("Pwned;!"); then stdout would get flushed before puts returns.

But with printf , the data is just sitting there in a stdio buffer until something else prints a newline, or until fflush(stdout) . exit() or cleanly returning from main will cause fflush, but segfaulting will kill the process without ever making a system call to hand that I/O data to the OS.

This is exactly the same problem as Using printf in assembly leads to an empty ouput except that case was using an _exit(2) system call instead of segfaulting.


If the goal is to force you to get win() called without breaking later execution, that's another level of challenge.

But if win() is supposed to represent something like a successful ROP attack that calls system() or execve with "/bin/sh" then win() is not well-written. execve will happen on the spot, not at some later time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM