Using PTYs to fool getpass()
This is an article that I had posted in my livejournal on 4th-May-2006 03:08 pm. I’m trying to migrate the most valuable stuff to wordpress.
Today we’ll discuss the getpass() library function and the hurdles it presents for a system administrator for system automation. The usual bash pipe (‘|’) wont help us in providing password for tools like ssh, ftp, su, etc. The main reason is the way in which getpass works to get the password from the terminal. Unlike other library routines like getchar() or scanf() which read from stdin, this one opens the /dev/tty to read the user input.
The only solution been provided to overcome this is to create pseudo terminals(pty) and run your application in that. One of the most useful of the various functions used for this is forkpty(). Yes, here I’m talking about writing your own program to create a new pty, fork and run its child in that pty, and exec the application(like ssh, ftp,…) in the child. You will get a file descriptor which can be used to read or write data to the pty(ie, the application i/o). Below is given a program that tries to make a connection between you and your application.
// ptymagic.c
#include <pty.h>
#include <utmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int readtunnel(int pty) // thread for reading from appl
{
char ch;
while(read(pty,&ch,1) != -1)
write(1,&ch,1);
}
int writetunnel(int pty) // thread for writing to appl
{
char ch;
while(read(0,&ch,1))
write(pty,&ch,1);
}
main(int argc, char **argv)
{
int pty,child;
int ret;
pthread_t pread,pwrite;if(argc < 2)
{
exit(-1);
}
child = forkpty(&pty,0,0,0);
if(!child)
{
struct termios tios;tcgetattr(0, &tios);
tios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
tios.c_oflag &= ~(ONLCR);
tcsetattr(0, TCSANOW, &tios);execv(argv[1],&argv[1]);
exit(-1);
}
if(child == -1)
exit(-1);
read(pty,&ret,1); // wait till the child has outputted atleast one character
write(1,&ret,1);pthread_create(&pread,0,readtunnel,pty);
pthread_create(&pwrite,0, writetunnel,pty);pthread_join(pread,0);
wait(&ret);
if(ret >= 0 && ret <= 255)
exit(ret);
exit(-1);
}
Compile the program as:
gcc -l pthread -l util -o ptymagic ptymagic.c
And try to run as:
echo “Your_Root_Password” | ./ptymagic su -c “cat /etc/shadow”
and see the magic.
Here, the defect is that we have to write a c program for every different kind of application which is going to be a tedious task. A better alternative is also there about which I’ll explain later.
Till then,
BYE.