この記事について
TryHackMeの「Linux Shells」というルームで学んだ内容を、Task単位でまとめたノートです。Cyber Security 101の「Command Line」モジュールに属するルームで、Linuxのシェル(shell)との対話・代表的なシェルの種類・シェルスクリプトの書き方を一通り扱っています。後半には、認証スクリプトを読み解く演習と、ログファイルからキーワードを探す実践ラボが含まれています。
課題の設問や答えはここには含めていません。各Taskで学んだコマンドやスクリプトの書き方、その背景にある考え方を、自分の理解として整理したものです。
Task 1: シェルとは何か、なぜ学ぶのか
シェル(shell)は、ユーザーが打ち込んだコマンドを解釈して、OSの中核であるカーネル(kernel)に伝え、結果を返してくれる仲介プログラムです。「殻」という名前は、カーネルを取り囲む外側の層というイメージから来ています。
ルームでは、レストランのたとえで説明されていました。メニューから注文してウェイターに運んでもらうのがGUI(グラフィカルユーザーインターフェース)、自分でキッチンに入って調理するのがCLI(コマンドラインインターフェース)、そのときレシピを教えてくれるのがシェル、という整理です。CLIで操作すると、作業に対してより細かい制御が効き、リソース消費も小さく済みます。
セキュリティの学習を進めると、GUIが用意されていないリモートのサーバーに、SSHの先の真っ黒な画面だけで向き合う場面が何度も出てきます。シェルの扱いに慣れることが、その土台になると改めて認識しました。
学んだこと
ターミナル(terminal)とシェル(shell)は別物だという点を、ここで整理できました。ターミナルは文字を入力・表示する「窓」であるアプリで、その窓の中で実際にコマンドを処理しているのがシェルです。普段は一体のものとして扱いますが、役割が違います。
Task 2: シェルの基本操作
演習用マシンへの接続手段が3通り紹介されていました。ページ内の分割画面(Split View)でGUIとして使う方法、AttackBoxからSSHで入る方法、自分の端末をVPN接続してそこからSSHで入る方法です。この「AttackBoxからSSHでターゲットに入る」流れは、他のルームでも繰り返し登場する基本操作でした。
基本コマンドは、Linux Fundamentalsで一度触れたものの復習です。
-
pwd(Print Working Directory): 今いるディレクトリの絶対パスを表示します。 -
cd <dir>(Change Directory): ディレクトリを移動します。cd ..で1つ上、引数なしのcdでホームに戻ります。 -
ls(List): ディレクトリの中身を一覧表示します。ls -lで詳細表示、ls -aで隠しファイルも表示します。 -
cat <file>(conCATenate): ファイルの中身を表示します。もともとは複数ファイルを連結するコマンドで、それが名前の由来です。 -
grep <語> <file>(Global Regular Expression Print): ファイルの中から、指定した単語やパターンを含む行だけを抜き出します。
プロンプトのuser@tryhackme:~$という表示は、ユーザー名@ホスト名:現在地という構成です。末尾の記号は、一般ユーザーだと$、rootだと#になります。この違いは、今どの権限で操作しているかをひと目で判断する手がかりになります。
学んだこと
grepは、大きなファイルや大量のログから目的の情報を絞り込む、調査の中心になるコマンドだと感じました。この後のTask 6の実践ラボでも、まさにgrepを使うスクリプトが題材になっています。単体で覚えるだけでなく、grep -r(ディレクトリを再帰的に検索)やgrep -i(大文字小文字を区別しない)のようなオプションと合わせて引き出しを増やしていきたいところです。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
| SSH(Secure Shell) | 暗号化された遠隔ログイン用のプロトコル |
| working directory(作業ディレクトリ) | シェルが「今いる」ディレクトリ。相対パスの起点になる |
| grep | ファイルから語・パターンを含む行を抜き出すコマンド |
prompt($ / #) |
入力待ちを示す記号。$は一般ユーザー、#はroot |
Task 3: Linuxシェルの種類
Linuxには複数のシェルがあり、それぞれ特徴が違います。今使っているシェルはecho $SHELLで確認でき、インストール済みの一覧は/etc/shellsというファイルに書かれています。デフォルトシェルを恒久的に変えるにはchsh -s <シェルのパス>(chsh は change shell)を使います。
ルームで比較されていたのは次の3つです。
-
Bash(Bourne Again Shell): ほとんどのディストリビューションのデフォルトです。
sh・ksh・cshといった古いシェルの機能を取り込んだ強化版という位置づけで、スクリプトの互換性とドキュメントの豊富さが強みです。Tabキーによる補完、historyコマンドや矢印キーによる履歴の呼び出しも備えています。 - Fish(Friendly Interactive Shell): 名前のとおり使いやすさを重視したシェルです。構文がシンプルで、コマンドのスペルを自動修正してくれます。構文ハイライト(syntax highlighting、コマンドの各部分を役割ごとに色分けする機能)が最初から組み込まれているのも特徴です。ただしBashとは構文が異なるため、Bash向けのスクリプトはそのままでは動きません。
-
Zsh(Z Shell): モダンなシェルで、高度なタブ補完と本格的なスクリプト機能を持ちます。
oh-my-zshというフレームワークで大きくカスタマイズできます。Fishと同じくスペルの自動修正があり、macOSのデフォルトシェルでもあります。
学んだこと
echo $SHELLが返すのは「ログイン時のシェル」であって、「今まさに動いているシェル」とは限らない、という点に気づきました。たとえばBashからzshと打って一時的にZshに入っても、$SHELLの値は変わりません。実行中のシェルを厳密に知りたいときはecho $0やps -p $$を使います。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
| environment variable(環境変数) | シェルやプログラムの動作を決める名前付きの値。$SHELL, $PATHなど |
/etc/shells |
ログインシェルとして有効なシェルのパス一覧ファイル |
| chsh(change shell) | デフォルトログインシェルを変更するコマンド |
| syntax highlighting | コマンドの要素を役割ごとに色分けして表示する機能 |
| oh-my-zsh | Zshの設定・プラグイン・テーマを管理するフレームワーク |
Task 4: シェルスクリプトの構成要素
シェルスクリプトは、要するにコマンドを並べたファイルです。繰り返す作業を1本のファイルにまとめておけば、実行1回で全部のコマンドが順に走ります。作業の自動化(automation)が目的です。
作成の流れは4ステップでした。
- エディタでファイルを作る(
nano first_script.shなど)。拡張子.shは慣習で、必須ではありません。 - 1行目にシバン(shebang)
#!/bin/bashを書く。#!に続けてインタプリタ(解釈・実行するプログラム)の絶対パスを指定し、「このスクリプトはbashで実行する」とOSに伝えます。 - 実行権限を付ける(
chmod +x first_script.sh)。 -
./first_script.shで実行する。
4番目で./を付けるのは、「今いるディレクトリにあるファイルを実行せよ」と明示するためです。./なしでスクリプト名だけを打つと、シェルは環境変数PATHに登録されたディレクトリの中だけを探します。カレントディレクトリは通常PATHに含まれないので、そのままではスクリプトが見つからずエラーになります。
学んだ構成要素は次のとおりです。
-
変数(variable):
name=値で代入します。=の前後にスペースを入れてはいけない点が独特です。参照するときは$nameと書きます。read nameはユーザーの入力を1行読み取ってnameに格納するコマンドです。 -
ループ(loop):
for i in {1..10}; do ... doneで、iを1から10まで変えながらdo〜doneの間を繰り返します。{1..10}はブレース展開(brace expansion)というbashの記法です。 -
条件分岐(conditional statement):
if [ 条件 ]; then ... else ... fiという形です。[ ]は実はtestというコマンドで、[の後と]の前にスペースが必須です。fiはifを逆さに綴った終端キーワードです。 -
コメント(comment):
#から行末までは無視されます(1行目の#!だけは特別扱い)。意図や前提を書き残すと、後から読む自分や他人が助かります。
学んだこと
[ ]の中はスペースが必須、というルールで最初つまずきました。["$name"や"Stewart"]のように詰めて書くとエラーになります。[がコマンドである、と理解すると腑に落ちます。コマンド名と引数の間にはスペースがいる、というだけの話でした。
比較演算子も、文字列は=(bashでは==も可)、数値は-eq・-ne・-lt・-gtと使い分けます。混同するとうまく動きません。
ついでに、実行権限まわりのrwxも整理しました。Linuxのファイル権限はr(read、読み取り)・w(write、書き込み)・x(execute、実行)の3種類が、所有者(owner)・グループ(group)・その他(others)の3セットに対して設定されます。数字で表すときはr=4・w=2・x=1として足し算し、chmod 755なら「所有者はrwx、他はr-x」という意味です。chmod +xは、そこに実行権限だけを足す書き方でした。なお、このrwxの手前には特殊権限という枠があり、中でもSUID(Set User ID)は権限昇格(privilege escalation)の調査で最初に探すポイントだと紹介されていました。ここでは名前を覚えておくにとどめます。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
shebang(#!) |
スクリプト先頭でインタプリタを指定する記法。#!/bin/bashなど |
chmod +x |
ファイルに実行権限を追加するコマンド |
$PATH |
コマンドを探索するディレクトリの一覧を持つ環境変数 |
read |
標準入力から1行読み取って変数に格納するコマンド |
test / [ ]
|
条件式を評価するコマンド。角かっこの内側はスペース必須 |
-eq / =
|
数値の等値比較 / 文字列の等値比較 |
Task 5: 総合演習「ロッカー・スクリプト」
Task 4で学んだ変数・ループ・条件分岐を、1本のスクリプトに組み合わせる演習です。銀行のロッカーを題材に、ユーザー名・会社名・PINを順に尋ね、3つすべてが正しければ認証を通す、という認証スクリプトを読み解きました。
構造として印象に残ったのは2点です。
-
for i in {1..3}のループの中でif/elif/elseを使い、iが1のときはユーザー名、2のときは会社名、それ以外(3)のときはPIN、というように入力項目を切り替えていました。elifは「else if」の短縮で、iの比較には数値用の-eqを使います。 - 最後の判定は
if [ 条件A ] && [ 条件B ] && [ 条件C ]という形で、&&(論理AND)で3つの条件をつなぎ、すべて真のときだけ認証成功にしていました。1つでも違えばelse側の拒否メッセージになります。「どれか1つ合えば通す」にしたいなら||(論理OR)を使うことになります。
学んだこと
このスクリプトは学習用なので、実運用ではやってはいけない書き方の見本でもあります。正解のPINがスクリプトの中に平文(plaintext)で書かれていて、ソースを読めば誰でも分かってしまいます。これはハードコードされた資格情報(hardcoded credentials)と呼ばれる典型的な弱点です。実務では、秘密の値はハッシュ化(hashing)して保存し、比較もハッシュ同士で行います。侵入テストの視点では、こういうスクリプトを見つけたら中の資格情報を真っ先に確認する、という着眼点につながります。設問はスクリプトを丁寧に読めば解ける作りになっていました。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
elif |
else ifの短縮形。ifに複数の条件分岐を追加する |
&& / ||
|
論理AND / 論理OR。条件やコマンドを連結する |
| hardcoded credentials | ソースコードに直接書き込まれたパスワードや鍵などの秘密情報 |
| hashing | データを不可逆な固定長の値に変換する処理。パスワード保存の定石 |
Task 6: 実践ラボ
演習用マシンのホームディレクトリに置かれたスクリプトを題材にした実践パートです。このスクリプトは、指定したディレクトリ内の.logファイルすべてから特定のキーワードを検索するもので、実行前にスクリプト内の空のダブルクォート""を正しい値で埋める必要がありました。ヒントは「クォートの中にスペースを残さない」、つまり" "ではなく"値"と詰めて書く、というものです。
作業の流れは次のとおりです。
- Task 2の手順で演習用マシンを起動し、一般ユーザーでログインする。
-
sudo suでrootになる。sudo(superuser do)は続くコマンドだけを管理者権限で実行するコマンド、su(switch user)はユーザーを切り替えるコマンドで、ユーザー名を省略するとrootになります。この組み合わせでrootのシェルに入り、プロンプトが$から#に変わります。 - スクリプトの空クォートを、指示された検索キーワードと検索対象ディレクトリで埋める。
- 実行権限を確認して実行し、出力を読む。
rootになることが推奨されていたのは、検索対象の/var/log(システムやサービスのログが集まるディレクトリ)の中に、一般ユーザーには読み取り権限がないファイルがあるためです。権限がないとgrepがそのファイルを開けず、検索結果が不完全になります。
学んだこと
sudoとsuの違い、そしてsudo suでrootのシェルに入るという操作は、権限昇格(privilege escalation)の最も基本的な形です。/var/logはインシデント調査やフォレンジックで最初に見る場所で、そこをgrepで横断検索する(イメージとしてはgrep -r <語> /var/log)という発想は、実務でもそのまま使える動作だと感じました。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
sudo(superuser do) |
続くコマンドだけを管理者権限で実行する |
su(switch user) |
別ユーザーに切り替える。引数なしでroot |
| privilege escalation(権限昇格) | 一般権限から管理者権限へ権限を引き上げること |
/var/log |
システム・アプリのログが格納される標準ディレクトリ |
grep -r |
ディレクトリ配下を再帰的に検索するオプション |
Task 7: まとめ
このルームでは、シェルとの対話 → シェルの種類 → シェルスクリプト → 実践、という流れを一通り経験しました。基本コマンド(pwd / cd / ls / cat / grep)、3つのシェルの違い(Bash / Fish / Zsh)、スクリプトの4要素(変数 / ループ / 条件分岐 / コメント)、そしてsudo suでrootになって/var/logを調べる実践まで、断片だったコマンドの知識が「スクリプトとしてつながる」感覚を持てました。
学んだこと
次に触れると効果的だと感じた項目を挙げておきます。回数の決まっていない繰り返しに使うwhileループ、1つの値を複数パターンと照合するcase文、処理に名前を付けて再利用する関数(function)、スクリプトに渡した引数を参照する位置パラメータ($1・$2・$@)、直前のコマンドの成否を表す終了ステータス($?)、そしてgrepの各種オプション(-r・-i・-n・-E)あたりです。ここを押さえると、スクリプトで書ける範囲が一気に広がりそうです。
関連キーワード
| キーワード(英語) | 説明 |
|---|---|
whileループ |
条件が真の間くり返すループ。回数が決まっていない処理に使う |
case文 |
1つの値を複数パターンと照合する多分岐構文。終端はesac
|
positional parameters($1, $2, $@) |
スクリプトに渡した引数を参照する変数 |
exit status($?) |
直前のコマンドの終了コード。0が成功、非0が失敗 |