• 简单shellcode编写


    0x00 介绍

    Shellcode 是指经过精心设计的一串指令,一旦注入正在运行的应用程序中即可运行,常用于栈和基于堆的溢出。术语Shellcode意思指的便是用于启动一个命令Shell的已编写好的可执行代码。

    0x01 预写c调用程序

    在linux中以C编写程序调用"/bin/sh"。

    #include "unistd.h"
    #include "stdio.h"
    
    char * buff[] = {"/bin/sh", NULL};
    void main(){
    	execve("/bin/sh", buff, NULL);
    }
    

    以execve开启一个bash进程,调用路径为/bin/sh。
    注:/bin/sh是一个指向dash的符号链接,实际运行的也是dash程序,dash即移植到linux的bash,比bash更小也更快。[#!/bin/bash和#!/bin/sh是什么意思以及区别]

    0x02 gdb调试

    以gdb打开编译好的文件,我调试的文件的为32-bit的,在64-bit中可以在gcc加上参数-m32即可编译为32-bit elf文件。(gcc-multilib)

    图中 1 处调用execve函数,通过plt表调用,而 2 处栈中已将参数压入,分别为程序路径、参数数组、环境变量数组(此处为NULL)。
    接着跟进,找到execve是怎么调用的:


    可以看到在0xf7e8b68d处赋予eax值0xb,0xb(11)为execve的系统调用号。下一步执行到系统调用中断(call dword ptr gs:0x10)时,ebx指向的是“/bin/sh”字符串,ecx指向的是{“/bin/sh”,NULL}数组,edx为0。于是execve在32位linux系统中的参数传递方式为“参数1->ebx;参数2->ecx;参数3->edx”。
    call *%gs:0x10 call will __kernel_vsyscall
    32位的中断调用可采用int 80;而64位可采用syscall。

    elf32函数系统调用号查看方式:cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep execve

    64位查看:cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h | grep execve

    0x03 编写汇编代码

    最终只有一个目的,就是使得参数存入寄存器,然后系统调用。

    section .text
    global _start
    _start:
      xor   eax, eax
      push  eax                  ; 字符串结尾 ==> NULL
      push  "//sh"               ; '/bin//sh'
      push  "/bin"
      mov   ebx,esp              ; '/bin//sh' address
      push  eax                  ; push 0
      push  ebx 
      mov   ecx,esp              ; array of argvs
      xor   edx,edx              ; edx = 0
      mov   al,0x0b             ; call execve
      int 80h
    

    编译:nasm -f elf32 -o test32 ./call_execve.asm
    链接:ld -m elf_i386 -o atest ./test32
    执行:


    执行成功!
    然后提取shellcode,objdump -d atest:

    Shellcode:"x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80"

    然后用C代码测试shellcode是否可用。

    #include "unistd.h"
    #include "stdio.h"
    
    void main(){
    	char *shellcode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80";
    	(*(void(*)())shellcode)();
    }
    

    其中的(*(void(*)())shellcode)();也可替换成((void(*)())shellcode)();,测试之后没有问题。在网上查找资料之后发现数据指针的*value操作符是取value地址下的数据,而在函数指针中*value则是将eip移至value地址处进行执行,而比如平时写程序的函数func();func也指向一个函数存储的位置,但是缺省了*

    编译并执行:gcc -z execstack -m32 -o ssssss shellcode_run_execve.c


    成功运行,但是得加上 -z execstack关闭NX,因为shellcode作为局部变量存于栈上。

    0x04 总结

    这是新的尝试,收获良多,计算机底层知识很重要。

    0x05 参考文章

    手把手简易实现shellcode及详解

  • 相关阅读:
    记一次文件转码与二进制查看学习
    JAVA线程池 之 Executors (二) 原理分析
    JAVA线程池 之 Executors (一) 简介
    问题:部分mysql版本问题
    Java中一个方法字节码的长度会影响程序并发下的性能?
    AccessController.doPrivileged
    Nginx配置WebService、MySQL、SQL Server、ORACLE等代理
    C# 序列化Json时如何忽略JsonProperty(PropertyName =“ someName”)
    C# 文件上传(另一台服务器的共享目录)
    C# 导入Excel读取图片上传
  • 原文地址:https://www.cnblogs.com/zUotTe0/p/10527129.html
Copyright © 2020-2023  润新知