ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

【Visual Basic】配列とメソッドを間違える

public class ClassA
    public sub main()
       Console.WriteLine("Hello, ClassA!")
    end sub
end class

public class Main
    public sub main()
        dim classA() as ClassA() ' ClassA型の配列
        ' dim classA() as new ClassA()  これはエラー。配列は初期化できない
        dim classA2 as new ClassA() ' ClassAをインスタンス化
        ' classA = classA2 これはエラー。ClassA型とClassAの配列では型が違うのでエラー
    end sub
end class

変数名に括弧をつけることで、配列として宣言される。

これを知らなかったので、「classA()とclassAは型が違います。」みたいなエラーで「???」を繰り返していた。

(´Д`)ハァ…めんどくさ(しらない俺が悪いけど)

地獄のはじまり

大げさかも知れないけど

はじまりの理由

  • 知らない言語を使って、あと期限3日のプロジェクトをアップデート
  • なんか細かいタスクが3つ以上ある
  • 副業がきた
  • 副業がきそう
  • 勉強会が今週土曜日にある(いけない可能性&モチベーションダウン)
  • 飲み会が今週金曜日にある(いけない可能性&モチベーションダウン)

いっぱいいっぱいorz

Visual Basicさん情報少なすぎないですか?

いやいや、過去から書いている人多そうじゃん? だから、いっぱいいると思うよ。

そう思っていた時期が俺にもありました(ちょうど今朝)

9:30 ・ω・)おお! VB初めて触ったけど、まぁまぁ面白いじゃん?

12:00 ^ω^)捗るわぁー!今日仕事めっちゃ捗るわぁー

14:00 ・ω・)おっ!この辺の処理リファクタしたほうがいいな。やろやろ。

15:00 ;・ω・)おやおや。。。? 雲行きが怪しくなってきましたよ? soapの管理してくれるクライアントライブラリないの?

16:00 ;・ω・)見つけたけど、なにこれ? 全然動かないし、エラーの原因もわからん。。。

17:00 ;;・ω・)ちょまってて、全然動かないし、色々探しているけど、情報少なすぎませんか?

18:00 #`ω´)キー!!!となりのPHPのサンプルコードは実行できているのに、VBだけ動かん!!!!!

そして今に至る。どうしてこうなった。

VBのことまだ良くわかっていないので、これが普通かもしれませんし、またわかっていたら解決できると思いますが、、、

しかし、今日のはちょっとひどい感じがする。全然見つからないの。。。

とりあえず、まだまだ地獄をさまよいます。これ出来ないと明日辛いのよ。。。どうしよう。

