Text
鍵付きハッシュ関数の存在的偽造とパスワードハッシュに対する脅威の評価
鍵付きハッシュ関数 (keyed hash functions) を改竄検知、MACを生成する関数として使う場合、攻撃者の目標としては鍵を知らずしてMACを計算する (偽造する) こととなる。
改竄検知ではなく、オフライン攻撃に耐性を持たせるために秘密鍵を使って (pepperというらしい) パスワードハッシュなどをとっている場合も、鍵を知らずにハッシュ値を計算できてしまうと「秘密鍵が漏れていなければオフライン攻撃ができない」というセキュリティの前提が崩れてしまう。
本エントリでは、鍵を知らずに鍵付きハッシュ関数のハッシュ値 (MAC) を計算する攻撃法であるLength Extension Attackについてざっくりと説明し、この攻撃法はパスワードハッシュのオフライン攻撃からの保護というコンテクストでは現実的な脅威とならないことを示す。
MD5, SHA1, SHA2-familyなどのよく使われている暗号学的ハッシュ関数 (cryptographic hash functions) は、衝突耐性を持たせるために、Markle Damgard Constructionという構成法で構成されている。
Markle Damgard Constructionは「ハッシュ関数の構成要素である圧縮関数が衝突耐性をもつならばハッシュ関数全体としても衝突耐性をもつ」という性質が証明できるため衝突耐性のあるハッシュ関数を構成するのに便利である。(なお、SHA3-familyはSponge CosntructionというMarkle Damgardでない構成法によって構成される)
なお、圧縮関数自体はDavies Myer構成法という構成法によって構成されるが、大雑把には、ハッシュ関数のために構成されたブロック暗号を使っているという理解で問題ないし、この記事を読むにはそれを知る必要はない (し、ぼくも調査中で説明できない。Unbalanced Feistel Structureがハッシュ関数構成に何故使われるかとか説明できない)
Markel Damgard Constructionは構成要素となる圧縮関数という関数 h を使って、下図のように平文を複数ブロックに分割した上で反復して適用して最終的なハッシュ値を得る。Initial valuesは固定値である。
図について簡単に説明する。入力のメッセージは、SHA1の場合はまず64バイトの倍数長になるようにpaddingをとってから、64バイト毎のブロックに分割される。各ブロックは、ハッシュ関数の初期値 (上図のInitial values) あるいは一つ前の圧縮関数の出力と共に圧縮関数 h に入力されて、その出力は次の圧縮関数 h の入力として使われる。これをブロックの個数だけ反復して最後の圧縮関数 h に出力された160bitのバイト列がハッシュ値として出力される。
鍵を知らない限り計算できないハッシュ関数 (MAC) の実装として、素朴に次のような構成を考えてしまうかもしれない。すなわち、秘密鍵のバイト列をメッセージのバイト列に連結してハッシュをとるという構成を。
しかし、このように鍵付きハッシュ関数を設計するとLength Extension Attackという攻撃に脆弱になる。
Length Extension Attackでは、攻撃者は標的となる鍵付きハッシュ関数によって計算されたハッシュ値 Hash Value を少なくとも一つ知っているものとする。ここで、攻撃者は自らの用意したメッセージ Msg’ と適当なパディング Pad’ を連結し、既知のハッシュ値 Hash Value とともに圧縮関数 h に入力する (下図。) その出力 Hash Value’ は、明らかに ハッシュ値 Hash Value を生成した元のメッセージを Msg、パディングをPad として、 Msg || Pad || Msg’ に対する鍵付きハッシュ値と一致する (下図。)
こうして、上記のような素朴な鍵付きハッシュ関数では、秘密鍵を知らずに何らかのメッセージ (メッセージの内容全体は完全には制御できないが) に対するハッシュ値 (MAC) を計算することができてしまう。このように「鍵を知らずして何らかのメッセージのMACを計算する攻撃」を存在的偽造 (existential forgery) といい、具体的に上のように既知のハッシュ値にメッセージとパディングを付加してMACを偽造する攻撃をLength Extension Attackという。
で。これは冒頭で想定したような脅威、すなわちpepperによってオフライン攻撃から保護されているパスワードのハッシュを脅かすものだろうか。
結論からいえば、SHA1やSHA2-familyなど現状としてよく使われているハッシュ関数を使う限りは安全だと言える。
こういうのは動くものを見ながらの方が理解が深まるので、SHA-1をサクッとPythonで実装してみた。SHA-1のパディングやMessage Schedule, 圧縮関数をそれぞれ独立して呼び出すこともできる。これを使って検討してみよう。
def K(t): if t < 20: return 0x5a827999 elif t < 40: return 0x6ed9eba1 elif t < 60: return 0x8f1bbcdc else: return 0xca62c1d6 def f(t): def ch(x, y, z): return (x & y) ^ ((~x & 0xffffffff) & z) def parity(x, y, z): return x ^ y ^ z def maj(x, y, z): return (x & y) ^ (y & z) ^ (z & x) if t < 20: return ch elif t < 40: return parity elif t < 60: return maj else: return parity def rotl(n): def _rotl(word): return ((word << n) & 0xffffffff) | (word >> (32 - n)) return _rotl def schedule(M): w = [int.from_bytes(M[4*i:4*i + 4], 'big') for i in range(16)] rotl1 = rotl(1) for t in range(16, 80): a = w[t - 3] b = w[t - 8] c = w[t - 14] d = w[t - 16] w.append(rotl1(a ^ b ^ c ^ d)) return w # これが圧縮関数 def compression(H, M): W = schedule(M) H = [int.from_bytes(H[4*i:4*i + 4], 'big') for i in range(5)] a = H[0] b = H[1] c = H[2] d = H[3] e = H[4] rotl5 = rotl(5) rotl30 = rotl(30) for t in range(0, 80): T = (rotl5(a) + f(t)(b, c, d) + e + K(t) + W[t]) & 0xffffffff e = d d = c c = rotl30(b) b = a a = T H[0] = (a + H[0]) & 0xffffffff H[1] = (b + H[1]) & 0xffffffff H[2] = (c + H[2]) & 0xffffffff H[3] = (d + H[3]) & 0xffffffff H[4] = (e + H[4]) & 0xffffffff return b''.join(H[i].to_bytes(4, 'big') for i in range(5)) # メッセージMと、長さlを与えると適当にMにパディングを付加して返す def pad(M, l): k = (448 - l - 1) % 512 zeros = (k // 8) * b'\x00' length = l.to_bytes(8, 'big') if k % 8 == 7: return M + b'\x80' + zeros + length else: x = M[-1] | (1 << ((k % 8) + 1)) return M[:-1] + x.to_bytes(1, 'big') + zeros + length initial_values = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0, ]
では、このSHA1の圧縮関数compression等を使って、実際にLength Extension Attackをやってみよう。
さて。さて、だ。本題に戻ろう。
確かに鍵付きハッシュ関数の設計に問題があると、既知のハッシュ値を使って他の何らかのメッセージのハッシュ値を計算できることが確認できたが、これは「パスワードハッシュをオフライン攻撃から保護する」という目標を損なうものだろうか。
答えとしては、否、となる。
上のkeyed_hash関数の入力 In [14] のあたりを見ていただきたいのだが、neko というパスワードに連結する文字列にNULL文字 (\x00) を複数含むのがわかるだろうか。これは偶然ではなく、パスワードのような短い文字列のハッシュをとると必ず入り込むものである。
SHA1やSHA2-familyなどのハッシュ関数は、入力の長さが512ビット (64バイト) の倍数長になるようにパディングを付加する。さらに、必ずブロック末尾に64ビット長の「メッセージ長」のフィールドが入ることになっている。64ビット長でメッセージ長を表そうとすると、パスワードのような高々数十文字程度の文字列のハッシュをとると、必ずこのフィールドにはNULL文字 (\x00) が入ることになる。
すなわち、パスワードのオフライン攻撃からの保護のためにpepperを使ったハッシュ関数によってハッシュ値をとっていた場合は、「パスワードの途中に6, 7バイトのNULL文字を含むのが当然であるようなパスワードポリシーを採用しているようなシステム」という猫が設計してもありえないシステムでない限りはLength Extension Attackによる脅威 (すなわち、攻撃者にとって既知のメッセージ・ハッシュ値の組み合わせから、他のメッセージのハッシュ値までオフラインで計算されてしまうという脅威) は存在しない。
0 notes
Text
眠りのスレッドのFizz Buzz
擬似乱数のランダムさに関する統計的仮説検定について書こうとしているところですが、アウトラインがまだかたまっておらず、内容的にもやや高度で噛み砕いて書くのに時間がかかりそうなので、ためていたネタを投稿します。
さて、プログラムを書けない人をふるいわける方法として、Fizz Buzz問題という簡単なプログラミングの問題がJeff Atwoodによって考案されたらしいことをご存知の方は多いかと思います。
「眠りのスレッドの」という表題から察した方もおられるかと思いますが、その「変態的」なプログラムというのは、sleepを利用してFizzBuzzを出力するプログラムです。
具体的には、30秒に一度Fizzと出力するプロセス、50秒に一度Buzzと出力するプロセスをバックグランドで動作させつつ、10秒に一度カウンターをインクリメントしFizzもBuzzも出力中でなければ現在のカウンターの値を出力する、というプログラムになっています。
さて、それではひいひい言いながら統計的仮説検定について続きを書きます。
2 notes
·
View notes
Text
擬似乱数って結局なんなの
Developer向けのドキュメントを書いていて、擬似乱数についてどう説明したものか悩みすぎてストレスで禿げたのだけど、失った頭髪と引き換えスッキリとした簡潔な解説を書けたように思う。
さて、擬似乱数とは何かという問いの答えとしては、さしあたり「乱数 (ランダムに選ばれる数) ではないのだが乱数に見えるもの」と答えるものであるが、何だかわかったようなわからないような説明だとぼくも思うし、これではディベロッパーは納得しなかろうと思う。
結論から言ってしまうと、擬似乱数というのは擬似乱数生成器というアルゴリズムによって生成される数 (列) のことで、擬似乱数生成器は実のところランダムに値を生成しているわけではない。擬似乱数生成器が次々に生成していくビット列 (あるいは同じことだが数を並べたもの. 擬似乱数) は、 シード と呼ばれる初期値によって一意に決まる。
実際、同じシードによって初期化したjava.util.Randomインスタンスを2つ作成し、それらが生成する値が一致するかを次のようなコードでテストしてみると
この通り、テストが通る、すなわち同じシードからは同じ値を生成し続けることが確認できる。
最も広く使われている擬似乱数生成器のアルゴリズムは線形合同法であり、これは次式の漸化式によって次々と数を生成していく。
$$x_{i + 1} = ax_i + b \pmod{m}$$
実はこれは、割り切れないような整数の割り算を筆算で計算して、各桁を割っていく際に現れる余りを集めるのと似たようなことをしている。
簡単のため \(b = 0\), 10進数での表現を考えると、\(x_0 = 1, m = 13\)として
\begin{align} x_1 &= 1 \cdot 10 \mod{13} = 10 \cr x_2 &= 10 \cdot 10 \mod{13} = 9 \cr x_3 &= 9 \cdot 10 \mod{13} = 12 \cr x_4 &= 12 \cdot 10 \mod{13} = 3 \cr x_5 &= 3 \cdot 10 \mod{13} = 4 \cr x_6 &= 4 \cdot 10 \mod{13} = 1 \cr x_7 &= 1 \cdot 10 \mod{13} = 10 \cr x_8 &= 10 \cdot 10 \mod{13} = 9 \cr \cdots \end{align}
であり、1➗13を筆算で実行していき、各桁の割り算を行った際の余りを見てみると、上の数列と一致していることが確認できる。

