20200812のLinuxに関する記事は6件です。

RobomasterS1をハックしたい ①ルート化とファイル構成確認

概要

何をしたか

  • Robomasters1をPCとのUSB接続し,adbを使ってルートにアクセスする。
  • 中身のファイル構成を覗いてみた

何ができるか?

  • わからない…(情弱)
  • コマンドライン上でPython環境を制限なしで走らせられる(アプリ経由すると使えないライブラリがある)

何がしたいか?

  • 下記参照

本記事の最終目的

  • RobomasterS1へPCから司令を送ったり,画像やセンサデータを収集したい 参考:Ishikawa氏の記事
  • 有志のデモのようにRobomasterの画像をPCで処理して制御信号を送るといったことに使いたい。

ボールトラッキングのデモ動画を以下に添付します。こういうのをやりたいです。

こういうのをやりたい

方針

RobomasterS1の後継となるEPという機種があり,そちらは今言ったようなことができます。SDKも配布されています。(Documentはこちら

https://github.com/dji-sdk/RoboMaster-SDK/tree/master/sample_code

この件に詳しいBruno氏に寄ればこのSDKでは本来S1のサポートはしていませんが,構成が似通っているため上手くやると流用できるとのことです。

参照:

実際にやったこと

ひとまず,rootアクセスが必要そうなので

Windows10 PC からadbを用いてrootアクセスする

Windows10 HomeのPCからmicroUSBコネクタを用いてRobomasters1に接続します。

ここのPDFをもとに進めていきますが,注意としてファームウェアが新しいとroot化できないなどの報告があるのでアップデートはしないことが挙げられます。

前準備

以下のものを準備します。

Platform Toolsは解凍してフォルダの場所を記憶しておきます。PCとRobomasters1を接続します。
image.png

次の工程に行く前にPCに接続されているAndroid機器を取り外しておいてください。

PCとRobomasters1の接続

  1. Robomasters1の電源を入れ,PC側もソフトを起動して接続します。(自分はWifi接続)

  2. 「ラボ」→「DIYプログラミング」からPythonスクリプトを書くページに行きます。

  3. 新規作成で下記のコードをコピペし,実行します。(adbを有効化するshを叩いているっぽい)

def root_me(module):
 __import__=rm_log.__dict__['__builtins__']['__import__']
 return __import__(module,globals(),locals(),[],0)
builtins=root_me('builtins')
subprocess=root_me('subprocess')
proc=subprocess.Popen('/system/bin/adb_en.sh',shell=True,executable='/system/bin/sh',stdout=subprocess.PIPE,stderr=subprocess.PIPE)

adbを用いた接続

次に先程解凍した,Platform Toolsのフォルダ(adbが実行可能なフォルダ)に行き,Powershellを起動します。(Linuxの人はTerminal)

.\adb.exe devices

を実行した後に,

.\adb.exe shell

を実行します。
上手く行けば以下のようにrootでは入れているはずです。

image.png

次にやること(多分)

  • なんとかしてRobomasters1側のConnectionRefusedError: [WinError 10061]を解除してSDKのサンプルプログラムを試す
  • どうやらRobomaster s1 にはSDKのトリガーとなるソケットのポートが開かれていないのでEPからファイルをコピーしてくる必要がある…EPも買うお金はない…

追記:ここのやり取りを見るに,Robomaster EPからファイルをコピーする必要があるようで自分の手持ちでは実現できなそう…となっています。

説明

2020年8月12日現在のSDKを見た感じでは,Robomasters1のアドレスの特定のポートに信号を送ることでSDKモードを有効にし,様々な司令を出しているようです。

例えば,SDKを有効にして各種命令をPCから実行するテストファイルではソケット通信で40923ポートに信号を投げています。

SDKサンプルコード
# -*- encoding: utf-8 -*-
# 测试环境: Python 3.6 版本

import socket
import sys

# 直连模式下,机器人默认 IP 地址为 192.168.2.1, 控制命令端口号为 40923
host = "192.168.100.111"
port = 40923

def main():

        address = (host, int(port))

        # 与机器人控制命令端口建立 TCP 连接
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        print("Connecting...")

        s.connect(address)

        print("Connected!")

        while True:

                # 等待用户输入控制指令
                msg = input(">>> please input SDK cmd: ")

                # 当用户输入 Q 或 q 时,退出当前程序
                if msg.upper() == 'Q':
                        break

                # 添加结束符
                msg += ';'

                # 发送控制命令给机器人
                s.send(msg.encode('utf-8'))

                try:
                        # 等待机器人返回执行结果
                        buf = s.recv(1024)

                        print(buf.decode('utf-8'))
                except socket.error as e:
                        print("Error receiving :", e)
                        sys.exit(1)
                if not len(buf):
                        break

        # 关闭端口连接
        s.shutdown(socket.SHUT_WR)
        s.close()

if __name__ == '__main__':
        main()

しかし,Client側からConnectする際に以下のようにエラーを出されてしまいます。

ConnectionRefusedError: [WinError 10061] 対象のコンピューターによって拒否されたため、接続できませんでした。

hostsか何か編集したり,Permissionをいじるとかが必要なのでしょうか?ちょっと調べている所です。(詳しい方に教わりたい。)

追記:試した所どうやら,EPには開かれているPortが,S1では開かれていないというのが問題のようです。

根拠として下記のサーバをRobomaster s1 で立ち上げてPCから接続できることを確認したためです。

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("192.168.100.111", 1235))
s.listen(5)

