Friday, January 18, 2019

Productivity Tactic: Fear Masked as Procrastination

I pride myself on noticing patterns in life. A particular pattern I've noticed in myself as well many others is this: Procrastination is pain avoidance. Now that may seem obvious in certain regards but what definitely wasn't obvious is that procrastination is really a manifestation of fear.

Think about it - you have an idea, a great idea, an exciting idea, you start fleshing out a couple details and get confident enough to start. You're about an hour in and then you find yourself having a desire to check Twitter, or reddit, or watch youtube videos, or check the fridge, or whatever else other than doing that thing. Why?

Well I noticed those moments arise almost exclusively when I'm about to start something unknown. Something a little uncomfortable. Something that doesn't bother me consciously, but subconsciously the fear of that unknown (and ultimately the fear of potentially failing at it) takes a toll on the momentum. That's when my body steers towards the familiar, the quick doses of dopamine from Facebook feeds, videogames, youtube, or a snack. These things are nothing more than escapist tricks from tackling that unknown problem.

So how do I battle it? The first is placing a mental breakpoint on those activities and then consciously asking myself: Am I avoiding my work? about 90% of the time the answer is yes. I then think back on the task my mind was avoiding and then get a little angry at it for effectively insulting me. Making me think I couldn't tackle it. Screw you man. You don't win this one.

The next step is to start tearing the task down, piece by piece until the individual tasks are so stupid and minuscule that it's impossible to fear or be uncomfortable with them. I did this with code projects, with report writing, with finances, with everything. It's an incredibly powerful tactic I recommend to everyone.

We are animals, rational thought is not something we were made for. We must understand the causes of our motivations, our emotions, our desires, and our thoughts if we ever stand a chance at making our lives collectively better.

Socrates was right, one of the best things a person can do is know thyself.

Friday, December 21, 2018

Python - Choose a Function at Random

If you need to randomly select from a number of defined functions, this is a simple way to achieve that:


import random

def function_A(some_var):
    return("{} - A".format(some_var))

def function_B(some_var):
    return("{} - B".format(some_var))

def function_C(some_var):
    return("{} - C".format(some_var))

#Run a random function with the input of "blahblah"
random.choice([function_A, function_B, function_C])("blahblah")
#do it as many times as you'd like, and you'll get different results
random.choice([function_A, function_B, function_C])("blahblah")
random.choice([function_A, function_B, function_C])("blahblah")
random.choice([function_A, function_B, function_C])("blahblah")
random.choice([function_A, function_B, function_C])("blahblah")

Friday, December 14, 2018

SSH Port Forwards In Simpler Terms

I love SSH, I love port forwards, I love all they allow you to do. I hate my memory and all it forgets to do. I decided to write the following so I can easily recall the syntax and meaning for SSH port forwards (-L & -R).

