English version is in the latter half of this page.
概要
Pwn2Win CTF 2021 (2021/05/29 01:37 ~ 2021/05/31 01:37 JST) に1人チームで参加した。
結果は405点で、正の点数を取った720チーム中55位だった。
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) を思い出すなあ。
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で接続すると、
Send the solution for "hashcash -mb 25 xyttzzozyb":
のような文字列が送られてきた。このhashcashとやらでググったところ、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は最近インストールしたので、Dockerで環境を構築することにした。
問題文には、
$ docker-compose up
$ nc localhost 1337
とあった。また、Docker用のファイルがtar.gz
形式で与えられた。
他の多くの問題では圧縮されたtarファイルはattachments.tar
という扱いやすいファイル名であったかわりに、
@PaxHeader
という謎のデータが含まれ、7-Zipで展開するとファイル名の衝突が何度も起こることがあった。
一方、この問題のファイルは、tarファイルの名前がやたら長かった一方、@PaxHeader
は含まれていなかった。
tarファイルの中身を適当なディレクトリに入れ、
そこでdocker-compose up
コマンドを実行すると、エラーになった。
エラーメッセージ
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
Docker Desktop を起動してからdocker-compose up
コマンドを実行することで、エラーは解消した。
このコマンドを実行することで、apachehost
とchallhost
の2台の仮想マシンが作られるようであった。
apachehost
の構築は数十秒程度で終わったが、challhost
の構築は長時間(15分以上)かかった。
構築が終わってもコマンドの実行は終わらず、そのまま仮想マシンのログらしきものが出力され始めた。
Tera Termでlocalhost:1337
に接続し、同様にhashcash
の実行結果の一部とApplesoft BASICのプログラムを送ると、
ここにCypressがインストールされていないというようなメッセージが出力され、
プログラムの実行結果は出力されずにTCPが繋がったままになった。
出力されたメッセージ
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/'
Docker Desktop の Containers / Apps からchallhost
のCLIを開き、
メッセージの通りにcypress install
コマンドを実行したところ、
/bin/sh: 1: cypress: not found
と出てきた。
仮想マシンの構築時のメッセージを参考にnpm install cypress
コマンドを実行してみても、
やはりApplesoft BASICのプログラムを送ると同様のエラーが出るし、cypress
コマンドも見つからなかった。
`npm install cypress` 実行時に出力されたメッセージ
> 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! │
│ │
╰────────────────────────────────────────────────────────────────╯
ここで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行目からの以下の部分をコメントアウトした。
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行目の
os.system("mv \"Actions -- .type() - type into a DOM element.png\" qr.png")
の次に
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
QRコードの作成
Psytec QR Code Editorを用い、表示させるQRコードのパターンを作成した後、手動で打ち込んでテキストに変換した。
最初はモジュールサイズを1にして画像出力し、ペイントでグリッド線付きで表示しようとしたが、
なぜか表示がおかしくなってしまった。
(他の画像編集ソフトでは正しく表示されたので、QRコード作成ソフトではなくペイントの問題だろう)
以下の例はls
を表すQRコードである。
ペイントの表示(100%) (MegaZoomで拡大) |
ペイントの表示(400%) | 正しいQRコード |
---|---|---|
そこで、ペイントを経由せず、作成ソフトに表示されるQRコードをそのまま見て打ち込むことにした。
打ち込み結果の例
#######...#.#.#######
#.....#.#.#.#.#.....#
#.###.#.#.##..#.###.#
#.###.#.....#.#.###.#
#.###.#.#####.#.###.#
#.....#.###...#.....#
#######.#.#.#.#######
........#............
##.#..##..###.###.##.
#####...#..#.#.#.#..#
..#...#..#.#..####..#
...##..#..#.#####..##
.#..#.######.###..##.
........##...##.#.#.#
#######.#####.#.##.#.
#.....#..#....#...###
#.###.#..#..###...###
#.###.#.#.#..###...##
#.###.#...##.###.##.#
#.....#.#..##..#.#...
#######.###..#.#..##.
Applesoft BASIC でのプログラミング
サーバにApplesoft BASICのプログラムを送ることで実行してくれるようだが、
結果が出るまで長時間かかる上、具体的な出力の情報はくれないので、開発には向かない。
「Applesoft BASIC」でググると、以下のインタプリタとリファレンスが見つかった。
このインタプリタで試してみたところ、この環境での数値は浮動小数点数で、32ビットを超える精度があるようだった。
さらに、IchigoJamが持っている
- 複数の文を
:
で繋げて1行に入れることができる - 多くの空白を省略できる
という特徴をこの環境も持っていることがわかった。
このことを踏まえ、生成したQRコードのデータを数値として埋め込み、描画することにした。
QRコードのデータを数値に変換するプログラム
#!/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";
結果、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 */*/*/*/*/*
というコマンドで実現できるようだった。これは
テキスト表現
#######.#####.#######
#.....#.#.#.#.#.....#
#.###.#.#.....#.###.#
#.###.#.####..#.###.#
#.###.#.....#.#.###.#
#.....#.##.#..#.....#
#######.#.#.#.#######
.........####........
##..###..#.#...#.####
.#####.##.#.#..#..##.
##.#..#.#..#..#....#.
.####....###.###...##
###..####.##..##.#.##
........##...#.#####.
#######......##..#.#.
#.....#.##..###..#.##
#.###.#.##.#..#.#..##
#.###.#...#..#.##.###
#.###.#...#..##.##...
#.....#.###.##.#.....
#######.#.#....#....#
という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
である。
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で扱う数値は16ビットの整数であり、
QRコードの無圧縮での表現に必要な21ビットには足りないので、1行を2個の数値で表現した。
IchigoJam 1.4版用の変換プログラム
#!/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";
商標について
- 「QRコード」は(株)デンソーウェーブの登録商標です。
- 「IchigoJam」はjig.jpの登録商標です。
About
I participated in Pwn2Win CTF 2021 (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.
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) 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, it sent a string like
Send the solution for "hashcash -mb 25 xyttzzozyb":
I googled "hashcash"and found 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 > 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.
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.
The error message
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
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.
The message given
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/'
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.
The message given in the execution of `npm install cypress` command
> 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! │
│ │
╰────────────────────────────────────────────────────────────────╯
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.
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
os.system("cp qr.png /tmp/a.png")
after the 28th line
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 (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%) (enlarged via MegaZoom) |
Display in Microsoft Paint (400%) | True QR Code |
---|---|---|
Seeing this, I decided not to use Microsoft Paint and to enter the pattern seeing the QR Code displayed on the generator.
An example of the pattern entered
#######...#.#.#######
#.....#.#.#.#.#.....#
#.###.#.#.##..#.###.#
#.###.#.....#.#.###.#
#.###.#.#####.#.###.#
#.....#.###...#.....#
#######.#.#.#.#######
........#............
##.#..##..###.###.##.
#####...#..#.#.#.#..#
..#...#..#.#..####..#
...##..#..#.#####..##
.#..#.######.###..##.
........##...##.#.#.#
#######.#####.#.##.#.
#.....#..#....#...###
#.###.#..#..###...###
#.###.#.#.#..###...##
#.###.#...##.###.##.#
#.....#.#..##..#.#...
#######.###..#.#..##.
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:
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 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.
The program to convert QR Code patterns into numbers
#!/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";
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:
Pattern expressed as text
#######.#####.#######
#.....#.#.#.#.#.....#
#.###.#.#.....#.###.#
#.###.#.####..#.###.#
#.###.#.....#.#.###.#
#.....#.##.#..#.....#
#######.#.#.#.#######
.........####........
##..###..#.#...#.####
.#####.##.#.#..#..##.
##.#..#.#..#..#....#.
.####....###.###...##
###..####.##..##.#.##
........##...#.#####.
#######......##..#.#.
#.....#.##..###..#.##
#.###.#.##.#..#.#..##
#.###.#...#..#.##.###
#.###.#...#..##.##...
#.....#.###.##.#.....
#######.#.#....#....#
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
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
The numbers on IchigoJam 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.
Puttern-to-number conversion program for IchigoJam 1.4 version
#!/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";
Trademark notice
- "QR Code" is a registered trademark of DENSO WAVE INCORPORATED.
- "IchigoJam" is a registered trademark of jig.jp.