Skip to content

Instantly share code, notes, and snippets.

@webstrand
Last active November 12, 2019 14:51
Show Gist options
  • Save webstrand/a1b926f576c9fbf4ed7f159aea211f1a to your computer and use it in GitHub Desktop.
Save webstrand/a1b926f576c9fbf4ed7f159aea211f1a to your computer and use it in GitHub Desktop.
A self-installing quine that can be piped to a perl binary over the network. Installs to /payload when running from STDIN, keeps STDIN open for interactivity.
#!/usr/bin/perl
BEGIN{B:{$_=<<'STRAP'; chomp; exit (eval() // exit print STDERR $@)}}
#line 4 "STDIN"
my $payload = "/tmp/payload";
last unless $0 eq "-";
my $F; do { local $^F=9999; open($F, '>', $payload) or die "$payload: $!" };
$payload //= "/proc/self/fd/" . fileno($F);
chmod(0744, $F) or die "$payload: $!";
$/="\n__END__\n";
print $F <<EVAL, scalar <STDIN> or die "$payload: $!";
#!/usr/bin/perl
BEGIN{B:{\$_=<<'STRAP'; chomp; exit (eval() // exit print STDERR \$@)}}
$_\nSTRAP
EVAL
use Fcntl; use Errno ':POSIX';
my $CHILD; pipe my $IN, my $OUT or die "pipe: $!";
unless(open($CHILD, "|-") // die "fork: $!") {
open STDIN, '<&', $IN or die "dup: $!";
exec 'perl', $payload, @ARGV;
}
close $IN; $OUT->autoflush(1);
my $flags = 0|(fcntl(STDIN, F_GETFL, 0) or die "fcntl GETFL: $!");
fcntl(STDIN, F_SETFL, $flags | O_NONBLOCK) or die "fcntl SETFL: $!";
while(read STDIN, my $data, 8192) { print $OUT $data }
fcntl(STDIN, F_SETFL, $flags) or die "fcntl SETFL: $!";
vec(my $vec = '', fileno(STDIN), 1) = 1;
vec($vec, fileno($OUT), 1) = 1;
for(my $readable;;) {
unless(select($readable=$vec, undef, undef, undef)) {
redo if not $! || $! == EINTR;
die "select: $!";
}
last if vec($readable, fileno($OUT), 1);
if(vec($readable, fileno(STDIN), 1)) {
if(sysread(STDIN, my $data, 8192)) {
print $OUT $data or die "write: $!";
}
else {
last unless $!;
redo if $! == EAGAIN || $! == EWOULDBLOCK || $! == EINTR;
die "read: $!";
}
}
}
close STDIN;
close $OUT or die "write: $!";
close $CHILD;
exit $? >> 8;
STRAP
STDOUT->autoflush(1);
print "Name? "; my $name = <STDIN>; chomp $name;
print "Hello, $name!\n";
print "Name? "; $name = <STDIN>; chomp $name;
print "Hello, $name!\n";
# Required for interactivity
# ./sipe stdin_quine.pl /dev/stdin | ssh remote perl
__END__
@webstrand
Copy link
Author

Leave $payload undefined to install to an anonymous file.
__END__ is unnecessary if STDIN isn't read from in the script body.
Data following "\n__END__\n" is treated as interactive STDIN when the script is executing over a pipe. Otherwise it is ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment