PHPMailerの脆弱性について

Wordpress

つい先日、社内で割りと話題になったPHPMailerの脆弱性。
一応ここでも共有しておこうかなと。


20170109追記

WordPressからの利用(wp_mailの使用)については、今回発覚した脆弱性を利用できず、早急なアップデートは必要ありません。
ただし、脆弱性が残ることにはなるので、できるだけアップデートはしましょう。


PHPMailerって?

端的に言うとWordpressやDrupalなどのCMSや
それ以外のオープンソースなソフトによく組み込まれていて、PHPを利用してメール送信を行うコードです。

これを使えば簡単にWordpressのお問い合わせページからメールを送信できたりします。
よく見るwp_mailとかで使っているコードというわけですね。

何が起きた?

先日、報告されていたPHPMailerの機能を利用してコードを送信し、リモート制御を行う手法についてです。
24日付でこの問題の緊急対応パッチがアップされ、米セキュリティ機関のSANS Internet Storm Centerより早くパッチ当てろと注意喚起されました。

まぁ、それを受けてCMSを運用している我が社はそれなりに蜂の巣をつついたように、上へ下への大騒ぎ。
先日12月のはじめにWordpressを4.7へアップデートしたんだから大丈夫だろうとしていたのが全然大丈夫じゃなかったと。

閑話休題。

とにかくそういった脆弱性が見つかっており、そのパッチを手動でダウンロードして当てろと言うことですね。

なんで手動なの?

WordPressしか知らないのですが、PHPMailerのように緊急パッチをすぐさま出す…ということができません。
なぜなら数回に分けて試行錯誤していき、まともな安定版を作成するからです。
このプロセスにはマイナーバージョンアップがあってから早くとも1ヶ月はかかります。
4.7になったのは12月の初めのことなので、どう考えても来月以降になるわけですね。年末年始ですが。

この場合、やはりWordpress自体をアップデート(しても何も起きない)ので
更新して本番に上げる前に検証くらいはしましょう。

アップデートするモジュールはどこに?

PHPMailerのコードはgithubで公開されています。ブックマーク推奨ですよ!
https://github.com/PHPMailer/PHPMailer/releases

なお、現在のバージョンは[5.2.21]となっており、
今アップデートするならば、最低でも[5.2.20]にはアップデートする必要があります。

ITメディアさんは27日に発表してくれていますが、更新してくれていません。
既に5.2.18は過去のバージョンになっています。
http://www.itmedia.co.jp/enterprise/articles/1612/27/news058.html

なお、SANS ISC InfoSec Forumsさまさまは[5.2.20]について説明してくれています。
最低でも[5.2.20]にはしろよと警告されていますね。
https://isc.sans.edu/forums/diary/Critical+security+update+PHPMailer+5220+CVE201610045/21855

注意です。
WordPress4.7ですが、PHPMailerのバージョンはかなり古いもので、昨年11月のソースが入っています。

以上!Wordpressに限った話ではないので気をつけて運用しましょう!

OBS-Studio+Radeon ReLiveでストリーミングができなかった話

OBS

つい最近AMDよりRadeon Software Crimson Reliveとやらが配信されたようです。
こやつはこれまでのRadeonドライバに多数の機能追加を行ってバージョンアップ版としてリリースされました。
Radeonユーザーはアップデート画面が出てきたのにバージョン下がっとるがな!と思うかもしれません。

さて、本題です。

アップデートしたらOBSで放送できなくなった!!

そうです。放送できなくなったのです。
と言っても、ログを確認してそれを頼りに英語ページを調べていくうちに解決しました。

ログはここにあると思います。
C:\Users\user\AppData\Roaming\obs-studio\logs

[AMF Encoder] <Plugin::AMD::VCEEncoder::SetFullColorRangeEnabled> Setting to Enabled failed with error AMF_INVALID_ARG (code 4).
[AMF Encoder] Exception: <Plugin::AMD::VCEEncoder::SetFullColorRangeEnabled> Setting to Enabled failed with error AMF_INVALID_ARG (code 4).
[AMF Encoder] Unable to create Encoder, see log for more information.

こんな感じのエラーが出てます。
まぁエンコードできねーんだけど…って怒ってるわけですね。

とりあえず解決法をどばーっと

githubにて最新のエンコードプラグインを公開してくれています。

