ジャンク品のnexus5xを電子レンジとパッチで直す。

ブートループして起動しないnexus5xを電子レンジで直す。
これの続きです。

メイン端末がnova liteなのですが、BlueBorneのパッチが来ないのと、Oreoの使える端末が必要になったので、ジャンクのnexus5xを手に入れて直してみることにしました。

ジャンク端末の状態

  • Googleのロゴがひたすらループする。いわゆるブートループしている状態。
  • ブートローダーに入れなかったり入れたりする
  • ブートローダーはロックされている
  • リカバリモードには入れない
  • 電源・充電系に異常はない

ブートローダーのロックが外れないとパッチを当てようがないので、どうにかして開発者向けオプションを起動させます。

ブートローダーのアンロック手順

  1. 分解して電子レンジをオーブンモードにしてマザーボードを焼く(物理)。200℃ 1分で加熱。
  2. 組み直した後、無事に起動を確認しました!!知らないエロゲの壁紙とか、普通に前の持ち主の情報が見えて動揺しました。ロック設定されてたらまずかったですね。
  3. ビルド番号を連打して開発者向けオプションを解除。
  4. 「OEMロック解除を有効にする」にチェック。

OSは7.1.2でした。
ここまできたらどうにかなりそうです。

Oreoへアップデート+CPU用のパッチ当て

Factory Images for Nexus and Pixel Devices | Google APIs for Android | Google Developers
BlueBorne対策済みのイメージが欲しいので8.0.0 (OPR4.170623.006, Sep 2017)をDLしました。
普通にブートローダーは起動したのでファクトリーイメージを焼いた後パッチを当てます。

  1. fastboot oem unlockでブートローダアンロック。
  2. Oreoのファクトリーイメージを焼く。
  3. Nexus 5X bootloop of death fix (BLOD) | 7/30… | LG Nexus 5X からDownloadsを選択し、「Boot.img from Android O DP6」から4CoreOreo.imgをDL。
  4. fastboot flash boot 4CoreOreo.img でパッチを当てる。

ファクトリーイメージを焼く時参考にしたページです。cache.imgはないので、その部分は fastboot format cache してます。
Nexus5Xを工場出荷時初期化~Xposed導入まで – akashisnの日記

無事起動しました。
電子レンジの力で一時的に動いてるだけかわからないので、予後を観察したいと思います。
TWRPを導入している端末であれば、EX kernelが焼けるので試してみても良いかもしれないですね。(TWRP自体がブートループで起動できないので私は試してません。)

起動しました。

BlueBorneも大丈夫。

追記(2017/10/16)

予後も順調なのでメイン端末をnova liteからnexus5xにしました。セキュリティパッチをOTAで当ててしまうとboot領域が書き換わってしまうので、fastbootコマンドで入れ替えています。
4コアしか動いてないのでパフォーマンスが心配ですが、Pokemon GOとIngressとメールとブラウザ使うくらいなら今の所問題ないので、このままメインで使っていこうと思います。

10月分のセキュリティパッチを当てました。

big側のコアは動いてない模様

悟空のきもちの予約フォームには致命的ではないが色々問題がある。

悟空のきもちというマッサージ屋さんが全然予約取れないらしいのと、予約フォームのソース見たらかなりひどい簡単に予約自動化できそうだったので、スクリプトを組んで予約してみました。
…のですが、「システム不具合で予約が取れなかった」とお店から連絡がきました。なぜ不具合が起こったか調査してるそうなので(本当に調査してるのかは別として)、私も調べてみることにしました。
ソースコードを見ればすぐわかるような、スクリプトキディレベルのことしか書いてないです。
詳細書きすぎると問題になりそうなのであえて書いてませんが、普通にHTMLとPOSTリクエストの組み方がわかる人なら10分ソースを眺めればわかることばかりです。

詳細

予約フォームは以下のURLですが、
https://goku-nokimochi.com/reservation.html
実際の予約本体は以下のURLを使用しています。
https://form.goku-nokimochi.com/form/reservation/index3.php?shop_id=