アメリカに質問しよ(´・ω・`)

【WordPress】サイト改ざんされました。まとめ

以前こんな記事をアップ。

www.aipacommander.com

「助けてー!レンタルサーバ会社から連絡がきたのー(><」って依頼があって、調べてみたら結構時間かかったので、メモしていました。

そのときの情報を今後のためにログ残しておきます。

気づいた理由

レンタルサーバの運営からメールがくる。

「あなたのサーバで、不審なプログラムが動いていたので、パーミッションを000に変更したお(^ω^;」

みたいなメールです。

その内容には、不審なプログラムのパスとファイル名も教えてくれます。

中身覗いたらゾッとした。

<?php

$xxxxx = Array(/* アルファベット大文字・小文字がランダムに配置された配列 */);
eval(xxx_function($base64_data, $xxxxx));
?>

xxx_function()base64エンコードされている文字&難読化されている文字列$base64_dataを、$xxxxxの配列を使って復元(?)しているっぽい。

で、動かしてみて、最後にeval()する箇所をechoに変更してみたところ。。。

class SMTP {}
class PHPMailer {}
class phpmailerException extends Exception {}

ひゃぁああああ! 第三者中継だね。。。orz

第三者中継 - Wikipedia

三者中継(だいさんしゃちゅうけい)または“Third-Party Mail Relay”とは、インターネット関連の用語で、関係の無い第三者が自由に、電子メール送信に用いる事が可能なメールサーバの設定、もしくはそのような状態を指す。

orz

さて、、、どうすりゃいいかな。

調査方法

まず初めに、ソースコードとDBをバックアップ。

作業しているときに、地雷踏んで全部消えたら冗談にならいので。

その次に、おかしなファイルを探すことにした。

こういう場合はシェルコマンドを叩けばなんとくなくうまくいくはず。

しかし、レンタルサーバなので、sshを使ってログインができない。

ちょっと特殊な方法でシェルを叩く。

PHPでシェルを実行して結果を参照するコードを用意する。

<?php
$command = 'ls -lhR';
$output = array();
$ret = null;
exec($command, $output, $ret);
file_put_contents('ls.txt', print_r($output, true));

↑のコードはドキュメントルート以下に配置。じゃないとブラウザからアクセス(実行)できないので。

実行すると、↑のphpを配置した箇所にls.txtってファイルが作成される。

こいつを参照してみると。。。

Array
(
  // ... 省略
    [2393] => ./wp:
    [2394] => total 224K
    [2395] => drwxr-xr-x  5 user group 4.0K Jan 27 09:55 .
    [2396] => drwxr-xr-x  6 user group 4.0K Jan 27 11:15 ..
    [2397] => -rw----r--  1 user group  101 Jan 26 14:55 .htaccess
    [2398] => -rw-r--r--  1 user group  418 Jan 25 2013  index.php
    [2399] => -rw-r--r--  1 user group  20K Jan  1 14:58 license.txt
    [2400] => -rw-r--r--  1 user group  10K Jan  1 14:58 readme.html
    [2401] => -rw-r--r--  1 user group 5.4K Jan  1 14:58 wp-activate.php
    [2402] => drwx---r-x  9 user group 8.0K Jan  1 14:58 wp-admin
    [2403] => -rw-r--r--  1 user group  364 Jan  1 14:58 wp-blog-header.php
    [2404] => -rw-r--r--  1 user group 1.5K Jan  1 14:58 wp-comments-post.php
    [2405] => -rw-r--r--  1 user group 3.8K Jan  1 14:58 wp-config-sample.php
    [2406] => -rw-------  1 user group 4.3K Jan 27 10:45 wp-config.php
    [2407] => drwx---r-x  7 user group 4.0K Jan 27 10:47 wp-content
    [2408] => -rw-r--r--  1 user group 3.3K Jan 24  2015 wp-cron.php
    [2409] => drwx---r-x 17 user group  16K Jan  1 14:58 wp-includes
    [2410] => -rw-r--r--  1 user group 2.4K Jan  1 14:58 wp-links-opml.php
    [2411] => -rw-r--r--  1 user group 3.3K Jan  1 14:58 wp-load.php
    [2412] => -rw-r--r--  1 user group  34K Jan  1 14:58 wp-login.php
    [2413] => -rw-r--r--  1 user group 7.7K Jan  1 14:58 wp-mail.php
    [2414] => -rw-r--r--  1 user group  14K Jan  1 14:58 wp-settings.php
    [2415] => -rw-r--r--  1 user group  30K Jan  1 14:58 wp-signup.php
    [2416] => -rw-r--r--  1 user group 4.0K Nov 30  2014 wp-trackback.php
    [2417] => -rw-r--r--  1 user group 3.0K Jan  1 14:58 xmlrpc.php
  // ... 省略
)

よし。うまく実行できました。

そこでわかったことは。。。

  • 運営から連絡のあったファイルの時間がJun 7って書いてあった
    • そいつで検索してみると、同じ時間で明らかにおかしいファイルが12個もあった。。。
    • server.php、utf7.phpcss.phpjavascript.php、、、などなど
    • 配置されるディレクトリはほんとにランダム
    • 中身を参照すると全部難読化されている
      • 読み解く2つのコードがありました
        • SMTP(第三者中継)
        • 攻撃ファイル。cookieかpostを使い、攻撃コードを鍵で暗号化してセット => 送信 => サーバで復号 => eval()で実行っていう恐ろしいコード

((((;゚Д゚))))ガクガクブルブル

おそろしいわ。。。

ファイルの配置は、↑の「cookieやpostデータにコードを〜eval()で実行」ってやつで色々ランダム配置されたんだと思う。

postって確かアクセスのログに残らないと思うから。。。レンタルサーバキツイ

対応内容

そもそもなんでやられたんでしょうね? 原因は?

ざっと上げてこんな感じ。

  • WordPressの管理者ユーザーが「admin」「password」
  • ログイン画面にて、ボット対策がされていなかった(画像認証とか、Basic認証だとか)
  • ftpログインパスワードが盗まれた・・・?
    • 恐らくこれはないと思う。webサーバのIPアドレスftpへ接続するIPアドレスは別になっているので、相手が知る方法がない。
  • sqlインジェクション・・・? xss
    • 今回のwebサイトはお問い合わせなどのフォームはないので、恐らくこれもないかな。
    • しかし怖かったので「vaddy」っていう脆弱性診断サービスを使ってサイトをクロール => 何も見つからないε-(´∀`*)ホッ

