君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

マルウェアとは何か〜WordPressに設置されていたマルウェアを解析してみた結果、恐ろしいソフトがでてきた〜

結論

WordPressのドキュメントルート上に、

wp-includes/wp-pages.lib.php

https://www.japan-secure.com/entry/how-to-perform-wordpress-security-measures.html

がもし設置されていたら、それはマルウェアなので

直ぐに削除すること。

※ 抜本的な対策ではないので、以下の対策も実行しましょう。

www.japan-secure.com

マルウェアとは

概要

マルウェアとは|マルウェアの脅威とその対策

マルウェア(Malware)とは、不正かつ有害な動作を行う意図で作成された悪意のあるソフトウェアや悪質なコードの総称です。

感染者

  • 利用者のPC

  • webサーバ

今回はwebサーバが被害にあった。

どんな攻撃をされるか

  • 情報漏えい

  • サイト改ざん

  • 不正な機能実行

  • 他サイトへの攻撃

基本的に、OSコマンド・インジェクション攻撃と同じです。

※ 徳丸本より

今回解析して出てきたソフトの概要

f:id:karoten512:20171126164158p:plain

※ 安全のため、ローカル上での実行&不完全な実行をしております

マルウェアを解析してみた結果、中身はこんなソフトだった。

画面を見てみると、このような機能があることがわかった。

基本データの収集

f:id:karoten512:20171126164436p:plain

ファイル操作

f:id:karoten512:20171126164810p:plain

f:id:karoten512:20171126164929p:plain

このファイルにアクセスしさえすれば、すきなphpファイルをuploadできるようなので、

実質サーバに対してはなんでもできる。

恐ろしい。

いきさつ

友人のwordpressサイトが攻撃され、サイトが全く見れなくなった。

マルウェアと思わしき怪しいファイルがあったので解析してみた。

解析

ファイルのパーミッションを確認

wp-includes/wp-pages.lib.php

他のphpファイルのパーミッションは644だが、

このファイルだけ755。怪しさ満点。

中身を見てみる

f:id:karoten512:20171126163330p:plain

怪しさ満点の難読文字列。

f:id:karoten512:20171126163340p:plain

base64_decodeとeval。

PHP: base64_decode - Manual

PHP: eval - Manual

まず、base64コードで普通は書かない。

この時点で「内容を知られたくないから難読化」していることがわかる。

そして、evalはとても危険。

evalに渡された文字列はphpとして実行されてしまうからだ。

どんな文字列も渡すことができるので、

実質phpでできることならなんだって出来てしまう。

evalをechoに変えて出力

f:id:karoten512:20171126163629p:plain

またbase64_decodeがでてきた。どうやら何重にもbase64_encodeをしているようだ。

この作業をひたすら繰り返していく。5〜6回繰り返した気がする。

php関数もencodeされていた

f:id:karoten512:20171126163843p:plain

どんどん解析してくと、普段使っているphp関数がbase64_encodeされていた。

ものすごい執念を感じる。

http://manual.xwd.jp/function.gzinflate.html

こちらの関数はdeflate圧縮されたものを解答する関数。

なんらかのソフトウェアっぽい雰囲気が出てきた。

phpコードがでてきた

更に解析をすすめると、phpコードがでてきた。

f:id:karoten512:20171126165716p:plain

変数名にランダムなアルファベットを使用していたので、わかりやすくかえた。

PHPリファレンス(ord())

冒頭のランダム文字列を1文字ずつ読み込んで、ASCII文字コードに変換している。

PHP関数 - ASCIIコードを特定の文字に変換 - chr() - PHP入門 - Webkaru

さらにそれを文字に変換している。

さらにphpコードがでてきた

f:id:karoten512:20171126170130p:plain

f:id:karoten512:20171126170141p:plain

また大量の文字列がでてきた。

これをまたechoすると、また大量の文字列。

f:id:karoten512:20171126171528p:plain

