【问题标题】:Why does the program catch SIGSEGV on push instructions?为什么程序会在推送指令上捕获 SIGSEGV?
【发布时间】:2020-11-30 15:46:50
【问题描述】:

编写了一个简单的 x86_64 shellcode:

BITS 64
xor rax, rax
push rax
push 0x68732f6e
push 0x69622f2f
mov rbx, rsp
push rax
mov rdx, rsp
push rbx
mov rcx, rsp
mov al, 221
int 0x80

通过缓冲区溢出,shellcode 被发送到处理器。一切顺利,直到执行完最后的第三条指令(push rbx)。然后程序捕获 SIGSEGV 并且永远不会到达珍贵的中断 - int 0x80。我想可能是堆栈溢出了,我在 shellcode 的开头插入了几个弹出指令。结果,SIGSEGV 在同一条指令上更改为 SIGILL - push rbx。根本没有任何想法。 GDB:

=> 0x7fffffffea72:  mov    rdx,rsp
   0x7fffffffea75:  push   rbx
   0x7fffffffea76:  mov    rcx,rsp
   0x7fffffffea79:  mov    al,0xdd
   0x7fffffffea7b:  int    0x80
   0x7fffffffea7d:  (bad)  
   0x7fffffffea7e:  (bad)  
   0x7fffffffea7f:  inc    DWORD PTR [rax]
-----------------------------------------------------------------------------------------------------------------------------
0x00007fffffffea72 in ?? ()
gdb$ n
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x00007FFFFFFFEA88  RBP: 0xFFFFFFFFFFFFFFFF  RSP: 0x00007FFFFFFFEA80  o d I t s Z a P c 
  RDI: 0x00007FFFFFFFEA60  RSI: 0x0000555555556021  RDX: 0x00007FFFFFFFEA80  RCX: 0x60FFFFFFFFFFFFFF  RIP: 0x00007FFFFFFFEA75
  R8 : 0x0000000000000000  R9 : 0x00007FFFF7FE14C0  R10: 0xFFFFFFFFFFFFF8F5  R11: 0x00007FFFF7E54B60  R12: 0x0000555555555060
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B                
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x7fffffffea75:  push   rbx
   0x7fffffffea76:  mov    rcx,rsp
   0x7fffffffea79:  mov    al,0xdd
   0x7fffffffea7b:  int    0x80
   0x7fffffffea7d:  (bad)  
   0x7fffffffea7e:  (bad)  
   0x7fffffffea7f:  inc    DWORD PTR [rax]
   0x7fffffffea81:  add    BYTE PTR [rax],al
-----------------------------------------------------------------------------------------------------------------------------
0x00007fffffffea75 in ?? ()
gdb$ n

Program received signal SIGSEGV, Segmentation fault.
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x00007FFFFFFFEA88  RBP: 0xFFFFFFFFFFFFFFFF  RSP: 0x00007FFFFFFFEA78  o d I t s Z a P c 
  RDI: 0x00007FFFFFFFEA60  RSI: 0x0000555555556021  RDX: 0x00007FFFFFFFEA80  RCX: 0x60FFFFFFFFFFFFFF  RIP: 0x00007FFFFFFFEA76
  R8 : 0x0000000000000000  R9 : 0x00007FFFF7FE14C0  R10: 0xFFFFFFFFFFFFF8F5  R11: 0x00007FFFF7E54B60  R12: 0x0000555555555060
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B

信息过程映射:

gdb$ info proc mappings
process 3025
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555555000     0x1000        0x0 /home/yagur/Hacking.exploits.study/exploits/buffer_overflow.bin
      0x555555555000     0x555555556000     0x1000     0x1000 /home/yagur/Hacking.exploits.study/exploits/buffer_overflow.bin
      0x555555556000     0x555555557000     0x1000     0x2000 /home/yagur/Hacking.exploits.study/exploits/buffer_overflow.bin
      0x555555557000     0x555555558000     0x1000     0x2000 /home/yagur/Hacking.exploits.study/exploits/buffer_overflow.bin
      0x555555558000     0x555555559000     0x1000     0x3000 /home/yagur/Hacking.exploits.study/exploits/buffer_overflow.bin
      0x7ffff7dbb000     0x7ffff7dbd000     0x2000        0x0 
      0x7ffff7dbd000     0x7ffff7de3000    0x26000        0x0 /usr/lib/libc-2.32.so
      0x7ffff7de3000     0x7ffff7f30000   0x14d000    0x26000 /usr/lib/libc-2.32.so
      0x7ffff7f30000     0x7ffff7f7c000    0x4c000   0x173000 /usr/lib/libc-2.32.so
      0x7ffff7f7c000     0x7ffff7f7f000     0x3000   0x1be000 /usr/lib/libc-2.32.so
      0x7ffff7f7f000     0x7ffff7f82000     0x3000   0x1c1000 /usr/lib/libc-2.32.so
      0x7ffff7f82000     0x7ffff7f88000     0x6000        0x0 
      0x7ffff7fca000     0x7ffff7fce000     0x4000        0x0 [vvar]
      0x7ffff7fce000     0x7ffff7fd0000     0x2000        0x0 [vdso]
      0x7ffff7fd0000     0x7ffff7fd2000     0x2000        0x0 /usr/lib/ld-2.32.so
      0x7ffff7fd2000     0x7ffff7ff3000    0x21000     0x2000 /usr/lib/ld-2.32.so
      0x7ffff7ff3000     0x7ffff7ffc000     0x9000    0x23000 /usr/lib/ld-2.32.so
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x2b000 /usr/lib/ld-2.32.so
      0x7ffff7ffd000     0x7ffff7fff000     0x2000    0x2c000 /usr/lib/ld-2.32.so
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
gdb$ 
New question: Changed the shellcode to the following:
BITS 64
pop rax
pop rax
pop rax
pop rax
xor rax, rax
push rax
push 0x68732f6e
push 0x69622f2f
mov rbx, rsp
push rax
mov rdx, rsp
push rbx
mov rcx, rsp
mov al, 221
int 0x80

