【问题标题】:Why didn't printf print out the string in this buffer overflow?为什么 printf 没有打印出这个缓冲区溢出中的字符串?
【发布时间】:2020-04-14 02:47:42
【问题描述】:

我正在学习缓冲区溢出。我写了一个小C程序:

#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);
}

vuln函数的反汇编:

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.

我设法通过使用有效负载跳转到win

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

问题是它没有打印出函数win中的字符串。我得到的只是分段错误。这是我得到的:

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

printf 怎么没有打印出字符串?

【问题讨论】:

    标签: c assembly x86-64 buffer-overflow


    【解决方案1】:

    stdout 默认为行缓冲,字符串不以换行符结尾。如果您将其更改为puts("Pwned!!");,那么stdout 将在puts 返回之前被刷新。

    但是对于printf,数据只是在stdio缓冲区中,直到其他东西打印换行符,或者直到fflush(stdout)exit()cleanlymain 返回将导致 fflush,但段错误将终止进程,而无需进行系统调用以将该 I/O 数据交给操作系统。

    这与Using printf in assembly leads to an empty ouput 的问题完全相同,只是这种情况使用_exit(2) 系统调用而不是段错误。


    如果目标是强制您调用 win() 而不会中断以后的执行,那是另一个级别的挑战。

    但是,如果 win() 应该代表类似于成功的 ROP 攻击,它使用 "/bin/sh" 调用 system()execve,那么 win() 写得不好。 execve 将在现场发生,而不是稍后发生。

    【讨论】:

    • 您所说的关于在不中断以后执行的情况下调用win(),您有什么好的参考资料可供我阅读吗?
    • @tuz:不,IDK 是简单还是困难。我并没有真正查看您的代码或调试会话来确定您可能需要放入堆栈的内容。鉴于main 可能会中断,如果vuln 最终返回的RSP 不等于调用之前的RSP,那么除非您将返回地址一直包含回_start 或其他东西,否则仅将更多返回地址放在堆栈上是行不通的。但是 x86-64 用户空间返回地址包含一个零字节。
    猜你喜欢
    • 1970-01-01
    • 2022-11-30
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    相关资源
    最近更新 更多