Categories
Coding Computers Hacking Linux Networks

Kali Dropbox

#Please note any links in this article are affiliate links. You will not be charged extra if you use these links however, I will get some kickback if you do so thank you.

As part of performing a Penetration Test, it is often good practice to try and get a device on the internal network, especially if performing a physical test. There are loads of ways of doing this with guides available from YouTube and other blog sites but I thought I would write up how I’ve done it in case, someone comes across this page and is intrigued. This should be pretty straightforward now as I’ve spent quite some time writing custom scripts to create reverse connections and other things to then realise you can just use a VPN connection.

So to the hardware then; here is a kit list of everything that I’ve got:

*Not strictly necessary but it does mean you can connect to a network if it’s PoE capable without the need for a Power supply

First things first, don’t be the idiot that I was and try and install the Pi into the case with the Micro SD card installed. It’ll cost you £10 for a replacement!

So now that we have everything we need, let’s get Kali installed on the SD Card. This is pretty easy as Kali have an ARM variant of their operating system https://www.kali.org/get-kali/#kali-arm. Download the image specific for your device. To get the image onto your SD card there are a few options for imaging software the one I use is called Etcher by Balena: https://www.balena.io/etcher/. It’s really easy to use, however, I did get an error message when adding my Kali ARM image stating it couldn’t be written properly. I ignored it and installed the SD Card in the Pi and the works fine.

Next we need to decide on how we’re going to connect out to our command and control system. As mentioned above, I went off on a complete tangent with this and tried creating my own Python script to be able to connect out and open a reverse connection. In the end this wasn’t necessary at all. As every business has an internet connection and the main use of this is web browsing using an SSL VPN service is almost always going to be open. To make this work Kali has OpenVPN already installed so you just need to set up a service which your Dropbox can connect to. In my case we’ve already set up a VPN service to our office which is available on TCP/443. All I needed to do is download the OpenVPN config file from my VPN server set the connection request to TCP/443 (default is UDP/1194) and connect up.

We’ve now got a device that can connect up to a remote service from anywhere in the world providing we run that script. Let’s get this to run on boot. To do this we need to enable OpenVPN from boot using this command: systemctl enable OpenVPN

This starts the service on boot and by default looks for a config file in /etc/openvpn/openvpn.conf. Moving our config file and renaming it to openvpn.conf in that location will solve this riddle. Now on boot it automatically starts OpenVPN and connects up to our VPN service. This is great the final piece is to have some error checking, should the VPN go down for whatever reason we need something to attempt to re-establish the connection and/or test for any internet connectivity problems. To solve this we will use a Python script and a Cron Job which will run the script every 5 minutes.

import http.client, urllib
import socket
import ipaddress
import os
import time
from netifaces import AF_INET, AF_INET6, AF_LINK, AF_PACKET, AF_BRIDGE
import netifaces as ni

def CheckIPAddress():
   try:
       SocforIP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
       SocforIP.connect(("IP of VPN Network", 80))
       vpnIP = SocforIP.getsockname()[0]
       if ipaddress.ip_address(vpnIP) in ipaddress.ip_network('Subnet of VPN Network'):
          VPNOn = CheckifVPNOperational()
          if VPNOn != None:
             return VPNOn
          return vpnIP
       else:
          return "1.1.1.1"
   except:
       return "1.1.1.1"

def CheckIfAddressDifferent(IpAddress):
    try:
        file = open("StoredIP.txt")
        line = file.readline()
        OriginalIP = line.split(",")[0]
        file.close
        if(OriginalIP != IpAddress):
            with open("StoredIP.txt", 'w') as OpenFile:
                OpenFile.truncate(0)
                OpenFile.write(str(IpAddress) + "," + str(time.time()))
                SendNotification("Tap Interface of the-box has change and is now: " + IpAddress)
    except:
        with open("StoredIP.txt", 'w') as file:
            file.write("new file opened")

def SendNotification(Message):
    PushoverConnection = http.client.HTTPSConnection("api.pushover.net:443")
    PushoverConnection.request("POST", "/1/messages.json",
        urllib.parse.urlencode({
            "token": "xxxxxx22222222",
            "user": "xxxxxxx33333333",
            "message": Message,
            "title": "Dropbox has connected to the VPN"
        }), {"Content-type": "application/x-www-form-urlencoded"})
    response = PushoverConnection.getresponse()

def CheckforInternetConnectivity():
    response = os.system("ping -c 1 8.8.8.8")
    if response == 0:
        os.system("systemctl restart openvpn")
        time.sleep(5)
        ipaddressfound = CheckIPAddress()
        if ipaddressfound == '1.1.1.1':
            True
    else:
        with open("StoredIP.txt", 'w') as file:
            file.truncate(0)
            file.write("There is no internet connectivity," + str(time.time()))

