c - 为什么 printf 没有打印出这个缓冲区溢出中的字符串?
问题描述
我正在学习缓冲区溢出。我写了一个小 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!!");
thenstdout
将在puts
返回之前被刷新。
但是使用printf
,数据只是坐在 stdio 缓冲区中,直到其他东西打印换行符,或者直到fflush(stdout)
。 exit()
或干净地返回main
将导致 fflush,但 segfaulting 将终止进程,而无需进行系统调用以将该 I/O 数据交给操作系统。
这与在汇编中使用 printf 导致空输出完全相同的问题,只是这种情况是使用_exit(2)
系统调用而不是段错误。
如果目标是强迫您在win()
不中断后续执行的情况下被跟注,那将是另一个级别的挑战。
但是 ifwin()
应该代表类似调用system()
或execve
with "/bin/sh"
then的成功的 ROP 攻击这样的东西win()
写得不好。 execve
将在现场发生,而不是在以后的某个时间。
推荐阅读
- angular - 渲染子组件后如何保留父组件事件
- lua - 如何修复“尝试索引零值”
- javafx - 防止 JavaFX Tooltip 聚焦后台阶段
- azure - 在 Azure AD 中设置单租户应用程序
- javascript - 嵌入式谷歌地图未在 Firefox 中完全呈现
- vue.js - Easeljs:“createjs.Ticker.paused = true”不起作用
- iccube - 服务器端PDF导出功能
- java - 如何在 Java 中向 Octoprint 发送 POST 请求?
- solr - 按 document.contentType 搜索
- amp-html - 您可以在非 amp 页面上使用 AMP 标签吗?