Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

sshのauthorized_keysのcommandでパイプは使えるか

authorized_keyscommand=オプションにパイプを含むコマンドを指定できるか実験。

command="find /home/satob -maxdepth 1 -name '*.sh' | xargs grep '#!'" ssh-ed25519 AAAAC3Nz... pipe@example.com

実行してみたらこんな感じ。問題なく実行できた。結局、内部では/etc/passwdで指定されたシェルが動いているから、ログインシェルでできることはcommand=でも可能みたい。

$ ssh -i id_pipe satob@localhost
/home/satob/sanitize1.sh:#!/bin/bash
/home/satob/sanitize2.sh:#!/bin/bash
/home/satob/sanitize4.sh:#!/bin/bash
/home/satob/sanitize3.sh:#!/bin/bash
Connection to localhost closed.

$0も参照できた。

command="echo $0" ssh-ed25519 AAAAC3Nz... shtype@example.com
$ ssh -i id_shtype satob@localhost
bash
Connection to localhost closed.

シェルは/etc/passwdで指定したものが使われる、という話は以下を参照。/sbin/nologinを指定しているユーザでもsshでトンネリングはできるが、command=は使えないことになる。 unix.stackexchange.com

rbashでディレクトリトラバーサルは防げない

satob.hatenablog.com

で挙げた

# cat authorized_keys
command="ls /$SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB....

$ ssh root@xxx.xxx.xxx.xxx -i ~/.ssh/com "tmp;hostname"
ls: /tmp;hostname: No such file or directory

みたいなケースで$SSH_ORIGINAL_COMMAND../とかを指定される問題の対策にrbashが使えないかと思って調べてみた。

$ echo $0
rbash
$ /bin/sh
rbash: /bin/sh: restricted: cannot specify `/' in command names
$ ./sanitize1.sh
rbash: ./sanitize1.sh: restricted: cannot specify `/' in command names
$ ls ../
satob

rbashで制限できるのは「実行プログラムのパスに/が含まれるケース」だけで、引き数に/が含まれるケースは制限してくれない。そのため、ディレクトリトラバーサルの防止には使えない。

OSSの脆弱性への対応が検討できないケースに関する考察

システムで利用しているOSS脆弱性が見つかったときの対応が検討できないの、なんでだろう?という気もするんだけど、

問:ある業務アプリケーションに組み込んでいたOSSに含まれていた既知の脆弱性を悪用され、情報セキュリティ事故が発生した。同様の事故に対する再発防止策として最も適切なものを選べ。

  • A: 脆弱性対策に漏れがないよう、AppScanなどの診断ツールを利用して、業務アプリケーションに対する脆弱性の確認を網羅的に実施する。
  • B: ソースコードが利用できる利点を生かし、OSSに対して静的解析を行うことで、既知の脆弱性がないか確認したうえで利用する。
  • C: NVDやJVNなどの脆弱性情報データベースを確認する頻度を上げ、アプリケーションに組み込んでいるOSS脆弱性が見つかった場合にはすぐに対策を検討する体制を整える。
  • D: OSS脆弱性脆弱性診断ツールでは摘出できないので、脆弱性の確認を手動で実施するようにテスト観点を追加する。

……みたいな問題が出たら誤答する人もいるだろうから、結局プロジェクトの中で誰かが気付いてあげるしかないのかもね。

ProcessBuilder freezes when you try to run a .bat containing PowerShell scripts

Background

By using the .bat file from here, you can run a PowerShell script by just click the .bat file.

reosablo.hatenablog.jp

Problem

When you are trying to run the .bat file from Java ProcessBuilder class like this, the .bat file will never finish and ProcessBuilder will freeze.

package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {
        List<String> list = new ArrayList<String>();
        list.add("c:/tmp/hoge.bat");
        ProcessBuilder pb = new ProcessBuilder(list);
        Process p = pb.start();
        p.waitFor();
        int returnValue = p.exitValue();
        System.exit(returnValue);
    }
}

You can run the .bat file from the command prompt correctly.

Cause

The PowerShell script in .bat file uses the $input automatic variable. It reads input from STDIN, so it will wait for input from STDIN.

You can reproduce this problem with a .bat file like this:

powershell.exe -Command "$input"

Solution

  • You can use another .bat file that doesn't use $input: www.pg-fl.jp
  • If you want to use PSCommandPath and $PSScriptRoot in the PowerShell script, you can do like this:
@setlocal enableextensions enabledelayedexpansion & set "THIS_PATH=%~f0" & PowerShell.exe -Command "& (iex -Command ('{$PSCommandPath=\"%~f0\"; $PSScriptRoot=\"%~dp0"; #' + ((gc '!THIS_PATH:'=''!') -join \"`n\") + '}'))" %* & exit /b !errorlevel!
  • You have to close STDIN when a PowerShell script in .bat file uses $input like:
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {
        List<String> list = new ArrayList<String>();
        list.add("c:/tmp/hoge.bat");

        ProcessBuilder pb = new ProcessBuilder(list);
        Process p = pb.start();
        p.getOutputStream().close();   // Close STDIN
        p.waitFor();
        int returnValue = p.exitValue();
        System.exit(returnValue);
    }
}

Eclipseの操作自動化プロジェクトの淘汰っぷりが凄い

Eclipseで、このプロジェクトのコンテキストメニューからこのプラグインのこの機能を実行して、実行構成で定義したこの処理を実行して……という作業をマクロ化したいんだけど(そしてよくありそうな話だと思うんだけど)、プロジェクトが産まれては消えているように見える。一体どうなってるんだ?

UIテスト用のツールを使う方がまだ望みがあるのかな。試してみる価値はあると思うけど、やっぱりどうしてこんなに種類があるんだ?