Jython and it’s java.nio.charset.UnsupportedCharsetException

 

I have been working on an Extender for Burp Suite (a local proxy which allows you to check for common problems and security weaknesses). While the proxy is written in Java it is common for the Extender’s to be made in Python.

Jython is the glue that keeps Java and Python working. My Extender had the need to execute python so I redirected the Standard Out and Standard Error streams to a MessageConsole.

Redirecting Standard out and err

The code for doing this is shown below:

// Redirect standard out and err to the MessageConsole
MessageConsole console = new MessageConsole(this.output);
console.redirectOut();
console.redirectErr(Color.RED, null)

Note: I might not leave this as the final product because I have just found this reference:

http://www.jython.org/javadoc/org/python/util/PythonInterpreter.html

Which indicates that “setErr” and “setOut” might work better for me somehow. However, that is a side show.

With the above code if you click the “Execute” button you trigger an event handler with this code:

// Get the python code from the text area
String python = pythonTextArea.getText();

// Show user that something is happening
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
PythonInterpreter interp = new PythonInterpreter();

// Run the user python in the Jython interpreter.
interp.exec(python);
// Close the interpreter
interp.close();

// Now our task is over show the user it is done.
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

Pretty simple; get me the python code, start an interpreter, execute, and close the interpreter.

UnsupportedCharsetException: cp0

Using the above code you will see that you get our pesky “UnsupportedCharsetException” on first execution of Jython as shown below:

unsupportedCharsetException.png
That makes for an unsightly error. It is not a blocker because as you can see the JOptionPane displayed its message after. But an error appearing to users is going to erode their trust in your software. Particularly since this happens once per execution. After it is displayed it seems Jython then selects an OK character set and plays happy from there.

Looking into it the exception is because the Java Virtual Machine has not been launched with an appropriate run-time parameter. According to the reference below:

https://wiki.python.org/jython/ConsoleChoices

You should be able to fix the problem by launching your Java process like this:

java -jar <yourexecutable> -Dpython.console.encoding=UTF-8

There are other Console Choices available. But this seems to be a way to prevent the error. This is also the accepted answer on bug trackers and forums across the Internet.

It seems possible to use a “jython registry” to apply this setting but that means shipping files with your tool or making users create them. It seemed messy when what I guess we really want is a way to set the character set somehow as a property of instantiating the “PythonInterpreter” object. That doesn’t appear to be in the API so we can only dream of that.

The Right Solution

The legend that is Paj working over at PortSwigger these days fired in this nugget:

Which effectively is the programmatic interface to interacting with run-time parameters. This solution works perfectly when I tested it. The code for this is below:


System.setProperty("python.console.encoding", "UTF-8");

// Redirect standard out and err to the pythonOutput textpane
MessageConsole console = new MessageConsole(this.output);
console.redirectOut();
console.redirectErr(Color.RED, null);

That got the job done right. If for some reason you are unable to use that. Then I have maintained my hilariously hacky solution which somewhat did the same job.

The Hacky Solution

In the realm of writing Burp Extenders I am not able to really influence how users launch their instance of Burp (so that -D approach is not likely). Nor would I imagine PortSwigger (the vendor) taking the time to cater for this edge case by making everybody launch burp a new way! Quite rightly too.

This means I came up with a hacky solution which avoids the errors for users:

// Here comes the dirty, dirty hack!
PythonInterpreter interp = new PythonInterpreter();
interp.exec("a=1+2");
interp.close();
// Yup. Launch the interpreter and do nothing of significance
// Do it before setting up your STDOUT and STDERR redirects

// Redirect standard out and err to the pythonOutput textpane
MessageConsole console = new MessageConsole(this.output);
console.redirectOut();
console.redirectErr(Color.RED, null);

I am going to need a shower. This feels particularly dirty even for me.

Folks from Google. You are welcome!

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.