SSH Fingerprint and Hostkey with Paramiko in Python

November 24th, 2014

Following on from SSH and SFTP with Paramiko & Python, I recently had the need to gain a remote SSH server’s fingerprint and hostkey for verification purposes. This is achievable through setting up a socket, and then applying paramiko.Transport over our established socket. First, we include the various bits and pieces we’ll need:

import socket
import paramiko
import hashlib
import base64

Next, we establish a socket connection ‘mySocket’ to “localhost” on port 22 – our dummy SSH server. We then use paramiko.Transport to gain access to paramiko’s core SSH protocol options on the socket.

mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.connect(("localhost", 22))
myTransport = paramiko.Transport(mySocket)
myTransport.start_client()

To get the remote hostkey, we call myTransport.get_remote_server_key():
Read the rest of this entry »

Linux Namespaces

November 23rd, 2014

Starting from kernel 2.6.24, there are 6 different types of Linux namespaces. Namespaces are useful in isolating processes from the rest of the system, without needing to use full low level virtualization technology.

  • CLONE_NEWIPC: IPC Namespaces: SystemV IPC and POSIX Message Queues can be isolated.
  • CLONE_NEWPID: PID Namespaces: PIDs are isolated, meaning that a PID inside of the namespace can conflict with a PID outside of the namespace. PIDs inside the namespace will be mapped to other PIDs outside of the namespace. The first PID inside the namespace will be ‘1’ which outside of the namespace is assigned to init
  • CLONE_NEWNET: Network Namespaces: Networking (/proc/net, IPs, interfaces and routes) are isolated. Services can be run on the same ports within namespaces, and “duplicate” virtual interfaces can be created.
  • CLONE_NEWNS: Mount Namespaces. We have the ability to isolate mount points as they appear to processes. Using mount namespaces, we can achieve similar functionality to chroot() however with improved security.
  • CLONE_NEWUTS: UTS Namespaces. This namespaces primary purpose is to isolate the hostname and NIS name.
  • CLONE_NEWUSER: User Namespaces. Here, user and group IDs are different inside and outside of namespaces and can be duplicated.

Let’s look first at the structure of a C program, required to demonstrate process namespaces. The following has been tested on Debian 6 and 7.

First, we need to allocate a page of memory on the stack, and set a pointer to the end of that memory page. We use alloca to allocate stack memory rather than malloc which would allocate memory on the heap.

void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);

Next, we use clone to create a child process, passing the location of our child stack ‘mem’, as well as the required flags to specify a new namespace. We specify ‘callee’ as the function to execute within the child space:

mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);

After calling clone we then wait for the child process to finish, before terminating the parent. If not, the parent execution flow will continue and terminate immediately after, clearing up the child with it:

while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
{
	continue;
}

Lastly, we’ll return to the shell with the exit code of the child:

if (WIFEXITED(r))
{
	return WEXITSTATUS(r);
}
return EXIT_FAILURE;

Now, let’s look at the callee function:

static int callee()
{
	int ret;
	mount("proc", "/proc", "proc", 0, "");
	setgid(u);
	setgroups(0, NULL);
	setuid(u);
	ret = execl("/bin/bash", "/bin/bash", NULL);
	return ret;
}

Here, we mount a /proc filesystem, and then set the uid (User ID) and gid (Group ID) to the value of ‘u’ before spawning the /bin/bash shell.
Read the rest of this entry »

SSH and SFTP with Paramiko & Python

November 23rd, 2014

Paramiko is a Python implementation of SSH with a whole range of supported features. To start, let’s look at the most simple example – connecting to a remote SSH server and gathering the output of ls /tmp/

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
        ssh.connect('localhost', username='testuser', password='t3st@#test123')
except paramiko.SSHException:
        print "Connection Failed"
        quit()

stdin,stdout,stderr = ssh.exec_command("ls /etc/")

for line in stdout.readlines():
        print line.strip()
ssh.close()

After importing paramiko, we create a new variable ‘ssh’ to hold our SSHClient. ssh.set_missing_host_key_policy automatically adds our server’s host key without prompting. For security, this is not a good idea in production, and host keys should be added manually. Should a host key change unexpectedly, it could indicate that the connection has been compromised and is being diverted elsewhere.

Next, we create 3 variables, stdin, stdout and stderr allowing us to access the respective streams when calling ls /etc/