ここでgzinflateがでてきたので、おそらく後ろのbase64_decodeが本体ファイルと思われる。

ここまで難読化されていると、マルウェアであることは確実と思われる。

ただ、結局このままではどのようなマルウェアがわからないので、

安全な状況を確保してから解凍することにした。

安全な状況を(出来る限り)確保してから解凍する

最悪な状況にそなえ、

普段使わない(そして壊れてもいい)windows + dockerにて、php実行環境を構築し、

スタンドアローンで実行。

※ 良い子は真似しちゃダメ

冒頭のソフトが現れた。

まとめ

マルウェアはすごく難読化されている。

phpで出来ているものの場合、evalやbase64_decode + 意味不明な文字列

が含まれていると怪しい。

マルウェア対策については、別の記事に書こうと思います。

追記

FilesMan? 運営サイトがハッキングされバックドアがサーバーに設置される! ( Twitter ) - 無題な濃いログ - Yahoo!ブログ

有名なバックドアだということが判明。

オーキド「こういうものには つかいどきがあるのじゃ」〜Rubyよりもシェルのほうが良いときもある。プログラミング技術は要件に応じて使い分けよう〜

上司からの司令

上司「data.txtファイル中の、この数字を昇順にしてくれ。なるはやで」

1
45
31
2

上司が欲しい出力結果はこんな感じ。

1
2
31
45

Rubyを使用した場合

elements = []

File.open('data.txt') do |file|
  file.each_line do |row|
    elements << row.chomp.to_i
  end 
end

p elements.sort_by {|a| a}

7行で出来た。

シェルを使用した場合

$ sort data.txt

1行で出来た。

オーキドの言葉「こういうものには つかいどきがあるのじゃ」

この言葉を思い出した。

f:id:karoten512:20171126080256j:plain

おそらく僕がRubyを選択したら、この言葉を言われたと思う。

求められている要件

txtファイルの内容をソートしたい

なるはやで

要件を満たす手段

1番目の要件を満たす言語は、いくらでもある。

ただ、「なるはや」という2番めの条件を入れると、

エクセルという選択肢も出てくる。

さらに知っているのであればシェルが一番早い。

求められている要件 別パターン

txtファイルをアップロードして、中身をソートしたい

その内容をみんなで共有したい

社内でのみ使うのでセキュリティはあまくて良い

なるはやで

要件を満たす手段

この場合は2番目の要件が重要で、共有サーバで見れる必要が出てくる。

ここで

「ファイルアップロード! データ共有!

 webアプリだ! webアプリならRailsだ!」

わかる。でも他にも方法はある。

3番目の要件は

「セキュリティがそれなりに担保されているフルスタックフレームワークである必要は無い」

と捉えることもできる。

1機能のみをフルスタックフレームワークで書くのは大げさすぎる。

すると、「生phpで書く」という選択肢が出てくる。

ファイル分割したとしても2ファイルくらいで実装できてしまいそう。

(もちろん機能的に大きくなることが予想されるのであれば、

 フレームワークという選択肢もあります)

技術は要件に応じて使い分けるのが大事

プログラミングはあくまで手段。

要件をなるべくすべて満たすような手段を選ぶことが、ビジネス的には大事そう。

とはいえ手段すべてをマスターすることはできない

マスターはしなくて良いので、それぞれの技術の特徴を抑えておくことがまずは大事。

抑えておくと、要件が降ってきたときにいろんな手段を思いつくことができる。

生PHP...小規模開発

Rails/PHPフレームワーク...中規模〜

Java…大規模な業務系開発(実績があるから)

SQL...集計

統計解析…Python, R

組み込み…C

コマンドライン上での簡単な処理...bash

※個人の見解です&ものすごくざっくりです

まとめ

弘法は筆を選ばないが、エンジニアは手段を選ぶほうがよい

そんなエンジニアになりたいと思った。

最近の出来事を元に脚本を書いてみる。その4