Firstly, both use the same syntax (order of parameters doesn't matter):

ssh root@someVPS -i ~/.ssh/whateverKey -L localhost:2323:localhost:2424
ssh root@someVPS -i ~/.ssh/whateverKey -R localhost:2323:localhost:2424

Even though they are both basically From:To, They have different meanings because -L & -R have different contexts.

-L localhost:2323:localhost:2424 means:

  • Create a listening socket on my local laptop (the client) listening at localhost:2323
  • Any connection coming into that socket (on my local laptop) send over the SSH connection to the VPS's "localhost:2424" - assuming some app or something is listening on the server on 2424 so this connection is actually useful.
  • Can be more easily understood as "-L LocalContextIP:LocalPort:RemoteContextIP:RemotePort"
-R localhost:2323:localhost:2424 means the inverse:
  • Create a listening socket on the VPS at localhost:2323
  • Any connection into that socket (on the remote VPS) send over the SSH connection to the Laptop's "localhost:2424"
  • Can be more easily understood as "-R RemoteContextIP:RemotePort:LocalContextIP:LocalPort"
It's important to note that this isnt restricted to localhost. You can "bounce" connections either way just by changing the "To:" location.

Bounce a connection from my laptop to my VPS and out to google? sure
ssh root@someVPS -i ~/.ssh/whateverKey -L localhost:2323:google.com:80

Bounce a connection from my VPS to my laptop and out to google? sure
ssh root@someVPS -i ~/.ssh/whateverKey -R localhost:2323:google.com:80

-L & -R are really doing nothing more than telling you the direction that the traffic flows. -L is from client -> server and -R is from server -> client. 

I use the term "Context" here because that's really what it is. It consults the machine's IPs/Hostnames/whatever that is local to _that_ machine.

This means that if my VPS has an entry in /etc/hosts for "1.1.1.1 yoloswag" and my Laptop has an entry for "2.2.2.2 yoloswag" - they will mean different things depending on where in the command you place "yoloswag"

There, now I won't have to second guess myself everytime I try to create a reverse tunnel through 8 different boxes.

Stupid SSH Trick:
So if you understood what I just wrote then you should say to yourself: "wait, doesnt that mean I can forever have two tunnels passing data back and forth forever" - yes. Yes you can. And it's dumb. Here's how it works:

First anything coming on your laptops localhost:3030 gets sent out to the VPS's localhost:3131
ssh yolohax -L localhost:3030:localhost:3131
Second, anything coming into your VPS's localhost:3131, send out to your Laptops:3030:
ssh yolohax -R localhost:3131:localhost:3030

Go ahead and try it, watch your network usage. Once you issue your first transmission (echo infinitelooplol | ncat localhost 3030) you should get a constant .5-1.5Kbps in both directions. Ctrl-c'ing it won't help because it's stuck in tunnel loop. You have to kill one of the tunnels for it to end.

Wednesday, November 28, 2018

Keep Track Of Your Source IP

Pentesters/RedTeamers often need to track their outgoing IPs for Blue Teams to be able to correlate activity and know if an attack is shceduled activity or something else.

Below is a script that will reach out, grab your public IP, and if it's different from the last entry, enter it into a log file. I use crontab to execute it at the top of every minute.
#!/bin/bash
# This script records changes to your external IP to a log file with timestamp
# Install:
# crontab -e
# * * * * * /Users/MYUSERNAME/WHEREVER/iplog.sh
# And then change the iplogfileloc below to where you want the logfile to save.

# You should have an iplog.txt with contents like this:
# $ cat iplog.txt
# Wed Nov 28 12:56:40 MST 2018 -- 177.243.11.21
# Wed Nov 28 13:00:07 MST 2018 -- 17.18.24.6

# Change the below location to what you want
iplogfileloc="/Users/MYUSERORWHATEVERHERE/iplog.txt"

myip=$(curl httpbin.org/ip 2> /dev/null| grep origin | awk '{print $2}' | tr -d '"')

#create file if it doesnt exist
[ -f ${iplogfileloc} ] || touch ${iplogfileloc}

if ! cat ${iplogfileloc} | tail -1 | grep ${myip} > /dev/null ; then
    # if your IP has changed, add it to the file
    echo $(date) '--' ${myip} >> ${iplogfileloc}
fi

Now you can change IPs via VPN or whatever and always be able to refer to it later. The only edge case is if you change IPs multiple times within one minute, but that should be rare and accounted for in sprays.

Monday, November 26, 2018

Ways to Enumerate Users

A couple of methods to identify usernames that can then be used in other areas of a pentest are below. I added as many as I could think of. I limited it to ones mostly seen from the public Internet.

Tuesday, September 18, 2018

Saner Bash Commands Inside Python

As great as Python is, sometimes the dev's make really weird decisions regarding defaults. A perfect example is running shell commands inside Python 3+. For some reason the dev thought it was a good idea to make the subprocess "run" method _not_ capture the output from stdout or stderr by default. I find this incredibly annoying and it constantly result in me having to look up the syntax since I always forget it.

I decided to instead have this little helper function to encapsulate what I consider to be saner defaults. I decode the bytes into utf8 since thats the output for 99% of all bash commands.

#!/usr/bin/env python3
import subprocess

def run_cmd(cmd):
    result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    result.stdout = result.stdout.decode('utf8')
    result.stderr = result.stderr.decode('utf8')
    return result

Running that function will execute whatever command you pass it (insecure, but use it appropriately) and returns an object that you can then check the return code, stdout, and stderr.

So now, it's just:

In [25]: if 'root' in run_cmd('whoami').stdout:
   ....:             print("you are root")
   ....:
you are root

Thursday, August 30, 2018

Download All Corporate Git Repos

Depending on the client you are testing, they may have an internal development team that checks code into a git repo. The vast majority of the clients I've seen implement the Atlassian suite of tools, typically containing an internally hosted Bitbucket.

The Bitbucket web interface has a search feature for looking for code snippets. It's absolutely awful. It's like an off brand tonka toys reject of a search function. You know what's way better? grep. That means I'd have to download every repo to search it locally. I did that with this script:

It's handy to note that grepping isn't the only good thing about cloning repos locally. It allows you to run the myriad of vuln checker tools, load up the code into an IDE and run source/sink analysis on it, and much more.

Wednesday, August 29, 2018

Brute Force LDAP Names (or how I kinda downloaded LDAP)

Running queries over a network using the ldapsearch tool can be a bit annoying. It's especially annoying when you constantly run into the "size limit exceeded" result when you get large responses.

I decided to write a little tool to recursively and conditionally search LDAP for CN entries (basically AD account names) and download them locally. If it detects the error size limit error, it automatically adds a new character to drill even further.

It works fantastically well. After you run this tool you should have many .out files containing ldap query responses. Grep to your hearts content:

Thursday, August 23, 2018

Apache Struts 2 Vulnerability & Exploit (CVE-2018-11776)

Yesterday a new vulnerability in certain versions of Apache Struts (2.3 - 2.3.34, 2.5 - 2.5.16)was discovered that leads to RCE. It requires both vulnerable versions as well as vulnerable configurations.

The gist of the issue is that if you have a vulnerable configuration that doesn't lend a namespace to struts, struts will take the user-specified namespace instead. Fortunately, it takes the namespace and evaluates it as a OGNL expression, allowing you to fairly easily get remote code execution.

Working PoC (I personally tested it myself and it works)
https://github.com/jas502n/St2-057

Technical deep dive on finding the vulnerability:
https://lgtm.com/blog/apache_struts_CVE-2018-11776

Vuln writeup by Semmle (including conditions for vulnerable configurations)
https://semmle.com/news/apache-struts-CVE-2018-11776

Apache's security bulletin for the vuln:
https://cwiki.apache.org/confluence/display/WW/S2-057

Mitre CVE link:
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-11776

A couple caveats I found while testing:
  • It definitely requires a lack of namespace attribute in the classes xml
  • All that is required for successful exploitation is a single proper GET request
  • Doesn't work on all struts-showcase installs (2.3.15 wasn't working for some reason), making me think it may be a bit finicky
