clinuxfifo

Linux program is able to read from STDOUT under terminal


Looks like it is possible to read from file descriptor 1 under Linux. I've attached example code below. I can interact with it using keyboard and provide valid password.

Problem is, that I'm unable to execute it without user involvement. For example:

echo "123" | ./stdout_as_stdin
./stdout_as_stdin < <(echo "123")

When I change line:

read(1, buff, buff_size-2); // reading from STDOUT

to

read(0, buff, buff_size-2); // reading from STDIN

input redirection is working fine.

How to perform Program Interaction from other bash/python script without user involvement in described scenario?

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
    const int buff_size = 1024;
    char buff[buff_size];
    char p_1[] = "123";
    char p_2[] = "abc";
    printf("Enter secret password (%s):\n", p_1);
    memset(buff, 0, buff_size);
    read(1, buff, buff_size-2); // reading from STDOUT
    if ((strlen(buff) == strlen(p_1) + 1) && (memcmp(p_1, buff, strlen(p_1)) == 0)) {
        printf("Secret token: %s\n", p_2);
        return 0;
    } else {
        printf("Failed\n");
        return 1;
    }
}

I'm looking for hack/solution which allows me to automate execution of program which reads data from STDOUT instead of STDIN.

Edit

To make something like this work, you need to connect the program's standard output to a file (in the broad sense) that will both provide the wanted input and accept the output delivered to it.

Thank you @john-bollinger for this precious information. I was able to solve my issue.

Bash

mkfifo ./my_fifo
exec ./stdout_as_stdin 1<> ./my_fifo &

I can interact with program using fifo file.

Python

os.mkfifo('./my_fifo', 0o600)
fd = os.open('./my_fifo', os.O_RDWR)
p = pwn.process(argv = ['./stdout_as_stdin'], stdout = fd)

Followed by the os.read(fd, ...) and os.write(fd, ...) calls.

Why?

Looks like I wasn't clear enough. I'm not writing program which act in a such way. Provided example showed that particular behavior is possible. I don't know why most of the feedback moved discussion away from "how to tackle such scenario". Anyway, thanks for the valuable comments.


Solution

  • Looks like it is possible to read from file descriptor 1 under Linux.

    You seem to be making an unwarranted generalization. Clearly, what you observed is possible under some circumstances. It definitely is not possible under other circumstances, however, such as when the standard output is connected to a file open only for writing, or to one that doesn't even support reading, such as the write end of a pipe.

    Moreover, although there may be special cases -- even common ones -- in which you can read the same data from stdout that you could have read from stdin, in the general case, you cannot expect stdout to yield the same data that stdin does. Nor is it safe to assume, in general, that reading stdout will yield data that your program or any other wrote to the same file. Nor that it will yield any data at all.

    I'm unable to execute it without user involvement. For example:

    echo "123" | ./stdout_as_stdin
    ./stdout_as_stdin < <(echo "123")
    

    That's not at all surprising. In general, stdout is not equivalent to stdin. Cases where one or the other have been redirected are especially likely to demonstrate that.

    When I change line:

    read(1, buff, buff_size-2); // reading from STDOUT
    

    to

    read(0, buff, buff_size-2); // reading from STDIN
    

    input redirection is working fine.

    Redirection was working fine in both cases. What you need to grasp is that redirection demonstrates that your assumption that stdout can safely be treated as an alias of stdin is not well founded.

    How to perform Program Interaction from other bash/python script without user involvement in described scenario?

    Programs that expect to read data provided on their standard input should read it from their standard input, and not from anywhere else. Details depend on programming language, among other things, but the general rule is universal. This is especially true for programs that want to support input coming from a pipe or redirected from a file, which work fine on Linux as long as the program actually reads from its input.

    I'm looking for hack/solution which allows me to automate execution of program which reads data from STDOUT instead of STDIN.

    This is an ill-conceived idea, because a program such as you want to automate is ill conceived in the first place. Especially so for a program that also wants to write output to its stdout (otherwise you could probably just dupe the standard input onto the standard output).

    To make something like this work, you need to connect the program's standard output to a file (in the broad sense) that will both provide the wanted input and accept the output delivered to it. A socket or the client end of a pseudoterminal could serve. Then you would need to drive it from a wrapper program that feeds in the wanted input and does something with the output. But I'm not sure what you prove by rigging up something like this.