def CheckifVPNOperational():
    response = os.system("ifconfig tun0")
    try:
       if "Device not found" in response:
         os.system("systemctl restart openvpn")
    except Exception as e:
         tun0ip = ni.ifaddresses('tun0')[AF_INET][0]['addr']
         return tun0ip

if __name__ == '__main__':
    ipaddressfound = CheckIPAddress()
    if ipaddressfound != '1.1.1.1':
        CheckIfAddressDifferent(ipaddressfound)
    else:
        CheckforInternetConnectivity()

Finally to run a Cron Job every five minutes you need to set the timings as follows: */5 * * * python3 notification.py

Categories
Coding

Python Port Scanner inc UDP

If for whatever reason you end up needing to do a port scan against a target but you cannot install NMAP then you may be able to use a Python script. If you do some googling you will find a variety of sources available that show you a script to perform a port scan using Python. From my searching, however, all of these are for TCP. If you search for UDP port scanning in Python you’ll likely become very disappointed. I know I have.

Fortunately, it is possible with some caveats, the first is the way in which UDP testing works, if you perform a scan against a target of a specific port e.g. DNS then the best way to get an absolute yes or no is to send a service-specific request to the target. If DNS is an open service then the target will respond with a DNS response. However, let’s say the target doesn’t support DNS then what will happen is you will receive an ICMP Unreachable. All of these are pretty common knowledge if you have some basic IT experience.

So, to Python then, to be able to ascertain the information outlined in the paragraph above we need to perform the following steps:

  1. Set up a listener so we can “hear” when packets come into our machine.
  2. Send either specially crafted or generic UDP packets depending on the service being tested.
  3. Check to see what response we have from the target to help ascertain whether the port is open, filtered or closed.

Setting up a Listener and checking the response

So setting up a listener is quite simple really. Here is how we’re going to do it:

StartTime = time.time()
#get the current IP Address of default routed interface
    HostIPSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    HostIPSocket.connect(("8.8.8.8", 80))
    HOST = HostIPSocket.getsockname()[0]
    HostIPSocket.close()

    #check if the application is running on windows or not. 
    if os.name == 'nt': 
        socket_protocol = socket.IPPROTO_IP
    else: 
        socket_protocol = socket.IPPROTO_ICMP 
    SocketListener = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 

    #bind the new listener to the IP address on the interface.
    SocketListener.bind((HOST, 0))
    SocketListener.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 

    #if windows turn on a bit so on the driver so it converts the interface to promiscuous mode
    if os.name == 'nt': 
        SocketListener.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
    #listen for returned packet on new thread after sending the request.
    newthread = threading.Thread(target=udp_sender, args=(target_ip, target_port))
    newthread.start() 
    count = 0
    while True:
        returnedPackets = SocketListener.recvfrom(65535)[0]
         
        # create an IP header from the first 20 bytes
        ip_header = IP(returnedPackets[0:20])
        if (str(ip_header.src_address) == str(target_ip) and ip_header.protocol == "ICMP"):
            offset = ip_header.ihl * 4
            buf = returnedPackets[offset:offset + 8]
            icmp_header = ICMP(buf)
            # check for TYPE 3 and CODE
            if icmp_header.code == 3 and icmp_header.type == 3:
                # make sure it has our magic message
                buf = returnedPackets[48:56]
                udp_header = UDP(buf)
                if returnedPackets[len(returnedPackets) - len(MESSAGE):] == bytes(MESSAGE, 'utf8'):
                    ClosedPorts.append(udp_header.dstport)
                    break
        
        #check if UDP response has been received.
        elif (str(ip_header.src_address) == str(target_ip) and ip_header.protocol =="UDP"):
            offset = ip_header.ihl * 4
            buf = returnedPackets[offset:offset + 8]
            udp_header = UDP(buf)
            if udp_header.srcport == target_port:
                OpenPorts.append(target_port)
                break
        else:
            EndTime = time.time()
            if EndTime - StartTime >= 3:
                OpenFilteredPorts.append(target_port)
                break

    #turn back off promiscuous mode after the operation
    if os.name == 'nt': 
        SocketListener.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) 
  1. So the first four lines is using a socket to capture our current IP Address rather than having it set as a static variable.
  2. Then we have an IF statement which checks whether we are using a Windows NT based system or not as that will determine what protocol our socket will connect on.
  3. After this we then bind the new socket to our interface with the IP Address picked up in original four lines of code.
  4. We then check again if were using Windows as if so we need to force promisicous mode. Because of this we will also need to run this as administrator when using Windows.
  5. The new thread bit is actually part of step 2 so we can send a UDP crafted message.
  6. Then the while statement which starts receiving the packets into our interface and analysing them.
    1. This first runs a function to convert the first 20 bytes of the packet into a nicely formatted IP header.
    2. Then we check if the packet received it an ICMP packet and is from the target if so, we perform some addtional functions to convert part of the packet to get the ICMP header portion. Then we check to see if it’s ICMP code equal 3 and whether the ICMP message is the same as the one we sent. If so then we can consider the port to be closed as we’ve received an ICMP unreachable.
    3. If we don’t receive an ICMP response then we check whether the target has sent us a UDP response. If they have then we perform a function to get the UDP headers so we can check if the source port is from the target port we sent the request to. If so, then we can assume that the port is open.
    4. Finally, if nothing matches then we wait for up to 50 packets to be recieved and if nothing matches our tests then we assume it’s refusing likely because it’s open but filtered.
  7. The last IF statement in this code snippet turns off promisicous mode if running on Windows.