はじめに

この話はいい感じにフィクションです。

登場人物

わたし(26)…会社員

マスター(41)…バーのマスター

省吾(42)…常連

小杉(35)…常連

杏奈(30)…常連

あやか(26)…常連

M 今日はマスターの誕生日。僕はケーキをもって店に向かった。

マスター「おーいらっしゃい」

わたし「マスターこれ。あとでみんなで食べましょう」

マスター「お〜、ありがとうございます!」

小杉「さ〜っすが!君仕事できるね〜!

   ちゃんとろうそく41本?」

わたし「いや5本です」

小杉「だめだね〜!やっぱ仕事できないね〜!」

M 熱い手のひら返しをくらう。面白い人だ。

SE ドアの開く音

省吾「こんばんは」

杏奈「こんばんは〜」

マスター「いらっしゃい」

マスター「かろてんくんがケーキをもってきてくれたんですよ」

杏奈「……」

省吾「……おー。すごいね。泡いれますか。かろてんくん飲む?」

かろてん「いただきます!」

M シャンパンなんて早々飲む機会がないので嬉しい。

M ものすごく美味しいシャンパンをのんでいると、

  なにやら省吾さんと杏奈さんが困惑した顔でアイコンタクトをしている。

杏奈「かろてんくんさぁ」(小声)

わたし「はい?」

杏奈「ダメだよ、誕生日プレゼントは一人でかっちゃあ」(小声)

わたし「なんでですか?」

M 私の質問に答えず、杏奈さんは省吾さんの方を見た。

杏奈「省吾さん、いつ出します?」

省吾「今のタイミングしかないんじゃないかな」

杏奈「ですよね〜」

M そういって杏奈さんは紙袋の中から箱を取り出した。

  嫌な予感がする。

杏奈「マスター、誕生日おめでと〜!」

M ケーキがでてきた。

  これでテーブルの上には大きなホールケーキが二つ。

  ショートケーキと、チョコレートケーキ。

わたし「いや〜やっちゃいましたね」

省吾「いやいやかろてんくんわかってる。チョコレートケーキをあえて選ぶ所が良いよね」

わたし「ショートケーキかシュークリームで悩んだんですよ。危ないところでした」

SE ドアの開く音

あやか「マスターおくれた!誕生日おめでと!!」

M 常連がまたやってきた。

あやか「マスター見てこれ!シュークリーム!!」

M 省吾さんと僕は思わず、顔を見合わせた。

そのテーブルに、idは必要ですか?〜idの必要性とデータの一意性についてもう一度考えてみる

テーブルに必ずと行っていいほど入っているidカラム

普段扱っているテーブルには、だいたいidカラムが含まれている。

Ruby on Railsのmigration機能を使うと勝手にidカラムが入ったりする。

当たり前のように存在するidカラム。

そのidカラムの必要性について、もう一度考え直してみる。

忙しい人のために結論

idカラムが重要なのではない。重要なのはデータが一意に特定できること

データが一意に特定できればidは必要ないことがある

ただ、あったほうが後々便利なことも多い

こんな例について考えてみる

f:id:karoten512:20171122231525p:plain

例えば30人の生徒がいるクラスに、同姓同名の生徒(山田太郎)がいたとする。

そして、このクラスの出席簿は名前カラムのみが存在している。

こんな感じ。

名前
...
山田太郎
山田太郎
...

このとき、

-- 朝会にて。出席をとる先生。山田太郎は1人欠席してる。

先生「山田太郎さん」

山田太郎「はい!」

先生「山田太郎さんは元気だね。山田太郎さんは休みかな?」

となり、

どっちの山田太郎が出席していてどっちの山田太郎が休んでいるのかわかりゃしない。

30人から1人が特定できないのだ。困った。

解決策

生徒1人を特定できるように、カラムを増やしてやればよい。

出席番号 名前
... ...
23 山田太郎
24 山田太郎
... ...