クソがぁっ!!!!

とりあえず、ログインパスワードがヤバイと思ったので、速攻で新規管理ユーザー作成&パスワード最強 => adminユーザーを削除しました。

んで、次に

  • WordPressを最新版にアップデート。
  • pluginは全部削除して、最新版をインストール
  • wp-config.phpの認証ユニークキー更新
  • dbのログインパスワード変更
  • siteguard pluginのインストール
    • ログイン履歴が取れる
    • ログイン画面で画像認証の機能を追加できる

これで良し。ってなりました。

終戦・・・?

とりあえず、これでいいんじゃないか? ということになりました。

だがしかし。。。

もうっかいやられる

対応したその翌日。。。朝ファイルを確認してみたらまたやられていた!!!!

なぜだぁ!!!!!! おかしなファイルは全部消して、WordPressも全部綺麗にしたじゃないかぁ!

どうして? (´;ω;`)ブワッ

ファイル改ざんされていたことに気づいた

うーむと悩んでいたところ。「まさか、、、ファイルが改ざんされているのでは?」と、ちょっと気になって、下記コードを書いてみて実行してみました。

<?php
$command = 'grep -E "(eval\(|base64_decode\(|error_reporting\(0\);|urldecode\(|chr\(|\$GLOBALS)" -r wp/';
$output = array();
$ret = null;
exec($command, $output, $ret);
file_put_contents('grep.txt', print_r($output, true));

最初のls.phpと違うのは、grepでファイルの中身を検索している点です。

今回難読化されたコードを読んでいて気づいたのは、eval()やらbase64_decodeをうまく利用している点でした。

なので、これで全ファイルを検索してみたらわかるかなと思い実行してみると。。。

Array
(
  // ... 省略
  [0] wp-admin/export.php => $GLOBALS['asf823ik'];global$sdadsf;$xiasd82=$GLOBALS;${"\x47\x4c\x53"} /* このあとコードがすげえいっぱい */
  // ... 省略
)

きゃぁー!!!キモい!!グロい!!!

なんじゃこりゃ。改ざんされているじゃん。 アップデートは? どうしてうまくいかなかったの・・・?

さらにgrepで引っかからないコードもありました。これはちょっと巧妙というか。。。そもそもそれ自体も難読化されているでキツイ

php -r "echo 'eva'.chr(108).PHP_EOL;"
eval

↑みたいな感じで、chr()関数でASCIIを数値で保存しておいて、それを変換して攻撃するなんてコードもありました。大変や。。。

なんかもう、ここまでされると「ご苦労様です(`・ω・´)ゞ」って気持ちになってきた。

さて、話戻しますと、どうやらアップデートは変更がないphpファイルは上書きしないっぽいですね。。。

また、私も先ほどあげた対策のなかで、wp cliを使ってのdiffを実行していませんでした。最新のWordPressと差分はないかチェックするのをしていなかったのです。

