WebGoat-5: Crypto Basics

主要な暗号手法を学ぶレッスン。

Page 2

Base64はあらゆる種類のバイナリデータを64(+ 1)種類の英数字記号に符号化する手法。
復号は簡単なので、パスワードなど秘匿性の高いデータをこれで符号化したものはTLSやHTTPSでやり取りする必要がある。

符号
$ echo -n "myuser:mypassword" | base64
bXl1c2VyOm15cGFzc3dvcmQ=
復号
$ echo -n "bXl1c2VyOm15cGFzc3dvcmQ=" | base64 -d # -d, --decodeオプションで復号
myuser:mypassword

上記の復号オプションを使って問題クリア。

Page 3

XOR演算は群としての性質をもっている。

  • 単位元は0
  • ある元aに対する逆元はa自身
  • 移項が可能

たとえ文字列データでも、それを文字列エンコード(ASKIIなりUTF-8なり)した数値として扱えばXOR演算を適用できる。
ここで、aを平文、bを鍵、cを暗号文とすると、

a xor b = c

と表せる。
また、上記の性質より、

a xor b = c
a xor b xor b = c xor b  # 両辺に xor b
a xor 0 = c xor b  # 左辺の b xor b は打ち消し合う
a = c xor b  # 0 は単位元なので左辺は a のまま

となる。結果的には、元の式の b を右辺に移項したということになる。
長々と書いたが、つまり鍵さえわかれば復号ができる。ただ、その鍵が全然わからない。
ここはヒント通りにおとなしくwebサービスを使わせて頂く。

http://www.poweredbywebsphere.com/decoder.html

答えはdatabasepassword

Page 4

ハッシュ関数は一方向関数で、戻り値から引数を割り出すのは不可能だが、引数と戻り値は基本的には一対一対応している(ごくまれにダブる)。
それでもレインボーテーブルという手法を使えばハッシュ値から元データを割り出すことは可能だったり、それを阻止するにはソルトやストレッチを行ったり。
問題はハッシュ値から元データを割り出せ、というもの。正直ザコエンジニアには荷が重すぎるが、以下のwebサービスを使えば一瞬だった。

https://crackstation.net/

回答は123456password。上記サイトではどのようなハッシュ・アルゴリズムが使われていたのかも示してくれる。前者がmd5、後者がsha256だった。

Page 6

opensslなんもわからんのでヒント見まくった。
まず提示されている秘密鍵をprivate.pemにコピペ。そのファイルを使って公開鍵を生成(てか秘密鍵さえあれば公開鍵を復元できるのはじめて知った)。

$ openssl rsa -in private.pem -pubout > public.pem

復元した公開鍵をもとにRSAモジュラスを生成。

$ openssl rsa -in public.pem -pubin -modulus -noout > modulus

Modulus=以降の文字列がRSAモジュラスにあてはまるので、これをコピペして1つ目のテキストボックスに入力。
ほんでRSAモジュラスをもとに電子署名を発行。Base64エンコードを忘れずに、出力された文字列を2つ目のテキストボックスに入力で問題クリア。

$ cat modulus
Modulus=(省略)
$ echo -n "(ここにRSAモジュラスをペースト)" | openssl dgst -sign private.pem -sha256 | base64

Page 8

パスワードファイルを配置したまんまのdockerコンテナに入りそれを使ってメッセージを解読せよ、とのこと。
まずはdockerコンテナを実行・内部に入る。

> docker run -d --name ass webgoat/assignments:findthesecret
> docker exec -it ass /bin/bash

パスワードファイルは/rootディレクトリにあるらしいが、ログインユーザはwebgoatなので当然ながら権限がない。

webgoat:$ cd /root
webgoat:$ bash: cd: /root: Permission denied

ヒントを見たら、root権限を奪取せよ、とあるではないか。こんな序盤でやらせる問題か?
さらにヒントを見ると、/etc/shadowファイルにユーザの情報が記述されているからdocker cpでホストOSにもってきてパスワードを改変せよ、とある。

(WSL2-ubuntuのターミナルで作業する。Pythonがあるならwindowsでも可。)
ubuntu:$ docker cp ass:/etc/shadow .
ubuntu:$ cat shadow
root:*:17918:0:99999:7:::
daemon:*:17918:0:99999:7:::
(省略)

各ユーザの情報フィールドは:で区切られており、第一フィールドがユーザ名、第二フィールドがハッシュ化されたパスワードらしい。つまり、任意のパスワードをそのまま挿入すればよいわけでなく、ハッシュ化しなければならない。ちなみにパスワードが*の場合は設定されておらず、そのユーザでログインすることは不可能。
ではハッシュ方式はどうすればよいのかで詰まった。ここで大いに参考にしまくったのが以下の記事。

https://blog.amedama.jp/entry/linux-shadow-passwd

まずwebgoatコンテナのglibcがどのハッシュ方式に対応しているか確認。

webgoat:$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Debian GLIBC 2.24-11+deb9u3) stable release version 2.24, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 6.3.0 20170516.
Available extensions:
        crypt add-on version 2.1 by Michael Glad and others
        GNU Libidn by Simon Josefsson
        Native POSIX Threads Library by Ulrich Drepper et al
        BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

glibcのバージョンが2.7未満なので、sha256やsha512には対応していない。適当にmd5でハッシュ化することにする。
ではパスワードをハッシュ化しよう。Pythonを使うのが手軽らしい。競プロとかだけでなくこういう分野でも人気な言語なのか?

#!/usr/bin/env python3
import crypt

# 第一引数はハッシュ化したいパスワード
# 第二引数の $1 はmd5方式を、$aho は適当なソルトを表す
hash = crypt.crypt("root", "$1$aho")
print(hash)
ubuntu:$ python3 -V
Python 3.8.2
ubuntu:$ python3 hash.py
$1$aho$JPoqGQ8t9GcaqO5tBeyw1/

表示された文字列をshadowファイルの該当箇所にペーストし、dockerコンテナ内に戻す。

ubuntu:$ docker cp shadow ass:/etc/shadow

ではrootユーザに切り替えよう。

webgoat:$ su -
Password: (root を入力)
root:# 

ここでおれの脳汁が噴射した。人生初のroot権限奪取である。
パスワードファイルは/rootディレクトリにあるらしいので探してみる。

root:# cd /root
root:# ls -alF
total 20
drwx------ 1 root root 4096 Nov 21  2019 ./
drwxr-xr-x 1 root root 4096 Sep 18 01:53 ../
-rw-r--r-- 1 root root  570 Jan 31  2010 .bashrc
-rw-r--r-- 1 root root  148 Aug 17  2015 .profile
-rw-rw-r-- 1 root root   29 Nov 20  2019 default_secret  # ← すげえそれっぽい
root:# cat default_secret
ThisIsMySecretPassw0rdF0rY0u

このパスワードファイルを鍵に指定して、問題文に示されているコマンドで暗号化されたメッセージを復号する。

root:# echo "(省略)" | openssl enc -aes-256-cbc -d -a -kfile /root/default_secret
Leaving passwords in docker images is not so secureroot:#

改行されていないのでやや分かりづらいが、Leaving passwords in docker images is not so secureが元のメッセージであり、これを一つ目のテキストボックスに入力。
パスワードが記載されていたファイル名default_secretを二つ目のテキストボックスに入力して問題クリア。
この問題を通してわかったのは、おれだからこそ回答に至るまで長い時間がかかったが、ふりかえってみるとdockerコンテナのroot権限奪取なんていともたやすいということだ。

ちなみに次のレッスンのWriting new lessonはWebGoatのコントリビュータ向けの内容なのでスルー。