セキュリティ
Qsyrupwdの背後にある暗号: IBM i パスワードハッシュの再構築
The Cipher Behind Qsyrupwd: Reconstructing IBM i Password Hashes (blog.silentsignal.eu)
要約
本稿では、IBM i の QSYRUPWD API が返す暗号化されたパスワードデータの構造について解説しています。特に、QPWDLVL システム値が 2 以上の場合、API の出力形式が変更され、John the Ripper などの既存のパスワードクラッキングツールとの互換性が失われることが判明しました。この問題を解決するため、筆者は API の動作を詳細に分析し、暗号化解除に必要な情報を提供しています。
全文翻訳
Intro
QSYRUPWD (Retrieve Encrypted User Password) は、IBM i の API で、権限のある呼び出し元に対して、指定されたユーザープロファイルのパスワード関連データを暗号化された形式で返します。IBM i は、AS/400 に端を発する IBM の統合エンタープライズプラットフォームであり、ERP、金融、ロジスティクス、製造などのビジネスクリティカルなワークロードで今なお広く使用されています。この API は主に、パスワード同期、移行、レプリケーション、その他の管理シナリオをサポートするために存在し、平文のパスワードを露出させることなくパスワード情報を転送する必要があります。IBM は QSYRUPWD を、暗号化されたパスワードデータを扱うためのセキュリティ関連 API セットの一部として文書化しています。
ある IBM i のペネトレーションテスト中に、クライアントのサーバーが QPWDLVW = 2 で設定されていることに気づきました。IBM i では、QPWDLVW システム値が、オペレーティングシステムで受け入れられるパスワードルールと、認証互換性のために維持される検証子の形式の両方を決定します。IBM は、パスワードレベル 0 および 1 が古い DES ベースのスキームに対応し、レベル 2 および 3 が SHA-1 ベースのスキームを使用し、レベル 4 が PBKDF2 ベースの検証子モデルを導入すると文書化しています。また、QPWDLVW が 2 に設定されている場合、オペレーティングシステムは、以前の形式を削除するのではなく、複数のパスワード検証子形式との互換性を維持すると述べています。この区別は、QSYRUPWD の出力を解釈する上で重要です。
John the Ripper には、レガシーな IBM i のデータ用の専用 IBM i クラッキングフォーマット(特に as400_des および as400_ssha1)が含まれており、これは古い DES ベースおよびソルト付き SHA-1 ベースの表現のサポートを反映しています。しかし、私たちのテストでは、QPWDLVW 2〜4 で実行されているシステムから取得した QSYRUPWD の出力は、John the Ripper の IBM i フォーマットが期待する形式と一致しませんでした。一方、レガシーな QPWDLVW 0〜1 のケースは、これらのモジュールで処理される QSYRUPWD から派生したデータと互換性があります。つまり、QPWDLVW 2〜4 では、QSYRUPWD によって返されるコンテンツは、既存の John the Ripper IBM i フォーマットで直接使用しても成功しないように変化します。これは、IBM がこれらのレベルの正確な返却構造を公に文書化しているという主張ではなく、私たちのテストとツールの分析からの経験的な観察です。その結果、*ALLOBJ および *SECADM(QSYRUPWD を呼び出すために必要)が付与されていても、API は実用的なパスワード強度テストに使用できなくなりました。このエンゲージメントの後、QSYRUPWD API を詳細に分析することにしました。
Tools
API の動作を直接調べるために、UPWD0100 フォーマットで QSYRUPWD を呼び出し、返されたバッファを取得して、さらに分析のために出力する小さな CL プログラムを作成しました。目標は完全な抽出ツールを作成することではなく、異なる QPWDLVW 設定の下で API がどのような種類のパスワード関連データを返すかを検証することでした。これにより、システム間の実際の出力フォーマットを比較し、返されたデータが John the Ripper のような既存のクラッキングツールが期待する入力と一致するかどうかを判断することができました。
PGM PARM(&USER)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&RCV) TYPE(*CHAR) LEN(4000)
DCL VAR(&LEN) TYPE(*INT) LEN(4) VALUE(4000)
DCL VAR(&FMT) TYPE(*CHAR) LEN(8) VALUE('UPWD0100')
DCL VAR(&ERR) TYPE(*CHAR) LEN(8) VALUE(X'0000000000000000')
DCL VAR(&N) TYPE(*INT) LEN(4)
DCL VAR(&N4) TYPE(*CHAR) LEN(4)
DCL VAR(&NCH) TYPE(*CHAR) LEN(11)
CALL PGM(QSZS/QSYRUPWD) PARM(&RCV &LEN &FMT &USER &ERR)
MONMSG CPF0000 EXEC(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('QSYRUPWD failed') MSGTYPE(*ESCAPE)
RETURN
ENDDO
CHGVAR VAR(&N4) VALUE(%SST(&RCV 1 4))
CHGVAR VAR(&N) VALUE(%BIN(&N4))
CHGVAR VAR(&NCH) VALUE(%CHAR(&N))
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('QSYRUPWD ok, bytes:' *BCAT &NCH) MSGTYPE(*INFO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Data: ' *BCAT &RCV) MSGTYPE(*INFO)
ENDPGM
Trace
PWDDUMP プログラムをコンパイルした後、呼び出しトレースを生成できるかどうか疑問に思いました。幸いなことに、IBM i には STRTRC というツールがあり、QSYRUPWD 内で行われた呼び出しの証拠を収集するために使用できます。そこで、*ALLOBJ および *SECADM 権限を持つユーザーでログインし(PWDDUMP を実行するために必要)、次のコマンドを実行しました。
STRTRC SSNID(MYTRACE) JOB(*ALL/QSECOFR/QPADEV0005) JOBTRCTYPE(*ALL) CALL USERB1/PWDDUMP USERB1
ENDTRC SSNID(MYTRACE) PRTTRC(*YES) PRTTRC DTALIB(QGPL) DTAMBR(MYTRACE)
これらのコマンドは、必要な呼び出しトレース情報を含むスプールファイルを作成しますが、構造は一見すると少し紛らわしいです。以下はそのスプールファイルのスニペットの例です。
| | SYNCHRONOU CALL | CPU | READS | WR TIME THREAD FLAG FUNCTION PROGRAM LIBRARY ENTRY EXIT LVL | TIME | DB NDB|
----------------------------------------------------------------------------------------------------------------------------------
12:53:35.829041 00000065 CALL QCMD QSYS x000519 x000519 1 .000000 0 0 0
12:53:35.829041 00000065 CALL QUICMENU QSYS x0000C1 x0000C1 2 .000000 0 0 0
12:53:35.829041 00000065 CALL QUIMNDRV QSYS x00061E x00061E 3 .000000 0 0 0
12:53:35.829041 00000065 CALL QUIMGFLW QSYS x0004D9 x0004D9 4 .000000 0 0 0
12:53:35.829041 00000065 CALL QUICMD QSYS x00056F x00056F 5 .000000 0 0 0
12:53:35.829041 00000065 XCTL QSCSNTRC QSYS x000A70 x000A70 6 .000000 0 0 0
12:53:35.829041 00000065 CALL QCMDEXC QSYS x00012F x00012F 7 .000000 0 0 0
12:53:35.829041 00000065 XCTL QYPESTRP QSYS 000000 000000 8 .000000 0 0 0
生のスパールファイルの内容を、より読みやすい形式に変換するスクレイパーを作成しました。例えば次のようになります。
PWDDUMP / PWDDUMP QCLRSLV QCLCLCPR -> QMHSNDPM -> return
PWDDUMP QSYRUPWD / QSYRUPWD QLEIT / Q LE sinit_processor -> itl_callInit__FPV12ITL_COM_AREA -> QPWFSMONOC -> return
QSYRUPWD QZLSRTPW / _CXX_PEP__Fv -> main
QZLSSRV1 / QzlsGetNTPassword__FPcP15QzlsNTPasswords QSYSERV / QSYSRVRTV / qsy_rtv_user_ent__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi QSYSERV / QSYSRVUTL / caller_is_authorized__FPCcPcPPvCs QSYMIUTLS / QSYGETSYP / qsy_getSYP__FPCcT1C11_OBJ_TYPE_TPPvPs qsy_getSYP_long__FPCcT1C11_OBJ_TYPE_TPPvPs QSYAUTUTLS / QSYCHKAUT / qsy_chkaut__FPvsT2cPs qsy_chkaut__FPvsT2cT4Ps
return
QSYSERV / QSYSRVRTV / qsy_rtv_user_ent__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi QSYSERV / QSYSRVRTV / rtv_user_entries__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi QSYSERV / QSYSRVUTL / get_security_index__FPCcPPv QSYMIUTLS / QSYGETSYP / qsy_getSYP__FPCcT1C11_OBJ_TYPE_TPPvPs qsy_getSYP_long__FPCcT1C11_OBJ_TYPE_TPPvPs
QSYMIUTLS / QSYMATSOBJ / qsy_matsobj__FPvP16_MSOB_Template_TPs
return
QSYSERV / QSYSRVRTV / rtv_user_entries__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi QSYSERV / QSYSRVRTV / qsy_rtv_user_ent__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi QSYSERV / QSYSRVRHS / returnIndividualEntry__FPCcT1P20_qsy_serv_user_ent_T QSYSERV / QSYSRVRHS / process2__FP20_qsy_serv_user_ent_T QSYSERV / QSYSRVRHS / unhide_edata__FPcsP20_qsy_serv_user_ent_T QSYSERV / QSYSRVRHS / get_offset__FP20_qsy_serv_user_ent_TPi
QSYMIUTLS / QSYCIPHER / qsy_cipher__FPvP17_CIPHER_Control_TT1Ps
return
QSYSERV / QSYSRVRHS / unhide_edata__ -> process2__
QSYCODEUTL / QSYAESFNC / qsy_aes_decrypt__FPcsT1T2PsT1 QSYMIUTLS / QSYCIPHER / qsy_cipher__FPvP17_CIPHER_Control_TT1Ps QSYMIUTLS / QSYCIPHER / qsy_cipher__FPvP17_CIPHER_Control_TT1Ps
return:
QSYSERV / QSYSRVRHS / process2__FP20_qsy_serv_user_ent_T QSYSERV / QSYSRVRHS / returnIndividualEntry__FPCcT1P20_qsy_serv_user_ent_T QSYSERV / QSYSRVRTV / qsy_rtv_user_ent__FPCcN21CcCiP20_qsy_serv_rtn_data_TPi
QZLSSRV1 / QzlsGetNTPassword__FPcP15QzlsNTPasswords QZLSRTPW QSYRUPWD PWDDUMP
Reviewing the output, I immediately focused on the following symbols because their names strongly suggested cryptographic processing, including generic cipher operations, AES-related functionality, and decryption routines:
QSYMIUTLS / QSYCIPHER / qsy_cipher__FPvP17_CIPHER_Control_TT1Ps
QSYCODEUTL / QSYAESFNC / qsy_aes_decrypt__FPcsT1T2PsT1
Disassembly
System Service Tools (SST) を使用して、QSYMIUTLS、QSYCODEUTL、QZLSRTPW、および QSYRUPWD *SRVPGM オブジェクトのアセンブリコードをスプールファイルにダンプしました。System Service Tools (SST) は、低レベルの診断、デバッグ、および...