なので、

  1. アップデートしたけど、改ざんされているphpをほったらかし => そのままファイルは残っている
  2. 改ざんされたphpcookieとpostにコードを仕込まし実行される => smtpやらファイルがランダム配置
  3. 我々が泣く

という流れに(´;ω;`)ブワッ

くっそと思いながらも、今度はちゃんと差分をとって、攻撃ファイルを排除しました。。。。(というかWordPress自体を入れ替えた)

また、注意する点が。実はthemeのファイルもやられていました。

しかし、仕事上、趣味でもそうですが、themeはオリジナルがほとんどだと思うので、やられていても気づきにくいし、検知も難しいかなと思います。

私の場合はすべて目で確認しました。幸いファイル数が少なかったので、そんなに時間はかからなかったです。

対応した内容その2

  • wordpress総入れ替え
    • wp-content/{uploads,themes}以外は全部削除して、最新のコードをgithubから取ってきてそれに差し替え
  • wp-content/plugins/をもっかい最新に
  • WordPressログインパスワード変更
  • DBログインパスワード変更
  • wp-config.phpの認証ユニークキー更新

最初よりは対応が少ないですが、まぁ良いでしょう。。。

今のところ・・・大丈夫そう・・・?

それから毎日アクセスログとファイルを検索してみていますが、やられていないですね。。。いまのところ。

恐らく根本な原因はログインパスワードが「admin」「password」だったからでしょうね。。。(´Д`;

辞書攻撃一発でやられると思うので、次回からそうしないように周知しておきます。。。

ハァ疲れた。

今後の対策

  • ソース管理
    • gitで管理したらサーバで書き換わっていることを検知することができる
    • 「本番が最新」って文化早く無くなれ
  • パスワードを難しく
  • 常にプログラムは最新に
    • 「動かなくなるから怖い」とかいう人いるけど、ハッキングされるよりはまし
    • パーミッションを強くしなよ」でもいいけど、メディアからファイルがアップロードができなくなるとかあるので、その辺は利便性とトレードな感じがする。

ぐらいかなぁ。。。

【WordPress】下層ページかどうか判断するコード書いた

仕事中に書いてみたけど、なんか違う気がしてきた。。。

下層ページかどうか判断する関数が欲しかった。

自分で考えたフローとしては

  • トップページではないこと
    • アクセスされたパスに対し、WordPressのwebルートで置換してみる
    • 置換した値が '/' でなければ下層ページ
    • または、クエリパラメータ(検索とかで使う?s="")があれば下層ページ

WordPressfunctions.phpに追記したら使えるど。

<?php
/**
 * 下層ページか判断する
 * @return bool
 */
function isUnderPage()
{
    $url = (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
    $getPath = parse_url($url, PHP_URL_PATH);
    $query = parse_url($url, PHP_URL_QUERY);

    // wordpressのwebrootを作成
    $getWordpressPath =parse_url(home_url(), PHP_URL_PATH);

    // wordpressのwebrootで現在の$pathを置換
    $path = preg_replace("|".preg_quote($getWordpressPath . '/')."|", '', $getPath);

    // どっちも空であればトップページ
    if (empty($path) && empty($query)) {
        return false;
    }
    return true;
}

parse_url'()でurlを渡してほしい箇所だけ取得することができます。

置換するとき、urlにスラッシュとか入っているとエラーになるので、preg_quote()でエスケープしましょう。自分で正規表現書くよりは楽だし、正確かと。

とりあえずこれででき。。。ぁああああああああああ!!!

そういや、クエリパラメータがついていたら全部下層になるので、これではダメだ。トップページにクエリを渡したい場合は全部下層になっちゃう。。。!

ということは。。。。あれ難しくね? どうやって検索判断する?( ゚д゚)ハッ!

  • トップページではないこと
    • アクセスされたパスに対し、WordPressのwebルートで置換してみる
    • 置換した値が '/' でなければ下層ページ
    • is_search()で検索だったら下層ページ

クエリパラメータで判断せずに、is_search()で判断すればいいのでは。これでよし。