timeout=60## run 60 sec
s.settimeout(timeout)

while True: 
    clientsocket, address = s.accept()
    print(f"Connection from {address} has been established!")
    clientsocket.send(bytes("Welcome to the server!", 'utf-8'))
    clientsocket.close()

print("Exit!")

補足:中身を探索する

自分はLinuxもこういったHackもズブの素人なので中身を覗いて理解するのも一苦労でした。一応記録までに載せておきます。

システム情報

一応Linuxシステムではあるようです。

$ cat /proc/version
Linux version 3.10.62 (jenkins@APServer01) (gcc version 4.7 (GCC) ) #1 SMP PREEMPT Tue Jul 16 04:08:11 CST 2019

/直下

なんもわからんのでこれを見てもって感じですが一応メモしておきます。

クリックして展開
amt
blackbox
cache
data
default.prop
dev
etc
file_contexts
ftp
init
init.environ.rc
init.lc1860.3connective.rc
init.rc
init.trace.rc
init.usb.rc
proc
property_contexts
root
sbin
sdcard
seapp_contexts
sepolicy
sys
system
system.md5
tmp
ueventd.rc
var
vendor

Python環境

data/python_fliesの中にPythonのフォルダがあります。

binの中身は以下の通り,

2to3
idle
pydoc
python
python-config
python3.6m
pyvenv

実際に実行もできます。環境は3.6のようです。