通过这样做,我可以防止我的 shellcode 被覆盖。结果:

gdb$ ni
--------------------------------------------------------------------------
---------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x00007FFFFFFFEAA8  RBP: 0xFFFFFFFFFFFFFFFF  RSP:
 0x00007FFFFFFFEAA0  o d I t s Z a P c 
  RDI: 0x00007FFFFFFFEA60  RSI: 0x0000555555556021  RDX: 0x00007FFFFFFFEAA0  RCX:
 0x60FFFFFFFFFFFFFF  RIP: 0x00007FFFFFFFEA79
  R8 : 0x0000000000000000  R9 : 0x00007FFFF7FE14C0  R10: 0xFFFFFFFFFFFFF8F5  R11:
 0x00007FFFF7E54B60  R12: 0x0000555555555060
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B
                
--------------------------------------------------------------------------
---------------------------------------------[code]
=> 0x7fffffffea79:  push   rbx
   0x7fffffffea7a:  mov    rcx,rsp
   0x7fffffffea7d:  mov    al,0xdd
   0x7fffffffea7f:  int    0x80
   0x7fffffffea81:  (bad)  
   0x7fffffffea82:  (bad)  
   0x7fffffffea83:  (bad)  
   0x7fffffffea84:  (bad)  
--------------------------------------------------------------------------------
---------------------------------------------
0x00007fffffffea79 in ?? ()
gdb$ ni

Program received signal SIGILL, Illegal instruction.
--------------------------------------------------------------------------
---------------------------------------------[regs]
  RAX: 0xFFFFFFFFFFFFFFF7  RBX: 0x00007FFFFFFFEAA8  RBP: 0xFFFFFFFFFFFFFFFF  RSP:
 0x00007FFFFFFFEA98  o d I t s Z a P c 
  RDI: 0x00007FFFFFFFEA60  RSI: 0x0000555555556021  RDX: 0x00007FFFFFFFEAA0  RCX:
 0x00007FFFFFFFEA98  RIP: 0x00007FFFFFFFEA81
  R8 : 0x0000000000000000  R9 : 0x00007FFFF7FE14C0  R10: 0xFFFFFFFFFFFFF8F5  R11:
 0x00007FFFF7E54B60  R12: 0x0000555555555060
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B
                
--------------------------------------------------------------------------
---------------------------------------------[code]
=> 0x7fffffffea81:  (bad)  
   0x7fffffffea82:  (bad)  
   0x7fffffffea83:  (bad)  
   0x7fffffffea84:  (bad)  
   0x7fffffffea85:  (bad)  
   0x7fffffffea86:  (bad)  
   0x7fffffffea87:  (bad)  
   0x7fffffffea88:  (bad)  
--------------------------------------------------------------------------------
---------------------------------------------
0x00007fffffffea81 in ?? ()
gdb$ 

【问题讨论】:

  • 如果您正在使用 gef,您能否包含 vmmap 的输出,如果您不是,您能否包含 info proc mappings 的输出?
  • 可以,但请包含info proc mappings的输出。
  • 您的 shellcode 在堆栈中,很可能会被推送覆盖。
  • 我添加了 info proc 映射
  • 小丑,这怎么可能?毕竟,堆栈从地址增长到最小地址。 push 指令不应该覆盖 shellcode

标签: linux assembly x86-64 shellcode


【解决方案1】:

两个问题。

首先,您正在使用n GDB 命令,该命令应该跳转到下一个源代码行,这可能需要很多指令。 (并且当您执行不属于二进制文件的代码时,行号无论如何都没有意义,n 将无法可靠地工作。)您想改用ni,或者更好的是si,哪个将始终只执行一条指令,而不会尝试跳过子程序调用等。

确实,请注意段错误后寄存器转储中RIP 的值。这不是您的push rbx 的地址,所以这不是出错的指令;相反,它是以下指令,您本来应该是 mov rcx, rsp

一个简单的寄存器移动如何导致段错误?因为它不再是注册移动 - 你只是覆盖了它。比较 RSP 和 RIP 的值。您正在执行堆栈中的代码,并且您的push rbx 存储到地址0x00007FFFFFFFEA78,而mov rcx, rsp 是从0x7fffffffea76 开始的三字节指令。所以你只是覆盖了它的第三个字节。如果此时你再执行一次disassemblex/i $rip,你会看到你最终执行的指令——我敢打赌它会访问内存。

确实,mov rcx, rsp 被编码为48 89 e1rbx 的低字节为0x88,用88 覆盖第三个字节产生48 89 88 xx xx xx xx,即mov [rax+disp], rcx

【讨论】:

  • 非常感谢您的回答!
  • 谢谢。我有一个新问题。我已经更改了 shellcode,并且我有一个 SIGILL 信号。我的问题中的新信息。
  • @СтаниславТимошко:可能仍然是因为覆盖堆栈上的代码。 add rsp, -128 或者如果您的漏洞利用使 RSP 代码低于进入时的 RSP 值,则可以将 RSP 移至新空间。另请注意What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code? - 您不能将int 0x80 与 64 位指针一起使用,并且堆栈指针始终位于低 32 位之外。
猜你喜欢
  • 2017-02-15
  • 1970-01-01
  • 2014-02-07
  • 2016-01-20
  • 2020-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-19
相关资源
最近更新 更多