Pwn2Win CTF 2021 Writeup

English version is in the [latter half of this page](#about).

# 概要

[Pwn2Win CTF 2021](https://pwn2win.party/) (2021/05/29 01:37 ～ 2021/05/31 01:37 JST) に1人チームで参加した。
結果は405点で、正の点数を取った720チーム中55位だった。

![got first blood](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/715d8a43-cc55-c92d-391e-97d51251b95a.png)

first blood を得たようだ。

# 解けた問題

|問題|点数|時刻 (JST)|
|---|---|---|
|~Rhiza - founded on the human being|50|2021/05/29 05:29:26|
|Oldschool Adventures - Apple II|355|2021/05/29 08:02:16|

## ~Rhiza - founded on the human being

問題文として長文が書かれており、最後の行にflagが書かれていた。

この解くだけなら最後だけ見ればいい感じ、
Geeky Fun Fact ([The 2013 ACM-ICPC Asia Danang Regional Contest](https://icpc.global/regionals/finder/Asia-Danang-2013)) を思い出すなあ。

```
CTF-BR{join_Lauras_fight_against_opression_and_discover_the_truth!}
```

## Oldschool Adventures - Apple II

### 問題文の情報

Applesoft BASIC のプログラムを実行できる、Apple II のエミュレータがある。
プログラムの実行結果としてQRコードを生成すると、
その読み取り結果をLinuxのシェルコマンドとして実行してくれる。

実行させるプログラムは、以下の条件を満たすことを求められる。

* 長さは 268 chars (サーバのソースコードより、268バイト?) 以内
* 1行で送信する
* プログラム中の改行文字は`§`で表し、高々1個のみ
* QRコードの生成まで50秒以内

TCPサーバの接続情報と、ローカルテスト用のDockerおよびLXC Containerのファイルがある。
また、DockerおよびLXC Container用の起動コマンドも示されている。

### サーバの観察結果

指定のサーバに[Tera Term](https://ttssh2.osdn.jp/)で接続すると、

```
Send the solution for "hashcash -mb 25 xyttzzozyb":
```

のような文字列が送られてきた。このhashcashとやらでググったところ、[Hashcash.org](http://www.hashcash.org/)が見つかった。
ページ左側のメニューから「binaries」をクリックし、実行するプラットフォームと種類を選ぶ
(例えばwindows → console) と、ファイルの一覧の画面になった、
最新の実行ファイルぽいもの(`hashcash-1.22-win32-exe.zip`)をダウンロードした。
ダウンロードしたファイルを展開すると、その中に`hashcash.exe`があったので、
これを用いてサーバーから送られてくる文字列

```
hashcash -mb 25 xyttzzozyb
```

をコマンドとして実行すると、数秒後以下のような出力が得られた。

```
hashcash stamp: 1:25:210530:xyttzzozyb::EKSU6xxV8EuRwams:0000002k/iI
```

このうち、 `1:25:210530:xyttzzozyb::EKSU6xxV8EuRwams:0000002k/iI` の部分をコピペして
サーバーに送信することで、次の段階に進むことができた。
次の段階では、

```
Send your payload here:
```

という文字列が送られてきた。
この後に条件を満たすApplesoft BASIC のプログラムを送れば実行してくれるようだが、
ちょっともたもたするとタイムアウトになってしまい、素早い操作が求められた。
また、hashcashの出力を貼り付けした後エンターキーを押してしまうと、それがプログラムと認識されてしまうようだった。
エンターキーは押さず、次の出力があるまで待つのがいいようだった。

試しにプログラムとして空文字列(改行のみ)を送ると、しばらくした後で

```
Not a valid QR!
```

と出力され、接続が切断された。
また、試しにUTF-8で`§§§§§`を送信したところ、

```
Just 1 line break (§) is allowed!
```

と出力された。このことから、プログラムはUTF-8で送ればいいことがわかった。
ちなみに、`§`はUTF-8で2バイト(`C2 A7`)である。

### Dockerによるローカルテスト環境の構築

今回はDockerとLXC Containerのデータが用意された。
LXC Containerとやらについての知識は無いが、
Dockerは[最近インストールした](https://qiita.com/mikecat_mixc/items/b1143557abb05d0f0f3c#git-master)ので、Dockerで環境を構築することにした。

問題文には、

```
$ docker-compose up
$ nc localhost 1337
```

とあった。また、Docker用のファイルが`tar.gz`形式で与えられた。
他の多くの問題では圧縮されたtarファイルは`attachments.tar`という扱いやすいファイル名であったかわりに、
`@PaxHeader`という謎のデータが含まれ、[7-Zip](https://sevenzip.osdn.jp/)で展開するとファイル名の衝突が何度も起こることがあった。
一方、この問題のファイルは、tarファイルの名前がやたら長かった一方、`@PaxHeader`は含まれていなかった。

tarファイルの中身を適当なディレクトリに入れ、
そこで`docker-compose up`コマンドを実行すると、エラーになった。

<details><summary>エラーメッセージ</summary><div>

```
Traceback (most recent call last):
  File "docker\api\client.py", line 214, in _retrieve_server_version
  File "docker\api\daemon.py", line 181, in version
  File "docker\utils\decorators.py", line 46, in inner
  File "docker\api\client.py", line 237, in _get
  File "requests\sessions.py", line 543, in get
  File "requests\sessions.py", line 530, in request
  File "requests\sessions.py", line 643, in send
  File "requests\adapters.py", line 439, in send
  File "urllib3\connectionpool.py", line 670, in urlopen
  File "urllib3\connectionpool.py", line 392, in _make_request
  File "http\client.py", line 1255, in request
  File "http\client.py", line 1301, in _send_request
  File "http\client.py", line 1250, in endheaders
  File "http\client.py", line 1010, in _send_output
  File "http\client.py", line 950, in send
  File "docker\transport\npipeconn.py", line 32, in connect
  File "docker\transport\npipesocket.py", line 23, in wrapped
  File "docker\transport\npipesocket.py", line 72, in connect
  File "docker\transport\npipesocket.py", line 52, in connect
pywintypes.error: (2, 'CreateFile', '指定されたファイルが見つかりません。')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose\cli\main.py", line 81, in main
  File "compose\cli\main.py", line 199, in perform_command
  File "compose\cli\command.py", line 60, in project_from_options
  File "compose\cli\command.py", line 152, in get_project
  File "compose\cli\docker_client.py", line 41, in get_client
  File "compose\cli\docker_client.py", line 170, in docker_client
  File "docker\api\client.py", line 197, in __init__
  File "docker\api\client.py", line 221, in _retrieve_server_version
docker.errors.DockerException: Error while fetching server API version: (2, 'CreateFile', '指定されたファイルが見つかりません。')
[11476] Failed to execute script docker-compose
```

</div></details>

Docker Desktop を起動してから`docker-compose up`コマンドを実行することで、エラーは解消した。
このコマンドを実行することで、`apachehost`と`challhost`の2台の仮想マシンが作られるようであった。
`apachehost`の構築は数十秒程度で終わったが、`challhost`の構築は長時間(15分以上)かかった。
構築が終わってもコマンドの実行は終わらず、そのまま仮想マシンのログらしきものが出力され始めた。

Tera Termで`localhost:1337`に接続し、同様に`hashcash`の実行結果の一部とApplesoft BASICのプログラムを送ると、
ここにCypressがインストールされていないというようなメッセージが出力され、
プログラムの実行結果は出力されずにTCPが繋がったままになった。

<details><summary>出力されたメッセージ</summary><div>

```
challhost     | > tira-screenshot@1.0.0 cypress:run /home/stevej/stuff/processing/172.19.0.1
challhost     | > cypress run --spec 'cypress/integration/manda-file/actions.spec.js'
challhost     |
challhost     | No version of Cypress is installed in: /home/stevej/.cache/Cypress/7.3.0/Cypress
challhost     |
challhost     | Please reinstall Cypress by running: cypress install
challhost     |
challhost     | ----------
challhost     |
challhost     | Cypress executable not found at: /home/stevej/.cache/Cypress/7.3.0/Cypress/Cypress
challhost     |
challhost     | ----------
challhost     |
challhost     | Platform: linux (Ubuntu - 20.04)
challhost     | Cypress Version: 7.3.0
challhost     | npm ERR! code ELIFECYCLE
challhost     | npm ERR! errno 1
challhost     | npm ERR! tira-screenshot@1.0.0 cypress:run: `cypress run --spec 'cypress/integration/manda-file/actions.spec.js'`
challhost     | npm ERR! Exit status 1
challhost     | npm ERR!
challhost     | npm ERR! Failed at the tira-screenshot@1.0.0 cypress:run script.
challhost     | npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
challhost     |
challhost     | npm ERR! A complete log of this run can be found in:
challhost     | npm ERR!     /home/stevej/.npm/_logs/2021-05-30T08_49_25_165Z-debug.log
challhost     | Unhandled exception in thread started by <function manipulador at 0x7f2ff1630150>
challhost     | Traceback (most recent call last):
challhost     |   File "server-cypress.py", line 123, in manipulador
challhost     |     cmd = readImg(pathPrincipal, barcodereaderPathCompleto)
challhost     |   File "server-cypress.py", line 27, in readImg
challhost     |     os.chdir(pathFinal)
challhost     | OSError: [Errno 2] No such file or directory: '/home/stevej/stuff/processing/172.19.0.1/cypress/screenshots/manda-file/actions.spec.js/'
```

</div></details>

Docker Desktop の Containers / Apps から`challhost`のCLIを開き、
メッセージの通りに`cypress install`コマンドを実行したところ、

```
/bin/sh: 1: cypress: not found
```

と出てきた。
仮想マシンの構築時のメッセージを参考に`npm install cypress`コマンドを実行してみても、
やはりApplesoft BASICのプログラムを送ると同様のエラーが出るし、`cypress`コマンドも見つからなかった。

<details><summary>`npm install cypress` 実行時に出力されたメッセージ</summary><div>

```
> cypress@7.4.0 postinstall /home/stevej/node_modules/cypress
> node index.js --exec install


Cypress 7.4.0 is installed in /home/stevej/.cache/Cypress/7.4.0

npm WARN saveError ENOENT: no such file or directory, open '/home/stevej/package.json'
npm WARN notsup Unsupported engine for cypress@7.4.0: wanted: {"node":">=12.0.0"} (current: {"node":"10.19.0","npm":"6.14.4"})
npm WARN notsup Not compatible with your version of node/npm: cypress@7.4.0
npm WARN enoent ENOENT: no such file or directory, open '/home/stevej/package.json'
npm WARN stevej No description
npm WARN stevej No repository field.
npm WARN stevej No README data
npm WARN stevej No license field.

+ cypress@7.4.0
updated 1 package and audited 352 packages in 4.518s

16 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities



   ╭────────────────────────────────────────────────────────────────╮
   │                                                                │
   │      New major version of npm available! 6.14.4 -> 7.15.0      │
   │   Changelog: https://github.com/npm/cli/releases/tag/v7.15.0   │
   │               Run npm install -g npm to update!                │
   │                                                                │
   ╰────────────────────────────────────────────────────────────────╯
```

</div></details>

ここで`cypress@7.4.0`と出てきたこと、およびエラーメッセージには`7.3.0`とあったことを参考に、
`npm install cypress@7.3.0`コマンドを実行した。
その結果。ローカルでもサーバーと同様にApplesoft BASICのプログラムの実行結果が得られるようになった。

### サーバープログラムの改造

Docker用の配布ファイルを展開した中にあった`files.tar.gz`の中に、
サーバープログラム`server-cypress.py`があった。
また、これは仮想マシン`challhost`内の`/home/stevej/stuff/server-cypress.py`に配置されていた。

ローカルでのテストがやりやすくなるよう、これに以下の改造を加えた。

まず、いちいちhashcashの情報を求められるのは邪魔なので、75行目からの以下の部分をコメントアウトした。

```py
		clientsock.send("Send the solution for \"hashcash -mb 25 " + randomstr + "\": ")
		solution = clientsock.recv(BUFF)
		
		if not check_pow(solution.strip(), randomstr):
			clientsock.send("\nInvalid PoW.\n")
			clientsock.close()
			return
```

さらに、プログラムの実行結果の画像を取り出せるよう、28行目の

```py
	os.system("mv \"Actions -- .type() - type into a DOM element.png\" qr.png")
```

の次に

```py
	os.system("cp qr.png /tmp/a.png")
```

を加えた。
仮想マシンでは`vi`も`vim`も`emacs`も`nano`も使えないようだったので、
仮想マシン外で編集し(このファイルを`server-cypress-mod.py`とする)、

```
docker cp server-cypress-mod.py (仮想マシンのID):/home/stevej/stuff/server-cypress.py
```

というコマンドで仮想マシンに入れた。
なお、ここで「仮想マシンのID」は`docker ps`コマンドで出力される`CONTAINER ID`である。

そして、生成された画像ファイルは

```
docker cp (仮想マシンのID):/tmp/a.png result.png
```

というコマンドで取り出すことができた。

参考：[Dockerでホストとコンテナ間でのファイルコピー - Qiita](https://qiita.com/gologo13/items/7e4e404af80377b48fd5)

### QRコードの作成

[Psytec QR Code Editor](http://www.psytec.co.jp/freesoft/01/)を用い、表示させるQRコードのパターンを作成した後、手動で打ち込んでテキストに変換した。
最初はモジュールサイズを1にして画像出力し、ペイントでグリッド線付きで表示しようとしたが、
なぜか表示がおかしくなってしまった。
(他の画像編集ソフトでは正しく表示されたので、QRコード作成ソフトではなくペイントの問題だろう)
以下の例は`ls`を表すQRコードである。

|ペイントの表示(100%)<br>([MegaZoom](https://www.vector.co.jp/soft/win95/util/se065542.html)で拡大)|ペイントの表示(400%)|正しいQRコード|
|---|---|---|
|![ペイントの表示(100%)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/f61e3803-15f2-7f32-0bdd-904f806776d6.png)|![ペイントの表示(400%)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/a1270d6b-b778-f9ea-cce0-b08c0cd406f9.png)|![正しいQRコード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/d2d57470-93fd-dec7-3525-c46395b6d3ac.png)|

そこで、ペイントを経由せず、作成ソフトに表示されるQRコードをそのまま見て打ち込むことにした。

<details><summary>打ち込み結果の例</summary><div>

```
#######...#.#.#######
#.....#.#.#.#.#.....#
#.###.#.#.##..#.###.#
#.###.#.....#.#.###.#
#.###.#.#####.#.###.#
#.....#.###...#.....#
#######.#.#.#.#######
........#............
##.#..##..###.###.##.
#####...#..#.#.#.#..#
..#...#..#.#..####..#
...##..#..#.#####..##
.#..#.######.###..##.
........##...##.#.#.#
#######.#####.#.##.#.
#.....#..#....#...###
#.###.#..#..###...###
#.###.#.#.#..###...##
#.###.#...##.###.##.#
#.....#.#..##..#.#...
#######.###..#.#..##.
```

</div></details>

### Applesoft BASIC でのプログラミング

サーバにApplesoft BASICのプログラムを送ることで実行してくれるようだが、
結果が出るまで長時間かかる上、具体的な出力の情報はくれないので、開発には向かない。
「Applesoft BASIC」でググると、以下のインタプリタとリファレンスが見つかった。

* [Applesoft BASIC in JavaScript](https://www.calormen.com/jsbasic/)
* [Applesoft BASIC Reference](https://www.calormen.com/jsbasic/reference.html)

このインタプリタで試してみたところ、この環境での数値は浮動小数点数で、32ビットを超える精度があるようだった。
さらに、[IchigoJam](https://ichigojam.net/)が持っている

* 複数の文を`:`で繋げて1行に入れることができる
* 多くの空白を省略できる

という特徴をこの環境も持っていることがわかった。
このことを踏まえ、生成したQRコードのデータを数値として埋め込み、描画することにした。

<details><summary>QRコードのデータを数値に変換するプログラム</summary><div>

```convert.pl
#!/usr/bin/perl

use strict;
use warnings;

my $first = 1;
while (my $line = <STDIN>) {
	my $res = 0;
	chomp($line);
	my $l = length($line);
	for (my $i = 0; $i < $l; $i++) {
		my $c = substr($line, $l - 1 - $i, 1);
		if ($c eq ".") {
			$res *= 2;
		} elsif ($c eq "#") {
			$res = $res * 2 + 1;
		}
	}
	unless ($first) { print ","; }
	print $res;
	$first = 0;
}
print "\n";
```

</div></summary>

結果、Lo-Res Graphicsを用いた以下のプログラムを送信することで、`ls`を実行させることができた。
実験の結果、`COLOR`は0を代入すると黒に、15を代入すると白になるようだった。

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,2086015,1070401,1527133,1527901,1531741,1066817,2086271,256,908491,1222943,1296964,1701016,847826,1401600,745343,1851969,1864285,1631581,1502301,170305,829311,0
```

最初の行の背景用の色を初期化していないバグがあるが、認識してくれたのでヨシ。

実行結果として、`1337`が出力された。
ローカルテスト環境と照らし合わせた結果、これは`/home/stevej/stuff/secret`ディレクトリの中身のようで、
ここにある`1337/1338/1339/1337/1338/flag_here_a5605a97da7d0e714adf9ee8a355ca12.txt`の
内容を出力させればいいようだった。
これは、

```
cat */*/*/*/*/*
```

というコマンドで実現できるようだった。これは

![`cat */*/*/*/*/*`を表すQRコード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/c8a02a84-bc13-22a3-d587-bfeb645f62fc.png)

<details><summary>テキスト表現</summary><div>

```
#######.#####.#######
#.....#.#.#.#.#.....#
#.###.#.#.....#.###.#
#.###.#.####..#.###.#
#.###.#.....#.#.###.#
#.....#.##.#..#.....#
#######.#.#.#.#######
.........####........
##..###..#.#...#.####
.#####.##.#.#..#..##.
##.#..#.#..#..#....#.
.####....###.###...##
###..####.##..##.#.##
........##...#.#####.
#######......##..#.#.
#.....#.##..###..#.##
#.###.#.##.#..#.#..##
#.###.#...#..#.##.###
#.###.#...#..##.##...
#.....#.###.##.#.....
#######.#.#....#....#
```

</div></summary>

というQRコードで表現できる。
画像を表す数値データを差し替えたプログラム

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,2088831,1070401,1524061,1527645,1527901,1067841,2086271,7680,2001523,824766,543051,1633822,1756647,1024768,680063,1733441,1657693,1942621,222301,46913,1082751,0
```

を送ることで、flagを得ることができた。
なお、実際に送ったのは、改行を`§`に置き換えた

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT§2DATA0,2088831,1070401,1524061,1527645,1527901,1067841,2086271,7680,2001523,824766,543051,1633822,1756647,1024768,680063,1733441,1657693,1942621,222301,46913,1082751,0
```

である。

<details><summary>実行結果の画像</summary><div>

![ローカルで得られた実行結果の画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/debd3bd2-1f0e-005d-7c74-b688d9d50c56.png)

</div></details>


### flag

```
CTF-BR{Appl3's_II_b4s1c_1s_1nt3r3st1ng_a5_w3ll}
```

### おまけ

#### バグ修正版 (未初期化の色を使わない)

```
1GR:FORY=4TO26:READD:FORX=4TO26:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,4177662,2140802,3048122,3055290,3055802,2135682,4172542,15360,4003046,1649532,1086102,3267644,3513294,2049536,1360126,3466882,3315386,3885242,444602,93826,2165502,0
```

サーバーに送るため、改行を`§`に置き換えるとこうなる。

```
1GR:FORY=4TO26:READD:FORX=4TO26:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT§2DATA0,4177662,2140802,3048122,3055290,3055802,2135682,4172542,15360,4003046,1649532,1086102,3267644,3513294,2049536,1360126,3466882,3315386,3885242,444602,93826,2165502,0
```

#### IchigoJam 1.4版

```
1CLV:LET[8],8063,127,5441,65,349,93,3933,93,4189,93,2881,65,5503,127,7680,0,2675,122,5566,50,2379,33,11806,99,3559,107,8960,62,8319,41,13121,105,2909,101,9309,118,9309,13,14145,2,1407,66
2FORY=0TO28:DRAW8,Y,37,Y:FORX=0TO20:DRAWX+12,Y,1-[Y*2+X/14]>>(X%14)&1:NEXT:NEXT
```

[IchigoJam web で実行する](https://fukuno.jig.jp/app/IchigoJam/#1CLV%3ALET%5B8%5D%2C8063%2C127%2C5441%2C65%2C349%2C93%2C3933%2C93%2C4189%2C93%2C2881%2C65%2C5503%2C127%2C7680%2C0%2C2675%2C122%2C5566%2C50%2C2379%2C33%2C11806%2C99%2C3559%2C107%2C8960%2C62%2C8319%2C41%2C13121%2C105%2C2909%2C101%2C9309%2C118%2C9309%2C13%2C14145%2C2%2C1407%2C66%0A2FORY%3D0TO28%3ADRAW8%2CY%2C37%2CY%3AFORX%3D0TO20%3ADRAWX%2B12%2CY%2C1-%5BY%2A2%2BX%2F14%5D%3E%3E%28X%2514%29%261%3ANEXT%3ANEXT%0ARUN%0A)

[IchigoJam](https://ichigojam.net/)で扱う数値は16ビットの整数であり、
QRコードの無圧縮での表現に必要な21ビットには足りないので、1行を2個の数値で表現した。

<details><summary>IchigoJam 1.4版用の変換プログラム</summary><div>

```convert-extra.pl
#!/usr/bin/perl

use strict;
use warnings;

my $first = 1;
while (my $line = <STDIN>) {
	my $res = 0;
	chomp($line);
	my $l = length($line);
	for (my $i = 0; $i < $l; $i++) {
		my $c = substr($line, $l - 1 - $i, 1);
		if ($c eq ".") {
			$res *= 2;
		} elsif ($c eq "#") {
			$res = $res * 2 + 1;
		}
	}
	unless ($first) { print ","; }
	printf("%d,%d", $res & ((1 << 14) - 1), $res >> 14);
	$first = 0;
}
print "\n";
```

</div></summary>

### 商標について

* 「QRコード」は(株)デンソーウェーブの登録商標です。
* 「IchigoJam」はjig.jpの登録商標です。

# About

I participated in [Pwn2Win CTF 2021](https://pwn2win.party/) (2021/05/29 01:37 ～ 2021/05/31 01:37 JST (UTC+9)) as a solo team.
I got 405 points, ranked 55th among the 720 teams that earned positive score.

![got first blood](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/715d8a43-cc55-c92d-391e-97d51251b95a.png)

It seems I got first blood.

# Challenges I solved

|Challenge|Score|Solved time (JST : UTC+9)|
|---|---|---|
|~Rhiza - founded on the human being|50|2021/05/29 05:29:26|
|Oldschool Adventures - Apple II|355|2021/05/29 08:02:16|

## ~Rhiza - founded on the human being

A long sentence was given as the challenge description, and the flag was on the last line.

This challenge looked like Geeky Fun Fact ([The 2013 ACM-ICPC Asia Danang Regional Contest](https://icpc.global/regionals/finder/Asia-Danang-2013)) because there were much sentence not directly related to the solution and we only had to look at the last part to solve.

```
CTF-BR{join_Lauras_fight_against_opression_and_discover_the_truth!}
```

## Oldschool Adventures - Apple II

### Information from the challenge description

An Apple II emulator that can run Applesoft BASIC programs is provided.
If the program generates a QR Code after being run, it executes what is read from that as a Linux shell command.

The program to run is required to satisfy following conditions:

* The length is at most 268 chars (looks like 268 bytes, according to the server source code)
* Sent in a single line
* Newline characters in the program is written as `§`, and it can appear at most once
* Take at most 50 seconds to generate a QR Code

Information to connect to a TCP server, and files for Docker and LXC Container for testing locally were provided.
There also were some commands to start the local-testing environment for Docker and LXC Container.

### Observation of the server

Connecting the specified server with [Tera Term](https://ttssh2.osdn.jp/index.html.en), it sent a string like

```
Send the solution for "hashcash -mb 25 xyttzzozyb":
```

I googled "hashcash"and found [Hashcash.org](http://www.hashcash.org/).
I firstly clicked the "binaries" from the menu in the left of the page.
Then I chose the platform to run on and the type of software (windows &gt; console, for example) in the menu.
Finally I downloaded what looked like latest executable (`hashcash-1.22-win32-exe.zip`) from the list of files.

I found `hashcash.exe` from files extracted from the downloaded archive.
Using this file, I executed the string sent from server

```
hashcash -mb 25 xyttzzozyb
```

as a command. After a few seconds, I got some output like this:

```
hashcash stamp: 1:25:210530:xyttzzozyb::EKSU6xxV8EuRwams:0000002k/iI
```

By copy-and-pasting the `1:25:210530:xyttzzozyb::EKSU6xxV8EuRwams:0000002k/iI` part of the output to the server, I succeeded to proceed to the next step.

In the next step, the server sent me this string:

```
Send your payload here:
```

The server will run the Applesoft BASIC programs sent after this,
but it timed out only after a few seconds and a quick operation was required.
Also, when I pressed Enter after pasting the Hashcash output, the server took the Enter (newline) as the program to run.
Therefore, I should wait for next message from the server without Pressing Enter key after pasting.

Sending only a newline character as a trial, the server gave me this after a while:

```
Not a valid QR!
```

and the connection was closed.

Also, when I sent `§§§§§` encoded in UTF-8, the server responded:

```
Just 1 line break (§) is allowed!
```

This fact suggests that the program should be sent in UTF-8.
The `§` symbol takes 2 bytes (`C2 A7`) in UTF-8.

### Building a local-testing environment with Docker

In this challenge, data for Docker and LXC Container was provided.
I don't know about LXC Container, but I recently installed Docker, so I decided to use Docker for building the local-testing environment.

The challenge description said:

```
$ docker-compose up
$ nc localhost 1337
```

Also files for Docker were given in `tar.gz` archive.
In most of other challenges in this CTF, the compressed tar files had an easy-to-handle name `attachments.tar`, but they contained `@PaxHeader` file and they caused many collisions in file names when extracted via [7-Zip](https://www.7-zip.org/).
On the other hand, the compressed tar file had a very long name, but it contained no `@PaxHeader` files.

I put the contents of the tar file in some directory and executed `docker-compose up` command.
It resulted in error.

<details><summary>The error message</summary><div>

```
Traceback (most recent call last):
  File "docker\api\client.py", line 214, in _retrieve_server_version
  File "docker\api\daemon.py", line 181, in version
  File "docker\utils\decorators.py", line 46, in inner
  File "docker\api\client.py", line 237, in _get
  File "requests\sessions.py", line 543, in get
  File "requests\sessions.py", line 530, in request
  File "requests\sessions.py", line 643, in send
  File "requests\adapters.py", line 439, in send
  File "urllib3\connectionpool.py", line 670, in urlopen
  File "urllib3\connectionpool.py", line 392, in _make_request
  File "http\client.py", line 1255, in request
  File "http\client.py", line 1301, in _send_request
  File "http\client.py", line 1250, in endheaders
  File "http\client.py", line 1010, in _send_output
  File "http\client.py", line 950, in send
  File "docker\transport\npipeconn.py", line 32, in connect
  File "docker\transport\npipesocket.py", line 23, in wrapped
  File "docker\transport\npipesocket.py", line 72, in connect
  File "docker\transport\npipesocket.py", line 52, in connect
pywintypes.error: (2, 'CreateFile', 'The system cannot find the file specified.')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose\cli\main.py", line 81, in main
  File "compose\cli\main.py", line 199, in perform_command
  File "compose\cli\command.py", line 60, in project_from_options
  File "compose\cli\command.py", line 152, in get_project
  File "compose\cli\docker_client.py", line 41, in get_client
  File "compose\cli\docker_client.py", line 170, in docker_client
  File "docker\api\client.py", line 197, in __init__
  File "docker\api\client.py", line 221, in _retrieve_server_version
docker.errors.DockerException: Error while fetching server API version: (2, 'CreateFile', 'The system cannot find the file specified.')
[11476] Failed to execute script docker-compose
```

</div></details>

I resolved this error by executing the `docker-compose up` command after launching Docker Desktop.

Executing this command, it created two virtual machines: `apachehost` and `challhost`.
`apachehost` took only a few tens of seconds, but `challhost` took long time (over 15 minuts) to be built.
After completing building them, the command didn't exit and it started to emit some logs about the virtual machines.

After that, I connected to `localhost:1337` via Tera Team, and sent data from Hashcash and an Applesoft BASIC program like I did for the remote server.
As a result, the `docker-compose up` command emitted some message that is suggesting that Cypress is not installed, and the TCP connection was left connected.

<details><summary>The message given</summary><div>

```
challhost     | > tira-screenshot@1.0.0 cypress:run /home/stevej/stuff/processing/172.19.0.1
challhost     | > cypress run --spec 'cypress/integration/manda-file/actions.spec.js'
challhost     |
challhost     | No version of Cypress is installed in: /home/stevej/.cache/Cypress/7.3.0/Cypress
challhost     |
challhost     | Please reinstall Cypress by running: cypress install
challhost     |
challhost     | ----------
challhost     |
challhost     | Cypress executable not found at: /home/stevej/.cache/Cypress/7.3.0/Cypress/Cypress
challhost     |
challhost     | ----------
challhost     |
challhost     | Platform: linux (Ubuntu - 20.04)
challhost     | Cypress Version: 7.3.0
challhost     | npm ERR! code ELIFECYCLE
challhost     | npm ERR! errno 1
challhost     | npm ERR! tira-screenshot@1.0.0 cypress:run: `cypress run --spec 'cypress/integration/manda-file/actions.spec.js'`
challhost     | npm ERR! Exit status 1
challhost     | npm ERR!
challhost     | npm ERR! Failed at the tira-screenshot@1.0.0 cypress:run script.
challhost     | npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
challhost     |
challhost     | npm ERR! A complete log of this run can be found in:
challhost     | npm ERR!     /home/stevej/.npm/_logs/2021-05-30T08_49_25_165Z-debug.log
challhost     | Unhandled exception in thread started by <function manipulador at 0x7f2ff1630150>
challhost     | Traceback (most recent call last):
challhost     |   File "server-cypress.py", line 123, in manipulador
challhost     |     cmd = readImg(pathPrincipal, barcodereaderPathCompleto)
challhost     |   File "server-cypress.py", line 27, in readImg
challhost     |     os.chdir(pathFinal)
challhost     | OSError: [Errno 2] No such file or directory: '/home/stevej/stuff/processing/172.19.0.1/cypress/screenshots/manda-file/actions.spec.js/'
```

</div></details>

I opened the CLI for `challhost` from Containers / Apps on Docker Desktop, and executed `cypress install` command as the message told.
It resulted in getting a message:

```
/bin/sh: 1: cypress: not found
```

After executing `npm install cypress` command inspired from the massage given while building the virtual machine, the error after sending Applesoft BASIC program persisted and `cypress` command was not found.

<details><summary>The message given in the execution of `npm install cypress` command</summary><div>

```
> cypress@7.4.0 postinstall /home/stevej/node_modules/cypress
> node index.js --exec install


Cypress 7.4.0 is installed in /home/stevej/.cache/Cypress/7.4.0

npm WARN saveError ENOENT: no such file or directory, open '/home/stevej/package.json'
npm WARN notsup Unsupported engine for cypress@7.4.0: wanted: {"node":">=12.0.0"} (current: {"node":"10.19.0","npm":"6.14.4"})
npm WARN notsup Not compatible with your version of node/npm: cypress@7.4.0
npm WARN enoent ENOENT: no such file or directory, open '/home/stevej/package.json'
npm WARN stevej No description
npm WARN stevej No repository field.
npm WARN stevej No README data
npm WARN stevej No license field.

+ cypress@7.4.0
updated 1 package and audited 352 packages in 4.518s

16 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities



   ╭────────────────────────────────────────────────────────────────╮
   │                                                                │
   │      New major version of npm available! 6.14.4 -> 7.15.0      │
   │   Changelog: https://github.com/npm/cli/releases/tag/v7.15.0   │
   │               Run npm install -g npm to update!                │
   │                                                                │
   ╰────────────────────────────────────────────────────────────────╯
```

</div></details>

Here I saw a phrase `cypress@7.4.0`. Also the error message contained `7.3.0`.
Using this as a hint, I executed `npm install cypress@7.3.0` command.
This let me get the results of execution of Applesoft BASIC program like what I get from the remove server from the local environment.

### Modification of the server program

I found the server program `server-cypress.py` in the file `files.tar.gz`, which was in the files for Docker.
I also found that this is placed at `/home/stevej/stuff/server-cypress.py` in the virtual machine `challhost`.

I made following modifications to this to make local-testing easier.

Firstly, I commented out the following part from the 75th line because it was annoying to be asked for information from Hashcash while testing locally.

```py
		clientsock.send("Send the solution for \"hashcash -mb 25 " + randomstr + "\": ")
		solution = clientsock.recv(BUFF)
		
		if not check_pow(solution.strip(), randomstr):
			clientsock.send("\nInvalid PoW.\n")
			clientsock.close()
			return
```

Then, to obtain the images produced by running Applesoft BASIC programs, I added

```py
	os.system("cp qr.png /tmp/a.png")
```

after the 28th line

```py
	os.system("mv \"Actions -- .type() - type into a DOM element.png\" qr.png")
```

I found that none of `vi`, `vim`, `emacs`, nor `nano` were available in the virtual machine, so I edited the file outside the virtual machine, named the modified version `server-cypress-mod.py`, and used the command

```
docker cp server-cypress-mod.py (the virtual machine ID):/home/stevej/stuff/server-cypress.py
```

to put the edited file into the virtual machine.
We can obtain "the virtual machine ID" as the `CONTAINER ID` printed from `docker ps` command.

Also I could take the image files generated out by the command:

```
docker cp (the virtual machine ID):/tmp/a.png result.png
```

### Generating QR Code

I used [Psytec QR Code Editor](http://www.psytec.co.jp/freesoft/01/) (Japanese page and software) to generate QR Code patterns and converted the pattern into texts by manually entering the pattern.
To do this, I saved a QR Code image with the module size set to 1 and viewed that via Microsoft Paint with the grid lines, but the display was broken for some reason.
(This looked like an error in Microsoft Paint, not in the QR Code generator, because some other image-editing software succeeded to display the image correctly.)

The QR Code standing for `ls` is shown below as an example:

|Display in Microsoft Paint (100%)<br>(enlarged via MegaZoom)|Display in Microsoft Paint (400%)|True QR Code|
|---|---|---|
|![Display in Microsoft Paint (100%)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/f61e3803-15f2-7f32-0bdd-904f806776d6.png)|![Display in Microsoft Paint (400%)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/a1270d6b-b778-f9ea-cce0-b08c0cd406f9.png)|![True QR Code](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/d2d57470-93fd-dec7-3525-c46395b6d3ac.png)|

Seeing this, I decided not to use Microsoft Paint and to enter the pattern seeing the QR Code displayed on the generator.

<details><summary>An example of the pattern entered</summary><div>

```
#######...#.#.#######
#.....#.#.#.#.#.....#
#.###.#.#.##..#.###.#
#.###.#.....#.#.###.#
#.###.#.#####.#.###.#
#.....#.###...#.....#
#######.#.#.#.#######
........#............
##.#..##..###.###.##.
#####...#..#.#.#.#..#
..#...#..#.#..####..#
...##..#..#.#####..##
.#..#.######.###..##.
........##...##.#.#.#
#######.#####.#.##.#.
#.....#..#....#...###
#.###.#..#..###...###
#.###.#.#.#..###...##
#.###.#...##.###.##.#
#.....#.#..##..#.#...
#######.###..#.#..##.
```

</div></details>

### Programming in Applesoft BASIC

The server runs Applesoft BASIC programs after sending them, but it didn't looked useful for development because it takes a while before producing the result and it doesn't give me the actual output of my programs.

I googled "Applesoft BASIC", finding an interpreter and a reference:

* [Applesoft BASIC in JavaScript](https://www.calormen.com/jsbasic/)
* [Applesoft BASIC Reference](https://www.calormen.com/jsbasic/reference.html)

After doing some tests with this interpreter, I found that numbers in this environment are floating-point numbers and their precision is more than 32 bits.

Moreover, I found that the environment also has following characteristics that [IchigoJam](https://ichigojam.net/index-en.html) has:

* We can put multiple statements in one line, concatenating them with `:`
* Most white-space characters can be omitted

Based on these findings, I decided to embed the QR Code image generated as numbers and draw the image from them.

<details><summary>The program to convert QR Code patterns into numbers</summary><div>

```convert.pl
#!/usr/bin/perl

use strict;
use warnings;

my $first = 1;
while (my $line = <STDIN>) {
	my $res = 0;
	chomp($line);
	my $l = length($line);
	for (my $i = 0; $i < $l; $i++) {
		my $c = substr($line, $l - 1 - $i, 1);
		if ($c eq ".") {
			$res *= 2;
		} elsif ($c eq "#") {
			$res = $res * 2 + 1;
		}
	}
	unless ($first) { print ","; }
	print $res;
	$first = 0;
}
print "\n";
```

</div></summary>

As a result, I succeeded to have the server execute `ls` command via the following program using Lo-Res Graphics:

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,2086015,1070401,1527133,1527901,1531741,1066817,2086271,256,908491,1222943,1296964,1701016,847826,1401600,745343,1851969,1864285,1631581,1502301,170305,829311,0
```

I found that `0` in `COLOR` means black and `15` in `COLOR` means white with some experiments.

This program contains a bug that the color for the background of the first line is not initialized, but fortunately the server kindly recognized the image.

The server gave me `1337` as the result.

Comparing with the local testing environment, this looked like the contents of the `/home/stevej/stuff/secret` directory and the goal looked like having the server print the contents of 
`1337/1338/1339/1337/1338/flag_here_a5605a97da7d0e714adf9ee8a355ca12.txt`.
This goal could be achieved by a command:

```
cat */*/*/*/*/*
```

A QR Code for this command is:

![A QR Code for `cat */*/*/*/*/*`](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/c8a02a84-bc13-22a3-d587-bfeb645f62fc.png)

<details><summary>Pattern expressed as text</summary><div>

```
#######.#####.#######
#.....#.#.#.#.#.....#
#.###.#.#.....#.###.#
#.###.#.####..#.###.#
#.###.#.....#.#.###.#
#.....#.##.#..#.....#
#######.#.#.#.#######
.........####........
##..###..#.#...#.####
.#####.##.#.#..#..##.
##.#..#.#..#..#....#.
.####....###.###...##
###..####.##..##.#.##
........##...#.#####.
#######......##..#.#.
#.....#.##..###..#.##
#.###.#.##.#..#.#..##
#.###.#...#..#.##.###
#.###.#...#..##.##...
#.....#.###.##.#.....
#######.#.#....#....#
```

</div></summary>

I succeeded to get the flag by sending this program with the numerical data replaced:

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,2088831,1070401,1524061,1527645,1527901,1067841,2086271,7680,2001523,824766,543051,1633822,1756647,1024768,680063,1733441,1657693,1942621,222301,46913,1082751,0
```

To clarify, I actually sent this (with the newline character replaced with `§` symbol):

```
1GR:FORY=0TO22:READD:HLIN0,39ATY:FORX=4TO25:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT§2DATA0,2088831,1070401,1524061,1527645,1527901,1067841,2086271,7680,2001523,824766,543051,1633822,1756647,1024768,680063,1733441,1657693,1942621,222301,46913,1082751,0
```

<details><summary>The outcome of this program</summary><div>

![The outcome of this program obtained in the local environment](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/debd3bd2-1f0e-005d-7c74-b688d9d50c56.png)

</div></details>

### The flag

```
CTF-BR{Appl3's_II_b4s1c_1s_1nt3r3st1ng_a5_w3ll}
```

### Extra

#### Bug-fixed version (don't draw without setting color)

```
1GR:FORY=4TO26:READD:FORX=4TO26:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT
2DATA0,4177662,2140802,3048122,3055290,3055802,2135682,4172542,15360,4003046,1649532,1086102,3267644,3513294,2049536,1360126,3466882,3315386,3885242,444602,93826,2165502,0
```

This is for sending to the server (with the newline character replaced with `§`):

```
1GR:FORY=4TO26:READD:FORX=4TO26:E=INT(D/2):COLOR=(1-D+E*2)*15:PLOTX,Y:D=E:NEXT:NEXT§2DATA0,4177662,2140802,3048122,3055290,3055802,2135682,4172542,15360,4003046,1649532,1086102,3267644,3513294,2049536,1360126,3466882,3315386,3885242,444602,93826,2165502,0
```

#### IchigoJam 1.4 version

```
1CLV:LET[8],8063,127,5441,65,349,93,3933,93,4189,93,2881,65,5503,127,7680,0,2675,122,5566,50,2379,33,11806,99,3559,107,8960,62,8319,41,13121,105,2909,101,9309,118,9309,13,14145,2,1407,66
2FORY=0TO28:DRAW8,Y,37,Y:FORX=0TO20:DRAWX+12,Y,1-[Y*2+X/14]>>(X%14)&1:NEXT:NEXT
```

[Execute on IchigoJam web](https://fukuno.jig.jp/app/IchigoJam/#1CLV%3ALET%5B8%5D%2C8063%2C127%2C5441%2C65%2C349%2C93%2C3933%2C93%2C4189%2C93%2C2881%2C65%2C5503%2C127%2C7680%2C0%2C2675%2C122%2C5566%2C50%2C2379%2C33%2C11806%2C99%2C3559%2C107%2C8960%2C62%2C8319%2C41%2C13121%2C105%2C2909%2C101%2C9309%2C118%2C9309%2C13%2C14145%2C2%2C1407%2C66%0A2FORY%3D0TO28%3ADRAW8%2CY%2C37%2CY%3AFORX%3D0TO20%3ADRAWX%2B12%2CY%2C1-%5BY%2A2%2BX%2F14%5D%3E%3E%28X%2514%29%261%3ANEXT%3ANEXT%0ARUN%0A)

The numbers on [IchigoJam](https://ichigojam.net/index-en.html) are 16-bit integers and it is less than 21 bits for expressing QR Code rows without compression, so one row is expressed in two integers in this version.

<details><summary>Puttern-to-number conversion program for IchigoJam 1.4 version</summary><div>

```convert-extra.pl
#!/usr/bin/perl

use strict;
use warnings;

my $first = 1;
while (my $line = <STDIN>) {
	my $res = 0;
	chomp($line);
	my $l = length($line);
	for (my $i = 0; $i < $l; $i++) {
		my $c = substr($line, $l - 1 - $i, 1);
		if ($c eq ".") {
			$res *= 2;
		} elsif ($c eq "#") {
			$res = $res * 2 + 1;
		}
	}
	unless ($first) { print ","; }
	printf("%d,%d", $res & ((1 << 14) - 1), $res >> 14);
	$first = 0;
}
print "\n";
```

</div></summary>

### Trademark notice

* "QR Code" is a registered trademark of DENSO WAVE INCORPORATED.
* "IchigoJam" is a registered trademark of jig.jp.