Obfuscating python Errors

Python code snippet

So the reaction to my Python sys.exit blog entry included people claiming this is fine and that duck typing is not that important in the Python language, and why would you do this for real anyways?

To me it felt like this is the kind of quirks that are perfect to obfuscate code, so I try to see if I could use the fact that exceptions are silently swallowed for fun and profit. Let’s assume I want my code to call some sensitive API (which might throw Exceptions), but without leaving the tell-tale catch statements. This is what the code below does.

#!/usr/bin/env python3

import sys

def do_something_sensitive():
  print("do_something_sensitive called")
  raise PermissionError("Illegal access!")

  
class Worker:
  def __init__(self, name):
    self.name = name
    self.error = None
    
  def __str__(self):
    if self.error:
      return f"{self.name}: {self.error()}"
    return self.name
    
  def work(self):
    self.error = do_something_sensitive
    
try:
  w = Worker("Worker A")
  print(f"Starting {w}")
  w.work()
  print(f"Done")
  sys.exit(w)
except Exception as e:
  sys.exit(f"Bad stuff: {e}", file=sys.stderr)

Execution on my machine is the following:

Starting
Done
do_something_sensitive called

The only hint that something went wrong is an exit status of 1. The PermissionError exception is silently swallowed, the exception handling block is never visited despite the fact that do_something_sensitive was called and threw. So if your code is trying to probe some security stuff, the only tell-tale will be an none zero exit status.

If the code catches SystemExit, you get more reasonable behaviour, do_something_sensitive is only called when __str__ is invoked and the exception is throw in that context.

Is it a security bug? I don’t know, but it looks like a mechanism to obfuscate malicious code.

Leave a Reply

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