はじめに
突然ですが、オープンソースのプログラムを改変したくなりました。
卒制に脆弱性調査をしよう!!というビッグな話があがったので、予行練習です。
ソースコードから目当ての実装を探し出す + 改変できたらいいなということで...
pingとは
ping コマンドは、インターネット制御メッセージ・プロトコル (ICMP) の ECHO_REQUEST を送信して、ホストまたはゲートウェイから ICMP ECHO_RESPONSE を取得します。 ping コマンドは、以下の場合に役立ちます。
- ネットワークの状態および各種の外部ホストの判別
- ハードウェアおよびソフトウェアの問題の追跡と分離
- ネットワークの検査、計測、および管理
IBM ping コマンドより
pingコマンドの使い方
ping [option] <destination>
pingはよく使うネットワーク系のコマンドです。以前Raw-Socketのプログラムを書いてみて、ネットワーク系コマンドに興味があったので選びました。
また、改造したいオプションについて、シンプルな仕組みで実装されていると予想し、簡単に改造できるのでは?と考察したためです。
なにをどうするのか
今回の改造では、pingコマンドのcオプションに着目しました。cオプションとは、指定した回数だけpingを送るといったシンプルなものです。
Linuxのpingコマンドでは、cオプションを指定しない場合、無限にECHO_REQUESTを送信してしまいます。これが煩わしいと感じました。
(オプションを入れないと無限にECHO_REQUESTが...)
そこで、cオプションを指定しないでも、windowsのpingコマンド仕様のように、4回だけECHO_REQUESTを送信するようにしたかったのです。
(オプションを指定しないで4回だけ送りたい)
pingの実装を覗いてみる
pingコマンドはOSSなので、ソースコードが公開されています。
ですので、今回は実装を見てから、改造コマンドを作ってみようと思いました。
膨大なソースコードから気になる機能を探すにはどうしたらよいか、友人に教えてもらいました。
結論を言うと、"grepをしまくる" これに尽きました。
目ぼしいコードの変数名や構造体名、宣言などを想像して検索をかけまくります。
例えば オプション 'c' を探す場合
github.devのWebベースエディターを使ってgrepします。
ping.cファイルにcase文を使ってオプションの制御を行っているであろう箇所を発見しました。
以下の画像では見えていませんが、オプションに使われる文字以外の値はdefault処理によって、usageを表示する仕組みになっていました。
また、親処理によって、オプションの引数エラーはgetopt関数によって制御されており、エラー文を標準出力していました。
(case文で書かれている)
getopt関数のエラーメッセージ
次に見つけた"strtol_or_err"について調査を進めます。
iputils_common.cファイルに詳細が見つかりました。
機能としては以下の通りです。
1. 受け取った数値を引数として、string型からlong型へ型変換をしている
2. 最大値がLONG_MAXの値以下であれば引数として受け取れる
3. cオプションの後の引数がない場合は、親の処理にあるgetopt関数によって、
制御されていることがわかりました。
LONG_MAXはC言語のlimits.hに定義してあり、
long型であり、以下を最大値としている。
- 32bit環境であれば 2147483647
- 64bit環境であれば、9223372036854775807
先程の調査によって、cオプションで受け取れる最大値とそれ以外の処理がわかりました。
そして、pingコマンドを実行している箇所を探します。
"npackets" でgrepをかけると、ping_common.cの600行目に怪しい箇所が見つかりました。
処理の内容について
for文でループ処理があり、送信完了カウントを表す"nreceived"と、送信に関するエラーカウントを表す"nerrors"を足して、
"npackets" より多い場合、ループを抜ける処理でした。
改造する
pingコマンドの動作する箇所とオプションを制御する箇所を見つけることができたので、ソースコードの改造に移ります。
やることは至ってシンプルで、以下のコードをping_common.cの596行目に書き足すだけです。
/* MODIFIED PING COUNT*/
if (!(rts->npackets)){
rts->npackets = 4;
}
npacketsが空の場合に4を代入することによって、cオプションが指定されていない場合でも、4回だけECHO_REQUESTを送信することになります。
また、IPv6のpingコマンドも問題なくIPv4同様に動作を確認しました。
使ってみる
実装したコードを自分の環境で動作させるには3ステップ必要です。
①自作コマンドをインストールする
githubからソースファイルをクローンする
git clone https://github.com/s7fy/custom_iputils.git
②インストールしてある既存のpingコマンドを無効化
pingコマンドが格納されている環境変数を確認する
which ping
既存のpingコマンドの名前を変える
sudo mv /usr/bin/ping /usr/bin/ping.bak
③ビルドをする
以下のリポジトリから自身のLinuxディストリビューションを選択し、スクリプトを実行
https://github.com/iputils/iputils/tree/master/ci
ビルドコマンドを叩く
sudo ./configre && sudo meson build
cd builddir && meson install
参考文献
オリジナルpingコマンドのリポジトリ: https://github.com/iputils/iputils
改造pingコマンドのリポジトリ: https://github.com/s7fy/custom_iputils
ping コマンド - IBM Documentationより: https://www.ibm.com/docs/ja/aix/7.1?topic=p-ping-command
【C言語/C++】データ型の最大値と最小値の一覧【32/64bit環境 limits.h/stdint.h】より: https://marycore.jp/prog/c-lang/data-type-min-max-values/