恐らくこちらの製品を使用しているようです。
メールフォームプロCGI/UTF-8対応・クレジット決済機能対応 | 無料素材

予約が空いているかどうかは、店舗名とコースを選択した時点でGETリクエストにより問い合わせが行われ、selectタグに反映されます。
例えば、銀座店で60分コースを選択すると以下にリクエストが飛び、JSON形式でレスポンスが返ってきますね。
https://form.goku-nokimochi.com/form/getReservation4.php?shop_id=4&course_id=157

index3.phpが出力しているHTMLのsetUpTimeメソッドを見ると、恐らく配列内には時刻が4ケタの数字で格納されているだろうことがわかります。(実際そうでした。)

value.substr(0,2) + "時"+ value.substr(2,2) + "分"...

フォームにはトークン等も設定されていないので、getReservation4.phpに定期的に問い合わせを送り、自分の都合の良い日時の空きがあれば、予約用のリクエストボディを組み立てて../sendmail2.php宛にcurlかなにかでPOSTしてしまえば良いことがわかります。

../sendmail2.php 宛にPOSTしても、実際にはまだ予約が完了にならず、customer_idが発行されるだけになります。どうやらsendmail2.php宛にリクエスト投げた時点で予約できてしまうようです。
customer_idが発行されると、以下のURLにジャンプします。
https://form.goku-nokimochi.com/form/reservation/sheet.php?customer_id=

sheet.phpのフォーム

トークン等は存在しないので、予約用のリクエストボディを組み立てて ../sendsheet.php にPOSTしてしまえば予約が取れてしまいますね。

このシステムで微妙な部分

予約が埋まっている時間帯を指定してリクエストを組み立ててもエラーが返ってきてしまいますが、エラーが返ってこなくなるまでリクエストを投げ続ければ、キャンセルで空きが出た瞬間に予約が取れますね。簡単に予約代行できそうです。
このマッサージ屋さんに限ったことではなく、似たような予約システムを抱えているところには同じ問題がいえますね。

このシステムで問題のある箇所

index3.php(予約フォームの本体)で、好きな日付を入力した上で時刻指定(r_time)の値を指定しなかった場合、customer_idが発行できてしまいます。
何かの拍子でr_timeが設定されていないのにリクエストが飛んだ場合、そのまま予約が(時刻指定なしのまま)とれてしまいますね。
私はコレにひっかかったのかも。
あと、コースIDが予測できるものなので、隠しコースとか予約できてしまいますね。実際予約できたんでこのままでいいや…。お金払うし…。

フロントのソースコードが中学生が作った掲示板レベルなので、調べたらもっといっぱい穴がありそうでオラワクワクしてきたぞ(悟空のきもちだけに)。
バックエンドもきっとヤバそうな気がします。

【雑感】Fiddlerを使ってHuawei nova liteのパケットをキャプチャした。

結構前からnova liteがBaiduと通信してると話題なのですが、2chのスレを見てもほぼまともな情報が得られないのと、ぐぐっても結局通信内容が不明のままだったので、諦めて自分でキャプチャすることにしました。
飽くまで私の持ってる端末・環境での観測結果なので、ご自身の端末がどのような通信をしているのか知りたい方は、ご自身でパケットキャプチャされることをおすすめします。
Wiresharkを使っても良かったのですが、手元にFiddlerの入ってるマシンしかなかったのでFiddlerを使いました。Androidでのパケットキャプチャ用の設定は以下の記事が分かりやすかったです。
Android端末上のHTTP/HTTPS(SSL)通信内容を傍受・解析する方法

観測対象

Huawei nova lite/PRA-LX2C635B160
(現在地が中国以外だと通信しないという話らしいので、情報を載せておくと、)位置情報設定は「高精度」に設定してあります。高精度じゃないとPokemon GOできなくなるので。

観測方法

1時間程度、スリープしないようにして端末を放置。

結果

