I was building some jar’s for a Jenkins shared pipeline and trying to validate what files/folders were included in the result. Normally I use the tree command to inspect directories like this, as it makes more visual sense to me. However to view the contents of a zip we have to do something like unzip -l filename.zip which gives us a pretty verbose and difficult to understand result (at least to me).
Solution
Add a the following function to my ~/.zshrc
function tree() {
arr=( "${@}" )
if ( file $arr[-1] | grep -q 'Zip archive' ) ; then
tar tf $arr[-1] | tree ${arr[@]:0:-1} --fromfile .
else
command tree $@
fi
}
Now we can tree somefolder just as well as tree somejar.jar, or any other Zip archive! For example:
When writing a discord bot, even if only for your own server, you need to use oauth to validate it. I wrote the following script to make it easy on myself, since i’m more than likely to do it again and forget how in the future. Make sure you have bottle, requests and discordpy (the bot framework i was writing in) runt hen simply browse to http://localhost:8080
Note that this requests Permissions(8) which is Administrator and only the scopes bot. You can change that at will - infact I suggest you don’t grant Admin.
import os, requests, string, random
from bottle import request, route, run, abort, redirect
from discord.utils import oauth_url
from discord import Permissions
state = ''.join(random.choice(string.ascii_letters) for i in range(10))
@route('/')
def index():
redirect(oauth_url(os.environ['CLIENT_ID'], permissions=Permissions(8), redirect_uri='http://localhost:8080/oauth', scopes=['bot'], state=state))
@route('/oauth')
def exchange_code():
code = request.query.code
incstate = request.query.state
if incstate != state:
abort(401, "State mismatch somehow, are you being hacked...?")
data = {
'client_id': os.environ['CLIENT_ID'],
'client_secret': os.environ['CLIENT_SECRET'],
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': 'http://localhost:8080/oauth'
}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
r = requests.post('https://discord.com/api/oauth2/token', data=data, headers=headers)
if 400 > r.status_code >= 200:
rdata = r.json()
access_token = rdata['access_token']
return "Successfully added bot"
print(r.text)
abort(401, "Failed to use code to auth")
if __name__ == '__main__':
if os.path.isfile('.env'):
with open('.env') as f:
for line in f:
k, v = line.strip().split('=', 1)
os.environ[k] = v
assert 'CLIENT_ID' in os.environ
assert 'CLIENT_SECRET' in os.environ
assert 'BOT_TOKEN' in os.environ
print('Open http://localhost:8080 in your browser')
run(host='localhost', port=8080, debug=True)
Many security features in Java rely on endpoint pattern matching which allow
for URL pattern matching bypasses if not careful. Additionally Spring MVC and
Spring Security together introduces are a few gotcha’s during implementation.
Security Constraint Matching
The most basic form of authentication within Java is using the
<security-constraint/> tag. The following is an example constraint
restricting access to /basic endpoint using Basic auth.
All official Java documentation uses the url-pattern /*, though details for
<url-pattern/> can be found in section 12.2 of the 3.0 servlet
specification. The following details mapping test-cases which have standard
Java servlets mapped to /basic
Wild cards do not function as expected, and only by leaving out extensions for
a literal matching or using /* can servlet patterns be correctly matched.
Security Constraints with Spring MVC
However if, for example, using the <security-restraint/> function to
protect Spring MVC controllers the following is observed:
The lesson here is never use standard <security-constraint/> methods when
attempting to restrict endpoints which are not servlets. We will touch on the
use of the . below.
Spring Security Pattern Matching
Security interceptors used by Spring Security use ANT pattern matching. This
type of matching is different from Regex. See the ANT documentation
on patterns for specifics.
The following is an example of a Spring Security URL pattern constraint:
The following is a test table showing various patterns, and their bypass:
MVC Map
Request
Response Code
/mvcpoint
/mvcpoint*
GET /mvcpoint/
200
/mvcpoint
/mvcpoint/
GET /mvcpoint
200
/mvcpoint
/mvcpoint/*
GET /mvcpoint
200
/mvcpoint
/mvcpoint**
GET /mvcpoint/
200
/mvcpoint
/mvcpoint/**
GET /mvcpoint.
200
/mvcpoint
/mvcpoint
GET /mvcpoint.
200
/mvcpoint
/mvcpoint/
GET /mvcpoint
200
/mvcpoint
/mvcpoint*/
GET /mvcpoint
200
/mvcpoint
/mvcpoint*/**
GET /mvcpoint.
401
The table shows that only a single spring-security pattern (*/**) is able to
secure against unauthorized access. To discover why, we must dig deeper.
Spring MVC with Spring Security
The problem arises in spring-mvc and its handling of extensions. We are able to
supply an incomplete extension (note the trailing . on the requests) to
spring-security which results in the bypass of the rule. When the incomplete
extension gets to spring-mvc however, the incomplete extension is treated as
erroneous and automatically returns the original mapping.
This results in the return of “/basic2.” due to the pathMatcher automatically
appending . to the pattern. In the end this function will find the correct
controller mapping in spite of the added period.
Summary
Only protect servlets with the <security-constraint/> element
Always use /* when defining <security-constraint/> patterns
Always use */** when defining <intercept-url/> patterns
If you get an error that looks anything like the following:
./working/samplecrack/theos/include/IOSurface/IOSurface.h:20:10:
fatal error: 'IOSurface/IOSurfaceAPI.h' file not found
#include <IOSurface/IOSurfaceAPI.h>
Then try including the IOSurfaceAPI.h in, I had to do this on lion.
You will probably need to comment out the following lines also:
/* This call lets you get an xpcobject_t that holds
a reference to the IOSurface.
Note: Any live XPC objects created from an IOSurfaceRef implicity increase
the IOSurface's global use
count by one until the object is destroyed. */
// xpc_object_t IOSurfaceCreateXPCObject(IOSurfaceRef aSurface)
// IOSFC_AVAILABLE_STARTING(_MAC_10_7, __IPHONE_NA);
/* This call lets you take an xpcobject_t created via IOSurfaceCreatePort()
and recreate an IOSurfaceRef from it. */
// IOSurfaceRef IOSurfaceLookupFromXPCObject(xpc_object_t xobj)
// IOSFC_AVAILABLE_STARTING(_MAC_10_7, __IPHONE_NA);
You are also going to need a copy of ldid. If you have ports, try there. Brew
doesn’t seem to hold a copy (They gave up on it because it fails with clang?
Use llvm g++). If those fail check try making it yourself:
These are the steps needed to crack (method patch the jailbreak function) an
iOS application to work on a rooted iOS device. This example uses “Sample.app”
from within OSX Lion. Mileage may vary.
Requirements
iOS Physical device rooted with cydia and some basic tools:
syslogd - See all console output in /var/log/
openssh
adv-cmds - Tools like ps, kill, etc
GNU debugger - (If GDB is working unexpectedly, install from
radare.org)
Darwin CC Tools - otool and such
Get the application and install it. This guide is assuming an encrypted IPA
(compiled for ARM) distribution.
Decrypting
In the cases in which the binary is encrypted, you must decrypt. The easiest
way to do this is to find a program to do it for you (Google this if you want
to skip this step). The surefire (manual) way to do this is to execute the
binary breaking at the end of the decoding stub. This will leave the entire
un-ecrypted binary in memory where you can then dump it to disk.
Locate application binary within the application folder on the device. e.g.:
Given cryptid 1 (0 == Not Encrypted). Keep note of the cryptsize, we will use
this value later.
Verify application is not FAT (That is does not contain multiple versions):
root# otool -f SampleApp
If the application contains multiple versions, you must use lipo to extract the
correct (armv7) version and continue.
Given a single encrypted binary:
root# gdb --quiet -e ./SampleApp
...
(gdb) set sharedlibrary load-rules ".*" ".*" none
(gdb) set inferior-auto-start-dyld off
(gdb) set sharedlibrary preload-libraries off
(gdb) rb doModInitFunctions
Breakpoint 1 at 0x2fe0cece
<function, no debug info>
__dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE;
(gdb) r
Starting program:
/private/var/mobile/Applications/BC2DA09D-7189-44E8-B190-2EE03BAAAAA8/SampleApp.app/SampleApp.app/SampleApp
Breakpoint 1, 0x2fe0cece in
__dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE
()
Dump the binary from memory to disk:
dump binary memory /var/root/dump 0x2000 0x18000
See python -c 'print(hex(4096+94208))' from crytpid analysis for the end limit,
which is 0x18000 bytes in the example. You will have to substitute your own
value in.
Examine dump for a root checking function (probably returns BOOL or _Bool) with
some grep-fu. You will most likely find multiple functions. If the application
is more complicated, cycript may help you find it.
Create a Cocoa Touch Static Library XCode Project.
Setup dylib compiling for iOS from XCode from the instructions at "Build and use dylib on iOS" by iOS
Place. I believe there are other ways to compile outside of XCode, if you
have any success there drop a comment.
All is needed now compile to dylib by running the application and copying it
over. Press the run button to compile. Find it by looking at the left hand bar,
mine was located at
/Users/user/Library/Developer/Xcode/DerivedData/NoCheck-abheoijxmwkxefbirkgyhsismoxg/Build/Products/Debug-iphoneos
Copy the output file to /Library/MobileSubstrate/DynamicLibraries/
user@box> cd
/Users/user/Library/Developer/Xcode/DerivedData/NoCheck-abheoijxmwkxefbirkgyhsismoxg/Build/Products/Debug-iphoneos
user@box> scp ./NoCheck.dylib
root@iphone:/Library/MobileSubstrate/DynamicLibraries/
Run application and be happy. If you’re not sure it worked tail your syslog
output to see if the module is loading (it will do so often) and the NSLog is
output.
Put this python file in your path to get the following:
#!/usr/bin/env python
"""
Command-line tool to validate and pretty-print XML.
Based on `pjson` but without the crap.
Usage::
$ echo '<bunk atr="hello">world</bunk>' | pxml
<?xml version="1.0" ?>
<bunk atr="hello">
world
</bunk>
Original Author: Igor Guerrero <igfgt1@gmail.com>, 2012
Contributor: Matthew Gill, 2012
"""
import xml.dom.minidom
import sys
from pygments import highlight
from pygments.formatters import TerminalFormatter
from pygments.lexers import XmlLexer
def format_xml_code(code):
"""
Parses XML and formats it
"""
x = xml.dom.minidom.parseString(code)
return x.toprettyxml()
def color_yo_shit(code):
"""
Calls pygments.highlight to color yo shit
"""
return highlight(code, XmlLexer(), TerminalFormatter())
if __name__ == '__main__':
code = format_xml_code(sys.stdin.read())
print color_yo_shit(code)
This was one of my favorite challenges at this year’s CTF. Thanks to the guys who put it on, it was a load of fun and I appreciate all the hard work I know that goes into this sort of thing.
The Challenge
Posted on one of the websites was the file fu2.zip contained the following files:
zoidberg% unzip fu2.zip -d ./fu2
zoidberg% cd fu2
zoidberg% file ./*
./BouncyCastle.Crypto.dll: PE32 executable for MS Windows (DLL) (console) Intel 80386 32-bit Mono/.Net assembly
./FileEncryptor.exe: PE32 executable for MS Windows (console) Intel 80386 32-bit Mono/.Net assembly
./plain1_encrypted: data
./plain2: ASCII text, with no line terminators
./plain2_encrypted: data
zoidberg% ls -al ./plain*
-rw-r--r-- 1 mgill staff 128 Sep 24 13:14 ./plain1_encrypted
-rw-r--r-- 1 mgill staff 112 Sep 17 06:18 ./plain2
-rw-r--r-- 1 mgill staff 128 Sep 24 13:14 ./plain2_encrypted
There are a few clues here if you just go off file names and file sizes, but let’s take the easy route and simply decompile the .NET binary. A quick google search on the md5sum of the BouncyCastle lib tells us it’s unlikely it has been modified so we only want to see what FileEncryptor.exe does. My favorite .net decompiler is dotPeek, and lucky us .net allows for some awesome code generation.
After looking through the code we get a better idea on what is going on. We pass in a password, a plain text file, and a output file. The program then encrypts the plain text file with the password, to produce the output. Here are the interesting functions:
Now we have all the key pieces of information. Our plain2 file, which is 112 bytes of repeating characters (‘KC57’*28) produces plain2_encrypted, at 128 bytes. We have plain1_encrypted, but no plain1. A brute force attack here seems a bit inelegant not to mention being the ballers we are we don’t have time for that shit.
Notice that the password is seeded with a salt and the IV is static. Generally speaking the IV should be a noonce value to stop different types of attacks against block encryptions. Static IV’s are bad. The Encrypt() function above shows that we’re using the OfbBlockCipher or Output-FeedBack. OFB is a stream cipher which generally means the keystream is xor’d with the plaintext value to produce the output. Really what we’re interested in is attacks against OFB, especially when the programmer makes the mistake of using a static IV.
All the stars align. We have a static IV making the keystreams identical for each encryption and a plaintext and encrypted value pair. This means we can decrypt the plain1_encrypted file without ever needing to know the key! Simply compute the value of the keystream by xoring the plain2 against the encrypted plain2_encrypted, and apply that keystream to the plain1_encrypted. Voila! Here is a bit of python code to get the job done
import itertools
#take in the plain1 encrypted file and convert to ints
p1e = open('plain1_encrypted','r').read()
p1e_ord = map(ord, p1e)
#take in the plain2 encrypted file and convert to ints
p2e = open('plain2_encrypted','r').read()
p2e_ord = map(ord, p2e)
#take in the plain2 file and convert to ints
p2 = open('plain2','r').read()
p2_ord = map(ord, p2)
keystream = []
for x,y in itertools.izip_longest(p2_ord, p2e_ord, fillvalue=0):
keystream.append(x^y)
final = []
for x,y in zip(p1e_ord, keystream):
final.append(chr(x^y))
print ''.join(final)
Success, the flag has been disclosed! While this is a workable solution, I’m not exactly sure how the bytes are properly padded (instead of using 0 in my case) nor am I sure why there are unprintable characters in the decoded stream. You can see them by directly printing the repr of the finalResult object. But it works and the flag is decoded. If you have any input please throw it my way, it would be nice to know if there is any way to improve on it all.