これで

-- 朝会にて。出席をとる先生

先生「23番!」

山田太郎(23)「はい!」

先生「24番!」

山田太郎(24)「はい!」

となり生徒の特定が可能だ。

f:id:karoten512:20171122231540p:plain

番号で呼んでるせいで刑務所みたいになってるけど。

出欠というより点呼とってる。

一意性

このように、大量のデータの中から1つのデータを特定できる性質のことを、

「一意性」という。

データはなによりも「一意性」を持っていることが非常に重要である。

もし一意性がないと、

出欠が取れなかったり、

どっちの口座に振り込めばよいかわからなくなったり、

どの飛行機に乗ればよいかわからなくなったり、、、

一意性がないと困ることはいっぱいある。

兎にも角にもデータは一意性が大事。

ここでid

idはデータに「一意性」をもたせるためによく使われる。

idさえ降っておけば、idのおかげでレコードが1つに特定できるからだ。実にお手軽。

(そもそもidは「identification(識別)」の略)

でも、いつもidは必要かというと、そういうわけではない。

家族テーブル

下の名前
太郎
次郎
三郎

「下の名前」だけで一意性が保たれる。

グローバルipアドレステーブル

ipアドレス
201.168.33.10
203.168.33.10
...

そもそもグローバルipアドレスが一意。

都道府県・市テーブル

都道府県名 市名
東京都 府中市
広島県 府中市
北海道 伊達市
福島県 伊達市
... ...

この場合、市名だけでは一意性が保たれない。

都道府県名と市名を組み合わせることで初めて一意性が保たれる。

このように、複数のカラムを組み合わせて一意性をもたせることもできる。

...こんなかんじで、扱うデータの種類によってidは必要じゃない場合がある。

ただし、idがあると便利なことがある

先ほど都道府県を例に出したが、この場合はidをふっておくと便利なことがある。

顧客テーブルに出身都道府県idカラムをもたせ、その中に都道府県idを入れた場合、

外部キーとして使いやすい。

データ単体としてみたとき一意性が保たれていても、

データを組み合わせて使う際、idがあったほうがシステム的に扱いやすいことも多い。

まとめ

テーブル設計をするときは

「ほんとにidが必要なのか?」

「idなくても一意性が保たれるのではないか?」

「idがなくても一意性が保たれる場合、idカラムをあえて使うメリットは何か?」

を考えて設計しよう。

もしかしたら、無駄なカラムが1つ減るかもしれない。

