Plainly the worst possible situation is a machine directly connected to the internet with all its ports open and with no root password, or the default user password, and a fixed IP address. It is a simple matter to contact such a machine via telnet or FTP and log in as root or the default user (who usually has admin rights). Even if an attacker doesn't have admin rights, if they have write-permission to web directories, they can cause a great deal of trouble. Even if the default passwords are changed, you need to make sure they are strong ones (i.e. not a common word, or word and numbers: advice from Google) as an open login console encourages people to try brute-force guessing of passwords, essentially running through lists of words and testing them. In addition, you should only ever log into your system on an encrypted line, for example a SSH connection, to lower the risk of MIM attacks.
This setup, however, is not now common. Most computers now are surrounded by a Firewall – a piece of software that closes all ports on a machine to externally-started communications and monitors for a wide range of common attacks. Moreover, most PCs connect to the internet via a router – a piece of hardware that allows multiple machines to connect to the internet at the same time. Routers usually have their own firewall that splits the network into the external network, and an internal private network with higher privileges. Firewalls generally don't allow external machines to initiate communications with internal machines, only allowing responses to communications initiated from inside the firewall.
Nevertheless, web servers present a particular issue. Webservers have to accept external communications, at least on port 80. They do this through port forwarding, where a network firewall on a router is set up to listen for port 80 communication and forward requests to the server machine (quite often Port 22 is also open to allow SSH admin connections, though you are better off doing these from internal machines if possible). If web servers just allowed for HTTP GET requests (the requests for webpages etc.) for simple web resources, this would be fine, but most also want to allow POST and PUT requests (requests for adjusting the state of the server), especially when dealing with processing HTML-based forms using scripts on the server (e.g. with Perl or PHP; example). Often these requests will include information to send to the scripts (as, infact, can GET). The scripts then take this information in and store it, opening themselves up to exploitation. While we're on the subject, it should also be noticed that HTTP GET and PUT requests encode information into the URL that is sent, so users can read any information in these very easily. Encoding is done in this form:
http://www.oggy.com/script.php?variable=value;&variable2=value2
This is both trivial for the user to read, but is also stored in web logs and sometimes available (for example, through the DOM document.referrer object) to subsequent webpages.
To understand why information sent to a server might be problematic, we need to understand a typical attack. By and large attacks against machines exploit issues with software that open up security holes. A classic example is the Buffer Overflow attack which (broadly) writes larger data to arrays in a program than the program is expecting, spilling the data out of the program's memory areas and into the surrounding memory running OS code. To run such an exploit, however, an attacker needs to be able to run a program on the computer. This isn't usually simple, but with web servers the options are higher as information is often sent to the scripts that run. The other classic attack, often combined with the Buffer Overflow, is to write input that evaluates to make a running program. If a server script is foolish enough to run input sent to it without checking the input, or a Buffer Overflow can be made to run the program, the server can be made to run arbitrary programs – in the case of the former situation with the web server software's permission privileges, which are often quite high. If the server script runs a program with sudo, this can be especially devastating. We'll see another example of where sending data to scripts is problematic when we look at attacks against clients.
While these types of attack usually rely on understanding the internals of code on the server, developers often make this very easy. An example of this is scripts that run arbitrary code sent to them. Such scripts easily allow for injection attacks, where the attacker simply sends in the code they want executed, for example through a web form. You might imagine that allowing arbitrary code to run is unusual, but, for example, if you send a server SQL queries, and don't check what they are doing, you are opening yourself up to a SQL injection attack.
Finally, any server script that demands a password to be input opens itself to brute-force password attacks, so should have strong passwords.
Plainly there's a good deal to get your head around, and we'll come back to some resources at the end. In the meantime, a few hints help for beginners:
U+000D
instead of a
Carriage Return), for example: ()[]{}|&;`'\"*?~<>>^$\n\r (we'll look at this "sanitization" shortly).myscript.bak
or myscript.txt
it, and any passwords in it, will be visible to the world.A starters guide to attacks against scripts can be found on the w3c security site (full FAQ - somewhat dated, but still useful).
Finally, note that while direct attacks against server software are generally rare, they do happen. Classic examples include the Heartbleed bug and Shellshock, both of which exploited deep issues with fundamental elements of key software that had gone undetected. Some have argued that these kinds of exploits will become more important as open source software increases, though generally most people subscribe to Linus' Law that bugs are more likely to get spotted with a community working on open source code.