Skip to content

Instantly share code, notes, and snippets.

@cutaway
Last active June 25, 2021 08:39
Show Gist options
  • Save cutaway/46b5e1df49071fa96e60 to your computer and use it in GitHub Desktop.
Save cutaway/46b5e1df49071fa96e60 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""
Name: extract_java_server_faces_viewstate
Purpose: Extract and parse the Java Server Faces viewstate
Date: 20150620
Author: Don C. Weber (@cutaway) of InGuardians, Inc.
Resources:
http://wiki.apache.org/myfaces/Secure_Your_Application
http://www.synacktiv.com/ressources/JSF_ViewState_InYourFace.pdf
https://github.com/frohoff/inyourface/blob/master/src/java/inyourface.java
https://prezi.com/t-lzwbqm2vwn/jsf-security/ - video shows fully encrypted viewstate value
TODO:
Identify if MAC has been enabled
Add functionality to grab a single page. For now just use Burp Suite.
"""
import urllib2
import base64
import gzip
from cStringIO import StringIO
import re
from copy import copy
import entropy as ent
def search_vs(data,relist = ['pass','user','secret','key']):
'''
Search parsed viewstate data for key terms
Inputs:
data: Parsed viewstate
relist: list of terms to search
'''
results = {}
for e in re.split(r'\x00*',data):
for n in relist:
if re.search(n,e):
if results.has_key(n):
results[n].append(e)
else:
results[n] = [e]
return results
def detect_vs(data,term = 'java'):
'''
Search parsed viewstate data for term that indicates unencrypted data
This test mimics SpiderLabs deface: https://github.com/SpiderLabs/deface
Inputs:
data: Parsed viewstate
term: term to use to detected unecrypted data
'''
for e in re.split(r'\x00*',data):
if re.search(term,e):
return True
return False
def extract_vs(data, param='value'):
'''
Extract a viewstate value from a line of HTML.
Inputs:
data: Single line of html with the viewstate parameter
param: the name of the viewstate parameter
'''
# Line will have spaces to separate values
for e in data.split(" "):
# Value will be separated by an "=" but only split on first occurrence
n = e.split("=",1)
# Viewstate should be the "value" parameter
if not n[0] == param:
continue
else:
# Remove quotes from beginning and end
# Returns base64 encoded viewstate
return n[1].replace("\"","")
return None
def parse_vs(data):
'''
Parse the viewstate data by decoding and unpacking it.
Inputs:
data: Single line of base64 encoded viewstate. URLENCODED data is okay
'''
# URL Encoding
urldelim = "%"
# Check to see if the viewstate data has urlencoded characters in it and remove
if re.search(urldelim,data):
d1 = urllib2.unquote(data).decode('utf8')
else:
d1 = copy(data)
# Base64 decode
d2 = base64.decodestring(d1)
# Generate a StringIO object since gzip wants a file descriptor
d3 = StringIO(d2)
# Decompress data
d4 = gzip.GzipFile(mode='rb', fileobj=d3)
# Get data from gzip file object
d5 = d4.read()
# Print viewstate and manually review for useful information
# Happy Hunting
return d5
def print_vs(data):
'''
Print the viewstate by converting from 'iso-8859-1' to 'utf8' encoding
Inputs:
data: Single line of parsed viewstate
'''
print data.decode('iso-8859-1').encode('utf8')
if __name__ == "__main__":
'''
# Usages:
# Extract Viewstate values from Burp Request/Response Extract file
grep javax.faces.ViewState burp_requests_responses.txt > burp_requests_responses_viewstate.txt
# Print parsed viewstate
data = open("burp_requests_responses_viewstate.txt",'r').readlines()
for e in data:
tmp = vs.extract_vs(e)
if tmp:
print "\n============\n"
print repr(vs.parse_vs(tmp))
print "\n============\n\n\n"
# Parse and search viewstate for key words
data = open("burp_requests_responses_viewstate.txt",'r').readlines()
for e in data:
tmp = vs.extract_vs(e)
if tmp:
results = vs.search_vs(vs.parse_vs(tmp))
if results:
for v in results.keys():
print v + ":",results[v]
print "\n===========\n\n"
'''
# Update "data" with data copied from viewstate
#d = "data"
d = sys.argv(1)
print parse_vs(d).decode('iso-8859-1').encode('utf8')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment