Browsing the archives for the Programming tag.

Vulnerable Code: MoinMoin User

Programming

I’ve just started posting code samples from the wonderful SpotTheVuln.com on the walls in our building on 11×17 cardstock behind thin plexiglass panes so they can be annotated with dry erase marker when people solve them or have comments:

I love the site but wanted to branch out a little bit into some samples outside of the PHP and Wordpress world. In my first attempt, I didn’t branch very far, and it’s a bit longer than I would have preferred, but here it is — from MoinMoin. Hopefully I included enough information to find the issue.

def getUserId(request, searchName):
    """
    Get the user ID for a specific user NAME.
 
    @param searchName: the user name to look up
    @rtype: string
    @return: the corresponding user ID or None
    """
    if not searchName:
        return None
    cfg = request.cfg
    try:
        _name2id = cfg._name2id
    except AttributeError:
        arena = 'user'
        key = 'name2id'
        cache = caching.CacheEntry(request, arena, key)
        try:
            _name2id = pickle.loads(cache.content())
        except (pickle.UnpicklingError, IOError, EOFError, ValueError):
            _name2id = {}
        cfg._name2id = _name2id
    id = _name2id.get(searchName, None)
    if id is None:
        for userid in getUserList(request):
            name = User(request, id=userid).name
            _name2id[name] = userid
        cfg._name2id = _name2id
        arena = 'user'
        key = 'name2id'
        cache = caching.CacheEntry(request, arena, key)
        cache.update(pickle.dumps(_name2id, PICKLE_PROTOCOL))
        id = _name2id.get(searchName, None)
    return id
 
class User:
    """A MoinMoin User"""
 
    def __init__(self, request, id=None, name="", password=None,
                 auth_username="", **kw):
        """ Initialize User object
 
        @param request: the request object
        @param id: (optional) user ID
        @param name: (optional) user name
        @param password: (optional) user password (unicode)
        @param auth_username: (optional) already authenticated user name
                              (e.g. when using http basic auth) (unicode)"""
        self._cfg = request.cfg
        self.valid = 0
        self.trusted = 0
        self.id = id
        self.auth_username = auth_username
        self.auth_method = kw.get('auth_method', 'internal')
        self.auth_attribs = kw.get('auth_attribs', ())
 
        # we got an already authenticated username:
        check_pass = 0
        if not self.id and self.auth_username:
            self.id = getUserId(request, self.auth_username)
            if not password is None:
                check_pass = 1
        if self.id:
            self.load_from_id(check_pass)
            if self.name == self.auth_username:
                self.trusted = 1
        elif self.name:
            self.id = getUserId(self._request, self.name)
            if self.id:
                self.load_from_id(1)
            else:
                self.id = self.make_id()
        else:
            self.id = self.make_id()
 
    def __filename(self):
        """ Get filename of the user's file on disk
        @rtype: string
        @return: full path and filename of user account file
        """
        return os.path.join(self._cfg.user_dir, self.id or "...NONE...")
 
    def save(self):
        """ Save user account data to user account file on disk.
 
        This saves all member variables, except "id" and "valid" and
        those starting with an underscore.
        """
        if not self.id:
            return
 
        user_dir = self._cfg.user_dir
        filesys.makeDirs(user_dir)
 
        self.last_saved = str(time.time())
 
        data = codecs.open(self.__filename(), "w", config.charset)
        data.write("# Data saved '%s' for id '%s'\n" % (
            time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())),
            self.id))
        attrs = vars(self).items()
        attrs.sort()
        for key, value in attrs:
            if key not in self._cfg.user_transient_fields and key[0] != '_':
                # Encode list values
                if key in ['quicklinks', 'subscribed_pages']:
                    value = encodeList(value)
                line = u"%s=%s\n" % (key, unicode(value))
                data.write(line)
        data.close()
 
        if not self.disabled:
            self.valid = 1
No Comments

Java is not Python and Cygwin is not Linux

Programming

I’m burning the midnight oil working on a project in Java and came upon a number of gripes, all right in a row, that I thought were all worth blogging about in case I can help make somebody else’s night a little bit better. So here are some things I learned today.

Java is not Python. Java’s changes that introduced generics (to allow expressions like, for example, “Vector<Integer>”) were pretty much all in the compiler. The bytecode stays the same; the compiler just gets some additional data to use for typechecking. Then your beautifully generic Java 5.0 code undergoes a process called type erasure producing the same — but better typechecked — bytecode that your old 1.4 code would have. The result is that when I, with my limited understanding of Java generics, tried to write overly dynamic code, the compiler scoffed.

“required: class or array”, it said. What it really meant was, “You can’t use a generic type in an instanceof operation, you dummy, because I’m about to erase that type and replace it with Object.” Doi.

Cygwin is not Linux. Especially where Java is concerned. I spent about 20 minutes trying to figure out why I couldn’t pass the JDK an absolute classpath from Cygwin when relative classpaths worked just fine. It was because the JDK I was calling is Windows native, not Cygwin, so it doesn’t understand the Unix-style directory structure I was giving it.

Java is not Python (redux). I’ve mostly been using Python for my various and sundry programming needs over the past couple of years. And it’s impressive how quickly one gets used to a REPL (read-eval-print-loop) — and how useful it is for quick debugging and answers.

For instance, I missed having a REPL when I had a simple question: can I typecast null to whatever object type I want (the answer is yes, by the way, which makes a lot of sense when you think about it)? I was in the midst of a fairly significant rewrite so I couldn’t just try it and run it. So I saw four choices: assume it would work and test it later, assume it wouldn’t work and rewrite it, look it up, or write a Java program to test it.

Turns out that there’s actually a fifth option: use the Java REPL. It’s called BeanShell (or bsh), and I feel pretty much ridiculous for not having found it before. Maybe you’ll enjoy it.

Okay, back to work.

No Comments