Linux 为什么'read()`syscall上的缓冲区溢出仅在GDB中导致'EFAULT'? 短篇小说

Linux 为什么'read()`syscall上的缓冲区溢出仅在GDB中导致'EFAULT'? 短篇小说,linux,assembly,x86-64,buffer-overflow,Linux,Assembly,X86 64,Buffer Overflow,我正在汇编中编写一个简单的程序来模拟缓冲区溢出。缓冲区只是512字节堆栈中的内存分配,然后用stdinfd中的4096字节调用read() 当我在GDB之外执行有效负载时,缓冲区溢出工作正常。但是当我在GDB中时,系统调用read()返回EFAULT 在这种情况下,我们的缓冲区溢出应该替换返回地址,并使%rip到达secret\u func 问题: 为什么在这种情况下,缓冲区溢出在GDB中不起作用 资源 代码测试 .section.rodata str1: .ascii“输入: str2:

我正在汇编中编写一个简单的程序来模拟缓冲区溢出。缓冲区只是512字节堆栈中的内存分配,然后用stdinfd中的4096字节调用
read()

当我在GDB之外执行有效负载时,缓冲区溢出工作正常。但是当我在GDB中时,系统调用
read()
返回
EFAULT

在这种情况下,我们的缓冲区溢出应该替换返回地址,并使
%rip
到达
secret\u func


问题: 为什么在这种情况下,缓冲区溢出在GDB中不起作用


资源 代码测试
.section.rodata
str1:
.ascii“输入:
str2:
.ascii“\n您找到了一个秘密函数!\n”
stru_end:
.第节.正文
.全球启动
_开始:
xorl%ebp,%ebp
andq$-16,%rsp
callq main
_出口:
移动%eax,%edi
movl$60,%eax
系统调用
主要内容:
subq$512,%rsp
movl$1,%eax
movl$1,%edi
leaq str1(%rip),%rsi
movl$(str2-str1),%edx
系统调用
xorl%eax,%eax
xorl%edi,%edi
movq%rsp,%rsi
movl$4096,%edx故意造成缓冲区溢出
系统调用
addq$512,%rsp
xorl%eax,%eax
retq
#我们通过缓冲区溢出(替换返回地址)实现此功能
秘密函数:
movl$1,%eax
movl$1,%edi
leaq str2(%rip),%rsi
movl$(str_end-str2),%edx
系统调用
xorl%eax,%eax
jmp_出口
已编译ELF的objdump
节的反汇编。文本:
0000000000401000 :
401000:31 ed异或%ebp,%ebp
401002:48 83 e4 f0和$0xFFFFFFFFFFF0,%rsp
401006:e8 09 00致电401014
0000000000 40100B:
40100b:89 c7 mov%eax%edi
40100d:b8 3c 00 mov$0x3c,%eax
401012:0f 05系统调用
0000000000401014 :
401014:48 81 ec 00 02 00分$0x200,%rsp
40101b:b8 01 00 mov$0x1,%eax
401020:bf 01 00 mov$0x1,%edi
401025:48 8d 35 d4 0f 00 lea 0xfd4(%rip),%rsi#402000
40102c:ba 11 00 mov$0x11,%edx
401031:0f 05系统调用
401033:31 c0异或%eax,%eax
401035:31 ff异或%edi,%edi
401037:4889E6MOV%rsp%rsi
40103a:ba 00 10 00 mov$0x1000,%edx
40103f:0f 05系统调用
401041:48 81 c4 00 02 00添加$0x200,%rsp
401048:31 c0异或%eax,%eax
40104a:c3 ret
0000000000 40104B:
40104b:b8 01 00 mov$0x1,%eax
401050:bf 01 00 mov$0x1,%edi
401055:48 8d 35 b5 0f 00 lea 0xfb5(%rip),%rsi#402011
40105c:ba 1d 00 mov$0x1d,%edx
401061:0f 05系统调用
401063:31 c0异或%eax,%eax
401065:eb a4 jmp 40100b

复制步骤 在没有GDB的情况下编译和运行(工作正常) 在这种情况下,我们计算返回地址的偏移量,并将其替换为
secret\u func
address

ammarfaizi2@integral:/tmp$gcc-O3-no pie-static-nostartfiles-ffreestanding test.S-o test
ammarfaizi2@integral:/tmp$perl-e'打印“A”x512、\x4b\x10\x40、“\x00”x5'>有效负载
ammarfaizi2@integral:/tmp$。/测试<有效负载
输入输入:
你找到了一个秘密函数!
ammarfaizi2@integral:/tmp$
在GDB中编译并运行(
read()
返回-14(-EFAULT)) 我们步进了
read()
syscall,发现它返回-14。它根本不从stdin读取

gef➤  主干道
0x401014处的断点1
全球环境基金➤  r<输入
[…省略全球环境基金产出…]
全球环境基金➤  si 11
[…省略全球环境基金产出…]
全球环境基金➤  x/5i$rip
=>0x401041:添加$0x200,%rsp
0x401048:xor%eax,%eax
0x40104a:ret
0x40104b:mov$0x1,%eax
0x401050:mov$0x1,%edi
全球环境基金➤  p/d$rax
$2 = -14
全球环境基金➤  壳牌14号
EFAULT 14错误地址
全球环境基金➤  

GDB和Linux版本
ammarfaizi2@integral:/tmp$gdb--版本
GNU gdb(Ubuntu10.1-2ubuntu2)10.1.90.20210411-git
版权所有(C)2021免费软件基金会。
许可证GPLv3+:GNU GPL版本3或更高版本
这是自由软件:您可以自由更改和重新发布它。
在法律允许的范围内,不存在任何担保。
ammarfaizi2@integral:/tmp$uname-r
5.13.0-rc2-fresh-tea-00005-g8ac91e6c6033
ammarfaizi2@integral:/tmp$

当您在GDB中运行它时,似乎得到的堆栈要少得多。因此,
rsp+4096
超出了程序的映射页面。如果没有GDB,堆栈指针为“较低”,并且
rsp+4096
仍在堆栈中。在调用
main
@MargaretBloom之前,您可以尝试减少读取的字节数或人为降低堆栈指针:实际上,直接执行时,堆栈上的辅助向量与argv/环境字符串之间的间隙略大于4K,其中填充了零。在gdb下运行时,没有间隙。