「サーバーの動きが少し重い」「見覚えのないログが残っている」——そんなとき、多くの人はプロセスやポートは疑ってもsystemd-timer(cron代替の定期実行の仕組み)までは見ません。しかし2026年は、ローカル特権昇格の脆弱性を突いてroot権限を奪った後、cronではなくsystemd-timerに常駐処理を仕込むケースが増えています。この記事ではsystemctl list-timersを使い、身に覚えのないタイマー登録をUbuntu/Debian環境で自分の手で洗い出す方法を、出力例つきで具体的に解説します。

なぜ2026年8月、systemd-timerを疑う必要があるのか

2026年に入ってから、Linuxカーネルのローカル特権昇格(LPE)脆弱性の報告が相次いでいます。代表的なものだけでも次の通りです。

  • Copy Fail(CVE-2026-31431):2026年4月29日公表。暗号化サブシステムの欠陥で、非特権ユーザーがroot権限を取得できる。2017年以降の主要ディストリ(Ubuntu 24.04 LTS、Debian、Fedora等)に影響
  • GhostLock(CVE-2026-43499):15年間カーネル内に潜んでいたuse-after-free脆弱性。ログインユーザーがrootを取得しコンテナを脱出できる可能性
  • Januscape(CVE-2026-53359):2026年7月6日公表。KVM/x86の脆弱性で、仮想マシンのゲストからホストへ脱出しroot権限でコマンド実行が可能。すべてのUbuntuリリースに影響

これらはいずれも「侵入経路」というより「侵入後にroot権限を奪う」ための脆弱性です。root権限を奪った攻撃者が次にやることの一つが、再起動や定期実行で処理を仕込む永続化(persistence)です。cronは監視対象として広く知られるようになったため、Ubuntu/Debianの標準機能であるsystemd-timerに紛れ込ませる手口が実務では警戒されています。まずはこの1点に絞って、自分の環境を点検します。

systemctl list-timersで登録済みタイマーを全部洗い出す

以下のコマンドは、今のシステムに登録されている定期実行の予定を一覧表示します。sudoは不要で、設定変更も一切行いません。

systemctl list-timers --all --no-pager

--allを付けないと現在アクティブなものしか出ないため、無効化されて潜んでいるタイマーを見逃します。--no-pagerは出力を折り返さず全部表示するオプションです。

出力例と見るべき列

NEXT                         LEFT          LAST                          PASSED    UNIT                          ACTIVATES
Wed 2026-08-26 09:17:00 JST  42min left    Tue 2026-08-25 09:17:03 JST   14h ago   apt-daily.timer               apt-daily.service
Wed 2026-08-26 12:23:16 JST  3h 48min left n/a                           n/a       snap.snapd.snapd-snap.timer   snap.snapd.snapd-snap.service
Thu 2026-08-27 00:00:00 JST  14h left      Wed 2026-08-26 00:00:00 JST   9h ago    logrotate.timer               logrotate.service
Wed 2026-08-26 09:20:00 JST  45min left    Tue 2026-08-25 09:20:01 JST   14h ago   sysupd-check.timer           sysupd-check.service

見るべきはUNIT列(タイマー名)とACTIVATES列(実際に実行されるサービス名)です。正常な環境ではapt-daily.timer(パッケージ一覧更新)、apt-daily-upgrade.timer(自動アップグレード)、logrotate.timer(ログ整理)、fstrim.timer(SSDの最適化)、man-db.timer(manページ索引更新)、Ubuntuならsnap.snapd.*.timerfwupd-refresh.timerua-timer.timer(Ubuntu Pro関連)あたりが並びます。上記の例で言えば、最後のsysupd-check.timerのようにUbuntu標準に存在しない、それらしく紛らわしい名前が混じっていたら要確認です(これは説明用の架空の名前で、実在のマルウェア名ではありません)。判断基準は次章にまとめます。

不審なタイマーの中身をservice・スクリプトまで追いかける

名前だけでは判断できないため、そのタイマーが実際に何を実行するのかを確認します。

systemctl cat sysupd-check.service

これはユニットファイルの中身(設定ファイル)をそのまま表示するコマンドで、変更は行いません。出力のExecStart=行が実行内容です。

[Service]
ExecStart=/bin/bash /var/tmp/.cache/update.sh
User=root

ここで異常と判断する具体的なポイントは次の3つです。

  • 実行パスが/tmp/var/tmp/dev/shm・隠しディレクトリ(.cacheなど)を指している——正規の管理スクリプトは通常/usr/local/bin/opt配下に置かれる
  • User=rootなのに、そのユニットファイル自体がroot以外の書き込み権限を持つ場所にある
  • ユニットファイルの設置場所が/etc/systemd/system/でも/usr/lib/systemd/system/でもない

