|
| ||||||||
|
巻き戻し中。
|
|
2013-11-08(金) 焦った(;´Д`) [長年日記]
_ 侵入
朝からperlがCPU食い潰しておかしいと思っていたら。。。
php経由でperlからGET掛けられたり、実行に失敗してperlが無限ループしていた模様。
プロセス監視で引っ掛けたperlでgetしようとしていたURLは、別の検証機からダウンロードしてみたら「PWNED!!」みたいなコメントがたくさん入ってるpythonのスクリプトとかw
パーミッションの関係から/tmpに落として実行しようとしていたツールもパスワード窃取系。
とりあえず、ログをチェックしながらファイルを確保、不審なプロセスをはたき落としながら応戦。*1
*1 お仕事柄、情報収集も兼ねて昼間の打合せラッシュをこなしながら、リモートでインシデント対応というw
_ 解析
さて、この侵入劇の入り口はどこかさっさと確定して手を打たねばならん。
当初、プロセスから得られた情報は「perlで叩かれてる」だけ。
調査の基本としては「最近何かやった?」が最初。
ここ数日で変更があったのは、rubyとtDiary。
どっちも、本日現在の最新。
脆弱性を調べても、そんなコマンド投げ込まれるようなものは該当しない。
でも、「ゼロディかな?」「なんか設定ミスった?」とか考えて時間を食ってしまった。
php/rubyを使うcgiを一時的に使用停止して様子を見ながらログ解析。
apacheのログを追いかけたら、「php.cgi」でperlを叩いてる。
何そのベタなコマンド・・・OTL
_ 原因
以前に、「妹認証」を実験する際にphpのインタープリタへのリンクを/cgi-binに置いたまま消し忘れてた。
で、該当の侵入者の行動を見ると/cgi-binの「php.cgi」「php4.cgi」「php5.cgi」などを当てずっぽうにプローブしてヒットしたものを使ったみたい。
確かにね。。。
ちなみに、過去のログまでチェックしたら、某脆弱性スキャナは発見していたようなんだけど、オレにレポート無かったなぁ(;´Д`)
さすがに、2年前の設定漏れを今日になって突かれるというのは予想外ですた。
先入観を持たずに調査しないとイカンというよい教訓。
_ 素性
一両日で始まったアクセス、登場したIPは2ヶ所。
「93.120.84.31」と「77.68.62.77」
欧州方面かな。
どっちも、ググると調査行為などで結構チェックされてるIPですわ。
調査やアクセス制限にブラックリストを使うのもありかもね。
_ 調査
そう言えば、落としてきたバイナリ類は実行に失敗してた。
stringsしたらLinux用のライブラリに色々リンクしてるようだったけど、、、
「Linuxだとおもった?残念、FreeBSDでした!」
って言う事ですねw
トップページ見てれば、日本語分からなくてもOSの想像できたろうに。
ついでなので、安全のために/tmpはnoexecでマウントし直しましたよ。
2013-11-09(土) tDiary [長年日記]
_ バージョンアップ
昨日の日記の通りで、先週末にtDiaryを4.0.1にした。
というよりも、うっかりrubyをportupgradeしたら1.8xが1.9xになってしまい、tDiaryが2.2では動かなくなったため。
とは言え、メジャーバージョン1個飛ばしてかなりの大騒ぎ。
_ Gemとか
色々お作法が変わったのね。
インストール時に「bundle install」とか。
モジュールによってエラーが出る度に、メッセージ見てモジュールの不足っぽかったらGemfileに書いて「bundle install」の繰り返し。
( ´ー`)y-~~
_ 文字コード
まず、日記がEUCからUTF-8になった。
2.x->3.xの更新だと、自動で表示の度に文字コードを更新してくれる事になっていたようだが、
さすがに4.0.1では無理みたい。
とりあえずスクリプト作って、data/「年]のディレクトリにあるファイルを文字コード変換。
ついでに、2.2とお作法が変わって行頭にプラグイン呼び出しするとレイアウトが崩れるので、それも修正する。
もちろん、日記本体だけでなくコメントやリンク元の情報ファイルも変換。
【こんなツール】*1
*1 sedで行頭に全角スペースおいてるのよん。コピペするとき気を付けてね。
#!/bin/sh if [ -d ./old ];then echo "old-dir existing" exit fi mkdir ./old mv ./*.td2 ./old mv ./*.tdc ./old cd ./old ls *.td2 |awk '{system ("sed s/'\'^\<%=isbn_detail\''/'\' \<%=isbn_detail\''/ "$1" >"$1".new")}' ls *.td2.new |awk '{system ("sed s/'\'^\<%=youtube\''/'\' \<%=youtube\''/ "$1" >"$1".new1")}' ls *.td2.new.new1 | awk '{system ("sed s/\"^\<a target=\"/\" \<a target=\"/ "$1" > "$1".new2")}' ls *.td2.new.new1.new2 | awk '{system ("sed s/\"Format: emptdiary\"/\"Format: tDiary\"/ "$1" > "$1".new3")}' ls *.td2| awk '{system ("nkf ./"$1".new.new1.new2.new3 \>../"$1)}' ls *.tdc| awk '{system ("nkf ./"$1" \>../"$1)}' chown www:wheel ../??*.td2 chown www:wheel ../??*.tdc
_ プラグイン
2.2系のもので使い慣れているけど4.xのパッケージにないものも多数。
大抵はnkfで文字コードをutf-8に変換して、一行目に
「# -*- coding: utf-8 -*-」
を突っ込めば、なんとか動く。
それでも、「へぇボタン」みたいに数値が保存されなかったり不具合があるものは原因調査&改修か、諦めるか。
2013-11-10(日) tDiary4.0.1+静的HTML出力 [長年日記]
_ てすと
静的HTMLの出力テスト
_ 残課題
細かい日記のエラーは、過去8年分ざっと見直したつもり。*1
残るは
・へぇボタンの数値が記録されない
・image-gallery.rbが動かない
・ソーシャルへのリンクが項目ごとだとウザイかな?
ってところ。
*1 先週末はそれで徹夜(;´Д`)
_ 静的出力
tDiary4.0.1で2.2の手法がまんま使えるとは思わないのだけど、負荷対策:静的 HTML 化とかtDiaryを最新エントリまで静的出力する方法とか参考に始めてみる。
微妙に変数とか変わってるのが面倒だw
tDiaryのファイル構成も大幅に変わって、tdiary/dispatcherの配下のファイルを弄る。
index_main.rbとupdate_main.rbの差分はこんな感じ。
cgiの権限で書き込める「【tDiaryのパス】/static」は先に掘っておく事。
*** index_main.rb.org Sun Nov 10 04:25:44 2013 --- index_main.rb Sun Nov 10 16:30:03 2013 *************** module TDiary *** 52,57 **** --- 52,75 ---- head['Cache-Control'] = 'no-cache' head['X-Frame-Options'] = conf.x_frame_options if conf.x_frame_options end + # Add for static HTML 20131110 start + if !request.mobile_agent? then + if params['date'] then + if /^\d{8}$/ =~ params['date'] then + File.open("【tDiaryのパス】/static/#{@params['date']}.html", "w") {|f|f.write body + File.open("【tDiaryのパス】/static/cache.log", "a+") {|f| + f.write "#{Time.now} static cache written(#{@params['date']}.html).\n" + } + } + end + elsif params['category'] then + else + File.open("【tDiaryのパス】/index.html", "w") {|f| + f.write body + } + end + end + # Add for static HTML 20131110 end head['cookie'] = tdiary.cookies if tdiary.cookies.size > 0 TDiary::Response.new( body, ::TDiary::Dispatcher.extract_status_for_legacy_tdiary( head ), head ) end *************** module TDiary *** 83,88 **** --- 101,122 ---- def create_tdiary begin if params['comment'] + # add for static index 20131110 + cache = "【tDiaryのパス】/index.html" + if FileTest.exist?(cache) then + File.delete(cache) + end + # add for static index 20131110 end + # Add for static HTML 20131110 start + date_string = params['date'] + cache = "【tDiaryのパス】/static/#{date_string}.html" + if FileTest.exist?(cache) then + File.delete(cache) + File.open("【tDiaryのパス】/static/cache.log", "a+") {|f| + f.write "#{Time.now} static cache cleared(#{date_string}.html).\n" + } + end + # Add for static HTML 20131110 end tdiary = TDiary::TDiaryComment::new( cgi, "day.rhtml", conf ) elsif params['plugin'] tdiary = TDiary::TDiaryPluginView::new( cgi, '', conf )
_ 【update_main.rb.patch】
*** update_main.rb.org Thu Aug 29 17:53:52 2013 --- update_main.rb Sun Nov 10 15:47:41 2013 *************** *** 2,7 **** --- 2,8 ---- module TDiary class Dispatcher class UpdateMain + def self.run( request, cgi ) new( request, cgi ).run end *************** module TDiary *** 15,23 **** --- 16,46 ---- @params = request.params end + # Add for static output 20131110 start + def delete_cache(request) + cache = "/home/www/htdocs/rewind/index.html" + if FileTest.exist?(cache) then + File.delete(cache) + end + # date_string = '20121004' + # date_string = params['date'] + date_string = sprintf("%04d%02d%02d", cgi['year'], cgi['month'], cgi['day']) + # date_string = sprintf("%04d%02d%02d", @params['year'], @params['month'], @params['day']) + # date_string = sprintf("%04d%02d%02d", @request['year'], @request['month'], @request['day']) + cache = "/home/www/htdocs/rewind/static/#{date_string}.html" + if FileTest.exist?(cache) then + File.delete(cache) + File.open("/home/www/htdocs/rewind/static/cache.log", "a+") {|f| + f.write "#{Time.now} static cache cleared(#{date_string}.html).\n" + } + end + end + # Add for static output 20131110 end + def run @tdiary = create_tdiary begin + head = {}; body = '' if request.mobile_agent? body = conf.to_mobile( tdiary.eval_rhtml( 'i.' ) ) *************** module TDiary *** 63,78 **** --- 86,116 ---- def create_tdiary begin if params['append'] + # Add for static output 20131110 start + delete_cache(@cgi) # For static + # Add for static output 20131110 end tdiary = TDiary::TDiaryAppend::new( cgi, nil, conf ) elsif params['edit'] + # Add for static output 20131110 start + delete_cache(@cgi) # For static + # Add for static output 20131110 end tdiary = TDiary::TDiaryEdit::new( cgi, 'update.rhtml', conf ) elsif params['replace'] + # Add for static output 20131110 start + delete_cache(@cgi) # For static + # Add for static output 20131110 end tdiary = TDiary::TDiaryReplace::new( cgi, nil, conf ) elsif params['appendpreview'] or params['replacepreview'] + # Add for static output 20131110 start + delete_cache(@cgi) # For static + # Add for static output 20131110 end tdiary = TDiary::TDiaryPreview::new( cgi, 'preview.rhtml', conf ) elsif params['plugin'] tdiary = TDiary::TDiaryFormPlugin::new( cgi, 'update.rhtml', conf ) elsif params['comment'] + # Add for static output 20131110 start + delete_cache(@cgi) # For static + # Add for static output 20131110 end tdiary = TDiary::TDiaryShowComment::new( cgi, 'update.rhtml', conf ) elsif params['saveconf'] tdiary = TDiary::TDiarySaveConf::new( cgi, 'conf.rhtml', conf )
_ httpd側は
.htaccessを↓な感じで追加設定。*1
要するに、通常はキャッシュがあればそっち。
携帯からのアクセスは整形されるので動的生成。
検索エンジンさんは強制的に静的htmlに飛ばして負荷軽減。
各個別の日付じゃない、一覧表示はキャッシュがないので動的生成。
もしかすると、今回から正式にfcgi使ってるので論理矛盾があるかもしんない。
【.htaccess】
*1 他にもspam避けとか沢山設定されてるw
Options +ExecCGI Options -Indexes Options +FollowSymLinks RewriteEngine on # If mobile, use index.rb RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/([0-9]+)\.html$ RewriteCond %{HTTP_USER_AGENT} ^DoCoMo [OR] RewriteCond %{HTTP_USER_AGENT} ^J-PHONE [OR] RewriteCond %{HTTP_USER_AGENT} ^MOT- [OR] RewriteCond %{HTTP_USER_AGENT} ^KDDI- [OR] RewriteCond %{HTTP_USER_AGENT} ^Vodafone [OR] RewriteCond %{HTTP_USER_AGENT} ^UP\.Browser [OR] RewriteCond %{HTTP_USER_AGENT} ^SoftBank RewriteRule .* index.fcgi?date=%1 [L] # If mobile, use index.rb RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/$ RewriteCond %{QUERY_STRING} ^$ RewriteCond %{HTTP_USER_AGENT} ^DoCoMo [OR] RewriteCond %{HTTP_USER_AGENT} ^J-PHONE [OR] RewriteCond %{HTTP_USER_AGENT} ^MOT- [OR] RewriteCond %{HTTP_USER_AGENT} ^KDDI- [OR] RewriteCond %{HTTP_USER_AGENT} ^Vodafone [OR] RewriteCond %{HTTP_USER_AGENT} ^UP\.Browser [OR] RewriteCond %{HTTP_USER_AGENT} ^SoftBank RewriteRule .* index.fcgi [L] # If search engine, goto html focebily RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/?date=([0-9]+$) RewriteCond %{HTTP_USER_AGENT} msnbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} psbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/2 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/1 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo! [NC,OR] RewriteCond %{HTTP_USER_AGENT} Y!J-SRD RewriteRule .* static/%1.html [L] # If search engine, goto index.rb.org "Non static" focebily RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/$ RewriteCond %{HTTP_USER_AGENT} msnbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} psbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/2 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/1 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo! [NC,OR] RewriteCond %{HTTP_USER_AGENT} Y!J-SRD RewriteRule .* index.fcgi [L] # If search engine, goto update.rb.org "Non static" focebily RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/update.rb$ RewriteCond %{HTTP_USER_AGENT} msnbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} psbot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/2 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Googlebot/1 [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo [NC,OR] RewriteCond %{HTTP_USER_AGENT} Yahoo! [NC,OR] RewriteCond %{HTTP_USER_AGENT} Y!J-SRD RewriteRule .* update.fcgi [L] # If there is cache, output from cache RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/([0-9]+\.html$) RewriteCond 【tDiaryの場所(絶対パス)】/static/%1 -f RewriteRule .* static/%1 [L] # If there is no cache, output from cgi RewriteRule ^([0-9]+)\.html$ index.fcgi?date=$1 [L] RewriteRule ^([0-9]+[-]+[0-9]+)\.html$ index.fcgi?date=$1 [L] # If it is comment, go to index.rb RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/$ RewriteCond %{REQUEST_METHOD} ^POST$ RewriteRule .* index.fcgi [L] # If selecting a category, go to index.rb RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/$ RewriteCond %{REQUEST_METHOD} ^GET$ RewriteCond %{QUERY_STRING} ^.+$ RewriteRule .* index.fcgi [L] # If there is no caache for top, go to index.rb RewriteCond %{REQUEST_URI} ^\/【tDiaryの場所】\/$ RewriteCond %{QUERY_STRING} ^$ RewriteCond 【tDiaryの場所(絶対パス)】/index.html !-f RewriteRule .* index.fcgi [L]
_ ツール
テーマを変えたり、設定変更したときに過去のキャッシュは自動じゃ変更されない。
なので、当日から日記を開始した2004年の12月31日まで週1回キャッシュを削除しながらツールで自動的に/dev/nullへwgetする。
と言っても、UserAgentとReferrerはちゃんと付けないと弾かれる。
所要時間は8年分で10分ほど。
今まではツールからtelnetでport80叩いていたんだけど、いろんな動作をちゃんとエミュレートしないとコメント欄が無いキャッシュができたりしたので改良。
Tweets by RC31E | |||||||||
| |||||||||
| |||||||||
|
_ わし [ツッコミのテストw]