線形の擬似乱数生成器は線形帰還シフトレジスタ (LFSR)、メルセンヌ・ツイスターを含めて概ね似たような考え方で理解できる。このことから、シード (初期値、つまりここでは割られる数) が同じであれば常に同じ数列を生成するのもご納得いただけるのではないかと思う。また、割る数 \(m\) と \(a\) 進表示の \(a\) というパラメーターをうまく選べば、周期が長く (つまり循環していることに実用上気づくことなく) 並ぶ数もランダムっぽく見えそうでもある。
「ランダムっぽさ」は、一般には統計的仮説検定の枠組みで定量的に評価する。帰無仮説\(H_0\)を「生成された数列はランダムに生成された」、対立仮説\(H_1\)を「生成された数列は何らかの規則に従って生成された (ランダムでない)」として、帰無仮説\(H_0\)の元で思いつく限りの統計量について帰無仮説が棄却されないことをもって「どうやらランダムっぽい」 (より正確には「大量のデータをもってしても、ランダムであることを否定するに足る根拠はない」) と判断する。
このとき、統計量としては、標本分布が (漸近的に) 正規分布やχ二乗分布に従うものを選ぶ。このような検定のスタンダードとしては、例えば、NISTのSP 800-22 Rev. 1aの統計的検定がある。統計的仮説検定によるランダムネスの検定については、長くなるのでまたいずれこのブログに書きたいと思う。
また、暗号用途で使われる擬似乱数は上のような線形な変換ではなく非線形な変換を含んでおり、次のビットを予測できないとか前の状態を推測できないとか色々と面倒臭い要件がある。一応は暗号の得意なフレンズという設定になっているので、これもいずれこのブログに書こうと思う。
長くなったので、今回はこんなところで。
0 notes
Text
Androidのtools (Lintなど) をrepo syncでダウンロードする
ちょっとわけあってAndroidのLintのソースコードを読む必要があり、repo syncしようとしたのだけど、ぼくのMacBook ProはSSDの容量が128GBしかなく、Dockerを多用することもあり、全てのプロジェクトをrepo syncでダウンロード (というかclone) するのは嫌、デカすぎる。
結論から言ってしまうと、repo initの-gオプションでtoolsを指定してからrepo syncを実行すればtools/baseのみをrepo syncでダウンロード (というかclone) できる。
次の通りにコマンドを叩けば、Android 8.0.0 r28のtools/baseのみをcloneできるはず。
$ repo init -u https://android.googlesource.com/platform/manifest -b android-8.0.0_r28 -g tools $ repo sync -c tools/base
以下は、上記のコマンドの説明 (になっているといいな)
repo init → repo syncでtools/baseだけsyncしようとすると、デフォルトの状態では、project group must be enabled for project tools/base とエラーを出力して終了してしまう。frameworks/baseなどはこの方法でframeworks/baseプロジェクトのみsyncできるのだが...
上記のエラーメッセージで .repo ディレクトリ内をfind/grepし、そこを起点にrepoのソースコードを辿っていった結果、どうやらrepo syncのデフォルトの挙動としてrepo/manifest.xmlに記述されている project要素のうちgroups属性の値がnotdefault のプロジェクトはsyncしないという挙動になっているらしかった。
下のリストの通り、tools/baseはgroupsにnotdefaultを含んでおり、そのためsyncに失敗したようだった。
<?xml version="1.0" encoding="UTF-8"?> <manifest> <remote name="aosp" fetch=".." review="https://android-review.googlesource.com/" /> <default revision="refs/tags/android-8.0.0_r28" remote="aosp" sync-j="4" /> ... <project path="tools/apksig" name="platform/tools/apksig" groups="pdk,tradefed" /> <project path="tools/base" name="platform/tools/base" groups="notdefault,tools" /> <project path="tools/build" name="platform/tools/build" groups="notdefault,tools" /> ... </manifest>
この挙動はどうやら、.repo/manifests.git/.repo_config.json に manifest.groups というエントリー (key-value) を追加してやればsyncの対象となるgroupを変更できるようであった。手動で書き換えるのは他のファイルと整合性が取れなくなるなどのトラブルのもとなので、repo helpを眺めていたところ、repo initに-gオプションというgroupを指定するオプションがあり、これを指定するとsync対象のgroupを変更できるようだった。
$ repo init -u https://android.googlesource.com/platform/manifest -b android-8.0.0_r28 -g tools というコマンドを叩くと、.repo_config.jsonは以下のように manifest.groupsというキーを含み、対応する値としてtoolsを含むようになる。この状態では repo sync tools/base というコマンドを叩くとエラーが発生することなくtools/baseをsyncできる。
"manifest.groups": [ "tools,platform-darwin" ],
0 notes
Text
t-SNEを使って可視化してみた
多次元のデータを可視化するときは、主成分分析、カーネル主成分分析や線形判別で次元を2次元あるいは3次元まで落として散布図にプロットすることが多いかと思います。
今朝いじっていた自然言語のデータは、主成分分析だと綺麗にクラスが分かれずに (もっと高次元では分かれているようだけど)、t-SNEを試してみた。
主成分分析
見ての通り、2次元だとぐちゃっと重なってしまっていてようわからん。
t-SNE
t-SNEだと2次元でもクラスがそこそこ分離しているように見える。
どのような理屈で動いるいるか全く理解していないので、主成分分析で綺麗に可視化できない場合以外は今のところ使うつもりはない。
0 notes
Text
自然言語での記述から脆弱性の種類を推定してみる
それぞれ200ずつダウンロードすると、先頭にヘッダーのついたTSVファイルがそれぞれ4ずつ28のファイルをダウンロードすることになりますが...
まずはこれらを結合して今回のタスク用に都合のいいファイルを作ってしまいましょう。
それぞれダウンロードする際に csrf1.tsv, csrf2.tsv や codeexec1.tsv, codeexec2.tsv のようなファイル名をつけておいて、findコマンドを使って結合します。-execオプションではsedコマンドを使ってヘッダーを取り除いています。
find . -type f -name "csrf[1-4].tsv" -not -name "csrf.tsv" -exec sed "/^#.*$/ d" {} \; > merged/csrf.tsv
続いて、このようにしてタイプごとに結合したファイルにから、awkを使って「ラベル, CVE (今回は使わず), 概要」とタブ区切りで並んでいるファイルを作成します。
<merged awk '{ print "CSRF\t", $2, "\t", $16 }' > merged/csrf-trans.tsv
最後に脆弱性種別ごとに作成したTSVファイルをcatコマンドで一つにまとめます。
cat merged/*-trans.tsv > merged/cves.tsv
では、機械学習で脆弱性の概要の記述から脆弱性の種類を予測できるか試してみましょう。
まずはデータを読み込み、訓練集合と検証用のテスト集合に分けるところから。
import csv import numpy as np cves = [] with open("cves.tsv", "r") as file: for line in csv.reader(file, delimiter="\t"): cves.append(line[0:2] + [line[2].strip()]) cves = np.array(cves) data = cves[:, 2] target = cves[:, 0] rnd_idx = np.random.permutation(1400) train = { 'data': data[rnd_idx[:1200]], 'target': target[rnd_idx[:1200]] } test = { 'data': data[rnd_idx[1200:]], 'target': target[rnd_idx[1200:]] }
まずは素朴にBag of Wordsでベクトル化して、カーネル主成分分析で次元削減してからサポートベクターマシンで学習してみましょう。(なお、事前にロジスティック回帰やカーネル法を使わない主成分分析も試してみたが、汎化性能はあんまり変わらないという印象でしたので、それらを使っても良いと思います。)
from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import KernelPCA from sklearn.svm import SVC from sklearn.multiclass import OneVsRestClassifier vectorizer = CountVectorizer() train["features"] = vectorizer.fit_transform(train["data"]) test["features"] = vectorizer.transform(test["data"]) pca = KernelPCA(kernel="rbf") train["reduced_features"] = pca.fit_transform(train["features"]) test["reduced_features"] = pca.transform(test["features"]) estimator = SVC(kernel="rbf") classifier = OneVsRestClassifier(estimator) classifier.fit(train["reduced_features"], train["target"])
続いて、検証用に残した200例から予測してみます。
predicted = classifier.predict(test["reduced_features"])
たとえば、Code Executionに属するものをうまく分類できているかを、まずは散布図で可視化して、続いて偽陽性、偽陰性などを数えてみますと...
from matplotlib import pyplot as plt plt.figure(figsize=(8,6)) plt.scatter( test["reduced_features"][np.char.find(predicted, "CodeExec") == 0, 0], test["reduced_features"][np.char.find(predicted, "CodeExec") == 0, 1], marker="o", label="predicted" ) plt.scatter( test["reduced_features"][np.char.find(test["target"], "CodeExec") == 0, 0], test["reduced_features"][np.char.find(test["target"], "CodeExec") == 0, 1], marker="+", label="expected" ) plt.legend() plt.title("Code Execution") plt.show() from IPython.display import display import pandas as pddef p(x): if x == 0: return 1 return 0def e(x): if x == 0: return 2 return 0tmp = np.vectorize(p)(np.char.find(predicted, "CodeExec")) + np.vectorize(e)(np.char.find(test["target"], "CodeExec")) true_positive = len(tmp[tmp == 3]) false_positive = len(tmp[tmp == 1]) false_negative = len(tmp[tmp == 2]) true_negative = len(tmp[tmp == 0]) df = pd.DataFrame([[true_positive, false_negative], [false_positive, true_negative]], columns=["Predicted +", "Predicted -"], index=["Target +", "Target -"]) display(df)
パッとみ印象としては、あんまり汎化性能はよくないなあという印象です。おそらくこれは、単純にBag of Wordsでベクトル化したために、ありふれた語などの影響を受けてしまっているのではないか?と考えました。
そこで、Bag of Wordsによってベクトル化するCountVectorizerではなく、次はTF-IDFでベクトル化するTfidfVectorizerを使ってみました。
コードは上のものとほぼ同じです。(CountVectorizerをTfidfVectorizerに変えただけ)
from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.decomposition import KernelPCA from sklearn.svm import SVC from sklearn.multiclass import OneVsRestClassifier vectorizer = TfidfVectorizer() train["features"] = vectorizer.fit_transform(train["data"]) test["features"] = vectorizer.transform(test["data"]) pca = KernelPCA(kernel="rbf") train["reduced_features"] = pca.fit_transform(train["features"]) test["reduced_features"] = pca.transform(test["features"]) estimator = SVC(kernel="rbf") classifier = OneVsRestClassifier(estimator) classifier.fit(train["reduced_features"], train["target"]) predicted = classifier.predict(test["reduced_features"])
先ほどの単純なBag of Wordsのベクトル化と比べると、やや改善しているという印象です。t-SNEで2次元に潰して可視化してみます。
左 (予測) と右 (正解) とを見比べると、右下のCodeExecをDoSと分類してしまうケースや、左側のSQL InjectionのあたりにあるCodeExecをCodeExecとして分類できていないなど予測に失敗しているところはありますが、パッとみた印象としては概ね8割がた以上はよく分類できているなあという印象です。
#機械学習#machine learning#SVM#PCA#Classification#分類#security#セキュリティ#natural language processing#NLP#自然言語処理
0 notes
Text
ニュートン・ラフソン法の収束条件をどうしたら良いのだろうか
表題の通りのことが気になっている。
scikit-learn付属のデータセットdigitsをロジスティック回帰で分類してみて、係数ベクトルの最尤推定量を求めるのにニュートン・ラフソン法を実装したのだけど、イテレーションごとの係数ベクトルの推定量のノルムをプロットすると下図のようになった。x軸がイテレーションで、y軸がノルム。
なんとなく収束しているようにも見えるけど...
更新後のベクトルと更新前のベクトルの差をとってノルムを求めると、これもまた最初���うちは安定していないけど100回くらい値を更新したところでほぼ収束している感じがする。
あんまり深く考えていなかったので、収束の判定をNumPyのnumpy.allclose関数で行なっているのだけど、これがworkしない。
というのも、上の図の通り収束しているように見えるが、NumPyのnumpy.isclose関数がTrueを返す要素数をプロットしてみると、イテレーションが100を超えたあたりからほぼ横ばいになっていて、おそらくどれだけイテレーションを回してもnumpy.allcloseがTrueを返すことはない。
ニュートン・ラフソン法は多変量のテイラー展開の2次の項までで関数を近似してから両辺偏微分して∇l(β) = 0 とおくことで得られるのだったから、テイラー展開を2次までで打ち切ったことによる誤差がつきまとうかもしれず、それを収束判定に取り入れるのかもしれないけど、今日はもう頭があんまり回らない。
誰か知っていれば、こっそり教えてくれるとありがたい。
#機械学習#machine learning#ロジスティック回帰#logistic regression#ニュートン法#ニュートン・ラフソン法#Newton's method#Newton-Raphson method#optimization#最適化
0 notes
Text
事後確率の比でデータを分類してみる (ロジスティック回帰)
機械学習の基本は特徴抽出 (次元削減), 回帰 or 判別, モデル選択であり、まずは扱いやすい次元に入力の素性ベクトルを射影し、それに対して回帰や判別のアルゴリズムを適用し、そしてそのアルゴリズムが推定したモデルが良い予測をもたらすモデルであるかをモデル選択で評価します。
次元削減の代表的な手法には、主成分分析や線形判別があります。これは以前に説明しました。モデル選択には交叉検定やAIC (赤池情報量基準) がありますが、これはまたいずれ説明します。
今回は判別 (分類) のアルゴリズムとして、事後確率の比に基づいてデータを分類するということをしてみます。具体的には2群に分類するケースにおいて、事後確率の比の対数 (対数オッズ) が係数ベクトル (重み) と入力の特徴ベクトルの線形結合で表せると仮定した場合のモデルの推定方法を考えます。
この方法は、入力を観測したときにそれが一方の群から出ているという事後確率 \(\pi = P(Y_i = 1 | x_i)\) の比の対数が線形であると考えます。すなわち、
$$ \log \frac{\pi}{1 - \pi} = \beta^T x_i $$
と考えます。このように、対数オッズが線形と考えるとロジスティック回帰の問題に帰着されます。
今回はScikit-learnに付属しているdigitsというデータセットを使います。 以前に主成分分析の対象としたデータセットです。(下図が主成分分析を適用して2次元にプロットした結果)
これに対して上の方法でロジスティック回帰によって新しく与えた200個のデータが 0 か 0以外かを分類した結果を示したのが下の左側の図です。右側の図は正解を表しています。この通り、ロジスティック回帰によって0か0以外かは正しく分類できています。
他にも4か4以外かを分類した結果も完璧ではありませんが、概ねよく分類できていました。
今回は2群の分類のみですが、次回以降のエントリーで、この判別アルゴリズムを多群に拡張したケースを扱いたいと思います。
ロジスティック回帰による分類の解説とコードおよび、最尤推定量を求めるためのニュートン・ラフソン法、及び上のプロットを得るコードは以下のリンクを参照してください。
https://nbviewer.jupyter.org/gist/0gawa/bba88dcabeb7e2ff5ae92ab0aa7c163d
0 notes
Text
Scapyで802.11のBeaconを飛ばす
表題の通りです。接続できるわけではありませんが、ヘンテコなSSIDのAPがあるかのように見せかけることもできますね。誰も得しない!
戯れに、「おちんちんびろーんww」というSSIDのbeaconを飛ばしてみる。
以下のように、monitor modeのインターフェースを追加してupしてからしてから、scapyを立ち上げてBeaconのフレームを作って送信する。
# iw phy phy0 interface add mon0 type monitor # ip link set mon0 up # scapy WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6 INFO: Please, report issues to https://github.com/phaethon/scapy Python 3.5.3 (default, Sep 14 2017, 22:58:41) Type 'copyright', 'credits' or 'license' for more information IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help. Welcome to Scapy (3.0.0) using IPython 6.2.1 In [1]: broadcast = "ff:ff:ff:ff:ff:ff" In [2]: fake_ssid = "00:11:22:33:44:55" In [3]: beacon = Dot11(addr1=broadcast, addr2=fake_ssid, addr3=fake_ssid)/Dot11Beacon(cap="ESS", timestamp=1)/Dot11Elt(ID="SSID", info="おちんちんびろーんww".encode("utf-8"))/Dot11E ...: lt(ID="DSset", info=b"\x01")/Dot11Elt(ID="Rates", info=b"\x82\x84\x0b\x16") In [4]: sendp(RadioTap(present=0)/beacon, iface="mon0", loop=1)
iPhoneの設定→Wi-Fiを開くと、この通り、おちんちんびろーんしている。

0 notes
Text
MacBook ProのAirMac Extremeをモニターモードで動作させたい
WireSharkはsudoつけて起動するとモニターモードでキャプチャできるのだけど (*1)、WireShark以外に自作ツールでモニターモードにしたいとか、そういうこともあるよねー。で、どうやったらモニターモードにできるか調べてみた。
結論から言ってしまえば、低レベルには/dev/bpf* をopenしてioctlで制御できるのだけど、もう少し高レベルなAPIとしてlibpcapの関数を利用できる。
以下のようなコードで、libpcapでen0をモニターモードにできる。肝はpcap_set_rfmonでこれによりpcap_activate呼び出し時にモニターモードで動作する。(なお、ビルドするときはgcc -lpcap -o target src.c ってやって動的リンクしてやらないとリンク時にエラーになるから注意)
#include <pcap/pcap.h> #include <stdio.h> int main(int argc, char **argv) { char errbuf[256]; pcap_t *p = pcap_create("en0", errbuf); if (p == NULL) { fprintf(stderr, errbuf); return 1; } // activate時にモニターモードで動作させる if (pcap_set_rfmon(p, 1)) return 1; // activate時にプロミスキャスモードを有効化する if (pcap_set_promisc(p, 1)) return 1; // パケットをキャプチャするときのバッファーの大きさ (?) if (pcap_set_snaplen(p, 2048)) return 1; // タイムアウト (ms) if (pcap_set_timeout(p, 1000)) return 1; // activateする。 if (pcap_activate(p)) return 1; return 0; }
また、適当にコールバックを書いてやることで、パケットをキャプチャしつつキャプチャした時点のタイムスタンプ (というよりは経過した時間) や、生の802.11フレームを出力するのも簡単にできる。
パケットキャプチャを開始するには、pcap_loop関数を使い、これに以下のようにコールバックを渡すことで上記のことを実現できる。
#include <pcap/pcap.h> #include <stdio.h> #include <stdlib.h> struct radiotap_header { unsigned char version; unsigned char padding; unsigned short len; unsigned int present; } __attribute__((__packed__)); struct ieee80211_header { unsigned short frame_control; unsigned short duration_id; unsigned char addr1[6]; unsigned char addr2[6]; unsigned char addr3[6]; unsigned short seq_ctrl; unsigned char addr4[6]; } __attribute__((__packed__)); void callback(u_char *ignore, struct pcap_pkthdr *header, const u_char *raw) { struct radiotap_header *rt; struct ieee80211_header *dot11; unsigned int offset; unsigned char *payload; rt = (struct radiotap_header*) raw; dot11 = (ieee80211_header*) (raw + rt.len); offset = rt.len + sizeof(ieee80211_header); if (header->len == header->caplen && header->caplen > offset + 4) { payload = malloc(header->len - offset - 4); memcpy(payload, raw + offset, header->len - offset - 4); // snip // ここにやりたいことをかく。たとえば、addr1〜3とペイロードを表示など。 free(payload); } else { // snip // この分岐に至るのはieee802.11 のヘッダーの後ろにペイロードがないケース } } int main(int argc, char **argv) { // snip // 10回キャプチャする pcap_loop(p, 10, callback, NULL); return 0; }
ioctlで頑張るよりもこのようにlibpcapを使った方が簡単にモニターモードでスニフするコードを書けるのだが、ぼくらのような高レベルな生き物は、より高レベルな言語で書きたくなる訳で、Cythonを使ってPythonから呼び出せるようなPythonモジュールを書いている。飽きて放擲するかもしれないけど、飽きるまではたまに機能を追加したり修正したりするよ。
https://github.com/0gawa/pylibpcap3
0 notes
Text
WEPの鍵復元
(きちんとFMS攻撃, PTW攻撃やKleinの論文に目を通していないので嘘を言っているかもしれない。)
基本的には、WEPの鍵復元はRC4の偏りを利用する。IVが特定の値のときにRC4の鍵ストリームの偏りが著しくなり予測可能になるというのは、例えばKRACKsで一躍有名になったVanhoefらも2015年に確認している[1]ことである。
最も初期に報告された現実的な攻撃法はFMS攻撃であり、これは特定のIVが使われた場合に、秘密鍵、IVおよび鍵ストリームに強い相関が生じることを利用している。そのような”弱い”IVが使われたパケットをかき集めて、IVと暗号化されたペイロードが大量に集まれば、WEPの鍵を復元できてしまう。このFMS攻撃を最適化した改良版がKoreKの攻撃であり、KoreKの攻撃はaircrack-ngに実装されている。
これらの攻撃の対策としてはWEPplusという方式を採用する場合がある。この方式では、弱いIVを使用せず、それゆえに上記の攻撃に耐性がある。
上記の攻撃では特定の条件を満たす値のIVを集められる場合にのみ有効なのだが、さらにこれらを改良した攻撃にTewsらのTPW攻撃がある。TPW攻撃もまたRC4の弱さにつけこむのだが、収集するフレームをARPレスポンスに絞り、ARPレスポンスのペイロードの先頭部分が固定であることを利用する。そのため、後述するARPリプレイと組み合わせて攻撃を構成することになり、ARPリプレイの対策がなされていない限りは数十秒から数分程度で高確率でWEPの鍵復元が可能となる。TPW攻撃とARPリプレイはaircrack-ng, aireplay-ngに実装されている。
ARPリプレイとTPW攻撃の実装されているこれらのツールはLinux上で動作し、モニターモードで動作可能でありパケットインジェクションの可能な無線LANインターフェースを利用している場合には、容易に攻撃を実行できる。以下は、これらのツールを使った攻撃手順である。ディストリビューションはUbuntu 17.04、無線LANアダプターはTL-WN722Nで動作確認済みである。
まずはTL-WN722Nを接続し、iw phyコマンドでモニターモードのインターフェースを追加し、ifconfigやiproute2でupする。
# iw phy phy0 interface add mon0 type monitor # ip link set mon0 up
続いて、aireplay-ngでFake Authenticationを実行し、ARPリプレイを開始する。
# aireplay-ng --fakeauth 6000 -q 10 -o 1 -b APのBSSID mon0 # aireplay-ng --arpreplay -b APのBSSID mon0
実のところ、Fake Authenticationなしに正規のクライアント(STA)の送信するARP要求をリプレイしても攻撃可能である。
# # aireplay-ng --fakeauthをスキップして... # aireplay-ng --arpreplay -b APのBSSID -h 正規クライアントの無線LANインターフェースのMACアドレス mon0
この場合は正規のクライアントがAPとの接続を解除した場合に以降のフレームが破棄されてしまう。802.11のフレームが破棄されないためには、ヘッダーに記載されている送信元MACアドレスの端末とAPの間でAssociationが確立されている必要がある。そして実はAssociationで止めてしまって以降の4-way handshakeを開始する前の状態でも任意のフレームを送ることはできて、それゆえにfake authenticationを実行しておくと送信元のMACアドレスのみ書き換えた正規クライアントからのARP要求を切断されることなくリプレイし続けることが可能となる。お
APから帰ってくる大量のARP応答のフレームにはフレッシュなIVと暗号化されたペイロードが含まれていて、あとはこれをairodump-ngというツールで集めて、aircrack-ngにキャプチャファイルを入力すれば高確率でWEPの鍵が復元される。
# airodump-ng --channel 標的ネットワークのchannel --bssid APのBSSID -w capture-file mon0 # # ある程度パケットが溜まってきたら... # aircrack-ng capture-file-01.cap
[1]: Vanhoef, Mathy, and Frank Piessens. "Predicting, Decrypting, and Abusing WPA2/802.11 Group Keys." USENIX Security Symposium. 2016.
0 notes
Photo

ElGamal暗号を説明しようと描いた図
0 notes
Text
Kotlinはじめました
Androidの実装ガイドを書くことになった。調査結果はどうせ公にされるのでされるので、そのうちこちらでも公開しようかなあと思っております。
どうせサンプルコードを書くならJavaとKotlinに対応したいなーと考えていて、Kotinに入門しました。少し前はRubyとかPythonとか型を静的にチェックしない、まあ実行時のDuck typingでよかろうくらいのゆるい言語が流行りでしたが、最近はJavaScriptでもflowで静的型付けするし、Pythonもmypyで静的型付けするし、RustやKotlin, Swingなど静的に型付ける機会が増えましたね。
で、このKotlin、flowの型なんかもそうなのだけど、Nullableな型の検査が結構賢くって、null-checkを通過したあとだとNonNullな型として扱われるんだよね。
例えば、下のコードだと、nameとemailがnullable (String?) 型なので、Customerのコンストラクタの型と一致せずコンパイルが通らないのだけど...
data class Customer(val name: String, val email: String) fun main(args : Array<string>) { val name = args.getOrNull(0) val email = args.getOrNull(1) val customer = Customer(name, email) println("$customer") }
それを次のようにnull-checkを加えて書き直すと、nullチェック通過後の型は String? ではなく String として扱われてコンパイルが通るのですね。
data class Customer(val name: String, val email: String) fun main(args : Array<string>) { val name = args.getOrNull(0) val email = args.getOrNull(1) if (name == null || email == null) { println("invalid arguments") return } val customer = Customer(name, email) println("$customer") }
もちろん、JavaでもChecker Frameworkを使えば同等の検査をビルド時にできるのだけど (Pluggable Type System)、Kotlinの型システムがNonNullとNullableを区別してくれるのでKotlinでは何のツールやライブラリも使うことなくこれをやってくれるのがうれしい。
他にも随時、下のリンク先に書き込んでいく予定。
英語での情報発信になれるため、英語で書いているのだけど、外国語苦手なので文法的に突っ込めるところがあったらissueあげてくださると助かりますー。
Kotlin for JAVA programmers @ Github
25 notes
·
View notes
Text
基本的なWi-Fiクラック
ちょっと調べて実際に攻撃してみたので、メモを残しておく。 攻撃手法の詳細はまた明日以降にでも書くよ。
WEPに対する攻撃
基本はRC4の脆弱性とWEPで送受信するパケットの構造の弱点を狙う。 よく知られている通り、RC4の暗号文は場合によって大きな偏りが生じることがあり、大量のパケットをキャプチャすればそれを利用して高確率で暗号文から鍵を復元できる。そのため、WEPを破るためにはいかにして短時間に大量のパケットを、受動的ではなく能動的に発生させるかが肝となる。
ARP replay
L2レベルで暗号化される大量のパケットを発生させる最も簡単な方法は、ネットワークに参加している正規のクライアントが送信したARPリクエストを傍受し、再送を繰り返すことで大量のARPレスポンスを発生させるという方法。
もしもWEPのネットワークに参加しているクライアントがARPを送信することがあれば、それをreplayし続けるだけで攻撃できるため、スクラッチで実装するにしても簡単な攻撃法。
KoreK ChopChop, Fragmentation攻撃
ただ、正規のクライアントが都合よくARPを投げてくれるとも限らないため、ARPリク��ストを偽造して能動的に送る方が確実である。
問題は平文のARPリクエストを送りつけるのは簡単だが、いかにしてAPが受け付けてくれる暗号化パケットを偽造するかである。このためには、APのPSK (とSSID) と、暗号化パケットと共に正規のクライアントから送信されるIVを結合して作った鍵から生成される鍵ストリームとして正当な鍵ストリームを手に入れる必要がある。
WEPがもしもAssociation時に認証を要求する場合、その認証方式の脆弱性を利用することで短いながらも正当な鍵ストリームとIVのペアを手に入れることができる。これによって、生成したARPリクエストを暗号化してIVを添えてAPに送れば、それは正当なARPリクエストとして受け入れられることになる。
あるいはKoreK ChopChop攻撃によってAPをCRCオラクルとしてごく短い鍵ストリームとIVを手に入れたり、効率がやや上がる手法としてはFragmentation攻撃によって同様に鍵ストリームとIVを手に入れたりして、それによって同様に偽造ARPリクエストを暗号化しAPに受け入れさせることが可能となる。
FMS攻撃
大量の暗号化されたARPレスポンスを受けとったならば、あとはFMSの方法によって高確率で鍵を復元できる。
WPAへの攻撃
WPAには、今年になってKRACKのような正しく実装している限り常に攻撃可能な脆弱性が発見されたが、その他昨年に報告された脆弱性として、仕様通りに乱数生成を実装するのが現実的でなく多くの実装でエントロピーが不足しTKIPにダウングレードさせることでRC4の偏りを利用して鍵を復元するという攻撃が成立する。
ここでは、そのような近年発見された脆弱性は述べない。
4-way handshakeのキャプチャとPMKの推測
WPA-PSKではSSIDとPSKから生成されるPMKという鍵から、4-way handshakeで交換されるnonceを使って、以降の通信で暗号化及びインテグリティチェックに使う鍵をそれぞれ生成する。
この4-way handshakeで交換されるnonceはmonitor modeで動作するWLAN interfaceで通信を傍受していれば簡単に見つけられる。問題はPMKをいかにして得るか、である。
PMKを手にする一つの方法としては、辞書攻撃がある。SSIDはbeaconを受信することで容易にわかるし、PSKはパスワードであるので、ユーザーが単純なパスワードを設定している場合には辞書攻撃によって簡単にPMKを得ることができる。そうなれば、4-way handshakeのパケットキャプチャから取り出したnonceと合わせて通信を全て解読できてしまう。
単純なパスワードでなかったとしても、実は桁数が10桁やそこらであればブルートフォースが可能である。加えて、PMKの生成に要する計算量はやや大きくなるよう設計されているが、生成にnonceなどランダムな要素はなく、SSIDとPSKから決定論的に生成される値であるため、SSIDが既知であれば事前計算が可能である。この攻撃のためのツールとしてPyritがある。
WPSクラック
WPSのPINモードが有効である場合、PINモードのプロトコルの脆弱性によりブルートフォースでPSKを得られる。PINモードは8桁のPINを入力することでAPに接続するモードだが、これはボタンを押すなどのユーザーの必要とせず電波の届く範囲では常にパケットの送信が可能である。そして、8桁のPINといっても、1桁はパリティチェックに使われ、残り7桁は4桁、3桁に分けてそれぞれチェックするため、11000通りの総当たりで必ずPINを当てられる。電波状況にもよるが、1PINあたり8秒として24時間程度で鍵が得られてしまう。
これを実装しているツールにreaverがある。
その他、WPSのPINモードを攻撃する方法として、実装の脆弱性をついたPixie dust attackという攻撃がある。これは、PINモードでの通信時にAPからクライアントへPINのハッシュ値 (HMAC) を送るが、一部の実装では乱数生成に脆弱性があり予測可能な鍵でハッシュ値を計算するため、オフラインでブルートフォースにより傍受したハッシュ値を生成した値、すなわちPINを推測できる。この攻撃は24時間などではなく、ものの数秒で成立する。
#security#network security#network#セキュリティ#ネットワーク#ネットワークセキュリティ#IEEE802.11#WLAN#wireless lan#無線LAN#Wi-Fi
0 notes
Text
箱庭ネットワークの構築
後日書き足すつもりだけど、まずはL2まで。
ネットワークの勉強あるいは実習をしようというときに困るのは、そう易々とスイッチやルーター、それにPCなど端末を買い揃えることは難しいよね...というところで、であるならば仮想化したネットワークを作れば良かろうと調査をはじめた。当エントリーはその際に残したメモである。
iproute2で仮想ブリッジや仮想Etherケーブルが作れる
仮想ブリッジをつくる
# ip link add name br0 type bridge # ip link set br0 up
仮想ブリッジを消す
# ip link set br0 down # ip link delete br0 type bridge
仮想Etherケーブルをつくる
# ip link add veth1_2 type veth peer name veth2_1 消す # ip link delete veth1_2 type veth # ip link delete veth2_1 type veth
ネットワークの隔離されたchroot環境をつくる
ひとまず、Busyboxのソースを落として make menuconfig で static library としてビルドするオプションを有効にしてビルド。 /path/to/busybox-src/_install にchrootする。
# chroot _install ash
この際、PIDもホストの環境から隔離するために unshare コマンドを使う。
# unshare -pf chroot _install ash
隔離されたネットワークをつくるには、ip netns をつかう。
# ip netns add isolated1 # ip netns add isolated2
これらのネットワーク上でコマンドを実行するには、 ip netns exec を使う。 上のChroot環境に入る場合は、
# ip netns exec isolated1 unshare -pf chroot _install ash
のようなコマンドを叩く。
仮想ケーブルで接続する
隔離されたネットワークにケーブルをさす。
# ip link set veth1_2 netns isolated1 up # ip link set veth2_1 netns isolated2 up
仮想ブリッジにケーブルをさす。
# ip link set veth0_1 master br0
仮想ブリッジからケーブルを抜く
# ip link set veth0_1 nomaster br0
IPアドレスの割り当て
これで、 isolate1 というネットワークと isolated2 というネットワークが仮想Etherケーブルで接続された。 IPでルーティングするためには、それぞれの環境で ip address add を叩けばよい。
たとえば、isolated1 にささっているインターフェース veth1_2 に 172.16.0.1、 isolated2 にささっているインターフェース veth2_1 に 172.16.0.2 を割り当てる場合は、 以下のようなコマンドを叩く。
# ip netns exec isolated1 unshare -pf chroot _install ash / # ip address add 172.16.0.1/24 dev veth1_2 / # ip address add 127.0.0.1/8 dev lo #ループバックにIPアドレスを割り当てるのも忘れずに。 / # ip link set lo up # ip netns exec isolated2 unshare -pf chroot _install ash / # ip address add 172.16.0.2/24 dev veth2_1 / # ip address add 127.0.0.1/8 dev lo / # ip link set lo up
疎通確認
ここまでできたら、疎通確認をしてみる。 172.16.0.1 → 172.16.0.2 あるいはその逆に ping が届くのが確認できる。
# ip netns exec isolated1 unshare -pf chroot _install ash / # ping 172.16.0.2 # ip netns exec isolated2 unshare -pf chroot _install ash / # ping 172.16.0.1
次やること
Busyboxだとできることが少なすぎる。Dropbearをstatic buildして動かせないか。
上の方法だと各コンテナ (もどき) がファイルシステムを共有している。overlayfs で下層のみ共通にして、あとは隔離できないか。
Routing protocolをしゃべる軽量なコンテナを作れないか (仮想ルーターを作りたい)
仮想ブリッジを使ってみる (STPとか使えるのかな)
0 notes
Text
VirtualBox上のUbuntuからUSB無線LANアダプターでインターネットに接続する
なんでそもそもVirtualBox上のUbuntuから無線LANでAPに接続したかったかと言うと、あんまり大きな声では言えないセキュリティに関連した活動を行うにあたって、社内のProxy、社内のゲートウェイを通して通信したくなかったという裏事情があるのだけど、それはそれ。
さて、表題の目的を達成するために、下記の手順を実施したわけですけど、まずは前提としてどのような環境で実施したのかを示しておきましょうかね。
USB無線LANアダプター: TL-WN722N
使用するAPのESSID: wx03-xxxxxx
ゲストOS: Ubuntu 16.04
(余談なのだけど、このTL-WN722NはWi-Fiに対する攻撃法の調査の為に私費で購入している。aircrack-ngやaireplay-ngもきちんと動くし3000円くらいで購入できるので、Wi-Fiクラックに興味のある方はマストバイだと思う。おすすめ。)
やること
インターフェースの有効化
wpa_supplicantの設定ファイルを用意
APに接続
DHCPによるIPアドレスの割り当て
インターフェースの有効化
iw dev でデバイスを確認。
# iw dev phy#0 Interface wlx8416f9xxxxxx ifindex 5 wdev 0x1 addr 84:16:f9:xx:xx:xx type managed
Ubuntu 16.04以降ではUSB無線LANのudevの命名規則としてMACアドレスをねじ込まれてしまい、wlan0のようなわかりやすいインターフェース名にならないので注意。 (ちなみに、udevのルールを上書きすればwlan0のような単純な名前にもできる)
今回のケースでは wlx8416f9xxxxxx がインターフェース名 このインターフェースを次のコマンドで有効化する
# ip link set wlx8416f9xxxxxx up
wpa_supplicantの設定ファイルの用意
WEPやWPAで保護されていないネットワークであれば以下のコマンドで接続できる。
# iw dev wlx8416f9xxxxxx connect wx03-xxxxxx
また、WEPで保護されているケースであっても、キーをfoobar01として、以下のコマンドで接続できる。
# iw dev wlx8416f9xxxxxx connect wx03-xxxxxx key 0:foobar01
しかし、今回はWPA-PSKで保護されたネットワークへの接続となるので、iwコマンドだけでは接続できない。 こういうときは、wpa_supplicantを使う。 Ubuntu Desktopでは標準でインストールされていると思うが、最小構成のUbuntu Minimalではインストールされていないのでaptでインストールする。
# apt install wpasupplicant #wpaとsupplicantの間に_が入らないことに注意
ESSIDやパスワードなどを記述した設定ファイルを用意して、 wpa_supplicant コマンドの -c オプションでそのパスを指定すれば、WPAでAP (無線LANルーター) との接続が確立される。
設定ファイルは次のようにESSIDやパスワード、鍵管理の方式 (WPA-PSK) などを記述する。 (TKIPはとても脆弱なので書かない方がいいかも; そのうち記事を書くかも…)
# cat ~/wpa_supplicant.conf ctrl_interface=/var/run/wpa_supplicant ap_scan=1 network={ ssid="wx03-xxxxxx" key_mgmt=WPA-PSK proto=WPA WPA2 pairwise=CCMP TKIP group=CCMP TKIP psk="......" }
なお、今回はSSIDが既知であったが、SSIDをスキャンする場合は iw コマンドでスキャンする。
# iw dev wlx8416f9xxxxxx scan
APに接続
2のwpa_supplicantの設定ファイルを書き終えていれば、次のように wpa_supplicant コマンドを叩くだけで接続できる。
# wpa_supplicant -Dwext -i wlx8416f9xxxxxx -c/root/wpa_supplicant.conf
接続が確立できているかは iw dev link で確認できる。 もしも、接続できていない場合には、下のように出力される
# iw dev wlx8416f9xxxxxx link Not connected.
接続が確立できている場合には、たとえば以下のようになる。
# iw dev wlx8416f9xxxxxx link Connected to 98:f1:99:xx:xx:xx (on wlx8416f9xxxxxx) SSID: wx03-xxxxxx freq: 2437 RX: 11911070 bytes (46333 packets) TX: 174697 bytes (1936 packets) signal: -49 dBm tx bitrate: 52.0 MBit/s MCS 5 bss flags: short-preamble short-slot-time dtim period: 1 beacon int: 100
DHCPによるIPの割り当て
あとは、DHCPによって無線LANインターフェース wlx8416f9xxxxxx にIPアドレスを割り当てれば 無線LANのAPを通してインターネットに接続できるようになりますが、その前に有線のネットワークインターフェースを落としておきます。
# ip link set enp0s3 down
つづいて、 dhclient コマンドで無線LANインターフェースにIPアドレスを割り当てます。
# dhclient wlx8416f9xxxxxx
おつかれさまでした。以上でインターネットに接続できるようになっているはずです。
0 notes
Text
CircleCI 2.0でDockerのイメージを苦もなくbuildできる件
表題の通り。驚いた。
CircleCI 1.0でDockerのイメージをビルドする場合には、結構ハマりどころがあると聞いていて、それゆえにCircleCIでビルドするのは避けていたのだけど、どうもCircleCI 2.0では `setup_remote_docker` というステップを追加してやれば良いらしく。試してみた。
こちら( https://github.com/0gawa/docker-pandoc ) でGHC, cabal, Pandocの入ったUbuntuベースのイメージのDockerfileを用意し、CircleCIでビルドするときちんとイメージがビルドされデプロイされた (https://hub.docker.com/r/ogawanne/pandoc/)。
同じようにこのイメージをベースに、Node.jsを追加したイメージをビルドし (https://hub.docker.com/r/ogawanne/node-pandoc/) 、これを現在製作中のpandocベースの静的サイトジェネレーター (*1) を作るためのnodeモジュール (https://www.npmjs.com/package/gulp-pandoc-convert) をビルドするコンテナに使っている。CircleCIは指定したイメージを使ってコンテナを立ち上げ、そのコンテナ内でビルドを走らせてくれるのだ。神。
静的サイトジェネレーターは、Pandoc-citeprocやPandoc-crossrefを使ってBibTeXで引用した文献の情報を挿し入れたり、相互参照を挿し入れたりするものを作っている。来年までにセキュリティ技術者向けの暗号の入門書を書こうとしており、その入門書のWeb版をつくるのに使おうとしている (https://github.com/0gawa/cryptobook)
0 notes