設置場所は次のコマンドで確認します。

systemctl show sysupd-check.timer -p FragmentPath

正常なら/usr/lib/systemd/system/xxx.timer(パッケージ提供)か/etc/systemd/system/xxx.timer(管理者が意図的に設定)のどちらかです。スクリプトの中身も確認します。

cat /var/tmp/.cache/update.sh

ここでcurlwgetで外部URLからファイルを取得して直接実行する記述、base64でエンコードされた読めない文字列、見慣れないIPアドレスへの通信が含まれていれば、悪用の可能性が高いと判断してよいレベルです。逆に、日本語や英語のコメントがあり、社内サーバーへのバックアップ処理など内容が読んで理解できるものは、誰かが業務用に設定した正規のタイマーである可能性が高いです。

正規のタイマーと不審なタイマーの見分け方

チェック項目

正規である可能性が高い

不審と判断してよい

UNIT名

apt-daily / logrotate / fstrim / snap.* / fwupd-refresh / ua-timer など既知の名前

OS名やアップデートを装うが微妙に違う名前、意味不明な英数字の羅列

ユニットファイルの場所

/usr/lib/systemd/system/ または /etc/systemd/system/

それ以外、もしくはFragmentPathの取得自体に失敗する

ExecStartのパス

/usr/bin, /usr/local/bin, /opt 配下

/tmp, /var/tmp, /dev/shm, 隠しディレクトリ

スクリプトの中身

読んで処理内容が理解できる、社内向けコメントがある

外部URLへのcurl/wgetと即実行、base64化された文字列

登録者の心当たり

自分や同僚が設定したと確認できる

誰も設定した覚えがない

1つでも「不審」列に当てはまるからといって即座に攻撃と断定する必要はありません。社内の運用チームが監視エージェントなどを独自に配置している場合もあるため、まずは同僚や過去の作業記録に心当たりがないか確認し、それでも不明なものだけを次のステップで対処します。

不審と判断した場合の停止と、元に戻す手順

不審なタイマーを見つけても、いきなり削除する必要はありません。まずは無効化(次回以降の実行を止める)だけで十分です。sudoが必要です。

sudo systemctl disable --now sysupd-check.timer

--nowを付けると現在の実行も即座に停止し、かつ次回起動時にも自動起動しなくなります。誤って正規のタイマーを止めてしまった場合は、次のコマンドで元通りに戻せます。

sudo systemctl enable --now sysupd-check.timer

より強く止めたい場合はmaskを使うと、他のサービスから依存されていても起動できない状態にできます(元に戻すのはunmask)。

sudo systemctl mask sysupd-check.timer   # 強制停止
sudo systemctl unmask sysupd-check.timer # 元に戻す

スクリプト本体は、証拠として残しつつ実行させないために削除ではなく隔離することをおすすめします。

sudo mkdir -p /root/quarantine
sudo mv /var/tmp/.cache/update.sh /root/quarantine/

ユニットファイル自体を消す場合も同様に、rmではなく一旦別フォルダへ退避してからsudo systemctl daemon-reloadを実行してください。本当に悪用の痕跡だった場合は、rootを奪われた経路(SSH設定やsudo権限の穴)も併せて点検する必要があります。関連する点検記事としてsudo -lとNOPASSWDを点検2026年8月版UFWとiptables突き合わせで設定漏れ確認2026も併せて確認しておくと、侵入経路側の見落としを減らせます。

ディストリによる違い

本記事の手順はUbuntu 24.04 LTS・Debian 12.15(2026年7月11日リリース)を含む、systemdを採用するディストリで共通して使えます。ただしタイマー名は環境によって異なり、UbuntuにはSnap関連(snap.snapd.*.timer)やUbuntu Pro関連(ua-timer.timer)がありますが、Debianには標準で存在しません。RHEL/Fedora系ではdnf-makecache.timerのようにパッケージ管理コマンド名を反映した名前になります。AlpineなどOpenRCベースのディストリはsystemdを使わないため、本記事のコマンドはそのままでは動作しません。

今回の点検はコマンドを打つだけで設定変更を伴わず、無効化もenable --now一発で元に戻せる範囲にとどめています。まずはsystemctl list-timers --all --no-pagerを実行し、見慣れないUNIT名がないかを確認するところから始めてください。1つでも心当たりのないタイマーがあれば、ExecStartのパスとスクリプトの中身を確認し、判断に迷う場合は無理に削除せず隔離だけして様子を見るのが安全です。定期的にこの一覧を見る習慣をつけておくと、次に同じ点検をするときの差分にすぐ気付けるようになります。