https://github.com/Xaymar/obs-studio_amf-encoder-plugin/releases/tag/1.4.3.3

つまり使えないなら差し替えればいいじゃないという話です。
enc-amf.dll
enc-amf.pdb
他にも色々と差し替えますが、主にこの2つが重要です。
\obs-plugins\32bit\とかにあります。

osbplugin

これをダウンロードしてOBSのインストールフォルダを指定して実行すれば完了です。

ログ見ればすぐに解決できることですが、情報があればもっと早く解決できますね。感謝感謝。

スプレッドシート+メール通知

今回したいこと

スプレッドシートで管理しているソフト等の更新日が近くなったらメールを送りたい。
更新日が迫っているものの一覧が欲しいだけ。

早速作る

まずはスプレッドシートを作成して良いように設定。

すぷれっどしーと

以下コードを作ったスプレッドシートのGASにぶっこむ。

//メイン処理
function Main() {
  var wkData = getValue();
  var message = "";
  for(key in wkData){
    message += key + ":" + wkData[key] + "\n";
  }
  
  if(message != ""){
    sendMail(message);
  }
}

//ID列をキーにして連想配列に格納する
function getValue() {
  var sheet = SpreadsheetApp.getActive().getSheetByName('シート1');
  var endRow = getLastRowNumber(sheet);
  var values = sheet.getRange(2,1,endRow-1,5).getValues();
  var data = {};
  for (var i = 0, l = values.length; i < l; i++) {
    var key = values[i].shift();
    if (key.length > 0) {
      if (isDateConvertCheck(values[i][1])){
        var today = new Date();
        var yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
        var nowDate = Utilities.formatDate(yesterday,'JST','yyyyMMdd');
        var wkDate = Utilities.formatDate(values[i][1],'JST', 'yyyyMMdd');
        
        if (wkDate > nowDate){
          continue;
        }
        
        var rtDate = Utilities.formatDate(values[i][2],'JST', 'yyyy年M月d日');
        values[i].splice(1,4);
        values[i][1] = "プロダクト期限:" + rtDate;
      }
      data[key] = values[i];
    }
  }
  return data;
}

//メールの送信
function sendMail(message) {
  GmailApp.sendEmail("メールアドレス(カンマ区切りで複数宛先)","プロダクト更新時期通知",message);
}

//変換出来るかチェック
function isDateConvertCheck(date){
  try{
    var cvDate = Utilities.formatDate(date, 'JST', 'yyyy年M月d日');
    return true;
  } catch(e){
    return false;
  }
}

//入力されている最終行の取得
function getLastRowNumber(sheet){
 var last_row = sheet.getLastRow();

 for(var i = last_row; i >= 1; i--){
  if(sheet.getRange(i, 2).getValue() != ''){
   return i;
    }
 }
}

後はトリガー設定して定期実行させるだけ。
ね?簡単でしょう?

受信したメールはこんな感じ。

mail

Fromがスクリプトを動かすユーザのメールアドレスになるので、個人や社内利用向けかなぁ。

IFTTTを使ってGmailをスプレッドシートに転記

最近流行りのIFTTTを使ってGmailとスプレッドシートを連携させてみました。

IFTTTとは

テンプレートを作って多数のWebサービスを連携させるサービスです。
例えばタイトルにもある通り、Gmailの受信メールをスプレッドシートに転記するとか。
IFTTTはここからアクセス
ちなみにイフトと読むそうです。

では今回の目玉である連携にいきましょう。

そもそもまともな状態で転記されない問題

連携するのに初端からコケてるじゃねーか!

まともではないというのは、転記時にメールの受信日付が独自のもので記入されてしまう所です。
例えば
May 14, 2016 at 05:12AM
こんな感じ。

ソートできませんよね。困りますよね。

ではこれを解決するにはどうしたら良いのか?
とりあえず思いつくのは何個かありますが、正規表現で抜き取っていくのが楽かもしれません。
ただ、この場合は書式が変わると対応に追われて死にます。
なので応急処置的なものだと考えてます。
(IFTTTとGmailやスプレッドシートを連携する方法は他で調べてね)

早速ポチポチ関数を使って引き抜いていく

想定は1行目に列名を入れて、日時はA2に格納されている状態。