1時間内で3回 www.baidu.com 宛にGETでアクセスをしていました。(HTTP宛で、クエリパラメータはなしです。)
あと、端末電源ON時に必ずbaiduと通信する、という話も見かけたので何度か電源ON時のパケットもキャプチャしましたが、いずれもbaidu宛の通信は見つかりませんでした。

以下リクエストのキャプチャ結果(3回とも全部同じでした)

GET http://www.baidu.com HTTP/1.1
Charsert: UTF-8
Accept-Charset: utf-8
Content-Type: application/x-www-form-urlencoded
contentType: utf-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; PRA-LX2 Build/HUAWEIPRA-LX2)
Host: www.baidu.com
Connection: Keep-Alive
Accept-Encoding: gzip

ちなみに肝心のレスポンスですが、Fiddlerは504を返してきました。うーん…。

[Fiddler] ReadResponse() failed: The server did not return a response for this request. Server returned 0 bytes.

名前解決用にリクエスト飛ばしてるのかもしれないですが、情報がなさすぎて憶測の域を出ませんね。
(24時間くらいがっつりモニタリングしたら何かわかるかもしれないですが、)1時間程度ではよくわかりません、という感想です。
Baiduと通信してるのは確実なことがわかったので、購入はあんまりおすすめできません。

追記(2017/08/20)

Fiddlerのようにローカルプロキシを挟むとローカルプロキシが解釈できないレスポンスがエラーになるので、Wiresharkを使おうとしたのですが、どう頑張っても家のWi-Fiでモニターモードが使用できなかったため、諦めてtPacketCaptureを使用してキャプチャしました。

3時間キャプチャして10回baidu宛の通信を確認しました。以下リクエストです。10回とも内容は全部同じでした。

# 103.235.46.39 宛に通信。
Hypertext Transfer Protocol
    GET / HTTP/1.1\r\n
    Charsert: UTF-8\r\n
    Accept-Charset: utf-8\r\n
    Content-Type: application/x-www-form-urlencoded\r\n
    contentType: utf-8\r\n
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; PRA-LX2 Build/HUAWEIPRA-LX2)\r\n
    Host: www.baidu.com\r\n
    Connection: Keep-Alive\r\n
    Accept-Encoding: gzip\r\n
    \r\n
    [Full request URI: http://www.baidu.com/]
    [HTTP request 1/1]
    [Response in frame: 471]

以下レスポンス。値がユニークっぽそうな箇所は念のため伏せました。

Hypertext Transfer Protocol
    HTTP/1.1 302 Found\r\n
    Cache-Control: no-cache\r\n
    Connection: Keep-Alive\r\n
    Content-Type: text/html;charset=utf-8\r\n
    Date: Sun, 20 Aug 2017 14:29:54 GMT\r\n
    Location: https://m.baidu.com/?from=844b&vit=fps\r\n
    P3p: CP=" OTI DSP COR IVA OUR IND COM "\r\n
    Server: apache\r\n
    Set-Cookie: BAIDUID=C438EAAB0EFE52A771xxxxx:FG=1; max-age=31536000; expires=Mon, 20-Aug-18 14:29:54 GMT; domain=.baidu.com; path=/; version=1\r\n
     [truncated]Set-Cookie: H_WISE_SIDS=118416_114550_117615_118309_117044_114744_118507_100100_118270_118057_xxx...
    Set-Cookie: BDSVRTM=42; path=/\r\n
    Tracecode: 1794964229xxxxxx\r\n
    Tracecode: 1794926598xxxxxx\r\n
    Traceid: 1503239394xxxxxxxxxx\r\n
    Content-Length: 0\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.189395000 seconds]
    [Request in frame: 469]

似たような通信がないかぐぐると2chのg07スレが見つかりました。
goo g07 Part3 [無断転載禁止]©2ch.net