Finally, for each “\n” terminated line on stdout, we print the line, stripping the trailing “\n” (as print adds one). Finally we close the SSH connection.

Let’s look at another example, where we communicate with stdin.
Read the rest of this entry »

Simple IMAP Account Verification in Python

November 22nd, 2014

imaplib is a great library for handling IMAP communication. It supports both plaintext IMAP and IMAP over SSL (IMAPS) with ease. Connecting to an IMAP server is achieved as follows:

import imaplib

host = "mx.sasdataservices.com"
port = 143
ssl = 0

try:
	if ssl:
		imap = imaplib.IMAP4_SSL(host, port)
	else:
		imap = imaplib.IMAP4(host, port)
	welcomeMsg = imap.welcome
	print "IMAP Banner: %s" %(welcomeMsg)
except:
	print "Connection Failed"
	quit()

This results in the following output: “IMAP Banner: * OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION STARTTLS] Courier-IMAP ready. Copyright 1998-2011 Double Precision, Inc. See COPYING for distribution information.” Now, to log in:

username="user@email.com"
password="password"

try:
	loginMsg = imap.login(username, password)
	print "Login Message: %s" %(loginMsg[1])
except:
	print "Login Failed"
	quit()

With acceptable credentials, the response is: “Login Message: [‘LOGIN Ok.’]”. Lastly, to print a list of all mailboxes in the account:

try:
	mBoxes = imap.list()
	for mBox in mBoxes[1]:
		print mBox
except:
	print "Couldn't get Mail Boxes"
quit()

Read the rest of this entry »

DNS Black List / RBL Checking in Python

November 22nd, 2014

Following on from performing basic DNS Lookups in Python, it’s relatively trivial to begin testing DNS Block Lists/Real Time Black Lists for blocked mail server IP addresses. To assist in preventing spam, a number of public and private RBLs are available. These track the IP addresses of mail servers that are known to produce spam, thus allowing recipient mail servers to deny delivery from known spammers.

RBLs operate over DNS. In order to test a RBL, a DNS query is made. As an example, zen.spamhaus.org is a popular RBL. If I wanted to test IP address 148.251.196.147 against the zen.spamhaus.org blocklist, I would reverse the octets in the IP address and then append ‘.zen.spamhaus.org’, i.e. 147.196.251.148.zen.spamhaus.org. I then perform an ‘A’ record lookup on said host:

root@w:~/tmp# host -t a 147.196.251.148.zen.spamhaus.org
Host 147.196.251.148.zen.spamhaus.org not found: 3(NXDOMAIN)

Excellent. IP 148.251.196.147 was not found in zen.spamhaus.org. NXDOMAIN is returned.

Now, to take a known spammer’s IP: 144.76.252.9:
Read the rest of this entry »

Performing DNS Queries in Python

November 21st, 2014

dnspython provides a detailed interface into DNS. In its simplest form, it’s possible to perform queries in only a couple of lines of code. Here’s a commented example:

import dns.resolver #import the module
myResolver = dns.resolver.Resolver() #create a new instance named 'myResolver'
myAnswers = myResolver.query("google.com", "A") #Lookup the 'A' record(s) for google.com
for rdata in myAnswers: #for each response
    print rdata #print the data

The results in my case are:

173.194.125.3
173.194.125.7
173.194.125.4
173.194.125.8
173.194.125.9
173.194.125.5
173.194.125.2
173.194.125.0
173.194.125.6
173.194.125.1
173.194.125.14

Read the rest of this entry »

Hard Drive Data Recovery

November 13th, 2014

This article discusses hard disk data recovery on Linux using dd and fdisk.

I recently left for a trip to South America, and took my trusty Intenso 320GB external drive with. Well aware that I’ve dropped it a couple too many times and that it was beginning to click more and more often during regular usage, I took a full backup before leaving. There’s nothing critical on the drive that I don’t have additional copies of elsewhere, however losing it would be a pain.

Having reached Madrid airport, I plugged the drive in and was about to pull some documents off it when disaster struck. The drive just clicked for about 30 seconds before Windows prompted me to format it. I tried removing it and reinserting it a couple of times but no luck – the drive had failed. I went to the duty free store in the airport and picked up a 1Tb WD Elements drive for 99 Euros, and planned to attempt data recovery when I arrived in South America.

I’m keen to get the data recovery started – it’s going to take a while on my USB 2.0 laptop and the more bad sectors, the longer it will take.

Read the rest of this entry »