E2セル =F2&"-"&G2&"-"&H2&" "&J2 //フィルタ用日時格納セル
F2セル =REGEXEXTRACT(A2,"[0-9][0-9][0-9][0-9]") //年
G2セル =VLOOKUP(REGEXEXTRACT(A2,"[A-Za-z]+"),month_table!A$1:B$12,2,FALSE)//月
H2セル =REGEXEXTRACT(A2,"[0-9]+")//日
I2セル =REGEXEXTRACT(A2,"[0-9]+:[0-9]+")//時刻(12時)
J2セル =IFERROR(IF(FIND("PM",A2,1)>0,IF(MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))<10,IF(HOUR(I2)=12,HOUR(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))&":0"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+")),HOUR(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))+12&":0"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))),IF(HOUR(I2)=12,HOUR(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))&":"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+")),HOUR(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))+12&":"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+")))),""),IFERROR(IF(FIND("12:",I2,1)>0,IF(MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))<10,"00:0"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+")),"00:"&MINUTE(REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))),""),REGEXEXTRACT(I2,"[0-9]+:[0-9]+"))) //時刻(24時)

最後だけ大変長くなっています。
これは0埋めとAM、PM変換のためです。AM12時なら12を足して0時になります。

ここまで記入していざテストする段階で気づくことがあると思います。ない?残念です。

それはIFTTTには入力された行をスキップする機能があるです。
実際めちゃくちゃ困りました。

とりあえずGAS(スクリプト)で解決を目指す

IFTTT側に設定した列を使用しないとしても、入力された行をスキップする機能を殺せないので
GAS(Google Apps Script)を使うことにします。

function SetCode() {
  var ss=SpreadsheetApp.getActiveSpreadsheet(); //スプレッドシートを取得
  var sheet=ss.getSheetByName("シート1"); //シートを取得
  var maxRow=sheet.getDataRange().getLastRow(); //シートの使用範囲のうち最終行を取得
  var code1 ='';
  var code2 ='';
  var code3 ='';
  var code4 ='';
  var code5 ='';
  var code6 ='';
            
/* スプレッドシートの入力が完了しているかをチェック */
  for(var i=2;i<=maxRow;i++){
    code1 ='=F'+i+'&"-"&G'+i+'&"-"&H'+i+'&" "&J'+i+'';
    code2 ='=REGEXEXTRACT(A'+i+',"[0-9][0-9][0-9][0-9]")';
    code3 ='=VLOOKUP(REGEXEXTRACT(A'+i+',"[A-Za-z]+"),month_table!A$1:B$12,2,FALSE)';
    code4 ='=REGEXEXTRACT(A'+i+',"[0-9]+")';
    code5 ='=REGEXEXTRACT(A'+i+',"[0-9]+:[0-9]+")';
    code6 ='=IFERROR(IF(FIND("PM",A'+i+',1)>0,IF(MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))<10,IF(HOUR(I'+i+')=12,HOUR(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))&":0"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+")),HOUR(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))+12&":0"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))),IF(HOUR(I'+i+')=12,HOUR(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))&":"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+")),HOUR(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))+12&":"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+")))),""),IFERROR(IF(FIND("12:",I'+i+',1)>0,IF(MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))<10,"00:0"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+")),"00:"&MINUTE(REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+"))),""),REGEXEXTRACT(I'+i+',"[0-9]+:[0-9]+")))';

    var code = [code1,code2,code3,code4,code5,code6];
    
      if(sheet.getRange(i,1).getValue()!=""){ 
        if(sheet.getRange(i,5).getValue()==""){
          var a=0;
          for(var j=5;j<=10;j++){
            sheet.getRange(i,j).setFormula(code[a]);
            a++;  
          }
          a=0;
        }
      }
  }
}

面倒なので相当雑なプログラムになっています。
こいつをGASでポチポチっと作ってトリガーを時間単位で設定します。
編集時に動かしたかったのですが、どうしてもトリガーが動かないなら定期的に実行すればいいか
くらいの気分です。

ここで共有してます。閲覧のみなのでマイドライブに追加→コピーでもして使ってみてください。

以上!

2016/12/08追記
どうやら正規表現のミスがあったようなので修正しましたよ。
AM12時=0時
PM12時=12時
たまに米国の悪しき慣習に引きづられそうになりますが。