**Title**: Linenoise

.:: Linenoise ::.

Introduction | Phrack Staff |

Loopback | Phrack Staff |

Linenoise | Phrack Staff |

Phrack Prophile on Tiago | Phrack Staff |

OSX heap exploitation techniques | Nemo |

Hacking Windows CE (pocketpcs & others) | San |

Games with kernel Memory...FreeBSD Style | jkong |

Raising The Bar For Windows Rootkit Detection | sherri sparks & jamie butler |

Embedded ELF Debugging | ELFsh crew |

Hacking Grub for Fun & Profit | coolq |

Advanced antiforensics : SELF | ripe & pluf |

Process Dump and Binary Reconstruction | ilo |

Next-Gen. Runtime Binary Encryption | zvrba |

Shifting the Stack Pointer | andrewg |

NT Shellcode Prevention Demystified | piotr |

PowerPC Cracking on OSX with GDB | curious |

Hacking with Embedded Systems | cawan |

Process Hiding & The Linux Scheduler | ubra |

Breaking Through a Firewall | kotkrye |

Phrack World News | Phrack Staff |

==Phrack Inc.== Volume 0x0b, Issue 0x3f, Phile #0x03 of 0x14 |=---------------------=[ L I N E N O I S E ]=---------------------------=| |=-----------------------------------------------------------------------=| |=------------------------=[ phrack staff ]=-----------------------------=| ...all that does not fit anywhere else but which is worth beeing mentioned in our holy magazine.... enjoy linenoise. 0x03-1 Analysing suspicious binary files by Boris Loza 0x03-2 TCP Timestamp to count hosts behind NAT by Elie aka Lupin 0x03-3 Elliptic Curve Cryptography by f86c9203 |=-------------------------=[ 0x03-1 ]=----------------------------------=| |=---------Analyzing Suspicious Binary Files and Processes---------------=| |=-----------------------------------------------------------------------=| |=-----------------------By Boris Loza, PhD------------------------------=| |=-------------------bloza@tegosystemonline.com--------------------------=| |=-----------------------------------------------------------------------=| 1. Introduction 2. Analyzing a 'strange' binary file 3. Analyzing a 'strange' process 4. Security Forensics using DTrace 5. Conclusion --[ Introduction The art of security forensics requires lots of patience, creativity and observation. You may not always be successful in your endeavours but constantly 'sharpening' your skills by hands-on practicing, learning a couple more things here and there in advance will definitely help. In this article I'd like to share my personal experience in analyzing suspicious binary files and processes that you may find on the system. We will use only standard, out of the box, UNIX utilities. The output for all the examples in the article is provided for Solaris OS. --[ Analyzing a 'strange' binary file During your investigation you may encounter some executable (binary) files whose purpose in your system you don't understand. When you try to read this file it displays 'garbage'. You cannot recognize this file by name and you are not sure if you saw it before. Unfortunately, you cannot read the binary file with more, cat, pg, vi or other utilities that you normally use for text files. You will need other tools. In order to read such files, I use the following tools: strings, file, ldd, adb, and others. Let's assume, for example, that we found a file called cr1 in the /etc directory. The first command to run on this file is strings(1). This will show all printable strings in the object or binary file: $ strings cr1 | more %s %s %s%s%s -> %s%s%s (%.*s) Version: 2.3 Usage: dsniff [-cdmn] [-i interface] [-s snaplen] [-f services] [-t trigger[,...]] [-r|-w savefile] [expression] ... /usr/local/lib/dsniff.magic /usr/local/lib/dsniff.services ... The output is very long, so some of it has been omitted. But you can see that it shows that this is actually a dsniff tool masquerading as cr1. Sometimes you may not be so lucky in finding the name of the program, version, and usage inside the file. If you still don't know what this file can do, try to run strings with the 'a' flag, or just '-'. With these options, strings will look everywhere in the file for strings. If this flag is omitted, strings only looks in the initialized data space of the object file: $ strings cr1 | more Try to compare this against the output from known binaries to get an idea of what the program might be. Alternatively, you can use the nm(1) command to print a name list of an object file: $ /usr/ccs/bin/nm -p cr1 | more cr1: [Index] Value Size Type Bind Other Shndx Name [180] |0 | 0| FILE | LOCL | 0 |ABS | decode_smtp.c [2198] |160348| 320| FUNC | GLOB | 0 | 9 | decode_sniffer Note that the output of this command may contain thousands of lines, depending on the size of the object file. You can run nm through pipe to more or pg, or redirect the output to the file for further analysis. To check the runtime linker symbol table - calls of shared library routines, use nm with the '-Du' options, where -D displays the symbol table used by ld.so.1 and is present even in stripped dynamic executables, and -u prints a long listing for each undefined symbol. You can also dump selected parts of any binary file with the dump(1) or elfdump(1) utilities. The following command will dump the strings table of cr1 binary: $ /usr/ccs/bin/dump -c ./cr1 | more You may use the following options to dump various parts of the file: -c Dump the string table(s). -C Dump decoded C++ symbol table names. -D Dump debugging information. -f Dump each file header. -h Dump the section headers. -l Dump line number information. -L Dump dynamic linking information and static shared library information, if available. -o Dump each program execution header. -r Dump relocation information. -s Dump section contents in hexadecimal. -t Dump symbol table entries. Note: To display internal version information contained within an ELF file, use the pvs(1) utility. If you are still not sure what the file is, run the command file(1): $ file cr1 cr1: ELF 32-bit MSB executable SPARC32PLUS Version 1, V8+ Required, UltraSPARC1 Extensions Required, dynamically linked, not stripped Based on this output, we can tell that this is an executable file for SPARC that requires the availability of libraries loaded by the OS (dynamically linked). This file also is not stripped, which means that the symbol tables were not removed from the compiled binary. This will help us a lot when we do further analysis. Note: To strip the symbols, do strip <my_file>. The file command could also tell us that the binary file is statically linked, with debug output or stripped. Statically linked means that all functions are included in the binary, but results in a larger executable. Debug output - includes debugging symbols, like variable names, functions, internal symbols, source line numbers, and source file information. If the file is stripped, its size is much smaller. The file command identifies the type of a file using, among other tests, a test for whether the file begins with a certain magic number (see the /etc/magic file). A magic number is a numeric or string constant that indicates the file type. See magic(4) for an explanation of the format of /etc/magic. If you still don't know what this file is used for, try to guess this by taking a look at which shared libraries are needed by the binary using ldd(1) command: $ ldd cr1 ... libsocket.so.1 => /usr/lib/libsocket.so.1 librpcsvc.so.1 => /usr/lib/librpcsvc.so.1 ... This output tells us that this application requires network share libraries (libsocket.so.1 and librpcsvc.so.1). The adb(1) debugger can also be very useful. For example, the following output shows step-by-step execution of the binary in question: # adb cr1 :s adb: target stopped at: ld.so.1`_rt_boot: ba,a +0xc <ld.so.1`_rt_boot+0xc> ,5:s adb: target stopped at: ld.so.1`_rt_boot+0x58: st %l1, [%o0 + 8] You can also analyze the file, or run it and see how it actually works. But be careful when you run an application because you don't know yet what to expect. For example: # adb cr1 :r Using device /dev/hme0 (promiscuous mode) 192.168.2.119 -> web TCP D=22 S=1111 Ack=2013255208 Seq=1407308568 Len=0 Win=17520 web -> 192.168.2.119 TCP D=1111 S=22 Push Ack=1407308568 We can see that this program is a sniffer. See adb(1) for more information of how to use the debugger. If you decide to run a program anyway, you can use truss(1). The truss command allows you to run a program while outputting system calls and signals. Note: truss produces lots of output. Redirect the output to the file: $ truss -f -o cr.out ./cr1 listening on hme0 ^C $ Now you can easily examine the output file cr.out. As you can see, many tools and techniques can be used to analyze a strange file. Not all files are easy to analyze. If a file is a statically linked stripped binary, it would be much more difficult to find what a file (program) is up to. If you cannot tell anything about a file using simple tools like strings and ldd, try to debug it and use truss. Experience using and analyzing the output of these tools, together with a good deal of patience, will reward you with success. --[ Analyzing a 'strange' process What do you do if you find a process that is running on your system, but you don't know what it is doing? Yes, in UNIX everything is a file, even a process! There may be situations in which the application runs on the system but a file is deleted. In this situation the process will still run because a link to the process exists in the /proc/[PID]/object/a.out directory, but you may not find the process by its name running the find(1) command. For example, let's assume that we are going to investigate the process ID 22889 from the suspicious srg application that we found running on our system: # ps -ef | more UID PID PPID C STIME TTY TIME CMD ... root 22889 16318 0 10:09:25 pts/1 0:00 ./srg ... Sometimes it is as easy as running the strings(1) command against the /proc/[PID]/object/a.out to identify the process. # strings /proc/22889/object/a.out | more ... TTY-Watcher version %s Usage: %s [-c] -c turns on curses interface NOTE: Running without root privileges will only allow you to monitor yourself. ... We can see that this command is a TTY-Watcher application that can see all keystrokes from any terminal on the system. Suppose we were not able to use strings to identify what this process is doing. We can examine the process using other tools. You may want to suspend the process until you will figure out what it is. For example, run kill -STOP 22889 as root. Check the results. We will look for 'T' which indicates the process that was stopped: # /usr/ucb/ps | grep T root 22889 0.0 0.7 3784 1720 pts/1 T 10:09:25 0:00 ./srg Resume the process if necessary with kill -CONT <PID> To further analyze the process, we will create a \core dump\ of variables and stack of the process: # gcore 22889 gcore: core.22889 dumped Here, 22889 is the process ID (PID). Examine results of the core.22889 with strings: # strings core.22889 | more ... TTY-Watcher version %s Usage: %s [-c] -c turns on curses interface NOTE: Running without root privileges will only allow you to monitor yourself. ... You may also use coreadm(1M) to analyze the core.22889 file. The coreadm tool provides an interface for managing the parameters that affect core file creation. The coreadm command modifies the /etc/coreadm.conf file. This file is read at boot time and sets the global parameters for core dump creation. First, let's set our core filenames to be of the form core.<PROC NAME>.<PID>. We'll do this only for all programs we execute in this shell (the $$ notation equates to the PID of our current shell): $ coreadm -p core.%f.%p $$ The %f indicates that the program name will be included, and the %p indicates that the PID will be appended to the core filename. You may also use adb to analyze the process. If you don't have the object file, use the /proc/[PID]/object/a.out. You can use a core file for the process dumped by gcore or specify a '-' as a core file. If a dash (-) is specified for the core file, adb will use the system memory to execute the object file. You can actually run the object file under the adb control (it could also be dangerous because you don't know for sure what this application is supposed to do!): # adb /proc/22889/object/a.out - main:b :r breakpoint at: main: save %sp, -0xf8, %sp ... :s stopped at: main+4: clr %l0 :s stopped at: main+8: sethi %hi(0x38400), %o0 $m ? map ... b11 = ef632f28 e11 = ef6370ac f11 = 2f28 `/usr/lib/libsocket.so.1' $q We start the session by setting a breakpoint at the beginning of main() and then begin execution of a.out by giving adb the ':r' command to run. Immediately, we stop at main(), where our breakpoint was set. Next, we list the first instruction from the object file. The ':s' command tells adb to step, executing only one assembly instruction at a time. Note: Consult the book Panic!, by Drake and Brown, for more information on how to use adb to analyze core dumps. To analyze the running process, use truss: # truss -vall -f -o /tmp/outfile -p 22889 # more /tmp/outfile On other UNIX systems, where available, you may trace a process by using the ltrace or strace commands. To start the trace, type ltrace -p <PID>. To view the running process environment, you may use the following: # /usr/ucb/ps auxeww 22889 USER PID %CPU %MEM SZ RSS TT S START TIME COMMAND root 22889 0.0 0.4 1120 896 pts/1 S 14:15:27 0:00 - sh _=/usr/bin/csh MANPATH=/usr/share/man:/usr/local/man HZ= PATH=/usr/sbin:/usr/bin:/usr/local/bin:/usr/ccs/bin:/usr/local/sbin: /opt/NSCPcom/ LOGNAME=root SHELL=/bin/ksh HOME=/ LD_LIBRARY_PATH=/usr/openwin/lib:/usr/local/lib TERM=xterm TZ= The /usr/ucb directory contains SunOS/BSD compatibility package commands. The /usr/ucb/ps command displays information about processes. We used the following options (from the man for ps(1B)): -a Include information about processes owned by others. -u Display user-oriented output. This includes fields USER, %CPU,o %MEM, SZ, RSS and START as described below. -x Include processes with no controlling terminal. -e Display the environment as well as the arguments to the command. -w Use a wide output format (132 columns rather than 80); if repeated, that is, -ww, use arbitrarily wide output. This information is used to decide how much of long commands to print. To view the memory address type: # ps -ealf | grep 22889 F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 8 S root 3401 22889 0 41 20 615a3b40 474 60ba32e6 14:16:49 pts/1 0:00 ./srg To view the memory usage, type: # ps -e -opid,vsz,rss,args PID VSZ RSS COMMAND ... 22889 3792 1728 ./srg We can see that the ./srg uses 3,792 K of virtual memory, 1,728 of which have been allocated from physical memory. You can use the /etc/crash(1M) utility to examine the contents of a proc structure of the running process: # /etc/crash dumpfile = /dev/mem, namelist = /dev/ksyms, outfile = stdout > p PROC TABLE SIZE = 3946 SLOT ST PID PPID PGID SID UID PRI NAME FLAGS ... 66 s 22889 16318 16337 24130 0 58 srg load > p -f 66 PROC TABLE SIZE = 3946 SLOT ST PID PPID PGID SID UID PRI NAME FLAGS 66 s 22889 16318 16337 24130 0 58 srg load Session: sid: 24130, ctty: vnode(60b8f3ac) maj( 24) min( 1) ... > After invoking the crash utility, we used the p function to get the process table slot (66, in this case). Then, to dump the proc structure for process PID 22889, we again used the p utility, with the '-f' flag and the process table slot number. Like the process structure, the uarea contains supporting data for signals, including an array that defines the disposition for each possible signal. The signal disposition tells the operating system what to do in the event of a signal - ignore it, catch it and invoke a user-defined signal handler, or take the default action. To dump a process's uarea: > u 66 PER PROCESS USER AREA FOR PROCESS 66 PROCESS MISC: command: srg, psargs: ./srg start: Mon Jun 3 08:56:40 2002 mem: 6ad, type: exec su-user vnode of current directory: 612daf48 ... > The 'u' function takes a process table slot number as an argument. To dump the address space of a process, type: # /usr/proc/bin/pmap -x 22889 To obtain a list of process's open files, use the /usr/proc/bin/pfiles command: # /usr/proc/bin/pfiles 22889 The command lists the process name and PID for the process' open files. Note that various bits of information are provided on each open file, including the file type, file flags, mode bits, and size. If you cannot find a binary file and the process is on the memory only, you can still use methods described for analyzing suspicious binary files above against the process's object file. For example: # /usr/ccs/bin/nm a.out | more a.out: [Index] Value Size Type Bind Other Shndx Name ... [636] | 232688| 4|OBJT |GLOB |0 |17 |Master_utmp [284] | 234864| 20|OBJT |GLOB |0 |17 |Mouse_status You may also use mdb(1) - a modular debugger to analyze the process: # mdb -p 22889 Loading modules: [ ld.so.1 libc.so.1 libnvpair.so.1 libuutil.so.1 ] > ::objects BASE LIMIT SIZE NAME 10000 62000 52000 ./srg ff3b0000 ff3dc000 2c000 /lib/ld.so.1 ff370000 ff37c000 c000 /lib/libsocket.so.1 ff280000 ff312000 92000 /lib/libnsl.so.1 --[ Security Forensics using DTrace Solaris 10 has introduced a new tool for Dynamic Tracing in the OS environment - dtrace. This is a very powerful tool that allows system administrators to observe and debug the OS behaviour or even to dynamically modify the kernel. Dtrace has its own C/C++ like programming language called 'D language' and comes with many different options that I am not going to discuss here. Consult dtrace(1M) man pages and http://docs.sun.com/app/docs/doc/817-6223 for more information. Although this tool has been designed primarily for developers and administrators, I will explain how one can use dtrace for analyzing suspicious files and process. We will work on a case study, as followes. For example, let's assume that we are going to investigate the process ID 968 from the suspicious srg application that we found running on our system. By typing the following at the command-line, you will list all files that this particular process opens at the time of our monitoring. Let it run for a while and terminate with Control-C: # dtrace -n syscall::open:entry'/pid == 968/ { printf("%s%s",execname,copyinstr(arg0)); }' dtrace: description 'syscall::open*:entry' matched 2 probes ^C CPU ID FUNCTION:NAME 0 14 open:entry srg /var/ld/ld.config 0 14 open:entry srg /lib/libdhcputil.so.1 0 14 open:entry srg /lib/libsocket.so.1 0 14 open:entry srg /lib/libnsl.so.1 D language comes with its own terminology, which I will try to address here briefly. The whole 'syscall::open:entry' construction is called a 'probe' and defines a location or activity to which dtrace binds a request to perform a set of 'actions'. The 'syscall' element of the probe is called a 'provider' and, in our case, permits to enable probes on 'entry' (start) to any 'open' Solaris system call ('open' system call instracts the kernel to open a file for reading or writing). The so-called 'predicate' - /pid == 968/ uses the predefined dtrace variable 'pid', which always evaluates to the process ID associated with the thread that fired the corresponding probe. The 'execname' and 'copyinstr(arg0)' are called 'actions' and define the name of the current process executable file and convert the first integer argument of the system call (arg0) into a string format respectively. The printf's action uses the same syntax as in C language and serves for the same purpose - to format the output. Each D program consists of a series of 'clauses', each clause describing one or more probes to enable, and an optional set of actions to perform when the probe fires. The actions are listed as a series of statements enclosed in curly braces { } following the probe name. Each statement ends with a semicolon (;). You may want to read the Introduction from Solaris Tracing Guide (http://docs.sun.com/app/docs/doc/817-6223) for more options and to understand the syntax. Note: As the name suggests, the dtrace (Dynamic Trace) utility will show you the information about a chnaging process - in dynamic. That is, if the process is idle (doesn't do any system calls or opens new files), you won't be able to get any information. To analyze the process, either restart it or use methods described in the previous two sections of this paper. Second, we will use the following command-line construction to list all system calls for 'srg'. Let it run for a while and terminate by Control-C: # dtrace -n 'syscall:::entry /execname == "srg"/ { @num[probefunc] = count(); }' dtrace: description 'syscall:::entry ' matched 226 probes ^C pollsys 1 getrlimit 1 connect 1 setsockopt 1 ... You may recognize some of the building elements of this small D program. In addition, this clause defines an array named 'num' and assigns the appropriate member 'probefunc' (executed system call's function) the namber of times these particular functions have been called (count()). Using dtrace we can easily emulate all utilities we have used in the previous sections to analyze suspicious binary files and processes. But dtrace is much more powerful tool and may provide one with more functionality: for example, you can dynamically monitor the stack of the process in question: # dtrace -n 'syscall:::entry/execname == "srg"/{ustack()}' 0 286 lwp_sigmask:entry libc.so.1`__systemcall6+0x20 libc.so.1`pthread_sigmask+0x1b4 libc.so.1`sigprocmask+0x20 srg`srg_alarm+0x134 srg`scan+0x400 srg`net_read+0xc4 srg`main+0xabc srg`_start+0x108 Based on all our investigation (see the list of opened files, syscalls, and the stack examination above), we may positively conclude that srg is a network based application. Does it write to the network? Let's check it by constructing the following clause: # dtrace -n 'mib:ip::/execname == "srg"/{@[execname]=count()}' dtrace: description 'mib:ip::' matched 412 probes dtrace: aggregation size lowered to 2m ^C srg 520 It does. We used 'mib' provider to find out if our application transmits to the network. Could it be just a sniffer or a netcat-liked application that is bounded to a specific port? Let's run dtrace in the truss(1) like fashion to answer this question (inspired by Brendan Gregg's dtruss utility ): #!/usr/bin/sh # dtrace=' inline string cmd_name = "'$1'"; /* ** Save syscall entry info */ syscall:::entry /execname == cmd_name/ { /* set start details */ self->start = timestamp; self->arg0 = arg0; self->arg1 = arg1; self->arg2 = arg2; } /* Print data */ syscall::write:return, syscall::pwrite:return, syscall::*read*:return /self->start/ { printf("%s(0x%X, \"%S\", 0x%X)\t\t = %d\n",probefunc,self->arg0, stringof(copyin(self->arg1,self->arg2)),self->arg2,(int)arg0); self->arg0 = arg0; self->arg1 = arg1; self->arg2 = arg2; } ' # Run dtrace /usr/sbin/dtrace -x evaltime=exec -n "$dtrace" >&2 Save it as truss.d, change the permissions to executable and run: # ./truss.d srg 0 13 write:return write(0x1, " sol10 - > 192.168.2.119 TCP D=3138 S=22 Ack=713701289 Seq=3755926338 Len=0 Win=49640\n8741 Len=52 Win=16792\n\0", 0x5B) = 91 0 13 0 13 write:return write(0x1, "192.168.2.111 -> 192.168.2.1 UDP D=1900 S=21405 LEN=140\n\0", 0x39) = 57 ^C Looks like a sniffer to me, with probably some remote logging (remember the network transmission by ./srg discovered by the 'mib' provider above!). You can actually write pretty sophisticated programs for dtrace using D language. Take a look at /usr/demo/dtrace for some examples. You may also use dtrace for other forensic activities. Below is an example of more complex script that allows monitoring of who fires the suspicious application and starts recording of all the files opened by the process: #!/usr/bin/sh command=$1 /usr/sbin/dtrace -n ' inline string COMMAND = "'$command'"; #pragma D option quiet /* ** Print header */ dtrace:::BEGIN { /* print headers */ printf("%-20s %5s %5s %5s %s\n","START_TIME","UID","PID","PPID","ARGS"); } /* ** Print exec event */ syscall::exec:return, syscall::exece:return /(COMMAND == execname)/ { /* print data */ printf("%-20Y %5d %5d %5d %s\n",walltimestamp,uid,pid,ppid, stringof(curpsinfo->pr_psargs)); s_pid = pid; } /* ** Print open files */ syscall::open*:entry /pid == s_pid/ { printf("%s\n",copyinstr(arg0)); } ' Save this script as wait.d, change the permissions to executable 'chmod +x wait.d' and run: # ./wait.d srg START_TIME UID PID PPID ARGS 2005 May 16 19:51:20 100 1582 1458 ./srg /var/ld/ld.config /lib/libnsl.so.1 /lib/libsocket.so.1 /lib/libresolv.so.2 ... ^C Once the srg is started you will see the output. However, the real power of dtrace comes from the fact that you can do things with it that won't be possible without writing a comprehensive C program. For example, the shellsnoop application written by Brendan Gregg (http://users.tpg.com.au/adsln4yb/DTrace/shellsnoop) allows you to use dtrace at the capacity of ttywatcher! It is not possible to show all capabilities of dtrace in such a small presentation of this amazing utility. Dtrace is a very powerful as well a complex tool with virtually endless capabilities. Although Sun insists that you don't have to have a 'deep understanding of the kernel for DTrace to be useful', the knowledge of Solaris internals is a real asset. Taking a look at the include files in /usr/include/sys/ directory may help you to write complex D scripts and give you more of an understanding of how Solaris 10 is implemented. --[ Conclusion Be creative and observant. Apply all your knowledge and experience for analyzing suspicious binary files and processes. Also, be patient and have a sense of humour! |=-------------------------=[ 0x03-2 ]=----------------------------------=| |=----------=[ TCP Timestamp To count Hosts behind NAT ]=----------------=| |=-----------------------------------------------------------------------=| |=-------------=[ Elie aka Lupin (lupin@zonart.net) ]=-------------------=| Table of Contents *=*=*=*=*=*=*=*=* 1.0 - Introduction 2.0 - Time has something to tell us - 2.1 Past history - 2.2 Present - 2.3 Back to the begin of timestamp history - 2.4 Back to school - 2.5 Back to the NAT - 2.6 Let's do PAT - 2.7 Time to fightback 3.0 History has something to tell us - 3.1 Which class ? - 3.2 So were does it come from ? - 3.3 How do you find it ? - 3.4 Back to the future - 4 Learning from the past aka conclusion - A Acknowledgements - B Proof of concept --[ 1.0 - Introduction This article is about TCP timestamp option. This option is used to offer a new way for counting host beyond a NAT and enhanced host fingerprinting. More deeply, this article tries to give a new vision of a class of bug known has "Design error". The bug described here, deserves interest for the following reasons. - It's new. - It affects every platform since it is related to the specification rather than implementation. - It's a good way to explain how some specifications can be broken. The article is organized has follow : First I will explain what's wrong about TCP timestamp. Then I will describe How to exploit it, the limitations of this exploitation and a way to avoid it. In the second part I will talk about the origin of this error and why it will happen again. At the end I will give a proof of concept and greeting as usual. --[ 2.0 - Time has something to tell us ----[ 2.1 - Past history Fingerprinting and Nat detection have been an active field for long time. Since you read phrack you already know the old school TCP/IP fingerprinting by Fyodor. You may also know p0f (Passive of fingerprinting) by M. Zalewski. With the version 2 he has done a wonderful tool, introducing clever ways to know if a host uses the NAT mechanism by analyzing TCP packet option. If you are interested in this tool (and you should !) read his paper : "Dr. Jekyll had something to Hyde"[5]. In fact the technique described here is related to p0f in the way, that like p0f, it can be totally passive. To be complete about NAT detection, I need to mention that AT&T has done research on counting host behind a NAT[1]. Their work focus on IP ID, assuming that this value is incremental in some OS. In fact they are mainly talking about Windows box which increment IP ID by 256 for each packet. Discovered by Antirez[7], Nmap[6] has used this fact for a long time (option -sI). Now that we know what we are talking about it's time to explain what's going on. ----[ 2.2 - Present NAT was designed to face the IP address depletion. It is also used to hide multiple hosts behind a single IP. The TCP timestamp option[2] is improperly handled by the IP Network Address Translator (NAT) mechanism[3]. In other words even scrubbing from pf doesn't rewrite the timestamp option. Until now this property of the NAT has been useless (in the security point of view). It is interesting to point out that the timestamp option by itself has already been used for information disclosure. Let's take a quick look at timestamp security history ----[ 2.3 - Back to the beginning of timestamp history In the past the timestamp has been used to calculate the uptime of a computer[4]. Any one who had try the TCP fingerprint option (-O) of Nmap has been impressed by a line like this one : "Uptime 36.027 days (since Tue May 25 11:12:31 2004)". Of course their is no black magic behind that, only two facts : - Time goes back only in movie (sorry boys...) - Every OS increments the timestamp by one every n milliseconds. So if you know the OS, you know how often the OS increment the timestamp option. All you have to do to know the uptime is to apply a trivial math formula : timestamp / num inc by sec = uptime in sec Has you can notice this formula does not take into account the warp around of integer. Here we know two information : the actual timestamp and the number of increments by second. This can only be done because we know the OS type. Let's see how we can improve this technique to do it without knowing the OS. ----[ 2.4 - Back to school Remember a long time ago at school, you heard about affine function. A basic example of it is : "y = Ax + B" where A is the slope and B the initial point. The graphic representation of it is straight line. From timestamp point of view this can be express has the follow : timestamp = numincbysec * sec + intial number When you do active fingerprinting you get the timestamp and know the numincbysec by guessing the OS. Now let's suppose you can't guess the OS. In this case you don't know the slope and can't guess the uptime. Here is an other way to know the slope of the OS. You need to get the computer timestamp twice. Name it ts1 and ts2 and name the time (in sec) where you gather it t1 and t2. With thoses informations, it is trivial to find the slope since we have the following equationnal system: ts1 = A*s1 + B ts2 = A*s2 + B which is solved by the following equation : ts1 - ts2 = A*(s1 - s2) <=> A = (ts1 - ts2) / (s1 - s2) An imediate application of this idea can be implemented in active scanner: requeste twice the timestamp to verify that the slope is the same as the one guessed. This can be use to defeat some anti-fingerprint tools. It also can be used as a standalone fingerprinting technic but will not be accurate has the TCP or ICMP one. Now that we have the theory ready, let's go back to NAT. ----[ 2.5 - Back to the NAT Let's make the connection with the NAT. Since the timestamp option is not rewritten by NAT, we can count the number of host behind the NAT using the following algorithm : 1. for each host already discovered verifying is the packet belong to it straight line equation. each host has a unique straight line equation until two host have booted at the same second. 2. otherwise add the packet to unmatched packet : a new host beyond NAT is detected. Look to the proof of concept if you need to make things more clear. This simple algorithm has a lot of room for improvement. It has been keeped has simple has possible for clarity. As you can see timestamp option can be used to count host beyond a NAT in a reliable manner. It will also giveo indication of the OS class. ----[ 2.6 - Let's do PAT PAT (Port Address Translation) is used to provide service on a box behind a NAT. The question is how do I know that the port is forwarded? Well timestamp is once again your friend. If for two different ports the slope of timestamp differs then there is a PAT and the OS of the two computers is different. If the timestamp gathered from the two ports does not belong to the same straight line, then it's the same OS but not the same computer. Another interesting use of PAT is the round robin. Until now their were no way to know if such mechanism is used. By comparing the different timestamps gathered you can determine how many hosts are beyond a single port. This might be an interesting functionality to add to an active scanner. ----[ 2.7 - Time to fight back Since playing with this option can give valuable information there is some limitation to this technique. Mainly Windows box does not use timestamp option when they establish connection[8] unless you activate it. This limitation only affects passive analysis, if you use timestamp when you connect to a windows it will use it too. Moreover many tweaks software activate the TCP extension in windows. To be completed on the subject I had to mention that it seems that TCP extension does not exist on win 9X. One other problem is the time gap. In passive mode there can be a desynchronization between computers due to computer desynchronization or network lags. In the proof of concept this phenomenon can occur. To handle it you need not to rely on the computer clock but on timestamp itself. What can we do against this ? Since no vendor except Microsoft (1) (Thanks Magnus) has answer to me, the following workaround may not be available. Here is a theoric way to patch this problem. 1. Disabling tcp timestamp. This is the worse solution since we will need it with fast network[2]. 2. Make NAT rewrite the timestamp and changing The NAT RFC. 3. Changing the RFC to specify that the timestamp option needs to have a random increment. Modifying each implementation to reflect this change. The a clean way to fix this thing because it's does not rely on an external system (the NAT computer in this case). Well I have to try to be as complete as possible for this technical part. The next part will be more "philosophic" since it deals with the cause instead of the consequence. --[ 3 - History has something to tell us In this part I will try to focus on why we have this situation and what we can do about it. Here I am not talking about the timestamp option by itself but about the interaction between the timestamp option and the NAT mechanism. ----[ 3.1 - Which class ? First question is what is this bug? This bug belongs to the design error class. To be more precise this bug exists because protocol specification overlap. IP was designed to be a one on one protocol: one client talks to one server. NAT violates this specification by allowing multiple to one. By itself this violation has caused so many problems that I lost the count of it, but it is pretty sure that the most recurrent problem is the FTP transfer. If you use FTP you know what I mean (other can look at netfilter ftp conntrack). ----[ 3.2 - So were does it come from ? FTP problem is a good example to explain the origin of the overlap specification problem. FTP was specified to work over a one to one reliable connexion (TCP in fact). NAT was designed to modify IP. So due to protocol dependency it also alter TCP and therefor FTP. During NAT specification it was not taken into account that every protocol that relies on IP, can conflict with the modified specification. To tell the truth ,even if the people that design the NAT mechanism have ever wanted to ensure that every protocol that relies on IP can work with the NAT they couldn't make it. Why ? because specification are RFC and RFC are in english. English is not a good way to specify things especially if you have a dependency graph for the specification. For example many programming languages have formal specifications. Which is a more full proof way. The reason of this lack of formal specification resides on the history of Internet[9]. At this time writing a simple text was good enough. Nowadays it can be very problematic. ----[ 3.3 - How do you find it ? The big question is, how do I find this bug ?. Well I found this problem by formalizing a part of the TCP RFC and confronts the result of this analysis to real execution traces. My analyzer (2) warned me about a timestamp that was less than the previous one and as you know time does not go back... I check out why and found this problem. What's interesting here is that the start point to find the bug is the specification rather than the implementation as it usually does to find a buffer overflow for example. ----[ 3.4 - Back to the future So from now on, what will happen ? Well more design errors will be found because we cannot change the past and we need to live with it. It is not reasonable to say that we can wipe off all that TCP stuff and start a new thing from scratch. Internet and network are simply too big to move just like that. Just think for one second about the IP v6 deployment and you will be convinced. All we can do is try to be as careful as possible when designing a new extension or a protocol. Trying to ensure that this new stuff does not conflicts with previous specification or breaks dependence. We can also try to formalize the protocols as much as we can to try and detect errors before they cause problems. Sadly patching is mainly our primary option for the coming years. --[ 4.0 - Learning from the past aka conclusion The past tells us that protocol is not well enough specified and leads to errors (bug, conflict...). It may be time to change our habits and try something in ad equation with our time. For example to design things with security in mind. In this article I have tried to show you that by simply understanding specification and with the help of some basic math you can: - Find a flaw with a worldwide impact. - Exploit this flaw in an elegant manner by the means of a simple theory. - Extend fingerprint state of art. I hope this will help to convince you that theory and formal tools are a necessary part of the computer security field. Next time I will focus on simple formal method to find bug. I hope you will be here :). --[ A Acknowledgements First I would like to thank Romain Bottier for his help and his patience. I also want to thank Plops and Poluc for having faith in me. See guys we made it! I also want to say that I take great care about non disclosure policy. I have informed major vendors (Kernel.org, freeBSD, OpenBSD, Cisco...) a month ago. As I said I did not get any feedback so I assume they do not care. References *=*=*=*=*= [1] AT&T Steven M. Bellovin. A Technique for Counting NATted Hosts http://www.research.att.com/~smb/papers/fnat.pdf [2] Jacobson, Braden, & Borman. RFC 1323 :TCP Extensions for High Performance . [3] K. Egevang, Cray Communications, P. Francis. RFC 1631 : The IP Network Address Translator (NAT). [4] Bret McDanel. TCP Timestamping - Obtaining System Uptime Remotely originally posted to Bugtraq Security Mailing List on March 11, 2001. [5] Michal Zalewski. p0f 2:Dr. Jekyll had something to Hyde. [6] Fyodor. Nmap - Free Security Scanner For Network Exploration & Security Audits. [7] Antirez. dumbscan original BUGTRAQ posting (18 Dec 1998) [8] Microsoft. TCP timestamp in windows : KB224829. [9] Hafner, Katie, Matthew Lyon. Where Wizards Stay Up Late: The Origins of the Internet. FootNotes *=*=*=*=*= (1) Microsoft point of view is that NAT is not a security mechanism so they do not want to patch. (2) If you are interested about my analyzer. I hope to publish soon a theoric paper on how it works. I also hope to release one day a version of it. To the question did I find other interesting things, the answer is: maybe I need to check out more deeply. --[ B - Proof of concept /* * Proof Of Concept : counting host behind a NAT using timestamp * To compile this file, you will need the libpcap * Copyright Elie Bursztein (lupin@zonart.net) * Successfully compiled on FreeBSD 5.X and Linux 2.6.X * * $gcc natcount.c -o natcount -I/usr/local/include -L/usr/local/lib * -lpcap */ #define __USE_BSD 1 #include <sys/time.h> #include <time.h> #include <netinet/in.h> #include <net/ethernet.h> #ifdef __FreeBSD__ # include <netinet/in_systm.h> #endif /* __FreeBSD__ */ #ifdef __linux__ # include <linux/if_ether.h> #endif /* __linux__ */ #include <netinet/ip.h> #include <stdlib.h> #include <string.h> #include <pcap.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <net/if.h> #include <netinet/tcp.h> #include <netinet/udp.h> #ifdef __linux__ # define th_off doff #endif /* __linux__ */ u_int32_t addr = 0; /* chain lists structures */ typedef struct listes_s { struct listes_s *next; void *elt; } listes_t; /* Structures for TCP options */ typedef struct { u_int32_t ts, ts_r; } timestamp_t; typedef struct { timestamp_t *ts; } tcp_opt_t; /* Structures for datas storage */ typedef struct { u_int32_t from, first_timestamp; struct timeval first_seen; } machine_t; typedef struct { u_int32_t host, nat; struct timeval first_seen; } nat_box_t; #define TIMESTAMP_ERROR_MARGIN 0.5 #define DELAY 1 /* * List functions */ int add_in_list(listes_t **list, void * elt) { listes_t *lst; lst = malloc(sizeof (listes_t)); lst->next = *list; lst->elt = elt; *list = lst; return (1); } void show_nated(listes_t *list) { nat_box_t *nat; struct in_addr addr; printf("-- Begin of nated IP list --\n"); while (list) { nat = (nat_box_t *) list->elt; if (nat->nat > 1) { addr.s_addr = nat->host; printf("I've guess %i computers sharing the same IP address (%s)\n", nat->nat, inet_ntoa(addr)); } list = list->next; } printf("-- End of nated IP list --\n"); } /* * Function used to get all TCP options * Simple TCP options parser */ int tcp_option_parser(const u_char *options, tcp_opt_t *parsed, unsigned int size) { u_int8_t kind, len, i; bzero(parsed, sizeof(tcp_opt_t)); i = 0; kind = *(options + i); while (kind != 0) /* EO */ { switch (kind) { case 1: i++; break; /* NOP byte */ case 2: i += 4; break; case 3: i += 3; break; case 4: i += 2; break; case 5: /* skipping SACK options */ len = (*options + ++i) - 1; i += len; break; case 6: i += 6; break; case 7: i += 6; break; case 8: i += 2; parsed->ts = (timestamp_t *) (options + i); i += 8; return (1); break; default: i++; } kind = *(options + i); } return (0); } /* * Most interesting function ... Here we can know if a TCP packet is * coming from someone we already know ! * Algo : * finc (seconds) = current_packet_time - first_packet_time <- time * between 2 packets * ts_inc = inc_table[i] * finc <- our supposed timestamp increment * between 2 packets * new_ts = first_timestamp + ts_inc <- new = timestamp we should have * now ! * * Now we just have to compare new_ts with current timestamp * We can authorize an error margin of 0.5% * * Our inc_table contain timestamp increment per second for most * Operating System */ int already_seen(machine_t *mach, tcp_opt_t *opt, struct timeval temps) { int inc_table[4] = {2, 10, 100, 1000}; unsigned int new_ts; float finc, tmp, ts_inc; int i, diff; finc = ((temps.tv_sec - mach->first_seen.tv_sec) * 1000000. + (temps.tv_usec - mach->first_seen.tv_usec)) / 1000000.; for (i = 0; i < 4; i++) { ts_inc = inc_table[i] * finc; new_ts = ts_inc + mach->first_timestamp; diff = ntohl(opt->ts->ts) - new_ts; if (diff == 0) { /* Perfect shoot ! */ return (2); } tmp = 100. - (new_ts * 100. / ntohl(opt->ts->ts)); if (tmp < 0.) tmp *= -1.; if (tmp <= TIMESTAMP_ERROR_MARGIN) { /* Update timestamp and time */ mach->first_seen = temps; mach->first_timestamp = ntohl(opt->ts->ts); return (1); } } return (0); } /* * Simple function to check if an IP address is already in our list * If not, it's only a new connection */ int is_in_list(listes_t *lst, u_int32_t addr) { machine_t *mach; while (lst) { mach = (machine_t *) lst->elt; if (mach->from == addr) return (1); lst = lst->next; } return (0); } /* * This function should be call if a packet from an IP address have been * found, * is address is already in the list, but doesn't match any timestamp * value */ int update_nat(listes_t *list, u_int32_t addr) { nat_box_t *box; while (list) { box = (nat_box_t *) list->elt; if (box->host == addr) { box->nat++; return (1); } list = list->next; } return (0); } int check_host(listes_t **list, listes_t **nat, u_int32_t from, tcp_opt_t *opt, struct timeval temps) { listes_t *lst; machine_t *mach; int found, zaped; found = zaped = 0; lst = *list; while (lst && !(found)) { mach = (machine_t *) lst->elt; if (mach->from == from) { if ( temps.tv_sec - mach->first_seen.tv_sec > DELAY ) { found = already_seen(mach, opt, temps); } else zaped = 1; } lst = lst->next; } if (!(zaped) && !(found)) { mach = malloc(sizeof (machine_t)); mach->from = from; mach->first_seen = temps; mach->first_timestamp = ntohl(opt->ts->ts); add_in_list(list, mach); update_nat(*nat, from); show_nated(*nat); return (1); } return (0); } void callback_sniffer(u_char *useless, const struct pcap_pkthdr* pkthdr, const u_char *packet) { static listes_t *list_machines = 0; static listes_t *list_nat = 0; const struct ip *ip_h; const struct tcphdr *tcp_h; tcp_opt_t tcp_opt; machine_t *mach; nat_box_t *nat; struct in_addr my_addr; ip_h = (struct ip *) (packet + sizeof(struct ether_header)); if (ip_h->ip_p == IPPROTO_TCP) { tcp_h = (struct tcphdr *) (packet + sizeof(struct ether_header) + sizeof(struct ip)); if (tcp_h->th_off * 4 > 20) { if (tcp_option_parser((u_char *) (packet + sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct tcphdr)), &tcp_opt, tcp_h->th_off * 4 - 20)) { if (is_in_list(list_machines, (ip_h->ip_src).s_addr)) { check_host(&list_machines, &list_nat, (u_int32_t) (ip_h->ip_src).s_addr, &tcp_opt, pkthdr->ts); } else { if (ntohl(tcp_opt.ts->ts) != 0) { addr = (ip_h->ip_src).s_addr; my_addr.s_addr = addr; mach = malloc(sizeof (machine_t)); mach->from = (ip_h->ip_src).s_addr; mach->first_seen = pkthdr->ts; mach->first_timestamp = ntohl(tcp_opt.ts->ts); nat = malloc(sizeof (nat_box_t)); nat->host = (u_int32_t) (ip_h->ip_src).s_addr; nat->nat = 1; nat->first_seen = mach->first_seen; add_in_list(&list_machines, mach); add_in_list(&list_nat, nat); } } } } } } int main(int ac, char *argv[]) { pcap_t *sniff; char errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program fp; char *device; bpf_u_int32 maskp, netp; struct in_addr my_ip_addr; char filter[250]; if (getuid() != 0) { printf("You must be root to use this tool.\n"); exit (2); } if (--ac != 1) { printf("Usage: ./natcount xl0\n"); return (1); } device = (++argv)[0]; pcap_lookupnet(device, &netp, &maskp, errbuf); my_ip_addr.s_addr = (u_int32_t) netp; printf("Using interface %s IP : %s\n", device, inet_ntoa(my_ip_addr)); if ((sniff = pcap_open_live(device, BUFSIZ, 1, 1000, errbuf)) == NULL) { printf("ERR: %s\n", errbuf); exit(1); } bzero(filter, 250); snprintf(filter, 250, "not src net %s", inet_ntoa(my_ip_addr)); if(pcap_compile(sniff,&fp, filter, 0, netp) == -1) { fprintf(stderr,"Error calling pcap_compile\n"); exit(1); } if(pcap_setfilter(sniff,&fp) == -1) { fprintf(stderr,"Error setting filter\n"); exit(1); } pcap_loop(sniff, -1, callback_sniffer, NULL); return (0); } |=-----------------------------=[ 0x03-3 ]=------------------------------=| |=---=[ All Hackers Need To Know About Elliptic Curve Cryptography ]=----=| |=-----------------------------------------------------------------------=| |=----------------------------=[ f86c9203 ]=-----------------------------=| ---[ Contents 0 - Abstract 1 - Algebraical Groups and Cryptography 2 - Finite Fields, Especially Binary Ones 3 - Elliptic Curves and their Group Structure 4 - On the Security of Elliptic Curve Cryptography 5 - The ECIES Public Key Encryption Scheme 6 - The XTEA Block Cipher, CBC-MAC and Davies-Meyer Hashing 7 - Putting Everything Together: The Source Code 8 - Conclusion 9 - Outlook A - Appendix: Literature B - Appendix: Code ---[ 0 - Abstract Public key cryptography gained a lot of popularity since its invention three decades ago. Asymmetric crypto systems such as the RSA encryption scheme, the RSA signature scheme and the Diffie-Hellman Key Exchange (DH) are well studied and play a fundamental role in modern cryptographic protocols like PGP, SSL, TLS, SSH. The three schemes listed above work well in practice, but they still have a major drawback: the data structures are large, i.e. secure systems have to deal with up to 2048 bit long integers. These are easily handled by modern desktop computers; by contrast embedded devices, handhelds and especially smartcards reach their computing power limits quickly. As a second problem, of course, the transportation of large integers "wastes" bandwidth. In 2048 bit systems an RSA signature takes 256 bytes; that's quite a lot, especially for slow communication links. As an alternative to RSA, DH and suchlike the so called Elliptic Curve Cryptography (ECC) was invented in the mid-eighties. The theory behind it is very complicated and much more difficult than doing calculations on big integers. This resulted in a delayed adoption of ECC systems although their advantages over the classic cryptographic building blocks are overwhelming: key lengths and the necessary processing power are much smaller (secure systems start with 160 bit keys). Thus, whenever CPU, memory or bandwidth are premium resources, ECC is a good alternative to RSA and DH. This article has two purposes: 1. It is an introduction to the theory of Elliptic Curve Cryptography. Both, the mathematical background and the practical implementability are covered. 2. It provides ready-to-use source code. The C code included and described in this article (about 500 lines in total) contains a complete secure public key crypto system (including symmetric components: a block cipher, a hash function and a MAC) and is released to the public domain. The code doesn't link against external libraries, be they of bigint, cryptographic or other flavour; an available libc is sufficient. This satisfies the typical hacker need for compact and independent programs that have to work in "inhospitable" environments; rootkits and backdoors seem to be interesting applications. As mentioned above the theory behind EC cryptography is rather complex. To keep this article brief and readable by J. Random Hacker only the important results are mentioned, theorems are not proven, nasty details are omitted. If on the other hand you are into maths and want to become an ECC crack I encourage to start reading [G2ECC] or [ECIC]. ---[ 1 - Algebraical Groups and Cryptography Definition. A set G together with an operation G x G -> G denoted by '+' is called an (abelian algebraical) group if the following axioms hold: G1. The operation '+' is associative and commutative: (a + b) + c = a + (b + c) for all a,b,c in G a + b = b + a for all a,b in G G2. G contains a neutral element '0' such that a + 0 = a = 0 + a for all a in G G3. For each element 'a' in G there exists an "inverse element", denoted by '-a', such that a + (-a) = 0. For a group G the number of elements in G is called the group order, denoted by |G|. Example. The sets Z, Q and R of integers, rational numbers and real numbers, respectively, form groups of infinite order in respect to their addition operation. The sets Q* and R* (Q and R without 0) also form groups in respect to multiplication (with 1 being the neutral element and 1/x the inverse of x). Definition. Let G be a group with operation '+'. A (nonempty) subset H of G is called a subgroup of G if H is a group in respect to the same operation '+'. Example. Z is a subgroup of Q is a subgroup of R in respect to '+'. In respect to '*' Q* is a subgroup of R*. Theorem (Lagrange). Let G be a group of finite order and H be a subgroup of G. Then |H| properly divides |G|. It follows that if G has prime order, G has only two subgroups, namely {0} and G itself. We define the "scalar multiplication" of a natural number k with a group element g as follows: k * g := g + g + ... + g + g \____ k times ____/ Theorem. For a finite group G and an element g in G the set of all elements k * g (k natural) forms a subgroup of G. This subgroup is named the "cyclic subgroup generated by g". Thus a prime order group is generated by any of its nonzero elements. We now introduce the Diffie-Hellman Key Exchange protocol: let G be a prime order group and g a nonzero element. Let two players, called Alice and Bob respectively, do the following: 1. Alice picks a (secret) random natural number 'a', calculates P = a * g and sends P to Bob. 2. Bob picks a (secret) random natural number 'b', calculates Q = b * g and sends Q to Alice. 3. Alice calculates S = a * Q = a * (b * g). 4. Bob calculates T = b * P = b * (a * g). By definition of the scalar multiplication it is apparent that S = T. Therefore after step 4 Alice and Bob possess the same value S. The eavesdropper Eve, who recorded the exchanged messages P and Q, is able to calculate the same value if she manages to determine 'a' or 'b'. This problem (calculating 'a' from G, g and 'a * g') is called the group's Discrete Logarithm Problem (DLP). In groups where DLP is too 'hard' to be practically solvable it is believed to be out of reach for eavesdroppers to determine the value S, hence Alice and Bob can securely establish a secret key which can be used to protect further communication. If an attacker is able to intercept the transmission of P and Q and to replace both by the group's neutral element, obviously Alice and Bob are forced to obtain S = 0 = T as shared key. This has to be considered a successful break of the crypto system. Therefore both Alice and Bob have to make sure that the received elements Q and P, respectively, indeed do generate the original group. The presented DH scheme may also serve as public key encryption scheme (called ElGamal encryption scheme): let Alice pick a random natural number 'a' as private key. The element P = a * g is the corresponding public key. If Bob wants to encrypt a message for her, he picks a random number 'b', symmetrically encrypts the message with key T = b * P and transmits the cipher text along with Q = b * g to Alice. She can reconstruct T = S via S = a * Q and then decrypt the message. Note the direct relationship between this and the DH scheme! Conclusion: Cryptographers are always seeking for finite prime order groups with hard DLP. This is where elliptic curves come into play: they induce algebraical groups, some of them suitable for DH and ElGamal crypto systems. Moreover the elliptic curve arithmetic (addition, inversion) is implementable in a relatively efficient way. You will find more information about groups and their properties in [Groups], [Lagrange], [CyclicGroups] and [GroupTheory]. Read more about the DLP, DH key exchange and ElGamal encryption in [DLP], [DH] and [ElGamal]. ---[ 2 - Finite Fields, Especially Binary Ones Definition. A set F together with two operations F x F -> F named '+' and '*' is called a field if the following axioms hold: F1. (F, +) forms a group F2. (F*, *) forms a group (where F* is F without the '+'-neutral element '0') F3. For all a,b,c in G the distributive law holds: a * (b + c) = (a * b) + (a * c) For 'a + (-b)' we write shorter 'a - b'. Accordingly we write 'a / b' when we multiply 'a' with the '*'-inverse of b. To put it clearly: a field is a structure with addition, substraction, multiplication and division that work the way you are familiar with. Example. The sets Q and R are fields. Theorem. For each natural m there exists a (finite) field GF(2^m) with exactly 2^m elements. Fields of this type are called binary fields. Elements of binary fields GF(2^m) can efficiently be represented by bit vectors of length m. The single bits may be understood as coefficients of a polynomial of degree < m. To add two field elements g and h just carry out the polynomial addition g + h (this means: the addition is done element-wise, i.e. the bit vectors are XORed together). The multiplication is a polynomial multiplication modulo a certain fixed reduction polynomial p: the elements' product is the remainder of the polynomial division (g * h) / p. The fact that field addition just consists of a bitwise XOR already indicates that in binary fields F each element is its own additive inverse, that is: a + a = 0 for all a in F. For a,b in F as consequence 2*a*b = a*b + a*b = 0 follows, what leads to the (at the first glance surprising) equality (a + b)^2 = a^2 + b^2 for all a,b in F. More about finite fields and their arithmetical operations can be found in [FiniteField], [FieldTheory], [FieldTheoryGlossary] and especially [FieldArithmetic]. ---[ 3 - Elliptic Curves and their Group Structure Definition. Let F be a binary field and 'a' and 'b' elements in F. The set E(a, b) consisting of an element 'o' (the "point at infinity") plus all pairs (x, y) of elements in F that satisfy the equation y^2 + x*y = x^3 + a*x^2 + b is called the set of points of the binary elliptic curve E(a, b). Theorem. Let E = E(a, b) be the point set of a binary elliptic curve over the field F = GF(2^m). Then 1. E consists of approximately 2^m elements. 2. If (x, y) is a point on E (meaning x and y satisfy the above equation) then (x, y + x) is also a point on E. 3. If two points P = (x1, y1) and Q = (x2, y2) on E with x1 != x2 are connected by a straight line (something of the form y = m*x + b), then there is exactly one third point R = (x3, y3) on E that is also on this line. This induces a natural mapping f:(P, Q) -> R, sometimes called chord-and-tangent mapping. Exercise. Prove the second statement. The chord-and-tangent mapping 'f' is crucial for the group structure given naturally on elliptic curves: a) The auxiliary element 'o' will serve as neutral element which may be added to any curve point without effect. b) For each point P = (x, y) on the curve we define the point -P := (x, y + x) to be its inverse. c) For two points P = (x1, y1) and Q = (x2, y2) the sum 'P + Q' is defined as -f(P, Q). It can be shown that the set E together with the point addition '+' and the neutral element 'o' defacto has group structure. If the curve's coefficients 'a' and 'b' are carefully chosen, there exist points on E that generate a prime order group of points for which the DLP is hard. Based on these groups secure crypto systems can be built. The point addition on curves over the field R can be visualized. See [EllipticCurve] for some nice images. In ECC implementations it is essential to have routines for point addition, doubling, inversion, etc. We present pseudocode for the most important ones: Let (x, y) be a point on the elliptic curve E(a, b). The point (x', y') := 2 * (x, y) can be computed by l = x + (y / x) x' = l^2 + l + a y' = x^2 + l*x' + x' return (x', y') For two points P = (x1, y1), Q = (x2, y2) the sum (x3, y3) = P + Q can be computed by l = (y2 + y1) / (x2 + x1) x3 = l^2 + l + x1 + x2 + a y3 = l(x1 + x3) + x3 + y1 return (x3, y3) Some special cases where the point at infinity 'o' has to be considered have been omitted here. Have a look at [PointArith] for complete pseudocode routines. But nevertheless we see that point arithmetic is easy and straight forward to implement. A handful of field additions, multiplications plus a single division do the job. The existence of routines that do point doubling and addition is sufficient to be able to build an efficient "scalar multiplier": a routine that multiplies a given curve point P by any given natural number k. The double-and-add algorithm works as follows: H := 'o' let n be the number of the highest set bit in k while(n >= 0) { H = 2 * H; if the nth bit in k is set: H = H + P; n--; } return H; Example. Suppose you want to calculate k*P for k = 11 = 1011b. Then n is initialized to 3 and H calculated as H = 2 * (2 * (2 * (2 * 'o' + P)) + P) + P = 2 * (2 * (2 * P) + P) + P = 2 * (5 * P) + P = 11 * P Some elliptic curves that are suitable for cryptographic purposes have been standardized. NIST recommends 15 curves (see [NIST]), among them five binary ones called B163, B233, B283, B409 and B571. The parameters of B163 are the following ([NISTParams]): Field: GF(2^163) Reduction poly: p(t) = t^163 + t^7 + t^6 + t^3 + 1 Coefficient a: 1 Coefficient b: 20a601907b8c953ca1481eb10512f78744a3205fd x coordinate of g: 3f0eba16286a2d57ea0991168d4994637e8343e36 y coordinate of g: 0d51fbc6c71a0094fa2cdd545b11c5c0c797324f1 group order: 2 * 5846006549323611672814742442876390689256843201587 The field size is 2^163, the corresponding symmetric security level is about 80 bits (see chapter 4). The field elements are given in hexadecimal, the curve's order in decimal form as h * n, where h (the "cofactor") is small and n is a large prime number. The point g is chosen in a way that the subgroup generated by g has order n. The source code included in this article works with B163. It can easily be patched to support any other binary NIST curve; for this it is sufficient to alter just 6 lines. Exercise. Try it out: patch the sources to get a B409 crypto system. You will find the curve's parameters in [NISTParams]. Read [EllipticCurve], [PointArith] and [DoubleAndAdd] for further information. ---[ 4 - On the Security of Elliptic Curve Cryptography We learned that the security of the DH key exchange is based on the hardness of the DLP in the underlying group. Algorithms are known that determine discrete logarithms in arbitrary groups; for this task no better time complexity bound is known than that for Pollard's "Rho Method" ([PollardRho]): Theorem. Let G be a finite (cyclic) group. Then there exists an algorithm that solves DLP in approximately sqrt(|G|) steps (and low memory usage). For elliptic curves no DLP solving algorithm is known that performs better than the one mentioned above. Thus it is believed that the ECCDLP is "fully exponential" with regard to the bit-length of |G|. RSA and classical DH systems can, by contrast, be broken in "subexponential" time. Hence their key lengths must be larger than those for ECC systems to achieve the same level of security. We already saw that elliptic curves over GF(2^m) contain about 2^m points. Therefore DLP can be solved in about sqrt(2^m) steps, that is 2^(m/2). We conclude that m-bit ECC systems are equivalent to (m/2)-bit symmetric ciphers in measures of security. The following table compares equivalent key sizes for various crypto systems. ECC key size | RSA key size | DH key size | AES key size -------------+--------------+-------------+------------- 160 | 1024 | 1024 | (80) 256 | 3072 | 3072 | 128 384 | 7680 | 7680 | 192 512 | 15360 | 15360 | 256 ---[ 5 - The ECIES Public Key Encryption Scheme Earlier we presented the DH Key Exchange and the ElGamal public key crypto system built on top of it. The Elliptic Curve Integrated Encryption Scheme (ECIES, see ANSI X9.63) is an enhancement of ElGamal encryption specifically designed for EC groups. ECIES provides measures to defeat active attacks like the one presented above. Let E be an elliptic curve of order h * n with n a large prime number. Let G be a subgroup of E with |G| = n. Choose a point P in G unequal to 'o'. We start with ECIES key generation: Alice picks as private key a random number 'd' with 1 <= d < n; She distributes the point Q := d * P as public key. If Bob wants to encrypt a message m for Alice he proceeds as follows: 1. Pick a random number 'k' with 1 <= k < n. 2. Compute Z = h * k * Q. 3. If Z = 'o' goto step 1. 4. Compute R = k * P. 5. Compute (k1, k2) = KDF(Z, R) (see below). 6. Encrypt m with key k1. 7. Calculate the MAC of the ciphertext using k2 as MAC key. 8. Transmit R, the cipher text and the MAC to Alice. Alice decrypts the cipher text using the following algorithm: 1. Check that R is a valid point on the elliptic curve. 2. Compute Z = h * d * R. 3. Check Z != 'o'. 4. Compute (k1, k2) = KDF(Z, R) (see below). 5. Check the validity of the MAC using key k2. 6. Decrypt m using key k1. If any of the checks fails: reject the message as forged. KDF is a key derivation function that produces symmetric keys k1, k2 from a pair of elliptic curve points. Just think of KDF being the cryptographic hash function of your choice. ECIES offers two important features: 1. If an attacker injects a curve point R that does not generate a large group (this is the case in the attack mentioned above), this is detected in steps 2 und 3 of the decryption process (the cofactor plays a fundamental role here). 2. The message is not only encrypted in a secure way, it is also protected from modification by a MAC. Exercise. Implement a DH key exchange. Let E be a binary elliptic curve or order h * n. Let G be a subgroup of E with |G| = n. Choose a point g in G unequal to 'o'. Let Alice and Bob proceed as follows: 1. Alice picks a random number 'a' with 1 <= a < n and sends P = a * g to Bob. 2. Bob picks a random number 'b' with 1 <= b < n and sends Q = b * g to Alice. 3. Alice checks that Q is a point on the curve that generates a group of order n (see the ECIES_public_key_validation routine). Alice calculates S = a * Q. 4. Bob checks that P is a point on the curve that generates a group of ordern n. He calculates T = b * P. If everything went OK the equality S = T should hold. ---[ 6 - The XTEA Block Cipher, CBC-MAC and Davies-Meyer Hashing XTEA is the name of a patent-free secure block cipher invented by Wheeler and Needham in 1997. The block size is 64 bits, keys are 128 bits long. The main benefit of XTEA over its competitors AES, Twofish, etc is the compact description of the algorithm: void encipher(unsigned long m[], unsigned long key[]) { unsigned long sum = 0, delta = 0x9E3779B9; int i; for(i = 0; i < 32; i++) { m[0] += ((m[1] << 4 ^ m[1] >> 5) + m[1]) ^ (sum + key[sum & 3]); sum += delta; m[1] += ((m[0] << 4 ^ m[0] >> 5) + m[0]) ^ (sum + key[sum >> 11 & 3]); } } Let E be a symmetric encryption function with block length n, initialized with key k. The CBC-MAC of a message m is calculated as follows: 1. Split m in n-bit-long submessages m1, m2, m3, ... 2. Calculate the intermediate values t0 = E(length(m)), t1 = E(m1 XOR t0), t2 = E(m2 XOR t1), t3 = E(m3 XOR t2), ... 3. Return the last value obtained in step 2 as MAC(k, m) and discard t0, t1, t2, ... Next we show how a block cipher can be used to build a cryptographic hash function using the "Davies-Meyer" construction. Let m be the message that is to be hashed. Let E(key,block) be a symmetric encryption function with block length n and key length l. 1. Split m in l-bit-long submessages m1, m2, m3, ... 2. Calculate the intermediate values h1 = E(m1, 0), h2 = E(m2, h1) XOR h1, h3 = E(m3, h2) XOR h2, ... 3. If h is the last intermediate value obtained in step 2 return E(length(m), h) XOR h as hash value and discard h1, h2, h3, ... The code included in this article uses the block cipher XTEA in counter mode (CTR) for encryption, a CBC-MAC garantees message authenticity; finally KDF (see chapter 5) is implemented using XTEA in Davies-Meyer mode. Read [XTEA] and [DMhashing] to learn more about the XTEA block cipher and the Davies-Meyer construction. ---[ 7 - Putting Everything Together: The Source Code The public domain source code you find at the end of this document implements the ECIES public key encryption system over the curve B163. The code is commented, but we outline the design here. 1. The central data structure is a bit vector of fixed but "long" length. It is the base data type used to represent field elements and suchlike. The dedicated typedef is called bitstr_t. Appropriate routines for bit manipulation, shifting, bitcounting, importing from an ASCII/HEX representation, etc do exist. 2. The functions with "field_" prefix do the field arithmetic: addition, multiplication and calculation of the multiplicative inverse of elements are the important routines. 3. ECC points are represented as pairs of elem_t (an alias for bitstr_t), the special point-at-infinity as the pair (0,0). The functions prefixed with "point_" act on elliptic curve points and implement basic point operations: point addition, point doubling, etc. 4. The function "point_mult" implements the double-and-add algorithm to compute "k * (x,y)" in the way described in chapter 3 . 5. The "XTEA"-prefixed functions implement the XTEA block cipher, but also the CBC-MAC and the Davies-Meyer construction. 6. The "ECIES_"-routines do the ECIES related work. ECIES_generate_key_pair() generates a private/public key pair, ECIES_public_key_validation() checks that a given point is on the curve and generates a group of order "n". ECIES_encryption/ECIES_decryption do what their names imply. 7. A demonstration of the main ECIES functionalities is given in the program's main() section. The code may be compiled like this: gcc -O2 -o ecc ecc.c ---[ 8 - Conclusion We have seen how crypto systems are built upon algebraical groups that have certain properties. We further gave an introduction into a special class of appropriate groups and their theory, namely to the binary elliptic curves. Finally we presented the secure public key encryption scheme ECIES (together with necessary symmetrical components). All this is implemented in the source code included in this article. We recall that besides security the central design goal of the code was compactness, not speed or generality. Libraries specialized on EC cryptography benefit from assembler hand-coded field arithmetic routines and easily perform a hundred times faster than this code. If compactness is not essential for your application you might opt for linking against one of the following ECC capable free crypto libraries instead: Crypto++ (C++) http://www.eskimo.com/~weidai/cryptlib.html Mecca (C) http://point-at-infinity.org/mecca/ LibTomCrypt (C) http://libtomcrypt.org/ borZoi (C++/Java) http://dragongate-technologies.com/products.html ---[ 9 - Outlook You have learned a lot about elliptic curves while reading this article, but there still remains a bunch of unmentioned ideas. We list some important ones: 1. Elliptic curves can be defined over other fields than binary ones. Let p be a prime number and Z_p the set of nonnegative integers smaller than p. Then Z_p forms a finite field (addition and multiplication have to be understood modulo p, see [ModularArithmetic] and [FiniteField]). For these fields the elliptic curve E(a, b) is defined to be the set of solutions of the equation y^2 = x^3 + ax + b plus the point at infinity 'o'. Of course point addition and doubling routines differ from that given above, but essentially these "prime curves" form an algebraical group in a similar way as binary curves do. It is not that prime curves are more or less secure than binary curves. They just offer another class of groups suitable for cryptographic purposes. NIST recommends five prime curves: P192, P224, P256, P384 and P521. 2. In this article we presented the public key encryption scheme ECIES. It should be mentioned that ECC-based signature schemes (see [ECDSA]) and authenticated key establishment protocols ([MQV]) do also exist. The implementation is left as exercise to the reader. 3. Our double-and-add point multiplicator is very rudimentary. Better ones can do the "k * P" job in half the time. We just give the idea of a first improvement: Suppose we want to calculate 15 * P for a curve point P. The double-and-add algorithm does this in the following way: 15 * P = 2 * (2 * (2 * (2 * 'o' + P) + P) + P) + P This takes three point doublings and three point additions (calculations concerning 'o' are not considered). We could compute 15 * P in a cleverer fashion: 15 * P = 16 * P - P = 2 * 2 * 2 * 2 * P - P This takes four doublings plus a single addition; hence we may expect point multiplicators using this trick to be better performers than the standard double-and-add algorithm. In practice this trick can speed up the point multiplication by about 30%. See [NAF] for more information about this topic. 4. In implementations the most time consuming field operation is always the element inversion. We saw that both the point addition and the point doubling routines require one field division each. There is a trick that reduces the amount of divisions in a full "k * P" point multiplication to just one. The idea is to represent the curve point (x,y) as triple (X,Y,Z) where x = X/Z, y = Y/Z. In this "projective" representation all field divisions can by deferred to the very end of the point multiplication, where they are carried out in a single inversion. Different types of coordinate systems of the projective type are presented in [CoordSys]. ---[ A - Appendix: Literature A variety of interesting literature exists on elliptic curve cryptography. I recommend to start with [G2ECC] and [ECIC]. Other good references are given in [ECC]. Elliptic curves and cryptographical protocols using them have been standardized by IEEE [P1363], ANSI (X9.62, X9.63) and SECG [SECG], to list just some. See [Certicom] and [ECCPrimer] for two tutorials about ECC. The best reference about classical cryptography is [HAC]. [G2ECC] Hankerson, Menezes, Vanstone, "Guide to Elliptic Curve Cryptography", Springer-Verlag, 2004 http://www.cacr.math.uwaterloo.ca/ecc/ [ECIC] Blake, Seroussi, Smart, "Elliptic Curves in Cryptography", Cambridge University Press, 1999 http://www.cambridge.org/aus/catalogue/catalogue.asp?isbn=0521653746 [HAC] Menezes, Oorschot, Vanstone: "Handbook of Applied Cryptography", CRC Press, 1996, http://www.cacr.math.uwaterloo.ca/hac/ [Groups] http://en.wikipedia.org/wiki/Group_(mathematics) [Lagrange] http://en.wikipedia.org/wiki/Lagrange's_theorem [CyclicGroups] http://en.wikipedia.org/wiki/Cyclic_group [GroupTheory] http://en.wikipedia.org/wiki/Elementary_group_theory [DLP] http://en.wikipedia.org/wiki/Discrete_logarithm [DH] http://en.wikipedia.org/wiki/Diffie-Hellman [ElGamal] http://en.wikipedia.org/wiki/ElGamal_discrete_log_cryptosystem [AliceAndBob] http://en.wikipedia.org/wiki/Alice_and_Bob [FiniteField] http://en.wikipedia.org/wiki/Finite_field [FieldTheory] http://en.wikipedia.org/wiki/Field_theory_(mathematics) [FieldTheoryGlossary] http://en.wikipedia.org/wiki/Glossary_of_field_theory [FieldArithmetic] http://en.wikipedia.org/wiki/Finite_field_arithmetic [ModularArithmetic] http://en.wikipedia.org/wiki/Modular_arithmetic [ECC] http://en.wikipedia.org/wiki/Elliptic_curve_cryptography [EllipticCurve] http://en.wikipedia.org/wiki/Elliptic_curve [PointArith] http://wikisource.org/wiki/Binary_Curve_Affine_Coordinates [DoubleAndAdd] http://en.wikipedia.org/wiki/Exponentiation_by_squaring [NIST] http://csrc.nist.gov/CryptoToolkit/dss/ecdsa/NISTReCur.ps [NISTParams] http://wikisource.org/wiki/NIST_Binary_Curves_Parameters [PollardRho] http://en.wikipedia.org/wiki/ Pollard's_rho_algorithm_for_logarithms [XTEA] http://en.wikipedia.org/wiki/XTEA [DMhashing] http://en.wikipedia.org/wiki/Davies-Meyer_construction [ECDSA] http://en.wikipedia.org/wiki/Elliptic_Curve_DSA [MQV] http://en.wikipedia.org/wiki/MQV [NAF] http://en.wikipedia.org/wiki/Non-adjacent_form [CoordSys] http://wikisource.org/wiki/Wikisource:Cryptography [P1363] http://en.wikipedia.org/wiki/IEEE_P1363 [SECG] http://en.wikipedia.org/wiki/SECG [Certicom] http://www.certicom.com/index.php?action=ecc,ecc_tutorial [ECCPrimer] http://linuxdevices.com/articles/AT7211498192.html ---[ B - Appendix: Code $ cat ecc.c.uue begin 644 ecc.c M+RH@"B`@5&AI<R!P<F]G<F%M(&EM<&QE;65N=',@=&AE($5#2453('!U8FQI M8R!K97D@96YC<GEP=&EO;B!S8VAE;64@8F%S960@;VX@=&AE"B`@3DE35"!" M,38S(&5L;&EP=&EC(&-U<G9E(&%N9"!T:&4@6%1%02!B;&]C:R!C:7!H97(N M(%1H92!C;V1E('=A<R!W<FET=&5N"B`@87,@86X@86-C;VUP86YI;65N="!F M;W(@86X@87)T:6-L92!P=6)L:7-H960@:6X@<&AR86-K(",V,R!A;F0@:7,@ M<F5L96%S960@=&\*("!T:&4@<'5B;&EC(&1O;6%I;BX**B\*"B-I;F-L=61E M(#QS=&1I;G0N:#X*(VEN8VQU9&4@/'-T9&QI8BYH/@HC:6YC;'5D92`\<W1R M:6YG+F@^"B-I;F-L=61E(#QF8VYT;"YH/@HC:6YC;'5D92`\=6YI<W1D+F@^ M"B-I;F-L=61E(#QS=&1I;RYH/@HC:6YC;'5D92`\;F5T:6YE="]I;BYH/@H* M(V1E9FEN92!-04-23RA!*2!D;R![($$[('T@=VAI;&4H,"D*(V1E9FEN92!- M24XH82P@8BD@*"AA*2`\("AB*2`_("AA*2`Z("AB*2D*(V1E9FEN92!#2$%2 M4S))3E0H<'1R*2!N=&]H;"@J*'5I;G0S,E]T*BDH<'1R*2D*(V1E9FEN92!) M3E0R0TA!4E,H<'1R+"!V86PI($U!0U)/*"`J*'5I;G0S,E]T*BDH<'1R*2`] M(&AT;VYL*'9A;"D@*0H*(V1E9FEN92!$159?4D%.1$]-("(O9&5V+W5R86YD M;VTB"@HC9&5F:6YE($9!5$%,*',I($U!0U)/*"!P97)R;W(H<RD[(&5X:70H M,C4U*2`I"@HO*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ+PH* M(V1E9FEN92!$14=2144@,38S("`@("`@("`@("`@("`@("`@("`@("\J('1H M92!D96=R964@;V8@=&AE(&9I96QD('!O;'EN;VUI86P@*B\*(V1E9FEN92!- M05)'24X@,R`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("\J(&1O;B=T('1O=6-H('1H:7,@*B\*(V1E9FEN92!.54U73U)$4R`H M*$1%1U)%12`K($U!4D=)3B`K(#,Q*2`O(#,R*0H*("`@+RH@=&AE(&9O;&QO M=VEN9R!T>7!E('=I;&P@<F5P<F5S96YT(&)I="!V96-T;W)S(&]F(&QE;F=T M:"`H1$5'4D5%*TU!4D=)3BD@*B\*='EP961E9B!U:6YT,S)?="!B:71S=')? M=%M.54U73U)$4UT["@H@("`@("\J('-O;64@8F%S:6,@8FET+6UA;FEP=6QA M=&EO;B!R;W5T:6YE<R!T:&%T(&%C="!O;B!T:&5S92!V96-T;W)S(&9O;&QO M=R`J+PHC9&5F:6YE(&)I='-T<E]G971B:70H02P@:61X*2`H*$%;*&ED>"D@ M+R`S,ET@/CX@*"AI9'@I("4@,S(I*2`F(#$I"B-D969I;F4@8FET<W1R7W-E M=&)I="A!+"!I9'@I($U!0U)/*"!!6RAI9'@I("\@,S)=('P](#$@/#P@*"AI M9'@I("4@,S(I("D*(V1E9FEN92!B:71S=')?8VQR8FET*$$L(&ED>"D@34%# M4D\H($%;*&ED>"D@+R`S,ET@)CT@?B@Q(#P\("@H:61X*2`E(#,R*2D@*0H* M(V1E9FEN92!B:71S=')?8VQE87(H02D@34%#4D\H(&UE;7-E="A!+"`P+"!S M:7IE;V8H8FET<W1R7W0I*2`I"B-D969I;F4@8FET<W1R7V-O<'DH02P@0BD@ M34%#4D\H(&UE;6-P>2A!+"!"+"!S:7IE;V8H8FET<W1R7W0I*2`I"B-D969I M;F4@8FET<W1R7W-W87`H02P@0BD@34%#4D\H(&)I='-T<E]T(&@[(%P*("!B M:71S=')?8V]P>2AH+"!!*3L@8FET<W1R7V-O<'DH02P@0BD[(&)I='-T<E]C M;W!Y*$(L(&@I("D*(V1E9FEN92!B:71S=')?:7-?97%U86PH02P@0BD@*"$@ M;65M8VUP*$$L($(L('-I>F5O9BAB:71S=')?="DI*0H*:6YT(&)I='-T<E]I M<U]C;&5A<BAC;VYS="!B:71S=')?="!X*0I["B`@:6YT(&D["B`@9F]R*&D@ M/2`P.R!I(#P@3E5-5T]21%,@)B8@(2`J>"LK.R!I*RLI.PH@(')E='5R;B!I M(#T]($Y535=/4D13.PI]"@H@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`O*B!R971U<FX@=&AE(&YU;6)E<B!O9B!T:&4@:&EG:&5S="!O;F4M8FET M("L@,2`J+PII;G0@8FET<W1R7W-I>F5I;F)I=',H8V]N<W0@8FET<W1R7W0@ M>"D*>PH@(&EN="!I.PH@('5I;G0S,E]T(&UA<VL["B`@9F]R*'@@*ST@3E5- M5T]21%,L(&D@/2`S,B`J($Y535=/4D13.R!I(#X@,"`F)B`A("HM+7@[(&D@ M+3T@,S(I.PH@(&EF("AI*0H@("`@9F]R*&UA<VL@/2`Q(#P\(#,Q.R`A("@J M>"`F(&UA<VLI.R!M87-K(#X^/2`Q+"!I+2TI.PH@(')E='5R;B!I.PI]"@H@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M+RH@;&5F="US:&EF="!B>2`G8V]U;G0G(&1I9VET<R`J+PIV;VED(&)I='-T M<E]L<VAI9G0H8FET<W1R7W0@02P@8V]N<W0@8FET<W1R7W0@0BP@:6YT(&-O M=6YT*0I["B`@:6YT(&DL(&]F9G,@/2`T("H@*&-O=6YT("\@,S(I.PH@(&UE M;6UO=F4H*'9O:60J*4$@*R!O9F9S+"!"+"!S:7IE;V8H8FET<W1R7W0I("T@ M;V9F<RD["B`@;65M<V5T*$$L(#`L(&]F9G,I.PH@(&EF("AC;W5N="`E/2`S M,BD@>PH@("`@9F]R*&D@/2!.54U73U)$4R`M(#$[(&D@/B`P.R!I+2TI"B`@ M("`@($%;:5T@/2`H05MI72`\/"!C;W5N="D@?"`H05MI("T@,5T@/CX@*#,R M("T@8V]U;G0I*3L*("`@($%;,%T@/#P](&-O=6YT.PH@('T*?0H*("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`O*B`H<F%W M*2!I;7!O<G0@9G)O;2!A(&)Y=&4@87)R87D@*B\*=F]I9"!B:71S=')?:6UP M;W)T*&)I='-T<E]T('@L(&-O;G-T(&-H87(@*G,I"GL*("!I;G0@:3L*("!F M;W(H>"`K/2!.54U73U)$4RP@:2`](#`[(&D@/"!.54U73U)$4SL@:2LK+"!S M("L](#0I"B`@("`J+2UX(#T@0TA!4E,R24Y4*',I.PI]"@H@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@+RH@*')A=RD@ M97AP;W)T('1O(&$@8GET92!A<G)A>2`J+PIV;VED(&)I='-T<E]E>'!O<G0H M8VAA<B`J<RP@8V]N<W0@8FET<W1R7W0@>"D*>PH@(&EN="!I.PH@(&9O<BAX M("L]($Y535=/4D13+"!I(#T@,#L@:2`\($Y535=/4D13.R!I*RLL(',@*ST@ M-"D*("`@($E.5#)#2$%24RAS+"`J+2UX*3L*?0H*("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`O*B!E>'!O<G0@87,@:&5X('-T<FEN9R`H M;G5L;"UT97)M:6YA=&5D(2D@*B\*=F]I9"!B:71S=')?=&]?:&5X*&-H87(@ M*G,L(&-O;G-T(&)I='-T<E]T('@I"GL*("!I;G0@:3L*("!F;W(H>"`K/2!. M54U73U)$4RP@:2`](#`[(&D@/"!.54U73U)$4SL@:2LK+"!S("L](#@I"B`@ M("!S<')I;G1F*',L("(E,#AX(BP@*BTM>"D["GT*"B`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@+RH@:6UP;W)T M(&9R;VT@82!H97@@<W1R:6YG("HO"FEN="!B:71S=')?<&%R<V4H8FET<W1R M7W0@>"P@8V]N<W0@8VAA<B`J<RD*>PH@(&EN="!L96X["B`@:68@*"AS6VQE M;B`]('-T<G-P;BAS+"`B,#$R,S0U-C<X.6%B8V1E9D%"0T1%1B(I72D@?'P* M("`@("`@*&QE;B`^($Y535=/4D13("H@."DI"B`@("!R971U<FX@+3$["B`@ M8FET<W1R7V-L96%R*'@I.PH@('@@*ST@;&5N("\@.#L*("!I9B`H;&5N("4@ M."D@>PH@("`@<W-C86YF*',L("(E,#AX(BP@>"D["B`@("`J>"`^/CT@,S(@ M+2`T("H@*&QE;B`E(#@I.PH@("`@<R`K/2!L96X@)2`X.PH@("`@;&5N("8] M('XW.PH@('T*("!F;W(H.R`J<SL@<R`K/2`X*0H@("`@<W-C86YF*',L("(E M,#AX(BP@+2UX*3L*("!R971U<FX@;&5N.PI]"@HO*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ+PH*='EP961E9B!B:71S=')?="!E;&5M7W0[ M("`@("`@("`@("`O*B!T:&ES('1Y<&4@=VEL;"!R97!R97-E;G0@9FEE;&0@ M96QE;65N=',@*B\*"F5L96U?="!P;VQY.R`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@+RH@=&AE(')E9'5C=&EO;B!P;VQY;F]M:6%L M("HO"@HC9&5F:6YE(&9I96QD7W-E=#$H02D@34%#4D\H($%;,%T@/2`Q.R!M M96US970H02`K(#$L(#`L('-I>F5O9BAE;&5M7W0I("T@-"D@*0H*:6YT(&9I M96QD7VES,2AC;VYS="!E;&5M7W0@>"D*>PH@(&EN="!I.PH@(&EF("@J>"LK M("$](#$I(')E='5R;B`P.PH@(&9O<BAI(#T@,3L@:2`\($Y535=/4D13("8F M("$@*G@K*SL@:2LK*3L*("!R971U<FX@:2`]/2!.54U73U)$4SL*?0H*=F]I M9"!F:65L9%]A9&0H96QE;5]T('HL(&-O;G-T(&5L96U?="!X+"!C;VYS="!E M;&5M7W0@>2D@("`@+RH@9FEE;&0@861D:71I;VX@*B\*>PH@(&EN="!I.PH@ M(&9O<BAI(#T@,#L@:2`\($Y535=/4D13.R!I*RLI"B`@("`J>BLK(#T@*G@K M*R!>("IY*RL["GT*"B-D969I;F4@9FEE;&1?861D,2A!*2!-04-23R@@05LP M72!>/2`Q("D*"B`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("\J(&9I96QD(&UU;'1I<&QI8V%T:6]N("HO M"G9O:60@9FEE;&1?;75L="AE;&5M7W0@>BP@8V]N<W0@96QE;5]T('@L(&-O M;G-T(&5L96U?="!Y*0I["B`@96QE;5]T(&(["B`@:6YT(&DL(&H["B`@+RH@ M87-S97)T*'H@(3T@>2D[("HO"B`@8FET<W1R7V-O<'DH8BP@>"D["B`@:68@ M*&)I='-T<E]G971B:70H>2P@,"DI"B`@("!B:71S=')?8V]P>2AZ+"!X*3L* M("!E;'-E"B`@("!B:71S=')?8VQE87(H>BD["B`@9F]R*&D@/2`Q.R!I(#P@ M1$5'4D5%.R!I*RLI('L*("`@(&9O<BAJ(#T@3E5-5T]21%,@+2`Q.R!J(#X@ M,#L@:BTM*0H@("`@("!B6VI=(#T@*&);:ET@/#P@,2D@?"`H8EMJ("T@,5T@ M/CX@,S$I.PH@("`@8ELP72`\/#T@,3L*("`@(&EF("AB:71S=')?9V5T8FET M*&(L($1%1U)%12DI"B`@("`@(&9I96QD7V%D9"AB+"!B+"!P;VQY*3L*("`@ M(&EF("AB:71S=')?9V5T8FET*'DL(&DI*0H@("`@("!F:65L9%]A9&0H>BP@ M>BP@8BD["B`@?0I]"@IV;VED(&9I96QD7VEN=F5R="AE;&5M7W0@>BP@8V]N M<W0@96QE;5]T('@I("`@("`@("`@("`@("`@("\J(&9I96QD(&EN=F5R<VEO M;B`J+PI["B`@96QE;5]T('4L('8L(&<L(&@["B`@:6YT(&D["B`@8FET<W1R M7V-O<'DH=2P@>"D["B`@8FET<W1R7V-O<'DH=BP@<&]L>2D["B`@8FET<W1R M7V-L96%R*&<I.PH@(&9I96QD7W-E=#$H>BD["B`@=VAI;&4@*"$@9FEE;&1? M:7,Q*'4I*2!["B`@("!I(#T@8FET<W1R7W-I>F5I;F)I=',H=2D@+2!B:71S M=')?<VEZ96EN8FET<RAV*3L*("`@(&EF("AI(#P@,"D@>PH@("`@("!B:71S M=')?<W=A<"AU+"!V*3L@8FET<W1R7W-W87`H9RP@>BD[(&D@/2`M:3L*("`@ M('T*("`@(&)I='-T<E]L<VAI9G0H:"P@=BP@:2D["B`@("!F:65L9%]A9&0H M=2P@=2P@:"D["B`@("!B:71S=')?;'-H:69T*&@L(&<L(&DI.PH@("`@9FEE M;&1?861D*'HL('HL(&@I.PH@('T*?0H*+RHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*B\*"B\J(%1H92!F;VQL;W=I;F<@<F]U=&EN97,@9&\@ M=&AE($5#0R!A<FET:&UE=&EC+B!%;&QI<'1I8R!C=7)V92!P;VEN=',*("`@ M87)E(')E<')E<V5N=&5D(&)Y('!A:7)S("AX+'DI(&]F(&5L96U?="X@270@ M:7,@87-S=6UE9"!T:&%T(&-U<G9E"B`@(&-O969F:6-I96YT("=A)R!I<R!E M<75A;"!T;R`Q("AT:&ES(&ES('1H92!C87-E(&9O<B!A;&P@3DE35"!B:6YA M<GD*("`@8W5R=F5S*2X@0V]E9F9I8VEE;G0@)V(G(&ES(&=I=F5N(&EN("=C M;V5F9E]B)RX@("<H8F%S95]X+"!B87-E7WDI)PH@("!I<R!A('!O:6YT('1H M870@9V5N97)A=&5S(&$@;&%R9V4@<')I;64@;W)D97(@9W)O=7`N("`@("`@ M("`@("`@("HO"@IE;&5M7W0@8V]E9F9?8BP@8F%S95]X+"!B87-E7WD["@HC M9&5F:6YE('!O:6YT7VES7WIE<F\H>"P@>2D@*&)I='-T<E]I<U]C;&5A<BAX M*2`F)B!B:71S=')?:7-?8VQE87(H>2DI"B-D969I;F4@<&]I;G1?<V5T7WIE M<F\H>"P@>2D@34%#4D\H(&)I='-T<E]C;&5A<BAX*3L@8FET<W1R7V-L96%R M*'DI("D*(V1E9FEN92!P;VEN=%]C;W!Y*'@Q+"!Y,2P@>#(L('DR*2!-04-2 M3R@@8FET<W1R7V-O<'DH>#$L('@R*3L@7`H@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("!B:71S=')?8V]P>2AY,2P@>3(I("D* M"B`@("`@("`@("`@("`@("`@("`@("`@("`@("\J(&-H96-K(&EF('E>,B`K M('@J>2`]('A>,R`K("IX7C(@*R!C;V5F9E]B(&AO;&1S("HO"FEN="!I<U]P M;VEN=%]O;E]C=7)V92AC;VYS="!E;&5M7W0@>"P@8V]N<W0@96QE;5]T('DI M"GL*("!E;&5M7W0@82P@8CL*("!I9B`H<&]I;G1?:7-?>F5R;RAX+"!Y*2D* M("`@(')E='5R;B`Q.PH@(&9I96QD7VUU;'0H82P@>"P@>"D["B`@9FEE;&1? M;75L="AB+"!A+"!X*3L*("!F:65L9%]A9&0H82P@82P@8BD["B`@9FEE;&1? M861D*&$L(&$L(&-O969F7V(I.PH@(&9I96QD7VUU;'0H8BP@>2P@>2D["B`@ M9FEE;&1?861D*&$L(&$L(&(I.PH@(&9I96QD7VUU;'0H8BP@>"P@>2D["B`@ M<F5T=7)N(&)I='-T<E]I<U]E<75A;"AA+"!B*3L*?0H*=F]I9"!P;VEN=%]D M;W5B;&4H96QE;5]T('@L(&5L96U?="!Y*2`@("`@("`@("`@("`@("\J(&1O M=6)L92!T:&4@<&]I;G0@*'@L>2D@*B\*>PH@(&EF("@A(&)I='-T<E]I<U]C M;&5A<BAX*2D@>PH@("`@96QE;5]T(&$["B`@("!F:65L9%]I;G9E<G0H82P@ M>"D["B`@("!F:65L9%]M=6QT*&$L(&$L('DI.PH@("`@9FEE;&1?861D*&$L M(&$L('@I.PH@("`@9FEE;&1?;75L="AY+"!X+"!X*3L*("`@(&9I96QD7VUU M;'0H>"P@82P@82D["B`@("!F:65L9%]A9&0Q*&$I.R`@("`@("`@"B`@("!F M:65L9%]A9&0H>"P@>"P@82D["B`@("!F:65L9%]M=6QT*&$L(&$L('@I.PH@ M("`@9FEE;&1?861D*'DL('DL(&$I.PH@('T*("!E;'-E"B`@("!B:71S=')? M8VQE87(H>2D["GT*"B`@("`@("`@("`@("`@("`@("`O*B!A9&0@='=O('!O M:6YT<R!T;V=E=&AE<B`H>#$L('DQ*2`Z/2`H>#$L('DQ*2`K("AX,BP@>3(I M("HO"G9O:60@<&]I;G1?861D*&5L96U?="!X,2P@96QE;5]T('DQ+"!C;VYS M="!E;&5M7W0@>#(L(&-O;G-T(&5L96U?="!Y,BD*>PH@(&EF("@A('!O:6YT M7VES7WIE<F\H>#(L('DR*2D@>PH@("`@:68@*'!O:6YT7VES7WIE<F\H>#$L M('DQ*2D*("`@("`@<&]I;G1?8V]P>2AX,2P@>3$L('@R+"!Y,BD["B`@("!E M;'-E('L*("`@("`@:68@*&)I='-T<E]I<U]E<75A;"AX,2P@>#(I*2!["@EI M9B`H8FET<W1R7VES7V5Q=6%L*'DQ+"!Y,BDI"@D@('!O:6YT7V1O=6)L92AX M,2P@>3$I.PH)96QS92`*"2`@<&]I;G1?<V5T7WIE<F\H>#$L('DQ*3L*("`@ M("`@?0H@("`@("!E;'-E('L*"65L96U?="!A+"!B+"!C+"!D.PH)9FEE;&1? M861D*&$L('DQ+"!Y,BD["@EF:65L9%]A9&0H8BP@>#$L('@R*3L*"69I96QD M7VEN=F5R="AC+"!B*3L*"69I96QD7VUU;'0H8RP@8RP@82D["@EF:65L9%]M M=6QT*&0L(&,L(&,I.PH)9FEE;&1?861D*&0L(&0L(&,I.PH)9FEE;&1?861D M*&0L(&0L(&(I.PH)9FEE;&1?861D,2AD*3L*"69I96QD7V%D9"AX,2P@>#$L M(&0I.PH)9FEE;&1?;75L="AA+"!X,2P@8RD["@EF:65L9%]A9&0H82P@82P@ M9"D["@EF:65L9%]A9&0H>3$L('DQ+"!A*3L*"6)I='-T<E]C;W!Y*'@Q+"!D M*3L*("`@("`@?0H@("`@?0H@('T*?0H*+RHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*B\*"G1Y<&5D968@8FET<W1R7W0@97AP7W0["@IE>'!? M="!B87-E7V]R9&5R.PH*("`@("`@("`@("`@("`@("`@("`@("`@("\J('!O M:6YT(&UU;'1I<&QI8V%T:6]N('9I82!D;W5B;&4M86YD+6%D9"!A;&=O<FET M:&T@*B\*=F]I9"!P;VEN=%]M=6QT*&5L96U?="!X+"!E;&5M7W0@>2P@8V]N M<W0@97AP7W0@97AP*0I["B`@96QE;5]T(%@L(%D["B`@:6YT(&D["B`@<&]I M;G1?<V5T7WIE<F\H6"P@62D["B`@9F]R*&D@/2!B:71S=')?<VEZ96EN8FET M<RAE>'`I("T@,3L@:2`^/2`P.R!I+2TI('L*("`@('!O:6YT7V1O=6)L92A8 M+"!9*3L*("`@(&EF("AB:71S=')?9V5T8FET*&5X<"P@:2DI"B`@("`@('!O M:6YT7V%D9"A8+"!9+"!X+"!Y*3L*("!]"B`@<&]I;G1?8V]P>2AX+"!Y+"!8 M+"!9*3L*?0H*("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("\J(&1R M87<@82!R86YD;VT@=F%L=64@)V5X<"<@=VET:"`Q(#P](&5X<"`\(&X@*B\* M=F]I9"!G971?<F%N9&]M7V5X<&]N96YT*&5X<%]T(&5X<"D*>PH@(&-H87(@ M8G5F6S0@*B!.54U73U)$4UT["B`@:6YT(&9H+"!R+"!S.PH@(&1O('L*("`@ M(&EF("@H9F@@/2!O<&5N*$1%5E]204Y$3TTL($]?4D1/3DQ9*2D@/"`P*0H@ M("`@("!&051!3"A$159?4D%.1$]-*3L*("`@(&9O<BAR(#T@,#L@<B`\(#0@ M*B!.54U73U)$4SL@<B`K/2!S*0H@("`@("!I9B`H*',@/2!R96%D*&9H+"!B M=68@*R!R+"`T("H@3E5-5T]21%,@+2!R*2D@/#T@,"D*"49!5$%,*$1%5E]2 M04Y$3TTI.PH@("`@:68@*&-L;W-E*&9H*2`\(#`I"B`@("`@($9!5$%,*$1% M5E]204Y$3TTI.PH@("`@8FET<W1R7VEM<&]R="AE>'`L(&)U9BD["B`@("!F M;W(H<B`](&)I='-T<E]S:7IE:6YB:71S*&)A<V5?;W)D97(I("T@,3L@<B`\ M($Y535=/4D13("H@,S([('(K*RD*("`@("`@8FET<W1R7V-L<F)I="AE>'`L M('(I.PH@('T@=VAI;&4H8FET<W1R7VES7V-L96%R*&5X<"DI.PI]"@HO*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ+PH*=F]I9"!85$5!7VEN M:71?:V5Y*'5I;G0S,E]T("IK+"!C;VYS="!C:&%R("IK97DI"GL*("!K6S!= M(#T@0TA!4E,R24Y4*&ME>2`K(#`I.R!K6S%=(#T@0TA!4E,R24Y4*&ME>2`K M(#0I.PH@(&M;,ET@/2!#2$%24S))3E0H:V5Y("L@."D[(&M;,UT@/2!#2$%2 M4S))3E0H:V5Y("L@,3(I.PI]"@H@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("\J('1H92!85$5!(&)L;V-K M(&-I<&AE<B`J+PIV;VED(%A414%?96YC:7!H97)?8FQO8VLH8VAA<B`J9&%T M82P@8V]N<W0@=6EN=#,R7W0@*FLI"GL*("!U:6YT,S)?="!S=6T@/2`P+"!D M96QT82`](#!X.64S-S<Y8CDL('DL('H["B`@:6YT(&D["B`@>2`]($-(05)3 M,DE.5"AD871A*3L@>B`]($-(05)3,DE.5"AD871A("L@-"D["B`@9F]R*&D@ M/2`P.R!I(#P@,S([(&DK*RD@>PH@("`@>2`K/2`H*'H@/#P@-"!>('H@/CX@ M-2D@*R!Z*2!>("AS=6T@*R!K6W-U;2`F(#-=*3L*("`@('-U;2`K/2!D96QT M83L*("`@('H@*ST@*"AY(#P\(#0@7B!Y(#X^(#4I("L@>2D@7B`H<W5M("L@ M:UMS=6T@/CX@,3$@)B`S72D["B`@?0H@($E.5#)#2$%24RAD871A+"!Y*3L@ M24Y4,D-(05)3*&1A=&$@*R`T+"!Z*3L*?0H@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@+RH@96YC<GEP M="!I;B!#5%(@;6]D92`J+PIV;VED(%A414%?8W1R7V-R>7!T*&-H87(@*F1A M=&$L(&EN="!S:7IE+"!C;VYS="!C:&%R("IK97DI(`I["B`@=6EN=#,R7W0@ M:ULT72P@8W1R(#T@,#L*("!I;G0@;&5N+"!I.PH@(&-H87(@8G5F6SA=.PH@ M(%A414%?:6YI=%]K97DH:RP@:V5Y*3L*("!W:&EL92AS:7IE*2!["B`@("!) M3E0R0TA!4E,H8G5F+"`P*3L@24Y4,D-(05)3*&)U9B`K(#0L(&-T<BLK*3L* M("`@(%A414%?96YC:7!H97)?8FQO8VLH8G5F+"!K*3L*("`@(&QE;B`]($U) M3B@X+"!S:7IE*3L*("`@(&9O<BAI(#T@,#L@:2`\(&QE;CL@:2LK*0H@("`@ M("`J9&%T82LK(%X](&)U9EMI73L*("`@('-I>F4@+3T@;&5N.PH@('T*?0H* M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`O*B!C86QC=6QA=&4@=&AE($-"0R!-04,@*B\*=F]I9"!85$5! M7V-B8VUA8RAC:&%R("IM86,L(&-O;G-T(&-H87(@*F1A=&$L(&EN="!S:7IE M+"!C;VYS="!C:&%R("IK97DI"GL*("!U:6YT,S)?="!K6S1=.PH@(&EN="!L M96XL(&D["B`@6%1%05]I;FET7VME>2AK+"!K97DI.PH@($E.5#)#2$%24RAM M86,L(#`I.PH@($E.5#)#2$%24RAM86,@*R`T+"!S:7IE*3L*("!85$5!7V5N M8VEP:&5R7V)L;V-K*&UA8RP@:RD["B`@=VAI;&4H<VEZ92D@>PH@("`@;&5N M(#T@34E.*#@L('-I>F4I.PH@("`@9F]R*&D@/2`P.R!I(#P@;&5N.R!I*RLI M"B`@("`@(&UA8UMI72!>/2`J9&%T82LK.PH@("`@6%1%05]E;F-I<&AE<E]B M;&]C:RAM86,L(&LI.PH@("`@<VEZ92`M/2!L96X["B`@?0I]"@H@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@+RH@;6]D:69I960H(2D@ M1&%V:65S+4UE>65R(&-O;G-T<G5C=&EO;BXJ+PIV;VED(%A414%?9&%V:65S M7VUE>65R*&-H87(@*F]U="P@8V]N<W0@8VAA<B`J:6XL(&EN="!I;&5N*0I[ M"B`@=6EN=#,R7W0@:ULT73L*("!C:&%R(&)U9ELX73L*("!I;G0@:3L*("!M M96US970H;W5T+"`P+"`X*3L*("!W:&EL92AI;&5N+2TI('L*("`@(%A414%? M:6YI=%]K97DH:RP@:6XI.PH@("`@;65M8W!Y*&)U9BP@;W5T+"`X*3L*("`@ M(%A414%?96YC:7!H97)?8FQO8VLH8G5F+"!K*3L*("`@(&9O<BAI(#T@,#L@ M:2`\(#@[(&DK*RD*("`@("`@;W5T6VE=(%X](&)U9EMI73L*("`@(&EN("L] M(#$V.PH@('T*?0H*+RHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*B\*"G9O:60@14-)15-?9V5N97)A=&5?:V5Y7W!A:7(H=F]I9"D@("`@("`O M*B!G96YE<F%T92!A('!U8FQI8R]P<FEV871E(&ME>2!P86ER("HO"GL*("!C M:&%R(&)U9ELX("H@3E5-5T]21%,@*R`Q72P@*F)U9G!T<B`](&)U9B`K($Y5 M35=/4D13("H@."`M("A$14=2144@*R`S*2`O(#0["B`@96QE;5]T('@L('D[ M"B`@97AP7W0@:SL*("!G971?<F%N9&]M7V5X<&]N96YT*&LI.PH@('!O:6YT M7V-O<'DH>"P@>2P@8F%S95]X+"!B87-E7WDI.PH@('!O:6YT7VUU;'0H>"P@ M>2P@:RD["B`@<')I;G1F*")(97)E(&ES('EO=7(@;F5W('!U8FQI8R]P<FEV M871E(&ME>2!P86ER.EQN(BD["B`@8FET<W1R7W1O7VAE>"AB=68L('@I.R!P M<FEN=&8H(E!U8FQI8R!K97DZ("5S.B(L(&)U9G!T<BD[(`H@(&)I='-T<E]T M;U]H97@H8G5F+"!Y*3L@<')I;G1F*"(E<UQN(BP@8G5F<'1R*3L*("!B:71S M=')?=&]?:&5X*&)U9BP@:RD[('!R:6YT9B@B4')I=F%T92!K97DZ("5S7&XB M+"!B=69P='(I.PI]"@H@("`@("`@+RH@8VAE8VL@=&AA="!A(&=I=F5N(&5L M96U?="UP86ER(&ES(&$@=F%L:60@<&]I;G0@;VX@=&AE(&-U<G9E("$]("=O M)R`J+PII;G0@14-)15-?96UB961D961?<'5B;&EC7VME>5]V86QI9&%T:6]N M*&-O;G-T(&5L96U?="!0>"P@8V]N<W0@96QE;5]T(%!Y*0I["B`@<F5T=7)N M("AB:71S=')?<VEZ96EN8FET<RA0>"D@/B!$14=2144I('Q\("AB:71S=')? M<VEZ96EN8FET<RA0>2D@/B!$14=2144I('Q\"B`@("!P;VEN=%]I<U]Z97)O M*%!X+"!0>2D@?'P@(2!I<U]P;VEN=%]O;E]C=7)V92A0>"P@4'DI(#\@+3$@ M.B`Q.PI]"@H@("`@("`O*B!S86UE('1H:6YG+"!B=70@8VAE8VL@86QS;R!T M:&%T("A0>"Q0>2D@9V5N97)A=&5S(&$@9W)O=7`@;V8@;W)D97(@;B`J+PII M;G0@14-)15-?<'5B;&EC7VME>5]V86QI9&%T:6]N*&-O;G-T(&-H87(@*E!X M+"!C;VYS="!C:&%R("I0>2D*>PH@(&5L96U?="!X+"!Y.PH@(&EF("@H8FET M<W1R7W!A<G-E*'@L(%!X*2`\(#`I('Q\("AB:71S=')?<&%R<V4H>2P@4'DI M(#P@,"DI"B`@("!R971U<FX@+3$["B`@:68@*$5#24537V5M8F5D9&5D7W!U M8FQI8U]K97E?=F%L:61A=&EO;BAX+"!Y*2`\(#`I"B`@("!R971U<FX@+3$[ M"B`@<&]I;G1?;75L="AX+"!Y+"!B87-E7V]R9&5R*3L*("!R971U<FX@<&]I M;G1?:7-?>F5R;RAX+"!Y*2`_(#$@.B`M,3L*?0H*=F]I9"!%0TE%4U]K9&8H M8VAA<B`J:S$L(&-H87(@*FLR+"!C;VYS="!E;&5M7W0@6G@L("`@("`O*B!A M(&YO;BUS=&%N9&%R9"!+1$8@*B\*"2`@("`@("!C;VYS="!E;&5M7W0@4G@L M(&-O;G-T(&5L96U?="!2>2D*>PH@(&EN="!B=69S:7IE(#T@*#,@*B`H-"`J M($Y535=/4D13*2`K(#$@*R`Q-2D@)B!^,34["B`@8VAA<B!B=69;8G5F<VEZ M95T["B`@;65M<V5T*&)U9BP@,"P@8G5F<VEZ92D["B`@8FET<W1R7V5X<&]R M="AB=68L(%IX*3L*("!B:71S=')?97AP;W)T*&)U9B`K(#0@*B!.54U73U)$ M4RP@4G@I.PH@(&)I='-T<E]E>'!O<G0H8G5F("L@."`J($Y535=/4D13+"!2 M>2D["B`@8G5F6S$R("H@3E5-5T]21%-=(#T@,#L@6%1%05]D879I97-?;65Y M97(H:S$L(&)U9BP@8G5F<VEZ92`O(#$V*3L*("!B=69;,3(@*B!.54U73U)$ M4UT@/2`Q.R!85$5!7V1A=FEE<U]M97EE<BAK,2`K(#@L(&)U9BP@8G5F<VEZ M92`O(#$V*3L*("!B=69;,3(@*B!.54U73U)$4UT@/2`R.R!85$5!7V1A=FEE M<U]M97EE<BAK,BP@8G5F+"!B=69S:7IE("\@,38I.PH@(&)U9ELQ,B`J($Y5 M35=/4D1372`](#,[(%A414%?9&%V:65S7VUE>65R*&LR("L@."P@8G5F+"!B M=69S:7IE("\@,38I.PI]"@HC9&5F:6YE($5#24537T]615)(14%$("@X("H@ M3E5-5T]21%,@*R`X*0H*("`@("`@("`@("`@("`@("`@+RH@14-)15,@96YC M<GEP=&EO;CL@=&AE(')E<W5L=&EN9R!C:7!H97(@=&5X="!M97-S86=E('=I M;&P@8F4*("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`H;&5N("L@14-)15-?3U9%4DA%040I(&)Y=&5S(&QO;F<@*B\*=F]I M9"!%0TE%4U]E;F-R>7!T:6]N*&-H87(@*FUS9RP@8V]N<W0@8VAA<B`J=&5X M="P@:6YT(&QE;BP@"@D)("`@("`@8V]N<W0@8VAA<B`J4'@L(&-O;G-T(&-H M87(@*E!Y*0I["B`@96QE;5]T(%)X+"!2>2P@6G@L(%IY.PH@(&-H87(@:S%; M,39=+"!K,ELQ-ET["B`@97AP7W0@:SL*("!D;R!["B`@("!G971?<F%N9&]M M7V5X<&]N96YT*&LI.PH@("`@8FET<W1R7W!A<G-E*%IX+"!0>"D["B`@("!B M:71S=')?<&%R<V4H6GDL(%!Y*3L*("`@('!O:6YT7VUU;'0H6G@L(%IY+"!K M*3L*("`@('!O:6YT7V1O=6)L92A:>"P@6GDI.R`@("`@("`@("`@("`@("`@ M("`@("`@("`@("\J(&-O9F%C=&]R(&@@/2`R(&]N($(Q-C,@*B\*("!]('=H M:6QE*'!O:6YT7VES7WIE<F\H6G@L(%IY*2D["B`@<&]I;G1?8V]P>2A2>"P@ M4GDL(&)A<V5?>"P@8F%S95]Y*3L*("!P;VEN=%]M=6QT*%)X+"!2>2P@:RD[ M"B`@14-)15-?:V1F*&LQ+"!K,BP@6G@L(%)X+"!2>2D["@H@(&)I='-T<E]E M>'!O<G0H;7-G+"!2>"D["B`@8FET<W1R7V5X<&]R="AM<V<@*R`T("H@3E5- M5T]21%,L(%)Y*3L*("!M96UC<'DH;7-G("L@."`J($Y535=/4D13+"!T97AT M+"!L96XI.PH@(%A414%?8W1R7V-R>7!T*&US9R`K(#@@*B!.54U73U)$4RP@ M;&5N+"!K,2D["B`@6%1%05]C8F-M86,H;7-G("L@."`J($Y535=/4D13("L@ M;&5N+"!M<V<@*R`X("H@3E5-5T]21%,L(&QE;BP@:S(I.PI]"@H@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@+RH@14-)15,@9&5C<GEP=&EO;B`J+PII;G0@14-)15-?9&5C<GEP M=&EO;BAC:&%R("IT97AT+"!C;VYS="!C:&%R("IM<V<L(&EN="!L96XL(`H) M"2`@("`@8V]N<W0@8VAA<B`J<')I=FME>2D*>PH@(&5L96U?="!2>"P@4GDL M(%IX+"!:>3L*("!C:&%R(&LQ6S$V72P@:S);,39=+"!M86-;.%T["B`@97AP M7W0@9#L*("!B:71S=')?:6UP;W)T*%)X+"!M<V<I.PH@(&)I='-T<E]I;7!O M<G0H4GDL(&US9R`K(#0@*B!.54U73U)$4RD["B`@:68@*$5#24537V5M8F5D M9&5D7W!U8FQI8U]K97E?=F%L:61A=&EO;BA2>"P@4GDI(#P@,"D*("`@(')E M='5R;B`M,3L*("!B:71S=')?<&%R<V4H9"P@<')I=FME>2D["B`@<&]I;G1? M8V]P>2A:>"P@6GDL(%)X+"!2>2D["B`@<&]I;G1?;75L="A:>"P@6GDL(&0I M.PH@('!O:6YT7V1O=6)L92A:>"P@6GDI.R`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@+RH@8V]F86-T;W(@:"`](#(@;VX@0C$V,R`J+PH@(&EF("AP M;VEN=%]I<U]Z97)O*%IX+"!:>2DI"B`@("!R971U<FX@+3$["B`@14-)15-? M:V1F*&LQ+"!K,BP@6G@L(%)X+"!2>2D["B`@"B`@6%1%05]C8F-M86,H;6%C M+"!M<V<@*R`X("H@3E5-5T]21%,L(&QE;BP@:S(I.PH@(&EF("AM96UC;7`H M;6%C+"!M<V<@*R`X("H@3E5-5T]21%,@*R!L96XL(#@I*0H@("`@<F5T=7)N M("TQ.PH@(&UE;6-P>2AT97AT+"!M<V<@*R`X("H@3E5-5T]21%,L(&QE;BD[ M"B`@6%1%05]C=')?8W)Y<'0H=&5X="P@;&5N+"!K,2D["B`@<F5T=7)N(#$[ M"GT*"B\J*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHO"@IV;VED M(&5N8W)Y<'1I;VY?9&5C<GEP=&EO;E]D96UO*&-O;G-T(&-H87(@*G1E>'0L M(&-O;G-T(&-H87(@*G!U8FQI8U]X+`H)"0D)8V]N<W0@8VAA<B`J<'5B;&EC M7WDL(&-O;G-T(&-H87(@*G!R:79A=&4I"GL*("!I;G0@;&5N(#T@<W1R;&5N M*'1E>'0I("L@,3L*("!C:&%R("IE;F-R>7!T960@/2!M86QL;V,H;&5N("L@ M14-)15-?3U9%4DA%040I.PH@(&-H87(@*F1E8W)Y<'1E9"`](&UA;&QO8RAL M96XI.PH*("!P<FEN=&8H(G!L86EN('1E>'0Z("5S7&XB+"!T97AT*3L*("!% M0TE%4U]E;F-R>7!T:6]N*&5N8W)Y<'1E9"P@=&5X="P@;&5N+"!P=6)L:6-? M>"P@<'5B;&EC7WDI.R`@("\J(&5N8W)Y<'1I;VX@*B\*"B`@:68@*$5#2453 M7V1E8W)Y<'1I;VXH9&5C<GEP=&5D+"!E;F-R>7!T960L(&QE;BP@<')I=F%T M92D@/"`P*2`O*B!D96-R>7!T:6]N("HO"B`@("!P<FEN=&8H(F1E8W)Y<'1I M;VX@9F%I;&5D(5QN(BD["B`@96QS90H@("`@<')I;G1F*")A9G1E<B!E;F-R M>7!T:6]N+V1E8W)Y<'1I;VXZ("5S7&XB+"!D96-R>7!T960I.PH@(`H@(&9R M964H96YC<GEP=&5D*3L*("!F<F5E*&1E8W)Y<'1E9"D["GT*"FEN="!M86EN M*"D*>R`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("\J('1H92!C;V5F9FEC:65N=',@9F]R($(Q-C,@*B\*("!B:71S M=')?<&%R<V4H<&]L>2P@(C@P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P M,#`P,#`P,#`P,&,Y(BD["B`@8FET<W1R7W!A<G-E*&-O969F7V(L("(R,&$V M,#$Y,#=B.&,Y-3-C83$T.#%E8C$P-3$R9C<X-S0T83,R,#5F9"(I.PH@(&)I M='-T<E]P87)S92AB87-E7W@L("(S9C!E8F$Q-C(X-F$R9#4W96$P.3DQ,38X M9#0Y.30V,S=E.#,T,V4S-B(I.PH@(&)I='-T<E]P87)S92AB87-E7WDL("(P M9#4Q9F)C-F,W,6$P,#DT9F$R8V1D-30U8C$Q8S5C,&,W.3<S,C1F,2(I.PH@ M(&)I='-T<E]P87)S92AB87-E7V]R9&5R+"`B-#`P,#`P,#`P,#`P,#`P,#`P M,#`R.3)F93<W93<P8S$R830R,S1C,S,B*3L*"B`@+R]%0TE%4U]G96YE<F%T M95]K97E?<&%I<B@I.R`@("`@("`@("`O*B!G96YE<F%T92!A('!U8FQI8R]P M<FEV871E(&ME>2!P86ER("HO"@H@(&5N8W)Y<'1I;VY?9&5C<GEP=&EO;E]D M96UO*")4:&ES('-E8W)E="!D96UO(&UE<W-A9V4@=VEL;"!B92!%0TE%4R!E M;F-R>7!T960B+`H)"0D@("`@("(Q8S4V9#,P,F-F-C0R83AE,6)A-&(T.&-C M-&9B93(X-#5E93,R9&-E-R(L(`H)"0D@("`@("(T-68T-F5B,S`S961F,F4V M,F8W-&)D-C@S-CAD.3<Y93(V-65E,V,P,R(L"@D)"2`@("`@(C!E,3!E-S@W M,#,V.30Q939C-SAD868X83!E.&4Q9&)F86,V.&4R-F0R(BD["B`@<F5T=7)N M(#`["GT*"B\J(&8X-F,Y,C`S.6,Y.3)D,F0R8F0R8C@U8S@X,#=A8S)F-V%F )-3=C-6,@*B\* ` end size 15669 f86c92039c992d2d2bd2b85c8807ac2f7af57c5c |=[ EOF ]=---------------------------------------------------------------=|

© Copyleft 1985-2024, Phrack Magazine.