Network
SSL
Wireshark
CTF
TLS

ksnctf: HTTPS is secure, Writeup (TLS 通信解読)

ksnctf(https://ksnctf.sweetduet.info/ ) の No.33 である HTTPS is secure の Writeup をメモします。
こちらは、2つの類似した証明書を利用して、TLS 通信を破ることでフラグを取り出します。パケットファイルは、http://ksnctf.sweetduet.info/q/33/q33.pcap から落としてきます。以下、Wireshark に取り込んでパケットキャプチャを行います。

TLS 通信の復習と共に、回答の手順が含まれますので、ネタバレしたくない場合は、読まないようお願いします。

TLS 通信のハンドシェイクについて

TLSのコネクションを確立するためには、以下のハンドシェイクを通して行われます。最初の ClientHello でクライアントが利用可能な暗号スイートを提示し、それに対してサーバーは自身が利用可能な暗号スイートと比較し、使用する暗号スイートを返します。それと同時 Certificate メッセージでサーバの証明書も返します。

      クライアント                                         サーバー



      ClientHello                  -------->

                                                      ServerHello

                                                     Certificate*

                                               ServerKeyExchange*

                                              CertificateRequest*

                                   <--------      ServerHelloDone

      Certificate*

      ClientKeyExchange

      CertificateVerify*

      [ChangeCipherSpec]

      Finished                     -------->

                                               [ChangeCipherSpec]

                                   <--------             Finished

      Application Data             <------->     Application Data

公開鍵の取得

q33.pcapファイル中では、SSL通信のハンドシェイクが No.4 ~ No.12のパケットで192.168.66.129のクライアントから192.168.0.39のサーバへ, No.73 ~ No.81のパケットで192.168.66.129のクライアントから192.168.0.40のサーバへと2回行われていることが確認されます。
与えられたヒントが、2つの類似した証明書を利用するとのことなので、このそれぞれ2つのSSL通信中の証明書を利用してときます。

  • 192.168.66.129のクライアントから192.168.0.39のサーバへのハンドシェイク
4   2013-11-04 04:02:38.599927  192.168.66.129  192.168.0.39    TLSv1   131 Client Hello
5   2013-11-04 04:02:38.600656  192.168.0.39    192.168.66.129  TCP 60  443 → 1529 [ACK] Seq=1 Ack=78 Win=64240 Len=0
6   2013-11-04 04:02:38.600714  192.168.0.39    192.168.66.129  TLSv1   1514    Server Hello
7   2013-11-04 04:02:38.600720  192.168.0.39    192.168.66.129  TLSv1   199 Certificate, Server Hello Done
8   2013-11-04 04:02:38.600727  192.168.66.129  192.168.0.39    TCP 54  1529 → 443 [ACK] Seq=78 Ack=1606 Win=64240 Len=0
9   2013-11-04 04:02:38.600798  192.168.66.129  192.168.0.39    TLSv1   364 Client Key Exchange, Change Cipher Spec, Finished
10  2013-11-04 04:02:38.601768  192.168.0.39    192.168.66.129  TCP 60  443 → 1529 [ACK] Seq=1606 Ack=388 Win=64240 Len=0
11  2013-11-04 04:02:38.605380  192.168.0.39    192.168.66.129  TLSv1   97  Change Cipher Spec, Finished
12  2013-11-04 04:02:38.606914  192.168.66.129  192.168.0.39    TLSv1   376 Application Data
  • 192.168.66.129のクライアントから192.168.0.40のサーバへのハンドシェイク
73  2013-11-04 04:02:39.695588  192.168.66.129  192.168.0.40    TLSv1   131 Client Hello
74  2013-11-04 04:02:39.695782  192.168.0.40    192.168.66.129  TCP 60  443 → 1531 [ACK] Seq=1 Ack=78 Win=64240 Len=0
75  2013-11-04 04:02:39.696909  192.168.0.40    192.168.66.129  TLSv1   1514    Server Hello
76  2013-11-04 04:02:39.696942  192.168.0.40    192.168.66.129  TLSv1   191 Certificate, Server Hello Done
77  2013-11-04 04:02:39.696952  192.168.66.129  192.168.0.40    TCP 54  1531 → 443 [ACK] Seq=78 Ack=1598 Win=64240 Len=0
78  2013-11-04 04:02:39.697976  192.168.66.129  192.168.0.40    TLSv1   364 Client Key Exchange, Change Cipher Spec, Finished
79  2013-11-04 04:02:39.698182  192.168.0.40    192.168.66.129  TCP 60  443 → 1531 [ACK] Seq=1598 Ack=388 Win=64240 Len=0
80  2013-11-04 04:02:39.702073  192.168.0.40    192.168.66.129  TLSv1   97  Change Cipher Spec, Finished
81  2013-11-04 04:02:39.702174  192.168.66.129  192.168.0.40    TLSv1   372 Application Data

証明書1の公開鍵

No.4のパケットで最初に ClientHello が投げられています。

4   2013-11-04 04:02:38.599927  192.168.66.129  192.168.0.39    TLSv1   131 Client Hello

具体的にパケットの中身を見てみると、TLS の層で11種類の暗号スイートをサーバへ提示しています。RSAとDHEの暗号化方式を提示していることがわかります。

Frame 4: 131 bytes on wire (1048 bits), 131 bytes captured (1048 bits)
Ethernet II, Src: Vmware_37:6a:33 (00:0c:29:37:6a:33), Dst: Vmware_f4:85:b0 (00:50:56:f4:85:b0)
Internet Protocol Version 4, Src: 192.168.66.129, Dst: 192.168.0.39
Transmission Control Protocol, Src Port: 1529, Dst Port: 443, Seq: 1, Ack: 1, Len: 77
Secure Sockets Layer
    TLSv1 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 72
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 68
            Version: TLS 1.0 (0x0301)
            Random
            Session ID Length: 0
            Cipher Suites Length: 22
            Cipher Suites (11 suites)
                Cipher Suite: TLS_RSA_WITH_RC4_128_MD5 (0x0004)
                Cipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005)
                Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
                Cipher Suite: TLS_RSA_WITH_DES_CBC_SHA (0x0009)
                Cipher Suite: TLS_RSA_EXPORT1024_WITH_RC4_56_SHA (0x0064)
                Cipher Suite: TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA (0x0062)
                Cipher Suite: TLS_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)
                Cipher Suite: TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (0x0006)
                Cipher Suite: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA (0x0013)
                Cipher Suite: TLS_DHE_DSS_WITH_DES_CBC_SHA (0x0012)
                Cipher Suite: TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA (0x0063)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 5
            Extension: renegotiation_info

ClientHelloを受け取ったサーバは次にServerHelloを返しています。

6   2013-11-04 04:02:38.600714  192.168.0.39    192.168.66.129  TLSv1   1514    Server Hello

具体的なパケットの中身を見てみるとクライアントから提示された暗号スイートに対して、TLS_RSA_WITH_RC4_128_MD5 の暗号スイートを選択したことが分かります。つまり、RSA の公開鍵暗号でRC4の共有鍵暗号方式でMD5のハッシュ関数を使用していることがわかります。

Frame 6: 1514 bytes on wire (12112 bits), 1514 bytes captured (12112 bits)
Ethernet II, Src: Vmware_f4:85:b0 (00:50:56:f4:85:b0), Dst: Vmware_37:6a:33 (00:0c:29:37:6a:33)
Internet Protocol Version 4, Src: 192.168.0.39, Dst: 192.168.66.129
Transmission Control Protocol, Src Port: 443, Dst Port: 1529, Seq: 1, Ack: 78, Len: 1460
Secure Sockets Layer
    TLSv1 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 81
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 77
            Version: TLS 1.0 (0x0301)
            Random
            Session ID Length: 32
            Session ID: 69bebcfca11a7c53259807575f85846ab23daf9e3b15d86f...
            Cipher Suite: TLS_RSA_WITH_RC4_128_MD5 (0x0004)
            Compression Method: null (0)
            Extensions Length: 5
            Extension: renegotiation_info

その後、サーバは証明書をクライアントに返しています。

7   2013-11-04 04:02:38.600720  192.168.0.39    192.168.66.129  TLSv1   199 Certificate, Server Hello Done

具体的にパケットの中身を見ていくと、subjectPublicKey の modulus というところに公開鍵の情報が含まれています。こちらの modulus が最初に必要な情報となります。

Frame 7: 199 bytes on wire (1592 bits), 199 bytes captured (1592 bits)
Ethernet II, Src: Vmware_f4:85:b0 (00:50:56:f4:85:b0), Dst: Vmware_37:6a:33 (00:0c:29:37:6a:33)
Internet Protocol Version 4, Src: 192.168.0.39, Dst: 192.168.66.129
Transmission Control Protocol, Src Port: 443, Dst Port: 1529, Seq: 1461, Ack: 78, Len: 145
[2 Reassembled TCP Segments (1510 bytes): #6(1374), #7(136)]
Secure Sockets Layer
    TLSv1 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 1505
        Handshake Protocol: Certificate
            Handshake Type: Certificate (11)
            Length: 1501
            Certificates Length: 1498
            Certificates (1498 bytes)
                Certificate Length: 754
                Certificate: 308202ee308201d6020900b5ca76b816420d2f300d06092a... (id-at-commonName=chihiro,id-at-organizationName=Chihiro,id-at-localityName=Otowa,id-at-countryName=JP)
                Certificate Length: 738
                Certificate: 308202de308201c602090094f8fffe850d57e3300d06092a... (id-at-commonName=ksnctf.sweetduet.info,id-at-organizationName=ksnctf)
                    signedCertificate
                        serialNumber: -7712132893252954141
                        signature (sha1WithRSAEncryption)
                        issuer: rdnSequence (0)
                        validity
                        subject: rdnSequence (0)
                        subjectPublicKeyInfo
                            algorithm (rsaEncryption)
                            subjectPublicKey: 3082010a0282010100ba7d3b1ed67d7ecfad8d536bee3531...
                                modulus: 0x00ba7d3b1ed67d7ecfad8d536bee3531747be94ea9e4ac14...
                                publicExponent: 65537
                    algorithmIdentifier (sha1WithRSAEncryption)
                    Padding: 0
                    encrypted: 8a6269e64c5d98953adc0a6f1b21f3c363c4f29c5f3181c0...
Secure Sockets Layer

こちらの値を右クリックで 「コピー > 値」と選択すると、以下の":"区切りの値が取り出されます。

00:ba:7d:3b:1e:d6:7d:7e:cf:ad:8d:53:6b:ee:35:31:74:7b:e9:4e:a9:e4:ac:14:03:a3:30:0f:be:fd:fc:4e:e2:41:36:25:19:fb:8e:28:ba:a2:72:79:40:8d:30:3f:38:c3:ae:19:72:b2:cd:5b:15:2e:da:a2:e9:a2:92:23:f1:c9:11:99:a0:37:4c:5a:06:d1:8c:0b:55:d7:67:b7:84:45:be:75:5c:65:78:7a:8b:c5:e0:a9:28:87:28:45:7c:91:44:1e:03:21:65:06:c8:7e:69:6e:b5:4f:4b:14:90:82:b1:bd:83:d2:77:2d:7a:c8:7c:b6:f0:6c:61:ca:0d:af:ec:27:5c:9a:30:a7:5c:9f:c8:d3:9a:65:67:21:01:62:cd:eb:5f:68:66:70:b5:85:07:29:c1:2f:3d:69:d5:16:ab:28:81:8c:43:46:0d:3d:05:31:e6:b2:5e:02:30:a1:84:fb:1b:b8:a0:0e:e0:b7:37:e2:48:d7:e6:a7:0b:c6:ab:e2:f3:d9:15:c3:d7:58:31:13:c8:d7:28:55:c0:e3:cb:50:53:14:80:ea:ec:e5:db:ab:5e:a1:64:17:88:b3:07:9d:3d:b0:2a:0f:e1:21:fd:1b:41:1c:10:8a:86:c4:b0:2f:4c:8f:9b:2a:83:86:cf:90:8b:4b:53:19:83

この値をエディタの置換機能等で":"を取り除くと以下のようになります。

00ba7d3b1ed67d7ecfad8d536bee3531747be94ea9e4ac1403a3300fbefdfc4ee241362519fb8e28baa27279408d303f38c3ae1972b2cd5b152edaa2e9a29223f1c91199a0374c5a06d18c0b55d767b78445be755c65787a8bc5e0a9288728457c91441e03216506c87e696eb54f4b149082b1bd83d2772d7ac87cb6f06c61ca0dafec275c9a30a75c9fc8d39a6567210162cdeb5f686670b5850729c12f3d69d516ab28818c43460d3d0531e6b25e0230a184fb1bb8a00ee0b737e248d7e6a70bc6abe2f3d915c3d7583113c8d72855c0e3cb50531480eaece5dbab5ea1641788b3079d3db02a0fe121fd1b411c108a86c4b02f4c8f9b2a8386cf908b4b531983

上記は16進数の数字ですが、10進数に直すと以下のようになります。変換は、どのような手段でもいいのですが、「2進数、8進数、10進数、16進数相互変換ツール( https://hogehoge.tk/tool/number.html )」こちらのサイトのツールを利用しました。こちらの値をu1とします。

23542078401445977491582187555358406277626961530410681341351413646839204193911833858881038261034069118969161638703136657118916899182578490915497753149887260831567926516391758114231928168566639210404236451288838928257916305340669368491719913927522510658180812971112923019250500479662167443924407765948316698727000721627241198221156194402344915063743640702715180639778981629051287418843949981843258352590283355963590064164706331873913433484206976862304714043765574194257912501410672053921789284948212520207569618096303687722482311329735803729406182287210885757517187688163718098757454136048850395842585001590124979624323

証明書2の公開鍵

No.73 ~ No.81のパケットで192.168.66.129のサーバと TLS 通信のハンドシェイクが行われています。
証明書1と同様の手順でNo.76のCertificateのメッセージを送っているパケットからsubjectPublicKeyのmodulusの値を取り出してきます。

00:a4:da:ad:49:ea:e0:b5:c5:9d:a0:45:29:78:ae:98:7e:1b:96:f1:49:de:db:62:27:4c:97:f9:9a:c4:54:4a:a9:0d:b4:aa:f9:a0:96:7f:11:8b:70:09:09:7b:cb:0b:ae:b4:a1:96:36:77:7a:77:47:e0:6a:d8:44:96:c9:c6:1d:18:a7:b5:ca:77:65:85:a8:17:52:6e:d6:d9:f0:f2:ab:d8:c4:34:c6:2c:bf:02:5e:b7:ce:5a:83:e4:a7:f9:93:8f:38:62:de:24:e6:29:2f:43:27:0f:fd:a7:57:c1:7a:aa:79:7f:f9:fe:18:fd:1c:b2:39:21:dc:58:5d:45:50:38:4f:f5:c4:f2:4e:6d:fc:6d:4f:44:b5:69:34:58:08:23:92:47:c2:0d:26:6c:d0:f5:e3:73:88:9e:d4:e4:59:59:0b:7d:74:2d:28:37:c1:c4:8d:cf:94:18:e2:21:91:ab:4a:0b:ca:0e:d7:9b:1d:45:c0:ca:5d:36:ea:69:60:c9:36:0c:11:41:23:29:fd:5d:90:ff:34:67:f2:d8:2e:23:02:1a:df:3b:6d:8b:e2:49:03:b7:6e:ff:c9:38:15:4e:c2:19:f3:44:11:8f:1c:41:fe:c3:11:71:b6:29:45:a0:7e:35:76:2a:96:1a:05:79:53:89:08:60:52:de:c7

同様に":"を取り除くと以下のようになります。

00a4daad49eae0b5c59da0452978ae987e1b96f149dedb62274c97f99ac4544aa90db4aaf9a0967f118b7009097bcb0baeb4a19636777a7747e06ad84496c9c61d18a7b5ca776585a817526ed6d9f0f2abd8c434c62cbf025eb7ce5a83e4a7f9938f3862de24e6292f43270ffda757c17aaa797ff9fe18fd1cb23921dc585d4550384ff5c4f24e6dfc6d4f44b569345808239247c20d266cd0f5e373889ed4e459590b7d742d2837c1c48dcf9418e22191ab4a0bca0ed79b1d45c0ca5d36ea6960c9360c11412329fd5d90ff3467f2d82e23021adf3b6d8be24903b76effc938154ec219f344118f1c41fec31171b62945a07e35762a961a05795389086052dec7

10進数に直すと以下のようになります。こちらの値をu2とします。

20810915617344661448636429656557804394262814688853534649734586652859523797380885650024809244693377123486154907319690068259378744245911427062593140588104970879344505836367952513105241451799550533959908906245319537215140226739848280012005678383612764589285444929414256249733809498630880134204967826503346173071037885178145189051140796573786694250069189599080301164473268293037575740360272856085402928759232391893060067823996007021668671352199570084430112300612196486186252109596457909476374557998336186613887204545677563178904634941310201398366965571422359228917354256271527331840144577394174480450746748283277750230727

メッセージの復号

先程の公開鍵を取得する中で、ハンドシェイク中で TLS_RSA_WITH_RC4_128_MD5 の暗号スイートが使用されることを決めていました。つまり、公開鍵暗号方式として、RSA が使用することになりました。

こちらの RSA ですが、暗号化されたメッセージを解くことが困難な根拠は、巨大な素数同士の積は素因数分解をすることが困難なことが大変難しいことを根拠としています。

証明書1の先程の取り出した値をu1で積を構成するそれぞれの素数をp1,q1とします。証明書2についても同様にu2で、積を構成するそれぞれの素数をp2,q2とします。

すると、以下のような式となります。

u1 = p1 * q1
u2 = p2 * q2

1024ビットの素因数分解を総当りで行うとなると億レベルのお金をかけて何年というほどの計算を要するものになるため、普通にしては解けません。
しかし、u1 と u2 がもし仮に、共通の因数を持つと仮定してみると、それを最大公約数を求める要領で同じ手順で求められることになります。
つまり、q1 と q2 が同じ値として、q = q1 = q2 とすると、以下の式になります。

u1 = p1 * q
u2 = p2 * q

ここで、最大公約数を求めるために u1 と u2 に対して、ユークリッドの互除法を適用します。すると、q の値が求められます。実際に Python で実行すると、以下のようなコードとなります。

def gcd(x, y):
    r = modlog(x, y)
    while r != 0:
        x = y
        y = r
        r = modlog(x, y)
    return y

def modlog(x, y):
    r = x % y
    return r

def main():
    u1 = 20912068408571562329765690555061159289641629285082404210189101064954330953315593257557260077525915152641073106397431556875680393639301995231540409600633056790407217644109479375811025952060540276714119842291972532268686811648476477127818267411283106601195166099848608860814911133056759210847640244371352294577674757844032344743192797680553522630615249481210459669536735468283778508143359159893770374788694416907786510825727199111604249000530550012491935109887922826382346971222271516625157446929215544796309806757863550058676780306722906895167581167203804721314732494889662194466565293268848629536070864750745494338531
    u2 = 20810915617344661448636429656557804394262814688853534649734586652859523797380885650024809244693377123486154907319690068259378744245911427062593140588104970879344505836367952513105241451799550533959908906245319537215140226739848280012005678383612764589285444929414256249733809498630880134204967826503346173071037885178145189051140796573786694250069189599080301164473268293037575740360272856085402928759232391893060067823996007021668671352199570084430112300612196486186252109596457909476374557998336186613887204545677563178904634941310201398366965571422359228917354256271527331840144577394174480450746748283277750230727

    q = gcd(u1, u2)
    print q


if __name__=="__main__":
    main()

すると、以下の値が得られます。こちらがqの値となります。

149964660518396798660782215517197000054264985822608779681144262791391323000835825727277636178043097046988857828384650158626906824855399961360412435818827649355003329726451846544435103030378220357694459358803967598155925736581896165952170564324730092516286266118841005062382011803493961966912439338500328959743

すると、u1,u2,qの値が分かっていることから、p1,p2の値はそれぞれ以下のようにして求められます。

p1 = u1 / q
p2 = u2 / q

実際に計算すると、p1は以下のようになります。

139446642537534304777628614240154046272434122794892522124374234093313897652592278876204620931659231555942782873768406065030569534203407105601097455479995730772421725109267044663491213232687718387909353507690622331780468229128999879032054673690005684809410661625656125511253714586807242182927209779610158700317

p2は以下のようになります。

138772131683595539379264396620735603425702925342291987755841498194704959931781364169698055070785331880014332847610595576230231417278730047109315439655930883451174914691703480278864120207968103099432047374677543229331540706277526947368767969434429565383119554767303697722958157645742281397722992120606265055289

以上で RSA の復号が困難な根拠とされた素因数分解ができました。
2つの証明書の類似性とは、2つの数字に共通の因数を持つことのようだったようです。
あとは、これを元に秘密鍵を構築します。

秘密鍵の構築

pem 形式の秘密鍵について

pem 形式の秘密鍵は、ASN.1のバイナリデータをBase64でエンコードされたテキストファイルとなります。こちらのファイルの中身は、-----BEGIN RSA PRIVATE KEY-----で始まり、-----END RSA PRIVATE KEY-----で終わるファイルとなります。この間に挟まれたデータは、ASN.1をDERという形式でエンコードされたバイナリファイルとなります。

RSAにおけるASN.1の定義は、以下のように定められています。versionは0か1の値で、otherPrimeInfosはversionが0のときは存在しません。

RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER, -- n
    publicExponent    INTEGER, -- e
    privateExponent   INTEGER, -- d
    prime1            INTEGER, -- p
    prime2            INTEGER, -- q
    exponent1         INTEGER, -- d mod (p-1)
    exponent2         INTEGER, -- d mod (q-1)
    coefficient       INTEGER, -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

(引用: RSA 秘密鍵/公開鍵ファイルのフォーマット http://bearmini.hatenablog.com/entry/2014/02/05/143510 )

publicExponentであるeの値は、公開指数として655337がよく用いられるそうです。以下のような理由があるようです。

公開指数eの値として65537もよく使われますが,その理由としては, これが素数であり,しかも65537=2^16+1 が成り立つためです。これを2進表現したものは1を 2つしか含まないので,この値でべき乗するには17回の乗算で済みます。 これは3を指数eとした場合の2回と比べると多いですが, 512ビットを無作為に選択した場合に必要とする平均乗算回数768回と比べると圧倒的に少ないといえます。 また,65537をeとして使う場合,eに3を使う場合に生じる問題をほとんど避けることが可能です。

(引用: RSA暗号体験入門 http://post1.s105.xrea.com/)

証明書1の秘密鍵の取得

秘密鍵を求めるに当って、prime1 である p , prime2 である q , publicExponent である e の3つをパラメータとして pem形式のファイルを作成することができます。

最初に証明書1から pem形式のファイルを求めるために、p1,q,e(=65537)の値から以下のようにして、pem形式のデータを出力します。こちらのデータをファイルに保存します。
ただし、こちらは Python の Crypto モジュールを使用しますので、sudo pip install crypto のようにモジュールをインストールする必要があります。

genpem1.py
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse


p = 139446642537534304777628614240154046272434122794892522124374234093313897652592278876204620931659231555942782873768406065030569534203407105601097455479995730772421725109267044663491213232687718387909353507690622331780468229128999879032054673690005684809410661625656125511253714586807242182927209779610158700317
q = 149964660518396798660782215517197000054264985822608779681144262791391323000835825727277636178043097046988857828384650158626906824855399961360412435818827649355003329726451846544435103030378220357694459358803967598155925736581896165952170564324730092516286266118841005062382011803493961966912439338500328959743
e = 65537

n = p*q
d = inverse(e, (p-1)*(q-1))

key = RSA.construct(map(long, (n,e,d)))
print key.exportKey()

上記を genpem1.py という名前で保存したとします。すると、以下のようにして秘密鍵を出力します。

python genpem1.py > private1.pem

こちらの秘密鍵はパスがかかった状態で、このままでは利用できないので、以下のコマンドを実行してパスを解除します。

openssl rsa -in private1.pem -out private.pem.unencrypted

上を実行しないと、Wireshark に読み込ませると、下記のエラーが出力されます。
ssl_load_key: can't import pem data: Base64 unexpected header error.

(参考: https://serverfault.com/questions/224589/error-while-decrypting-https-traffic-in-wireshark )

証明書2の秘密鍵の取得

こちらも証明書1の秘密鍵の取得の手順と同様にして、以下の gempem2.py というファイル名で Python のコードを準備します。

genpem2.py
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse


p = 138772131683595539379264396620735603425702925342291987755841498194704959931781364169698055070785331880014332847610595576230231417278730047109315439655930883451174914691703480278864120207968103099432047374677543229331540706277526947368767969434429565383119554767303697722958157645742281397722992120606265055289
q = 149964660518396798660782215517197000054264985822608779681144262791391323000835825727277636178043097046988857828384650158626906824855399961360412435818827649355003329726451846544435103030378220357694459358803967598155925736581896165952170564324730092516286266118841005062382011803493961966912439338500328959743
e = 20912068408571562329765690555061159289641629285082404210189101064954330953315593257557260077525915152641073106397431556875680393639301995231540409600633056790407217644109479375811025952060540276714119842291972532268686811648476477127818267411283106601195166099848608860814911133056759210847640244371352294577674757844032344743192797680553522630615249481210459669536735468283778508143359159893770374788694416907786510825727199111604249000530550012491935109887922826382346971222271516625157446929215544796309806757863550058676780306722906895167581167203804721314732494889662194466565293268848629536070864750745494338531
e = 65537

n = p*q
d = inverse(e, (p-1)*(q-1))

key = RSA.construct(map(long, (n,e,d)))
print key.exportKey()

以下のコマンドを実行して秘密鍵を生成します。

python genpem2.py > private.pem
openssl rsa -in private2.pem -out private2.pem.unencrypted

TLS 通信の復号

最後に暗号化された TLS 通信を作成した秘密鍵で復号します。

Wireshark で実際に Certificate メッセージを送っていたフロー上(パケット No.7)で、右クリックします。「プロトコル設定 > RSA keys list...」を選択します。

SSL Decryptというウィンドウで、「IP addres, Port, Protocol, Key File, Password」の列名の表が現れますので、以下のように入力します。Protocolとしてhttp,Portとして443を指定します。httpsと指定するわけではないことに注意して下さい。

192.168.0.39    443     http    /Users/......../private1.pem.unencrypted
192.168.66.129  443     http    /Users/......../private2.pem.unencrypted

すると、先程まで、SSL通信として中身が見えていなかった通信(No.12 と No.81)が以下のようにHTTPプロトコルとして通信が見えるようになりました。

12  2013-11-04 04:02:38.606914  192.168.66.129  192.168.0.39    HTTP    376 GET /flag.jpg HTTP/1.1 
81  2013-11-04 04:02:39.702174  192.168.66.129  192.168.0.40    HTTP    372 GET /flag.jpg HTTP/1.1 

なお、こちらのデバッグとして、「プロトコル設定 > SSL debug file...」という項目でデバッグログの出力設定ができるので、こちらに出力されるログを見ながらデバッグすることが可能です。

最後の上記通信中でやりとりされていたjpgの画像ファイルを取り出します。
「ファイル(F) > オブジェクトをエクスポート > HTTP...(H)」を選択します。
最後にパケット49と125のファイルを選択してSaveします。

すると、以下のような2枚の画像ファイルが取り出されます。これらを組み合わせると、"FLAG_"で始まる文字列が取り出されます。

https_is_secure_flag 2.png

補足

クライアントとして、ブラウザが提示する暗号スイートについて

SSL Labsの以下のサイトの実行結果により、ブラウザが提示する暗号スイートについて、確認してみました。

「SSL/TLS Capabilities of Your Browser」
https://www.ssllabs.com/ssltest/viewMyClient.html

Chromeで以下のバージョンを使用したところ、クライアントから提示される暗号スイートは以下のようになっていました。

バージョン: 63.0.3207.0(Official Build)canary (64 ビット)
TLS_GREASE_AA (0xaaaa)  -
TLS_AES_128_GCM_SHA256 (0x1301)   Forward Secrecy   128
TLS_AES_256_GCM_SHA384 (0x1302)   Forward Secrecy   256
TLS_CHACHA20_POLY1305_SHA256 (0x1303)   Forward Secrecy 256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)   Forward Secrecy  128
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   Forward Secrecy    128
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)   Forward Secrecy  256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   Forward Secrecy    256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)   Forward Secrecy    256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)   Forward Secrecy  256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)   Forward Secrecy   128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)   Forward Secrecy   256
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c)  128
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d)  256
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f) 128
TLS_RSA_WITH_AES_256_CBC_SHA (0x35) 256
TLS_RSA_WITH_3DES_EDE_CBC_SHA (0xa)   WEAK  112
(1) When a browser supports SSL 2, its SSL 2-only suites are shown only on the very first connection to this site. To see the suites, close all browser windows, then open this exact page directly. Don't refresh.