126|root@xw607_dz_ap0002_v4:/data/python_files/bin # ./python
Python 3.6.6 (default, Jul 16 2018, 17:22:20)
[GCC 4.8.3 20140320 (prerelease)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

robomasterのアプリとの違いは,特定のパッケージが使えることです。

例えば,アプリで作成したコードではsocketなどはimportした時点でエラーとして弾かれるのに対してrootのコマンドライン実行では普通に実行できます。

viなどのエディタがあればいいのですが,ls /system/binの出力を見る限りエディタはないのでファイル転送などをする必要がありそうです。

アプリで作成したファイルがどこにあるかがわかればroot上である程度操作ができそうですね。

devの中身

ttyとかは省略。video0とかはありますね。

クリックして展開
alarm
android_adb
apple_roleswitch
applecp
ashmem
binder
block
bulk_usb
bus
comip-snd-lowpower
comip-ureg
console
cpu_dma_latency
cuse
full
fuse
graphics
hx170dec
hx280enc
hx280enc_h1
i2c-0
i2c-1
i2c-3
i2c-4
input
ion
kmsg
lcmem
log
loop-control
mem
modem
mtp_usb
network_latency
network_throughput
null
on2map
on2psm
ptmx
pts
random
rtc0
sdpr
sdps
snd
socket
spidev0.0
spidev1.0
spidev2.0
uio0
uio1
uio2
urandom
vcs
vcs1
vcsa
vcsa1
video0
zero

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sshfsコマンド ディレクトリの同期

SSH接続でディレクトリを同期する

sshfsコマンドを使用する

sshfs  pi:/home/work/  ./pi_work/

接続相手がpiという名前の相手のディレクトリを、現在のディレクトリ直下のpi_workとう名前を付けて同期したいとき。

いちいちscp,rsync コマンドを使用せずに、他のコンピュータのファイルにアクセスできるので便利。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ディレクトリ内のPSDファイルをPDFに一括変換

psdファイル(元データ)とpdfファイル(変換後)それぞれ用のディレクトリがある親ディレクトリで実施する前提

$ ls
psd_dir/ pdf_dir

ImageMagickを利用

for file in `ls psd_dir`; do
  # 拡張子削除
  base=`basename "${file}" .psd`
  # 変換
  convert -flatten -density 300 -compress zip psd_dir/"${base}".psd pdf_dir/"${base}".pdf; 
done

参考
- ファイル名からディレクトリや拡張子を取り除くには
- 表紙の画像ファイルを PDFファイルに変換 解像度 350dpi

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

port forwardingをunix domain socketにbindすると捗る

port forwardingをunix domain socketにbindすると、dockerコンテナ内にvolume mountを通じて持っていけるので便利。
以下、mysqlを例にする。

コマンド

ssh -o StreamLocalBindUnlink=yes -fNL /tmp/sock/db.sock:$DB_HOST:3306 bastion

bastionはもちろん、踏み台サーバー
fNオプションは不要であれば外して良い。
-o StreamLocalBindUnlink=yes をつけると、指定したpathにunix domain socketが既に存在する場合でも上書きしてforwardingしてくれる。

dockerコンテナ内での使用

--volume /tmp/sock:/tmp/sock 付きでコンテナを起動する。

mysql --socket /tmp/sock/db.sock -u ...

curlでも使える

https://qiita.com/toritori0318/items/193df8f749a9c4bda883
ブラウザからアクセスできないのが残念(コンテナ内でブラウザを使うわけではないが、portにbindするのとunix domain socketにbindするのを切り替えるのが面倒くさい)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

port forwardingをunix socketにbindするとはかどる

port forwardingをunix socketにbindすると、dockerコンテナ内にvolume mountを通じて持っていけるので便利。
以下、mysqlを例にする。

コマンド

ssh -o StreamLocalBindUnlink=yes -fNL /tmp/sock/db.sock:$DB_HOST:3306 bastion

bastionはもちろん、踏み台サーバー
fNオプションは不要であれば外して良い。
-o StreamLocalBindUnlink=yes をつけると、指定したpathにunix socketが既に存在する場合でも上書きしてforwardingしてくれる。

dockerコンテナ内での使用

--volume /tmp/sock:/tmp/sock 付きでコンテナを起動する。

mysql --socket /tmp/sock/db.sock -u ...

curlでも使える

https://qiita.com/toritori0318/items/193df8f749a9c4bda883
ブラウザからアクセスできないのが残念(コンテナ内でブラウザを使うわけではないが、portにbindするのとunix socketにbindするのを切り替えるのが面倒くさい)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Linux】FQDNの安全な確認方法について検証してみた(CentOS7)

はじめに

以前の記事にてこのようなご質問を頂きました。

スクリーンショット 2020-08-12 8.19.56.png

【以前の記事】
【Linux】インフラエンジニアの僕が「hostname」コマンドを使わない理由とは?

申し訳ございませんが、FQDNまで考慮しておりませんでした。(業務にてFQDNまで確認するシチュエーションがなかったため。)

せっかくなので、検証してみようと思います。

今回検証するOS等の情報

OSバージョン
[root@tspdev01 ~]# cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
[root@tspdev01 ~]#

※事前に/etc/hostnameをこのようにしました。

ホスト名
[root@tspdev01 ~]# cat /etc/hostname
tspdev01.example.com
[root@tspdev01 ~]#



「そもそもrootユーザーでやらないだろ!」
そのような声もよくわかります。(既存サーバには、基本的にrootログインしません。)

しかし、今回は検証用のためrootユーザーでやってみたいと思います。

そもそも、「hostname -f」の出力結果とは?

実行コマンド
hostname -f
実行結果
[root@tspdev01 ~]# hostname -f
tspdev01.example.com
[root@tspdev01 ~]#

実行結果を確認すると、FQDN(tspdev01.example.com)にて表示されております。

他のコマンドで試してみる

他のコマンドでFQDNを確認してみたいと思います。

質問にあったコマンドにて実行

質問にあったコマンドを実行してみる。

実行コマンド
echo `uname -n`.`dnsdomainname`

実行結果は、こんな感じです。

実行結果
[root@tspdev01 ~]# echo `uname -n`.`dnsdomainname`
tspdev01.example.com.example.com
[root@tspdev01 ~]#

結果、ドメインが2回表示されています。

「uname -n」にて実行してみる

こちらのコマンドにて実行

実行コマンド
uname -n

実行結果はこちらになります。

実行結果
[root@tspdev01 ~]# uname -n
tspdev01.example.com
[root@tspdev01 ~]#

FQDNにて表示されました!

ホスト名を短縮名で表示してみる

通常のホスト名の短縮名表示

実行コマンド
hostname -s

実行結果はこちらになります。

実行結果
[root@tspdev01 ~]# hostname -s
tspdev01
[root@tspdev01 ~]#

ホスト名の短縮系のみ表示される。

awkを使った短縮ホスト名確認方法

実行コマンド
uname -n | awk -F "." '{print $1}'

実行結果はこちらになります。

実行結果
[root@tspdev01 ~]# uname -n | awk -F "." '{print $1}'
tspdev01
[root@tspdev01 ~]#

このように、短縮されたホスト名のみ表示させることができます。
tspdev01.example.com.で区切っています。

参考記事
awkの-Fオプションで区切り文字を指定する方法

ドメイン名のみ確認

通常のドメイン名確認方法

実行コマンド
hostname -d

実行結果は、こちらになります。

実行結果
[root@tspdev01 ~]# hostname -d
example.com
[root@tspdev01 ~]#

安全なドメイン名確認方法

実行コマンド
echo `dnsdomainname`

実行結果は、こちらになります。

実行結果
[root@tspdev01 ~]# echo `dnsdomainname`
example.com
[root@tspdev01 ~]#

ドメイン名のみ表示されております。

まとめ

FQDNでの表示方法

uname -n

短縮ホスト名のみ表示

uname -n | awk -F "." '{print $1}'

ドメイン名のみ表示

echo `dnsdomainname`


おそらく、他にも方法があると思われます。
まだまだ勉強不足なので、これからもキャッチアップしていく所存です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む