Sending a UDP Message

Sending a UDP message in Python is quite possibly the easiest thing I’ve ever done:

def udp_sender(target_ip, target_port):
#run UDP port check now.
    connection_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        if(str(target_port) in UDP_sig):
            connection_socket.sendto(UDP_sig[str(target_port)], (target_ip,target_port))
        else:
            connection_socket.sendto(bytes(MESSAGE, 'utf8'), (target_ip,target_port))
    finally:
        connection_socket.close()

This code snippet is super simple. First, we create a UDP socket using the SOCK_DGRAM function. Next, we check to see if we have any protocol-specific messages for the port we are targeting, if so we pull that byte array, if not we use a string variable called MESSAGE and convert it to a byte array. Then we close the connection. This function is called in the thread in the previous step.

Additional Thoughts

As you can see this is a bit dirty, especially with the whole wait for 3-second thing at the end of the loop. However, it does work at scale, to make this work faster you could implement byte string variables for each specific service of a UDP request. That way when you send a request for say DNS you should get a response rather than nothing as the service you’re attempting to access doesn’t know how to respond.

Note: if you’re running this on Windows you will need to disable your firewall as it blocked ICMP Unreachable packets from being received by the OS. You can do this either in the Python script or just as and when you run it.

Categories
Coding Hacking Linux

Stupidity at its best.

So I’ve been in the IT industry for over ten years working with a variety of organisations doing all sorts of cool things. Thoughout my career I have done a variety of stupid things and as I got older I was convinced that these stupid mistakes would become less or would become so obscure that they wouldn’t be considered stupid. This obviously isn’t the case based on the title of this blog post.

About a month ago, I got an email from EC-Council’s training platform: Codered, due to my Certified Ethical Hacker (CEH) certification expiring. Offering a bunch of courses all for $1. Now I know what you’re thinking here, this is a phishing scam but I went directly to the website signed in and it was true. I signed up for Wireshark for Hackers and Black Hat Python. The Wireshark course was for beginners which needless to say it very much was. I picked up a few things but what annoyed me the most was watching the trainer figure out what he was trying to teach on video, not cool. The Python course though was cool, the educator was brilliant. Super detailed but put it all in a way that was really easy to understand. This was also helped by the fact that I’ve done some Python work before so the syntax was familiar.

Now the backstory is done, onto the stupidity part. Within the Python course, there was a module specifically dedicated to Brute Force cracking Linux/Unix passwords from the /etc/shadow or /etc/passwd file. This used the module crypt. I build the script and had it all ready but with me being on a Windows machine it wouldn’t work with a sample shadow/passwd file available on the internet. So after a little bit of time, I built a Linux VM for something else, copied the file across and tried it out.

Fail. The code wouldn’t run and just threw the following error:

AttributeError: ‘module’ object has no attribute ‘crpyt’

So to everyone’s favourite troubleshooter, Google. I put the error into Google and nothing. This is very unusual, I almost always find someone with an error pretty much matching what I have. I’m not a programmer after all. I found a bunch of people with the same error but not against the same attribute. I spent hours, researching into this trying to find if there was a Pip module that I hadn’t installed. For those of you that are unsure Pip is a program to install Python modules onto a system. Everything suggested that I needed to install the cryptography module on Linux but when I tried that it said it was already installed. So I thought maybe it was the distribution of Linux that I was using, Kali. The trainer used Ubuntu so I moved over to one of my servers with Ubuntu on to try that. No dice.

Finally, I decided to give up on searching and went to the line of code in question which was throwing the error:

digest = crypt.crpyt(word, hashed_pass)

I use Visual Studio Code (VSCode) for my programming and the nice thing is in Python on VSCode each piece of code is usually colour coded, so green for a module, yellow for a function, light blue for variable and orange for some text, etc. This was when I realised the word crpyt after crypt. was white. Oh, balls, it’s a typo, changed it to crypt, the word went yellow, re-copied it to my Kali machine and hey presto everything is working.

For all of you out there that are either just starting out or have been in the field for a short while and end up making a mistake like this. Don’t worry, someone who’s got a job as a Senior Engineer makes these mistakes too and I don’t doubt that I won’t stop making these mistakes until I retire. Don’t get disheartened by it, it’s human nature and I hope this post helps you in realising that. For those of you that run into this issue yourself whilst messing about with Python, check your code and make sure you haven’t made a typo as that error can be quite misleading if you don’t read it letter by letter like me.