公開鍵認証によるssh接続ができない。パスワード認証になってしまう(/var/log/secureにてsshd[3437]: error: key_from_blob: can't read rsa key が表示された時の対処法)

ssh接続が出来ずパスワード認証になってしまう

こういうとき見るべきところは、だいだい以下の項目。

接続元
接続先
  • authorized_keysのパーミッションは600か
  • sshdの設定が「RSAAuthentication yes」「PubkeyAuthentication yes」かどうか

などがある、、が、

全部出来ているはずなのに、

なぜかパスワード認証時のパスワードが聞かれてしまう。

/var/log/secureの確認

サーバ側の

/var/log/secure

を見てみると、

error: buffer_get_ret: trying to get more bytes 257 than in buffer 254

なんだこれ?って感じのエラーが吐かれていた。

error: buffer_get_ret: trying to get more bytes 257 than in buffer 254 
error: buffer_get_string_ret: buffer_get failed 
error: buffer_get_bignum2_ret: invalid bignum 
error: key_from_blob: can't read rsa key 
error: key_read: key_from_blob 公開鍵の文字列 vagrant@vagrant\n failed

あ、、、なんか最後に怪しいやつがいる。

原因

公開鍵の最後に改行コード\nがついていたことが原因でエラーが起きたっぽい。

解決

公開鍵から改行コードを取り除いたところ、正常に動いた。

putty上で公開鍵をコピーして貼り付けたときに起こる。。ようです。

参考

dqn.sakusakutto.jp

【脚本】最初で最後のssh〜プロセス1〜

登場人物

  • 伊藤彩(27)…インフラ&サーバサイドエンジニア。

  前職で本番環境のDBを吹き飛ばした経験あり(※)

  • 田端祐介(32)…プロジェクトマネージャ

  • 白井(30)…サーバサイドエンジニア。中途入社。彩の部下。

○株式会社セントレイ(午後)

 ワンフロアのオフィスに20人のエンジニアが働いている。

 その真中の島の席で、彩が黒い画面を見ながら眉間にシワを寄せている。

彩「おっかしーなー。なんでバッヂが返ってこないんだろ。。。」(※)

祐介「伊藤〜、そこのバッヂ処理、修正したらステージングに上げなおしといてね。

   今・日・中」(※)

彩「わ、わかりました!」

彩「……今日中かぁ。。。間に合うか?これ。返ってきてくれ、バッヂ。。」

祐介「それと! 今日から中途採用の子の教育担当をやってもらうから」

彩「えぇ!きいてませんよ!」

祐介「けっこう急に決まったらしいからさ。よろしく!ちなみに、推薦したの俺」

彩「勝手なことしないでくださいよぉ!」

祐介「あと伊藤より年上な」

彩「えぇ!」

祐介「大丈夫大丈夫。優秀なやつらしいから」

○祐介、そのままお昼を食べに外出

その後姿を睨みつける彩。

彩「忙しいときに限っていろいろ重なるんだから。。」

彩「何ていうんだっけ。こういうの」

彩「マフィン?の法則?」

??「美味しそうですね。マーフィーですよ。彩先輩」(※)

○彩、後ろを振り返る

 見たことのない男が立っている。

 前髪で目が隠れて表情が見えない。

 彩、すこし表情をこわばらせる。

彩「えーと、、誰?」

??「聞いてませんか?今日からお世話になる白井です」

白井「よろしく、マフィン先輩」

○彩、眉間に指を当て、イライラしながら

彩「よろしく白井さん」

彩「さっそくだけど、今テストサーバで動いているバッヂがどこかで止まってるの。

  ログを確認してもらえる?」(※)

白井「ログファイルもらえます?」

彩「鍵ファイルを渡すから、sshなりscpなりで自分で入手してもらえる?(※)

 こっちも忙しいんだよね。バッヂの修正で」

白井「マフィン先輩」

彩「何?」

○白井を見上げる彩。白井の顔がこわばっている。

白井「僕、sshはちょっと」

彩「やりかたはググればでてくるって」

白井「いや、そういうわけじゃなくて」

○ゆっくり息を吸って吐く白井。

白井「sshは、ダメなんです」

続く

用語集

本番環境のDBを吹き飛ばす

mc.matome-complate.com

滅多にないが、

誤って顧客データ等の大事なデータが入ったDBを削除してしまうこと。

この後滅茶苦茶辞職した。

バッヂ処理

時間がかかる処理を、お客様への影響が少ない時間帯にまとめて行うこと。

例えば、月毎の売上集計・一日の売上集計などは

一般的に集計に時間がかかる&サーバにも負荷がかかるので、

夜間(深夜)にまとめて処理する事が多い(夜間バッヂと呼んだりする)

ステージング

ステージングとは - IT用語辞典 Weblio辞書

本番環境と同じ環境で作った、最終動作確認用サーバ。

ここでシステムを動かして最終確認をし、問題なければ本番にデプロイする。

なお、ステージングの前がテストサーバ。

マーフィーの法則

f:id:karoten512:20171119204653j:plain

先達の経験から生じた数々のユーモラスでしかも哀愁に富む経験則をまとめたもの(wikiより)

例えば、「傘を持っていないときに限って雨が降る」とか

「浮気をしているときに限って目撃される」とか。

ログ

ここではサーバ上に保持されている、時系列データのこと。

/var/log

以下にだいたい入っている。

apacheをwebサーバとする場合、

/var/log/httpd

アクセスログやエラーログが入っていることが多い。

ssh

外部のコンピュータと通信するためのプロトコル

暗号や認証の技術を利用しているので、安全に通信できる。

telnetも外部のコンピュータと通信するが、暗号化はされていないのでsshの方が安全。

scp

qiita.com

sshプロトコルを用いてファイルを送受信するコマンド。

wgetのセキュアバージョンと捉えれば良さそう。

ftpとは違ってディレクトリごと送れるので便利。

なぜ、データベースを正規化するのか。正規化のメリットについてソースコードレベルで考えてみる(第一正規化)

正規化のメリットについてソースコードレベルで考えてみる

DB設計をする際、あたりまえのように正規化していたのですが、

「なぜ正規化するか」についてはあまり良くわかっていませんでした。

調べると

正規化の理論は、

データの冗長性を排除し、

更新時の整合性を維持しやすくすることを目指しています。

とあるのですが、抽象的でイマイチよくわかりません。

そこで今回は、

正規化した場合としなかった場合を、

仕様変更時にどれだけ大変か

という観点で比較してみました。

実験

RPGの主人公がアイテムを3つだけ持つことができる」

という仕様でDB設計を行います。

また、主人公の情報とアイテムの情報をviewファイルに書き出すことにします。

A. 正規化をしなかった場合

DB(Heroテーブル)

# 物理名 論理名
1 id id
2 名前 name
3 レベル level
4 アイテム1の名前 item1_name
5 アイテム2の名前 item2_name
6 アイテム3の名前 item3_name

コントローラ

Heroを1人取得しておきます。

class HeroController
  def index
    @hero = Hero.find(1)
  end
end

view

<%= @Hero.name %>
<%= @Hero.age %>
<%= @Hero.level %>

<%= @Hero.item1_name %>
<%= @Hero.item2_name %>
<%= @Hero.item3_name %>
仕様変更

このような状態で、

「Heroのアイテムを1つ増やしたい」という仕様変更があると、

* DBのカラムにitem4_nameを増やす

* viewファイルにitem4_nameを出力するように修正

という変更が必要となってきます。

今回の場合、1コントローラ1viewなので修正範囲は狭いですが、

このテーブルが多くのコントローラ・viewで参照されている場合修正箇所はどんどん増えます。

またこの修正は、Heroのアイテムを増やすたびに行われます。

-- なんだかおかしなことになってきましたね。

B. 正規化する場合

そこでDBを第一正規化してみます。

第1正規化では、同一の情報のグループが繰り返し出現している部分を分離します。

www.atmarkit.co.jp

DB(Hero, Itemテーブル)

Heroテーブル
# 物理名 論理名
1 id id
2 名前 name
3 レベル level
Itemテーブル
# 物理名 論理名
1 id id
2 HeroId hero_id
3 アイテム名 name

controller

class HeroController
  def index
    @hero = Hero.find(1)
    @items = Item.where(hero_id: 1)
  end
end

view

<%= @Hero.name %>
<%= @Hero.age %>
<%= @Hero.level %>

<%= @items.each do |item| %>
  <%= item.name %>
<% end %>
特徴

正規化されていないテーブルから、

「繰り返しが発生しているデータ(Item)」

「発生していないデータ(Hero)」

をわけたことにより、

繰り返しが発生している部分を、eachで回して処理することができるようになりました。

よって、アイテムが1つ増えてもDBやソースコードを修正する必要はありません。

おまけ

以下のようなときは正規化する必要はありません。

個数が変わらないことが保証されているデータ

例えば、人間のパーツをDBで管理することを例として考えてみましょうか。

人間は肺という臓器を2個持っています。腎臓も然り。

この場合、よほどのことがない限り3個以上にはならないので、

別テーブルに分ける必要はありません。

…変な例で失礼しました。