13 SIM無しさん (オイコラミネオ MMf6-0Bqe)2017/03/29(水) 16:32:10.03ID:8pI43FAvM
GPSの関係でBidouにアクセスが発生する端末が
あると聞いたが、広告騒ぎとは関係なさそうだけどこの通信が必要な理由はなんだろう

Source 103.235.46.39  (BAIDU-HK)
Dustination (略)

HTTP/1.1 302 Found
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 0
Content-Type: text/html;charset=utf-8
Date: Wed, 29 Mar 2017 05:57:17 GMT
Location: https://m.baidu.com/?from=844b&vit=fps
P3p: CP=” OTI DSP COR IVA OUR IND COM ”
Server: apache
Set-Cookie: BAIDUID=(略):FG=1; max-age=31536000; expires=Thu, 29-Mar-18 05:57:17 GMT; domain=.baidu.com; path=/; version=1
Set-Cookie: H_WISE_SIDS=102569_108266_100043_102435_103300_111882_112106_107313_114130_115245_115110_115055_115244_115044_114797_114513_114998_114330_114535_115031_114276_110085; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=81; path=/

gooのg07ってcovia製ですよね。あるぇー…。
これ以上調べても新しい情報が見つからなさそうなので私は調査を降ります…。まさに「何の成果も!!得られませんでした!!」って感じですね。何のために通信してるのか全くわからん。

追記(2017/09/17)

Huawei nova lite/PRA-LX2C635B170にアップデートしたところ、6時間観測して1度もbaiduとの通信を検出しませんでした。位置情報をOFFにしても検出しなかったのでかなり謎いです。
しれっとバグを直したとか、通信しないようにしたとかそんな感じでしょうか。如何せん公式に発表もないですし、怪しいことには変わりないので、購入はあんまりおすすめできません。BlueBorneのパッチもいつくるかわからないし…

retrorocket.bizのSSL証明書を再発行しました。

SSLサーバ証明書再発行のお願い – さくらのサポート情報
retrorocket.bizも対象なので再発行しました。これから3年間分無料とはありがたいです…。期限ギリギリまで発行を粘ってちょっとでも証明書の有効期限を伸ばそうかと思いましたが、引き伸ばしてるうちに対応を忘れてしまいそうなのでやめました。
nginxの場合、ssl_certificateに中間証明書を設定しないとサーバから中間証明書が送付されないのですが、完っ全に失念してまして30分くらい本気で悩みました。次の移行時にまた忘れそうですね。

再発行に至った背景は以下の記事がとてもわかりやすいです。
Symantecが再びGoogleの信頼を失った件についてのメモ – Technically, technophobic.
個人的に「シマンテックの言い分が大変うんこである」以外の感想はないです。ブラウザベンダー側が拒否らないと改善されないのもひどい。でもお金払っちゃったから使います。

retrorocket.bizのSSL証明書をラピッドSSLに移行しました。
去年くらいにラピッドSSLに移行したものだと思っていたら2年前でビビりました。

とりあえずOCSP Responseが返ってくるかは確認しました。

$ openssl s_client -connect retrorocket.biz:443 -status -servername retrorocket.biz < /dev/null | head
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:1
depth=1 C = US, O = GeoTrust Inc., CN = RapidSSL SHA256 CA
verify return:1
depth=0 CN = retrorocket.biz
verify return:1
CONNECTED(00000003)
OCSP response:
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: 04F2100E425F1B9605707A171B87FDED0C1A9B92
    Produced At: Jul 20 09:29:11 2017 GMT
    Responses:
DONE

問題ないですね。

Amazon Dash ButtonとIRKitとLINE Message APIでバルスダッシュボタンを作る。

プライムデーでダッシュボタンが1個100円だったので、IRKitとLINEBotと連携して部屋の家電の電源を全部消すバルスダッシュボタンを作ることにしました。

使用したもの

  • Raspberry Pi 3
  • 天然水ダッシュボタン

今回はLINE botでCallbackを使用しないため、ローカルホストに適当にhttpで通信できるWebサーバが立っていれば十分です。

準備

