While available shelf penetration programs/tools are used widely, there can be situations when certain tools might fail. Security Professionals love to automate pentesting tasks and write their own set of tools while testing.
For example one can write his/her own port scanner program when nmap fails. Here a custom script would send packets to the static host and gives out result but how about the case when we are trying to attack an interactive service such as SSH, FTP, TELNET etc. Lets say we wish to bruteforce the ssh service on the remote machine and there are a series of prompts that are expected depending upon the interaction between client and ssh server.
Lets check out some of the prompts ssh service sends to a connecting client –
1. When connecting to a ssh server for the first time, a yes/no prompt gets introduced.
2. While trying password.
3. While trying passwords, if the first try fails, ssh prompts for a consecutive second and third password prompt.
4. Another case when the remote host has ssh service disabled.
Here we need a dynamic tool that can proactively interact with the remote hosted service as if a human were typing responses. For countering such kind of challenges, Pexpect is our hero which is a pure Python module that makes Python a better tool for controlling and automating other programs. It is basically a pattern matching system which runs program and watches output.
Lets have a look at some basic Pexpect functions that makes this module so powerful.
- spawn() spawn class can be used to create an external child application and then interact with it by sending lines and expecting responses. Picture it as if someone issues a ssh command on the terminal for connecting to a ssh enabled host.
- expect() This takes strings as input and matches if the spawned child application response matches the string. Imagine this as the expected response on your shell from the remote server when trying to connect using ssh. Expected responses can be a “Are you sure you want to continue connecting (yes/no)?” or “connect to host xx.xx.xx.xx port 22: Connection refused”.
- send()/sendline() This method will write/send a string to the spawned child application. Its just like someone typed the text on the terminal.
- before() Gives out all the response text received by the spawned child upto the expected string.
We’ll next quickly jump on to the scripting stuff. Fire up a python terminal and start testing using all that we have learned so far.
Above we have imported the pexpect module and assigned username, password, remote host IP to variables. Next we have created 2 variables ssh_newkey and refused. They will be used in the cases when someone tries to connect for the first time(ssh_newkey) or if the remote host has ssh service disabled(refused).
child = pexpect.spawn(connStr) will spawn a child application that tries connecting to remote IP 192.168.2.171 with root as user. ret = child.expect() takes input strings as a list. pexpect.TIMEOUT is one of the entry that will account for the case when there’s no response received. Strings ssh_newkey and refused are already discussed in the above images. ‘[P|p]assword’ is when the remote ssh server prompts to try a password. ret variable will contain the index value of that particular string that matched the spawned child response. Here we got 2 which means that a string ‘password’ or ‘Password’ was received. Thus we infer that a password prompt is waiting for us. Something like this.
Next we’ll feed in the password string using child.sendline(password) and check how the child application behaves further. We get a number ‘6’ upon hitting enter but that’s not of much importance to us here. Proceeding further.
Note that we have created a list PROMPT that contains some strings. All these strings denotes shell/terminal prompts. Again use the expect() method for guessing the expected response from the ssh server and we get a value 0 here which we means that we have received a response that contains a ‘#’. Lets try reading everything before the ‘#’ using print child.before.
Voila ! our spawned child application was able to login on to the remote ssh server 192.168.2.171.
I’ve written a short python script using the above illustrated concepts. It tries login to the remote ssh server, executes command uname -v and shows the response.
Now further executing it.
From whatever we have learned till now we can build our own pen-testing tools in python for interactive services like telnet, ssh, ftp etc.
Violent Python by TJ