为什么printf没有打印出这个缓冲区溢出的字符串呢?
Why didn't printf print out the string in this buffer overflow?
我正在学习缓冲区溢出。我写了一个小 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
没有打印出字符串?
stdout 默认为行缓冲,字符串不以换行符结尾。如果将其更改为 puts("Pwned!!");
,则 stdout
将在 puts
returns.
之前被刷新
但是对于 printf
,数据只是坐在 stdio 缓冲区中,直到其他东西打印换行符,或者直到 fflush(stdout)
。 exit()
或 cleanly 从 main
返回将导致 fflush,但段错误会终止进程,而无需进行系统调用以将 I/O 数据交给OS.
这与 的问题完全相同,只是那个案例使用的是 _exit(2)
系统调用而不是段错误。
如果目标是强制您在不中断后续执行的情况下调用 win()
,那就是另一个级别的挑战。
但是如果 win()
应该代表某种成功的 ROP 攻击,用 "/bin/sh"
调用 system()
或 execve
那么 win()
就不好-书面。 execve
将在现场发生,而不是稍后发生。
我正在学习缓冲区溢出。我写了一个小 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
没有打印出字符串?
stdout 默认为行缓冲,字符串不以换行符结尾。如果将其更改为 puts("Pwned!!");
,则 stdout
将在 puts
returns.
但是对于 printf
,数据只是坐在 stdio 缓冲区中,直到其他东西打印换行符,或者直到 fflush(stdout)
。 exit()
或 cleanly 从 main
返回将导致 fflush,但段错误会终止进程,而无需进行系统调用以将 I/O 数据交给OS.
这与 _exit(2)
系统调用而不是段错误。
如果目标是强制您在不中断后续执行的情况下调用 win()
,那就是另一个级别的挑战。
但是如果 win()
应该代表某种成功的 ROP 攻击,用 "/bin/sh"
调用 system()
或 execve
那么 win()
就不好-书面。 execve
将在现场发生,而不是稍后发生。