|
package main |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"io/ioutil" |
|
"log" |
|
"os" |
|
"os/exec" |
|
) |
|
|
|
func main() { |
|
var stdout, stderr bytes.Buffer |
|
// the idea is to 'secret' to the path provided |
|
// in argument 1 ("testprog0" is arg0 when sh -c). |
|
// we write to /proc/self/fd/<fd> to trick a program (tssnvread) |
|
// to avoid writing to a file on the filesystem. |
|
// so our 'sh' program here mimics a call to 'tssnvread -of <path>' |
|
// |
|
// One of the hacky parts here is that we just "know" the |
|
// inherited fd will be number 3, as golang closes all but |
|
// stdin, stdout, stderr. |
|
cmd := exec.Command("sh", "-ec", ` |
|
out=$1; shift; |
|
echo "message on stdout: will write to $out" |
|
echo "message on stderr: will write to $out" 1>&2 |
|
ls -l /proc/self/fd/ |
|
echo "secret" >"$out" |
|
exit 0 |
|
`, |
|
"testprog0", |
|
fmt.Sprintf("/proc/self/fd/%d", 3), |
|
) |
|
|
|
cmd.Stdout = &stdout |
|
cmd.Stderr = &stderr |
|
|
|
pipeRead, pipeWrite, err := os.Pipe() |
|
if err != nil { |
|
log.Fatalf("os.Pipe() failed: %s\n", err) |
|
} |
|
defer pipeRead.Close() |
|
defer pipeWrite.Close() |
|
|
|
cmd.ExtraFiles = []*os.File{pipeWrite} |
|
|
|
// the order of the Close calls is important. |
|
// copy the implementation of cmd.StderrPipe() which does the |
|
// close of the pipeWrite after Start and close of pipeRead after Wait. |
|
if err := cmd.Start(); err != nil { |
|
log.Fatalf("start failed: %s\n", err) |
|
} |
|
pipeWrite.Close() |
|
|
|
data, err := ioutil.ReadAll(pipeRead) |
|
if err != nil { |
|
log.Fatalf("read failed: %s\n", err) |
|
} |
|
|
|
if err := cmd.Wait(); err != nil { |
|
fmt.Printf("stdout: %s", string(stdout.Bytes())) |
|
fmt.Printf("stderr: %s", string(stderr.Bytes())) |
|
log.Fatalf("Wait failed: %s", err) |
|
} |
|
pipeRead.Close() |
|
|
|
fmt.Printf("got the data!: %s", data) |
|
fmt.Printf("stdout: %s", string(stdout.Bytes())) |
|
fmt.Printf("stderr: %s", string(stderr.Bytes())) |
|
|
|
} |