ボタンのセットアップと、ボタン押下を検出してくれるdasherのインストールは以下の記事の内容をそのまま実施しました。ありがたいです。
Amazon Dash ButtonをただのIoTボタンとして使う – Qiita

ダッシュボタンが押された時に動作するWebhookの立ち上げ

(私が最速で作れる方法なので)hypnotoadとMojolicious::Liteでセットアップしました。
ローカルホストのポート8093で立ち上げてダッシュボタンの押下を待ち受けます。
動作としては、IRKitに家電の消灯信号を送った後、LINEの特定グループトーク宛にdasherからPOSTされたJSONの内容を送信します。

ソースはこんな感じ。

#!/usr/bin/perl
use utf8;
use strict;
use warnings;

use LINE::Bot::API;
use LINE::Bot::API::Builder::SendMessage;
use LWP::UserAgent;
use Mojolicious::Lite;

### CONSTS
my $ua   = new LWP::UserAgent();
my $log = app->log;
my $CHANNEL_ACCCESS_TOKEN = "xxx"; # LINE developersから取得したtokenを指定
my $CHANNEL_SECRET="xxx";

# API認証情報
my $bot = LINE::Bot::API->new(
    channel_secret       => $CHANNEL_SECRET,
    channel_access_token => $CHANNEL_ACCCESS_TOKEN,
    );

app->config(
    hypnotoad => {
      listen => ['http://*:8093'],
      workers => 2,
    },
);

sub call_api(){
  my $url = shift;
  my $method = shift;
  my $headers = shift;
  my $content = shift;

  my $req = HTTP::Request->new($method, $url);
  while (my ($key, $value) = each(%$headers)){
    $req->header($key => $value);
  }
  $req->content($content);
  return $ua->request($req);
}

my $IRKIT = "http://192.168.xx.xxx/messages"; # IRKitのエンドポイント
my %IRKIT_H = ("X-Requested-With" => "curl");
sub call_irkit(){
  my $content = shift;
  return &call_api($IRKIT, "POST", \%IRKIT_H, $content);
}

post '/barusu' => sub {
  my $self = shift;
  my $messages = LINE::Bot::API::Builder::SendMessage->new;
  my $data = $self->req->json; # dasherから送られたJSON

  my $light_off = '{"format":"raw","freq":38,"data":[消灯用データ]}';
  my $aircon_off = '{"format":"raw","freq":38,"data":[消灯用データ]}';
  # 他の消したい家電
  &call_irkit($light_off);
  &call_irkit($aircon_off);
  # 以下略
  $messages->add_text( text => $data->{text} );
  $bot->push_message("Cxx投稿先のグループID", $messages->build);
  return $self->render(json => {'status' => "OK. BARUSU."});
} => 'barusu';

app->start;

投稿先のグループIDだけはwebhook-event-object以外の確認方法がわからなかったので、適当にhttpsで通信できるサーバを立てて取得しました。
自分だけに飛ばすなら、自分のUserIdをLINE developersから確認できるのでここまでめんどくさくないと思います。

dasherの設定をする

dasherの設定(config/config.json)は以下のような感じです。

{"buttons":[
  {
    "name" : "天然水バルスダッシュボタン",
    "address": "ダッシュボタンのMACアドレス",
    "url": "http://127.0.0.1:8093/barusu",
    "method": "POST",
    "json": true,
    "body": {"text":"バルス!"}
  }
]}

使ってみる

dasherのREADMEどおり起動させました。

コマンドラインはこんな感じ

ボタンを押したところ電気が消えてエアコンも消えてテレビも消えました。(画像クリックでGIFアニメが再生されます。)

ポチッとな。

LINEには通知が飛びました。

LINEのようす。

これ、サーバで処理できることはなんでもボタン一つでできますね。とりあえずバルスボタンは玄関に設置しました。あと、作ってからLINEはあんまり関係なかったなと思いました。
もう1個ポテチのダッシュボタンがあるので何か別のものを作りたいですね。夢が広がります。