I modified the PoC listed above into a simple python function, making everything simpler:

Below is it being run against a vulnerable VM I set up

Wednesday, August 15, 2018

Twitter Controlled Anything - Micropython on ESP32

I recently purchased an ESP32 from amazon for testing purposes and a colleague mentioned you could install a minimalist python environment on them for control. To say the least, I was intrigued.

I wanted to be able to control a light (or anything really) using tweets. Below are the instructions/scripts I wrote to get it working. First comes the prerequisites:
  • ESP32 (duh)
  • A VPS, Pi, or really any computer acting as a flask server (it just needs internet access)
  • A wifi network for the ESP32 to connect to, I just used the hotspot on my phone as a PoC
  • Twitter API credentials (really easy to get, just fill out the forms)
TLDR:
Your ESP32 will query your flask server for a trigger word to enable the LED. The Flask server will query twitter for your latest top tweet, if it has a trigger word in it, relay that to the esp32 client. Boom, tweet causes LED to turn on.

The first step is to get your ESP32 setup running the micropython environment. I followed this excellent guide

Once you get your ESP32 configured to run python code, go ahead and transfer the following script to act as the client. You just need to change the wifi details and target flask server:

import machine
import urequests
import time

pin = machine.Pin(2, machine.Pin.OUT)

def connect():
    import network
    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('connecting to network...')
        sta_if.active(True)
        sta_if.connect('WIFINETWORKSSIDHERE', 'WIFIPASSWORDHERE')
        while not sta_if.isconnected():
            pass
    print('network config:', sta_if.ifconfig())

def no_debug():
    import esp
    # this can be run from the REPL as well
    esp.osdebug(None)

no_debug()
connect()

while True:
    time.sleep(2)
    if 'yes' in urequests.get('http://MYFLASKDOMAINHERE.com:5000').text:
        pin.value(1)

Connect the LED to Pin 2 on the ESP32 and it's all set to go. Now onto the flask server...

On your VPS/Pi/whatever, install flask and tweepy and create a directory to hold your script files. Grab the Access Token, Access Secret, Consumer Secret, Consumer Key from your Twitter Dev console that you set up earlier and place them in a "twitter_creds.py" file like the following:

ACCESS_TOKEN = '18077065-lakjsdflkajshdlfkajshdflkajsdhqqSYOtHSXtK1'
ACCESS_SECRET = 'hPqlkwjehrlkfjnlqwejhqrwklejrqhlwkejrJr1'
CONSUMER_KEY = 'QZlk9qlkwejrhqlkwjerhlqwlLh'
CONSUMER_SECRET = 'uEnkzjxcnvluqblwjbefkqwlekjflkqjwehflqlkjhuOE'

Then paste the following into "tweepy-top.py"

from twitter_creds import *

import tweepy

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)

api = tweepy.API(auth)

def get_top_tweet():
    top_tweet = api.user_timeline(count=1)
    return top_tweet[0].text

Now create your main flask app by pasting the following into "flaskhello.py":

from flask import Flask
from tweepy_top import get_top_tweet

app = Flask(__name__)

@app.route("/")
def hello():
    if 'light' in get_top_tweet():
        return 'yes'
    else:
        return 'no'

if __name__ == "__main__":
  app.run(host="0.0.0.0", threaded=True)

There you can see 'light' is used as the trigger word. Using this setup, every 2 seconds the esp32 will make a request to your flask server, which causes the flask server to query twitter for the user's top tweet, if the top tweet contains the word "light" in it, it returns the string "yes". The ESP32 recognizes the "yes" and turns on pin 2.

This is a very simple PoC and gets the job done. You can take this and expand in a thousand directions with it, some ideas:

  • A desktop counter that keeps track of your followers, retweets, likes, etc
  • A LED scroller that outputs your latest mentions
  • Or simply use twitter as the control for some device
The options are endless...enjoy :D