0はじめに
Jumpserverは、オープンソースのバスティオンマシンであり、4A仕様に準拠した運用およびメンテナンスセキュリティ監査システムです。素人の用語では、それはスプリングボードマシンです。
2021年1月15日、Jumpserverはセキュリティアップデートをリリースし、リモートコマンドの実行の脆弱性を修正しました。一部のJumpserverインターフェイスには認可制限がないため、攻撃者は悪意のあるリクエストを作成して機密情報を取得するか、すべてのマシンを制御して任意のコマンドを実行するための関連操作を実行できます。
影響バージョン:
JumpServer V2.6.2JumpServer V2.5.4JumpServer V2.4.5JumpServer=V1.5.9
1。脆弱性分析
修理コードのコミットレコードを参照してください: https://github.com/jumpserver/jumpserver/commit/f04e2fa0905a7cd439d7f6118bc810894eed3f3e
CeleryLogWebsocketクラスの接続がID認証で追加されたことがわかりました。
インポート時間
OSをインポートします
スレッドをインポートします
JSONをインポートします
common.utilsからImport get_loggerから
from .celery.utilsインポートget_celery_task_log_path
.ansible.utilsからImport get_ansible_task_log_pathから
from Channels.generic.websocketインポートjsonwebsocketconsumer
logger=get_logger(__ name__)
クラスTaskLogWebsocket(JSONWebsocketConsumer):
切断=false
log_types={
'Celery ': get_celery_task_log_path、
'ansible ': get_ansible_task_log_path
}
def connect(self):
user=self.scope ['user']
user.is_authenticatedおよびuser.is_org_admin:の場合
self.accept()
else:
self.close()
def get_log_path(self、task_id):
func=self.log_types.get(self.log_type)
func:の場合
return func(task_id)
def receive(self、text_data=none、bytes_data=none、** kwargs):
data=json.loads(text_data)
task_id=data.get( 'task')
self.log_type=data.get( 'type'、 'celry')
if task_id:
self.handle_task(task_id)
def wait_util_log_path_exist(self、task_id):
log_path=self.get_log_path(task_id)
self.disconnected:ではありません
os.path.exists(log_path):ではない場合
self.send_json({'message':'。 '、' task ': task_id}))
time.sleep(0.5)
続行します
self.send_json({'message':' \ r \ n '})
try:
logger.debug( 'タスクログPATH: {}'。フォーマット(log_path)))
task_log_f=open(log_path、 'rb')
return task_log_f
OSERROR:を除く
なしなし
def read_log_file(self、task_id):
task_log_f=self.wait_util_log_path_exist(task_id)
そうでない場合は、task_log_f:
logger.debug( 'タスクログファイルはne: {}'。フォーマット(task_id)))
戻る
task_end_mark=[]
self.disconnected:ではありません
data=task_log_f.read(4096)
data:の場合
data=data.replace(b '\ n'、b '\ r \ n')
self.send_json(
{'message': data.decode(errors=' agnore ')、' task ': task_id}
))
data.find(b'suceded in ')!=-1:の場合
task_end_mark.append(1)
data.find(bytes(task_id、 'utf8'))!=-1:の場合
task_end_mark.append(1)
Elif Len(task_end_mark)==2:
logger.debug( 'タスクログend: {}'。フォーマット(task_id)))
壊す
time.sleep(0.2)
task_log_f.close()
def handle_task(self、task_id):
logger.info( 'task id: {}'。形式(task_id)))
スレッド=threading.thread(ターゲット=self.read_log_file、args=(task_id、)))
thread.start()
def disconnect(self、close_code):
self.disconnected=true
self.close()
このクラスのHTTPインターフェイスをご覧ください。
このクラスを通じて、このインターフェイスのアクセスチェーンは次のとおりです。
ws/ops/tasks/log/
-TaskLogWebsocketクラスの受信関数を入力します
-TaskLogWebsocketクラスのhandle_task関数を入力します
-loglogwebsocketクラスのread_log_file関数を入力します
-Wait_util_log_path_exist tasklogwebsocketクラスの関数を入力します
-loglogwebsocketクラスのread_log_file関数を入力します
-App/ops/utls.py にget_task_log_path関数を入力します
TaskIDは、送信したtext_dataから解析されるため、制御可能です。次の方法を使用して、ログファイル/opt/jumpserver/logs/jumpserver.logを読むことができます。
ws: //10.10.10.1033608080/ws/ops/tasks/log/に送信
{'task':'/opt/jumpserver/logs/jumpserver '}上記はファイル読み取りの原則です。ログファイルの読み取りには次の制限があります。
ファイルは、絶対パスを使用してのみ読み取ることができます。ログで終わるファイルのみが読み取られます。次の分析は、リモートコード実行を実装する方法です。
/opt/jumpserver/logs/gunicorn.logを読むことで、運が良ければ、ユーザーUID、システムユーザーUID、およびAsset IDを読むことができます。
ユーザーidasset idsystemユーザーID上記の3つの情報を、ユーザーがログから取得するためにWeb端末にログインしていることを確認する必要があります。それを取得した後。 /api/v1/authentication/connection-token/interfaceを介して、/apps/authentication/api/userconnectiontokenapiを入力できます
user_id asset_id system_user_idを使用して、20秒の有効期間のみのトークンを取得できます。このトークンは、KokoコンポーネントのTTYを作成するために使用できます。
https://github.com/jumpserver/koko/blob/master/pkg/httpd/webserver.go#342
-https://github.com/jumpserver/koko/blob/4258b6a08d1d3563437ea2257ece05b22b093e15/pkg/httpd/webserver.go#l167特定のコードは次のとおりです。
完全なRCE使用手順は次のように要約されています。
WebSocket接続は許可なしに確立できます。ログファイルをWebSocketを介して読み取り、LOGファイルのシステムユーザー、ユーザー、およびアセットフィールドを取得できます。 3のフィールドを通じて、トークンを通して20秒のトークンを取得し、Koko Ttyに入ることができます。コマンドを実行する
2脆弱性の再発
2.1環境構築
ローカル環境:Xubuntu20.04JumpServerバージョン:2.6.1バージョンインストール手順:
#ダウンロード
git clone 3https://github.com/jumpserver/installer.git
CDインストーラー
#国内のDockerソースアクセラレーション
Export docker_image_prefix=docker.mirrors.ustc.edu.cn
#開発バージョンをインストールしてから2.6.1に切り替えます(2.6.1を直接インストールできるはずです。最初はデフォルトの開発バージョンとしてインストールされましたが、問題ではありません)
sudo su
./jmsctl.shインストール
./jmsctl.shアップグレードv2.6.1
# 起動する
./jmsctl.shフルログを再起動します
#yanq @ yanq-desk in〜/gitrepo [22:18336053] c:127
$ git clone 3https://github.com/jumpserver/installer.git
「インストーラー」へのクローニング.
remote:列挙オブジェクト: 467、完了。
remote:合計467(デルタ0)、再利用0(デルタ0)、パックリューズ467
: 100%(467/467)、95.24 kib | 182.00キブ/s、完了。
プロセス: 100%(305/305)、完了。
#yanq @ yanq-desk in〜/gitrepo [22:20:27]
$ CDインストーラー
#yanq @ yanq-desk in〜/gitrepo/installer on git:master o [22:20:30]
$ ls
Config-example.txt config_init jmsctl.sh readme.md scripts static.env utilsを作成します
#yanq @ yanq-desk in〜/gitrepo [22:18336059]
$ export docker_image_prefix=docker.mirrors.ustc.edu.cn
#yanq @ yanq in〜/github/installer on git:master o [22336003:43] c:130
$ sudo su
root@yanq:/home/yanq/github/installer#./jmsctl.shインストール
██╗██╗██╗███╗██╗███╗███╗██████╗██╗
██║██║███████████████████╔═════════════════════██║███████████████████╔═════════════════════██║
██║██║██║██║██████╔╝██║██║█████╗██████╔╝
█████████████║╚██║╚██╔╝██═══╝╚════██╔══╝╚════██╔══╝██╔═══╝██╔══╝
╚█████╔╝╚██████╔╝██║╚═╝╚═╝██║██║██║╚████╔╝███████╗██║
╚════╝╚═══╝╚════╝╚═╝╚═╝╚═╝
version: dev
1. JumpServerを構成します
1.構成ファイルを確認します
各コンポーネントは、YAML形式の代わりに環境変数構成ファイルを使用し、構成名は前のものと一致しています
構成ファイルの場所: /opt/jumpserver/config/config.txt
仕上げる
2。nginx証明書を構成します
証明書の場所は:/opt/jumpserver/config/nginx/certです
仕上げる
3。バックアップ構成ファイル
/opt/jumpserver/config/backup/config.txt.2021-01-17_22-03-52にバックアップします
仕上げる
4.ネットワークを構成します
IPv6をサポートする必要がありますか? (y/n)(デフォルトはn): n
仕上げる
5.暗号化キーを自動的に生成します
仕上げる
6.永続性ディレクトリを構成します
ログ記録などの永続的なディレクトリを変更し、最大のディスクを見つけ、 /opt /jumpserverなどのディレクトリを作成します
インストール後に:を変更できないことに注意してください。そうしないと、データベースが失われる可能性があります。
使用可能なファイルシステム容量は、使用済みの使用%マウントポイントです
udev 7.3g 0 7.3g 0% /dev
/dev /nvme0n1p2 468g 200g 245g 45% /
/dev/loop1 56m 56m 0 100%/snap/core18/1944
/dev/loop2 65m 65m 0 100%/snap/gtk-common-themes/1513
/dev/loop3 218m 218m 0 100%/snap/gnome-3-34-1804/60
/dev/loop0 56m 56m 0 100%/snap/core18/1932
/dev/loop5 32m 32m 0 100%/snap/snapd/10492
/dev/loop6 65m 65m 0 100%/snap/gtk-common-themes/1514
/dev/loop4 52m 52m 0 100%/snap/snap-store/498
/dev/loop7 52m 52m 0 100%/snap/snap-store/518
/dev/loop8 219m 219m 0 100%/snap/gnome-3-34-1804/66
/dev/loop9 32m 32m 0 100%/snap/snapd/10707
/dev/nvme0n1p1 511m 7.8m 504m 2%/boot/efi
永続的なボリュームストレージディレクトリ(デフォルトは /opt /jumpserver):を設定します
仕上げる
7. mysqlを構成します
外部mysql(y/n)を使用するかどうか(デフォルトはn): n
仕上げる
8。redisを構成します
外部redis(y/n)を使用するかどうか(デフォルトはn): n
仕上げる
2。Dockerをインストールして構成します
1。Dockerをインストールします
Dockerプログラムのダウンロードを開始します.
-2021-01-17 22:04336012--- https://Mirrors.aliyun.com/docker-ce/linux/static/statable/x86_64/docker-8.06.2-ce.tgz
ホストmirrors.aliyun.com(mirrors.aliyun.com). 180.97.148.110、101.89.125.248、58.216.16.38、
mirrors.aliyun.com(mirrors.aliyun.com)| 180.97.148.110 | :443 .接続。
HTTPリクエストが発行され、応答を待っています. 200 OK
長さ:43834194(42M)[アプリケーション/X-TAR]
: "/tmp/docker.tar.gzに節約
/tmp/docker.tar.gz 100%[======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
2021-01-17 22:04336016(13.8 MB/s)-Saved "/tmp/docker.tar.gz" [43834194/43834194]))
Docker Composeプログラムのダウンロードを開始します.
-2021-01-17 22:04336017--https://Get.daocloud.io/docker/compose/releases/dowdoload/1.27.4/docker-compose-linux-x86_64
ホストの解決get.daocloud.io(get.daocloud.io). 106.75.86.15
接続get.daocloud.io(get.daocloud.io)| 106.75.86.15 | :443 .接続。
HTTPリクエストが発行され、応答を待っています. 302が見つかりました
場所:https://DN-DAO-GITHUB-MIRROR.DAOCLOUD.io/docker/compose/releases/download/1.27.4/docker-compose-linux-x86_64 [新しいURLに従ってください]
-2021-01-17 223:04:28--- https://DN-DAO-GITHUB-MIRROR.DAOCLOUD.IO/DOCKER/COMPOSE/RELEASES/DOWNLOAD/1.27.4/DOCKER-COMPOSE-LINUX-X86_64
ホストdn-dao-github-mirror.daocloud.io(dn-dao-github-mirror.daocloud.io). 240e:ff:a024:200:33603fe、 240E:964:100:302:33603FE、61.160.204.242、
DN-DAO-GITHUB-MIRROR.DAOCLOUD.IO(DN-DAO-GITHUB-MIRROR.DAOCLOUD.IO)| 240E:FF:A024:200:33603FE | :43 .接続。
HTTPリクエストが発行され、応答を待っています. 200 OK
長さ:12218968(12M)[アプリケーション/X-執行可能]
: "/tmp/docker-compose"に節約
/TMP/Docker-Compose
Recommended Comments