LDAPとBindRequest(simple認証)の監視

プロトコル監視

この記事はLDAPというディレクトリーサービスにアクセスするためのプロトコルについて説明します。また、Hack The BoxのReturnというマシンを使ってBindRequestの通信を見て見たいと思います。

LDAPとは?

LDAP(Lightweight Directory Access Protocol)は、ディレクトリサービスにアクセスするためのプロトコルです。ディレクトリサービスは、ネットワーク上のユーザー、デバイス、リソース(プリンター、サーバーなど)を効率的に管理するためのデータベースのようなもので、階層構造(ツリー構造)を持ちます。

LDAPは、TCP/IP上で動作し、デフォルトでは次のポートを使用します。

  • 389/tcp(プレーンなLDAP通信)
  • 636/tcp(LDAPS、TLS/SSLを使用した暗号化通信)

Active Directory(AD)などのディレクトリサービスでもLDAPが使われます。

仕様書

LDAP(Lightweight Directory Access Protocol)の仕様は、IETF(Internet Engineering Task Force)によって定義されており、主に RFC(Request for Comments) 文書に記載されています。以下が主な仕様です。
理解を深めるのに重要なRFC 4511(プロトコル仕様)RFC 4513(認証・セキュリティ) のURLをリンクしておきます。

LDAPの主要な仕様(RFC)

  1. LDAPv3 の基本仕様(最新版)
  2. LDAPv2(旧仕様・非推奨)
    • RFC 1777 – 旧 LDAPv2 の仕様(現在は LDAPv3 に移行)

メッセージの種類

以下はRFC4511で定義されているLDAPのメッセージの種類です。
この後認証部分について深堀したいと思います。

メッセージ種類説明リクエストレスポンス
認証(Bind)クライアントがサーバーに認証を要求BindRequestBindResponse
検索(Search)ディレクトリ内の情報を検索SearchRequestSearchResultEntry / SearchResultDone
追加(Add)新しいエントリをディレクトリに追加AddRequestAddResponse
変更(Modify)既存のエントリの属性を変更ModifyRequestModifyResponse
削除(Delete)既存のエントリを削除DeleteRequestDeleteResponse
接続終了(Unbind)サーバーとの接続を終了UnbindRequest(レスポンスなし)
拡張操作(Extended)LDAPの標準操作にない特殊な処理(例: パスワード変更)ExtendedRequestExtendedResponse

Bind Requestについて

BindRequest は、LDAP クライアントがディレクトリサーバーに対して認証を試みる際に使用するメッセージです。

2つの認証方式

シンプル認証(Simple Authentication)

  • authentication フィールドに プレーンテキストのパスワード が含まれる。
  • LDAP:// で通信すると 暗号化されずにパスワードが送信 されるため危険。
  • LDAPS://STARTTLS を使用して暗号化するのが推奨。

SASL 認証

  • Kerberos や NTLM などの安全な認証方式を使用可能。
  • authentication フィールドが [3] SaslCredentials になり、SASL プロトコルで処理される。

RFC 4511 による定義

RFC 4511 では、BindRequest は以下のように定義されています。

BindRequest ::= [APPLICATION 0] SEQUENCE {
version INTEGER (1 .. 127),
name LDAPDN,
authentication CHOICE {
simple [0] OCTET STRING,
sasl [3] SaslCredentials
}
}

※EXPLICIT TAG[0] ⇒ バイナリでは[80]となります(下の通信データ例参照)
※EXPLICIT TAG[3] ⇒ バイナリでは[A3]となります

各フィールドの詳細

フィールド名説明
versionINTEGER (1..127)LDAP のバージョン。一般的には 3 が使われる。
nameLDAPDNバインドするユーザーの識別名(DN: Distinguished Name)。
authenticationCHOICE認証方法を示す。
├─ simple[0] OCTET STRINGプレーンテキストのパスワード(基本認証)。
├─ sasl[3] SaslCredentialsSASL 認証(Kerberos, DIGEST-MD5 などの方式をサポート)。

Bind Request の例

それではHack The BoxのReturnというマシンとのLDAPの通信内容を見ていきます。

通信内容を見る前に前提の説明をさせていただきます。

  • 10.10.11.108 = Return (クライアント)
  • 10.10.16.2 = 私(疑似サーバ)
  • ReturnはAD(ActiveDirectory)配下のプリンター
  • Returnの管理画面からADの接続先を私に変更している(Returnは私をADコントローラーだと思って接続しにきます)
  • こちらではResponderというツールで擬似的に応答を返している
  • 上記やりとりをWiresharkを使って監視

Wiresharkの通信状況

ポート389でフィルターすると、上から4つ目にBind Requestがあります。

3ハンドシェイクの流れ

BindRequestの上にある3つの通信は3ハンドシェイク(Three-Way Handshake)と言われるものです。3ハンドシェイクはTCP通信の接続を確立するために行われる3回のメッセージ交換のプロセスです。このプロセスによって、クライアントとサーバーが通信可能な状態になります。

  1. SYN(Synchronize)
    • クライアントがサーバーに接続要求を送ります。この要求には、接続を開始するためのシーケンス番号(初期シーケンス番号)も含まれています。
    • 例:クライアント → SYN(シーケンス番号X)
  2. SYN-ACK(Synchronize-Acknowledge)
    • サーバーがクライアントの要求を受け入れ、接続の準備ができたことを示す応答を送ります。応答には、自分のシーケンス番号と、クライアントから受け取ったシーケンス番号+1を確認応答として含めます。
    • 例:サーバー → SYN-ACK(シーケンス番号Y、確認応答番号X+1)
  3. ACK(Acknowledge)
    • クライアントがサーバーからの応答を確認し、最終的な接続確認を送ります。このメッセージには、サーバーから受け取ったシーケンス番号+1を確認応答として含めます。
    • 例:クライアント → ACK(確認応答番号Y+1)

この3つのメッセージ交換が完了することで、クライアントとサーバーは通信を開始できる状態になります。

3ハンドシェイクの目的

  • 接続の確立: クライアントとサーバーはお互いに通信可能か確認し、シーケンス番号の同期を取ることで、データの送受信の順番を正確に管理します。
  • 信頼性の確保: 3ハンドシェイクを通じて、両者が接続に合意したことを確認し、途中でデータが欠落しないようにします。

Bind Requestの通信データ

それでは今回の目的となるBindRequestの通信データを見てみたいと思います。
ただ、いきなり見ても、、、
通信データでは上で説明したBindRequest以外の部分も含まれているので、
わかりやすく順に説明していきます。

0000   45 00 00 54 53 3c 40 00 7f 06 78 e6 0a 0a 0b 6c   E..TS<@...x....l
0010   0a 0a 10 02 c9 f9 01 85 bc ab 18 b2 7b c0 3c 09   ............{.<.
0020   50 18 04 00 23 87 00 00 30 2a 02 01 01 60 25 02   P...#...0*...`%.
0030   01 02 04 12 72 65 74 75 72 6e 5c 73 76 63 2d 70   ....return\svc-p
0040   72 69 6e 74 65 72 80 0c 31 65 64 46 67 34 33 30   rinter..1edFg430
0050   31 32 21 21                                       12!!

TCPヘッダー部分

最初の0x00 – 0x28は TCPヘッダ なので、LDAPメッセージは0x29 から始まります( 30 2a)。

0000   45 00 00 54 53 3c 40 00 7f 06 78 e6 0a 0a 0b 6c  # IP ヘッダ(省略)
0010   0a 0a 10 02 c9 f9 01 85 bc ab 18 b2 7b c0 3c 09  # TCP ヘッダ(省略)
0020   50 18 04 00 23 87 00 00                           # TCP フラグメント終了

LDAP Message本体

まずは先頭7byteについて説明します。
上述の通りLDAPにはBindRequest以外にもメッセージの種類がありますが、先頭7byteではどのメッセージ種類かを知ることができます。

0020   50 18 04 00 23 87 00 00 30 2a 02 01 01 60 25 
30                            # [30] = SEQUENCE (LDAPMessage) 
2a                            # [2a] = LDAPMessageの長さ 42 バイト
02 01 01                      # messageID: INTEGER (1)
                              # [02] = INTEGER型(ASN.1 の識別子)
                              # [01] = 長さ(1バイト)
                              # [01] = 値(1)
60                            # [60] = BindRequest
25                            # [25] = BindRequestの長さ 37 バイト

※MessageIDは値としては1となりますが、ANS.1/BERの書式では上記のようになります

BER(Basic Encoding Rules)とは?

バイナリデータ に変換するルールです。

📌 BER の基本構造

[タグ (Type)] [長さ (Length)] [値 (Value)]
  • タグ(Type) → データの型(INTEGER, SEQUENCE, OCTET STRINGなど)
  • 長さ(Length) → データのバイト数
  • 値(Value) → 実際のデータ
ASN.1(Abstract Syntax Notation One)のタグ番号とは?

ASN.1 のデータ型には 標準のタグ番号 が割り当てられています。
INTEGER のタグ番号は「2(0x02)」 です。

ASN.1 の基本的な型のタグ番号は以下のようになっています:

ASN.1 型タグ(16進数)タグ(10進数)
BOOLEAN0x011
INTEGER0x022
BIT STRING0x033
OCTET STRING0x044
NULL0x055
OBJECT IDENTIFIER0x066
SEQUENCE0x3048

Bind Request本体

ここからがBindRequestです。
冒頭のBind Requestの定義と見比べながら読んでください。

0020   50 18 04 00 23 87 00 00 30 2a 02 01 01 60 25 02   P...#...0*...`%.
0030   01 02 04 12 72 65 74 75 72 6e 5c 73 76 63 2d 70   ....return\svc-p
0040   72 69 6e 74 65 72 80 0c 31 65 64 46 67 34 33 30   rinter..1edFg430
0050   31 32 21 21                                       12!!
02 01 02                             # バージョン: INTEGER (2)
                                     # [02] = INTEGER型(ASN.1 の識別子)
                                     # [01] = 長さ(1バイト)
                                     # [02] = 値(2)
04                                   # [04] = 名前 (DN)
12                                   # [12] = 名前の長さ :OCTET STRING (18 バイト)
72 65 74 75 72 6e 5c 73 76 63 2d 70 72 69 6e 74 65 72
                                     # "return\svc-printer"(LDAPのユーザ名)
80                                   # [80] = 認証パスワード(SIMPLE BIND)
0C                                   # [0C] = 認証パスワードの長さ(12 バイト)
31 65 64 46 67 34 33 30 31 32 21 21  # "1edFg43012!!"(平文パスワード)

さいごに

今回はBind Requestの平文パスワードを取得する例を見ながらLDAPのさわり部分を見てみました。
興味を持った方はReturnというマシンのWriteupも合わせて読みながら是非HackTheBoxで手を動かしながら試してください。

タイトルとURLをコピーしました