Firefoxで以下のバージョンを使用したところ、クライアントから提示される暗号スイートは以下のようになっていました。

55.0.3 (64-bit)
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)   Forward Secrecy  128
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   Forward Secrecy    128
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)   Forward Secrecy    256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)   Forward Secrecy  256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)   Forward Secrecy  256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   Forward Secrecy    256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)   Forward Secrecy     256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)   Forward Secrecy     128
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)   Forward Secrecy   128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)   Forward Secrecy   256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33)   Forward Secrecy   128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39)   Forward Secrecy   256
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)     128
TLS_RSA_WITH_AES_256_CBC_SHA (0x35)     256
TLS_RSA_WITH_3DES_EDE_CBC_SHA (0xa)   WEAK  112

プロフェッショナル SSL/TLSには、以下のような記述がありますが、上記の通り、必ずしも現時点では、ブラウザ等の実装でそうではなさそうです。

現在、TLSでは3つの鍵アルゴリズムに対応しておますが、そのうちで完全に実用的といえるのは1つ、RSAのみです。DSAはかなり以前から見捨てられており、ECDSAはこれから数年かけて利用が広がるアルゴリズムです。

(引用: プロフェッショナル SSL/TLS https://www.lambdanote.com/products/tls )

作成したpem形式の秘密鍵のフォーマットの形式確認方法

作成したpem形式の秘密鍵のフォーマットが正しいかを確認する方法があります。

private1.pem.unencryptedについては、以下のコマンドを実行します。

$ openssl asn1parse -inform pem < private1.pem.unencrypted

以下の結果が出力されます。

    0:d=0  hl=4 l=1187 cons: SEQUENCE          
    4:d=1  hl=2 l=   1 prim: INTEGER           :00
    7:d=1  hl=4 l= 257 prim: INTEGER           :A5A7CE44462E8AC6E4DA5E8A8D58E003B8267568B358106CF06412884CEEB7CC4251C2CCE2DB74689D1AFA109BDE9762402E81D96CB6C8C6C5AEBC8D45A96BF214A618B499A8C6134035C5039BF9A39BC47190E4CC4560CB75AB8D63635CDEE8E50F5815B29180CC51A4C8CF76A8BBE6E61C68ACA385FDF99E712B10A6BE7ED794CF27540B7AA00F59DA5579040A9B3B7C23E9E22A15C29EB0C060B96D1F48D1C458E2C412512962CE5AF885237B6138DF6C9E85D101C266C3B80B02FF97D6FDE46598E19E3FA1DF2C56BD34ADDFE716569A2ED42C6442BF2DB5E9A51CC2D7DD4497717DDD9A8A66AE281E1A2ABF7DF7A59779B499CC0F8167A19E3CA5C9BBE3
  268:d=1  hl=2 l=   3 prim: INTEGER           :010001
  273:d=1  hl=4 l= 257 prim: INTEGER           :96B06F11EC45AA380336218A27CA10FD5126AAE6F33DC8B35079B7E20519A2584C7BD3984D45143F95AA548F873A94BAEB6762F745CD801650FD02C7FFF67E1B586D3F4C09FB5D3365D583C224C091F3C05F0E4F1302896A8B3FE2FDE6053540E61D6F234DACCE5D0E67B7C4014CBCA0EDF229C5E17AA1EDD01361F963B525EBBEAA2BAB232940ACFFB08F2683A291BF28F803B37360CE3A8B4875D1DAEB34A6D0A90D9E4B8EA29AEC615B71329221B3C2F46DCA19B80B96540BCE135716DC46E5B3B320257B0593BFF2C74D0388E20A4597EF0AACA32340F569B0BB53ED9DA811E5959A89800624EEA057224254D20C9C257FD08A570F6F6E946F7D20734F01
  534:d=1  hl=3 l= 129 prim: INTEGER           :C6941FD1FD3DEDF69080356F0C76E2497F2569519BCEFFF5DC72B63FAE2F352ED1F4EFB254FCDDB45979216C9164FF946234A3EFDD0143747F55380E003BECCED49D04A8E2A1F35586C3A15C3B81EE1FB18D8528C02C2A0FA29209E4621C316DFA4FF4FA400D3EC4AA900F631AF61E6BB6F0D1EDA6F2FBF8E10E15B51B7D171D
  666:d=1  hl=3 l= 129 prim: INTEGER           :D58E882C1BE40C480E11A517C3DEEECDBBE5FD02EBE7A9F1F5F4E47CF8CD1B6443888238CB4A3424913487744D5DE2EC32D7DAFCB4A53B23DFED9A1261B3E9C7FE5AF4534908D0F700ED15402598C2E0C36880D8C999BA8A560D963728AE21E02D39FCDB6D118E88175BD89033B08D2958A7E8D0EFA7A26A2A7E3E1D1D42AEFF
  798:d=1  hl=3 l= 128 prim: INTEGER           :4CDC0C2CE4CDD18AFB8704278535868457F80CF98F4AE17B31E61C702D650C3AA0FD22C16D6FAA0822116644754A183A40808B6B4DA92D88ABB83A48010330B72547D903DD243DE0BE967DA00B5050F0677295359E9BF973AFC2C29D68F3EC95DAAA93F14055601412C84B8C5A652485207BB965389717BBCEAFFAEAEC46D069
  929:d=1  hl=3 l= 128 prim: INTEGER           :71C005D058DAD39FDDBE904D644B6EAFAF1205FE74616528387644EE3C28241AF7CDD26F25F95464D5E340F335F278588F8C625C906C22602D7A85C29CC0141A2EE58B9681246D09E438644552C157AC18E9A517D3EA4A6E3CFFE7AF61BFBED385C38967E7649EA2E6AE496025E83888796C969A13CD1AB9AA00AC5D1DA4D349
 1060:d=1  hl=3 l= 128 prim: INTEGER           :79F4EEF19181750A4313AF2495331ED2AB837D54CB2D9447FC40A5B92383ACB44F28186405DD8C400650B1E87DB84981CC250C6CE00120319CD6AD00CEE30E48D59F6E1983AEBA91D57A47DBF072A0A13CAEE426DED9E5635895780746DADAACD568E70B7462FBA117CE8F869D447CBBF2753CCE8FC6BD4934EE4D112EEB9AA2

同様にprivate2.pem.unencryptedについては、以下のコマンドを実行します。

$ openssl asn1parse -inform pem < private2.pem.unencrypted

以下の結果が出力されます。

    0:d=0  hl=4 l=1186 cons: SEQUENCE          
    4:d=1  hl=2 l=   1 prim: INTEGER           :00
    7:d=1  hl=4 l= 257 prim: INTEGER           :A4DAAD49EAE0B5C59DA0452978AE987E1B96F149DEDB62274C97F99AC4544AA90DB4AAF9A0967F118B7009097BCB0BAEB4A19636777A7747E06AD84496C9C61D18A7B5CA776585A817526ED6D9F0F2ABD8C434C62CBF025EB7CE5A83E4A7F9938F3862DE24E6292F43eifjccfuvccgdgniddrfugibhlthkkucegrjvfifikhc
    270FFDA757C17AAA797FF9FE18FD1CB23921DC585D4550384FF5C4F24E6DFC6D4F44B569345808239247C20D266CD0F5E373889ED4E459590B7D742D2837C1C48DCF9418E22191AB4A0BCA0ED79B1D45C0CA5D36EA6960C9360C11412329FD5D90FF3467F2D82E23021ADF3B6D8BE24903B76EFFC938154EC219F344118F1C41FEC31171B62945A07E35762A961A05795389086052DEC7
  268:d=1  hl=2 l=   3 prim: INTEGER           :010001
  273:d=1  hl=4 l= 256 prim: INTEGER           :30DFFC5C5BDC7F47B571DCCF6CCE26BBCCA635A7370147DA6AE4EBC5ACCB68CF32170C51B200AC6FA12D78206DA9472F66B2397CB0738885B0CD3C8D293F6D13174A31A5733C9021C3B856D0301135812965125866CFC27E1E7479757D0728014D86E419044B908E48947E332FB7DECEE557DC4F5BBC40DE8F204D1FACBB0A5F424B3B658651BD0F2F704D81F7E51DA39A6C37D6BDB7E0A256859735FB4AA0B3100CC352EAB05F35D499B3AB73BECC22433013D6F72AAD5F57B4D5B242EA8176102D2E4393BEF21772538A27D6A4D7137777B0A41B3120E9EF0FE3099A78F454775FEA44FF8978996401D1E474AE8704E25B5F329099E364CA6F677A2E275B61
  533:d=1  hl=3 l= 129 prim: INTEGER           :C59E3A2D1E4F9084A4D06997B987D39FC007C0BBD781C4658860D8BA81D7AB0D94A19548BDF92EEEB4EC3CDB6BFDABF674C09FC0A34C96488ABD8936671BB888AB9D0E825CF0FA93E33A6CA9CE9BFDA28F1F39E63EF426274771F3A9F9109D6554B34801C29FDF3BC03DCEFDA3469F2609E8AC02B32A48B82360B78B15EE1839
  665:d=1  hl=3 l= 129 prim: INTEGER           :D58E882C1BE40C480E11A517C3DEEECDBBE5FD02EBE7A9F1F5F4E47CF8CD1B6443888238CB4A3424913487744D5DE2EC32D7DAFCB4A53B23DFED9A1261B3E9C7FE5AF4534908D0F700ED15402598C2E0C36880D8C999BA8A560D963728AE21E02D39FCDB6D118E88175BD89033B08D2958A7E8D0EFA7A26A2A7E3E1D1D42AEFF
  797:d=1  hl=3 l= 128 prim: INTEGER           :07BB3D036EE026034A7F6CE226BC0DA77E57CF4E8A0BE5A72342C6B7E5448EC8A53BFD1F2F6F844A8A81839002159698B9D09F6F65F4251D097088E1BBFEF5A543318DD3C3D719B697793DAF170A3B4E14D35FEC8621FF2C223B6F1103518716E3CD6FCFC1D187664B0B200204554AFCADFE905C3AAE38D21B70393E13C990E1
  928:d=1  hl=3 l= 128 prim: INTEGER           :71C005D058DAD39FDDBE904D644B6EAFAF1205FE74616528387644EE3C28241AF7CDD26F25F95464D5E340F335F278588F8C625C906C22602D7A85C29CC0141A2EE58B9681246D09E438644552C157AC18E9A517D3EA4A6E3CFFE7AF61BFBED385C38967E7649EA2E6AE496025E83888796C969A13CD1AB9AA00AC5D1DA4D349
 1059:d=1  hl=3 l= 128 prim: INTEGER           :35D4716BF825CA1701850D080F507CA4C757B692BCBF641FD1E47EFE264832CE90308FC1B3530570634E988907DF27404D9E4E1191810EBB5A841337C09ADE3613315E26F55CC18951AA1D21A24847AFCA30ED5B2FFAC88E63453D1DF6476B6C90A6A56930FBC79B5EBBB556C5BE8BE495DA5D02DAA10C3006712A6145F92791

上記について、先程のRSAのASN.1での定義を表現したものに対応しています。

RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER, -- n
    publicExponent    INTEGER, -- e
    privateExponent   INTEGER, -- d
    prime1            INTEGER, -- p
    prime2            INTEGER, -- q
    exponent1         INTEGER, -- d mod (p-1)
    exponent2         INTEGER, -- d mod (q-1)
    coefficient       INTEGER, -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

private1.pem.unencryptedの場合、以下のように対応することが分かります。

version = 00
modulus(n) = A5A7CE44462E8AC6E4DA5E8A8D58E003B8267568B358106CF06412884CEEB7CC4251C2CCE2DB74689D1AFA109BDE9762402E81D96CB6C8C6C5AEBC8D45A96BF214A618B499A8C6134035C5039BF9A39BC47190E4CC4560CB75AB8D63635CDEE8E50F5815B29180CC51A4C8CF76A8BBE6E61C68ACA385FDF99E712B10A6BE7ED794CF27540B7AA00F59DA5579040A9B3B7C23E9E22A15C29EB0C060B96D1F48D1C458E2C412512962CE5AF885237B6138DF6C9E85D101C266C3B80B02FF97D6FDE46598E19E3FA1DF2C56BD34ADDFE716569A2ED42C6442BF2DB5E9A51CC2D7DD4497717DDD9A8A66AE281E1A2ABF7DF7A59779B499CC0F8167A19E3CA5C9BBE3

publicExponent(e) = 010001
privateExponent(d) = 96B06F11EC45AA380336218A27CA10FD5126AAE6F33DC8B35079B7E20519A2584C7BD3984D45143F95AA548F873A94BAEB6762F745CD801650FD02C7FFF67E1B586D3F4C09FB5D3365D583C224C091F3C05F0E4F1302896A8B3FE2FDE6053540E61D6F234DACCE5D0E67B7C4014CBCA0EDF229C5E17AA1EDD01361F963B525EBBEAA2BAB232940ACFFB08F2683A291BF28F803B37360CE3A8B4875D1DAEB34A6D0A90D9E4B8EA29AEC615B71329221B3C2F46DCA19B80B96540BCE135716DC46E5B3B320257B0593BFF2C74D0388E20A4597EF0AACA32340F569B0BB53ED9DA811E5959A89800624EEA057224254D20C9C257FD08A570F6F6E946F7D20734F01

prime1(p) = C6941FD1FD3DEDF69080356F0C76E2497F2569519BCEFFF5DC72B63FAE2F352ED1F4EFB254FCDDB45979216C9164FF946234A3EFDD0143747F55380E003BECCED49D04A8E2A1F35586C3A15C3B81EE1FB18D8528C02C2A0FA29209E4621C316DFA4FF4FA400D3EC4AA900F631AF61E6BB6F0D1EDA6F2FBF8E10E15B51B7D171D

prime(q) = D58E882C1BE40C480E11A517C3DEEECDBBE5FD02EBE7A9F1F5F4E47CF8CD1B6443888238CB4A3424913487744D5DE2EC32D7DAFCB4A53B23DFED9A1261B3E9C7FE5AF4534908D0F700ED15402598C2E0C36880D8C999BA8A560D963728AE21E02D39FCDB6D118E88175BD89033B08D2958A7E8D0EFA7A26A2A7E3E1D1D42AEFF

exponent1(d mod (p-1)) = 4CDC0C2CE4CDD18AFB8704278535868457F80CF98F4AE17B31E61C702D650C3AA0FD22C16D6FAA0822116644754A183A40808B6B4DA92D88ABB83A48010330B72547D903DD243DE0BE967DA00B5050F0677295359E9BF973AFC2C29D68F3EC95DAAA93F14055601412C84B8C5A652485207BB965389717BBCEAFFAEAEC46D069

exponent2(d mod (q-1)) = 71C005D058DAD39FDDBE904D644B6EAFAF1205FE74616528387644EE3C28241AF7CDD26F25F95464D5E340F335F278588F8C625C906C22602D7A85C29CC0141A2EE58B9681246D09E438644552C157AC18E9A517D3EA4A6E3CFFE7AF61BFBED385C38967E7649EA2E6AE496025E83888796C969A13CD1AB9AA00AC5D1DA4D349

coefficient((inverse of q) mod p) = 79F4EEF19181750A4313AF2495331ED2AB837D54CB2D9447FC40A5B92383ACB44F28186405DD8C400650B1E87DB84981CC250C6CE00120319CD6AD00CEE30E48D59F6E1983AEBA91D57A47DBF072A0A13CAEE426DED9E5635895780746DADAACD568E70B7462FBA117CE8F869D447CBBF2753CCE8FC6BD4934EE4D112EEB9AA2

q の値で素数であることの確認

以下のPythonのファイルを用意します。

def is_prime(q):
    q = abs(q)
    if q == 2: return True
    if q < 2 or q&1 == 0: return False
    return pow(2, q-1, q) == 1

def main():
    x = 149964660518396798660782215517197000054264985822608779681144262791391323000835825727277636178043097046988857828384650158626906824855399961360412435818827649355003329726451846544435103030378220357694459358803967598155925736581896165952170564324730092516286266118841005062382011803493961966912439338500328959743
    z = is_prime(x)
    print z

if __name__=="__main__":
    main()

上記ファイルを実行すると、以下の結果が出力されます。

True