hang with pty's and processes

John J. Lee jjl at pobox.com
Sun Oct 28 14:01:53 EST 2001


I'm not used to forking, pty's, etc., so I'm hoping my problem here is
something elementary.

On the 84th password tried (on my linux machine at least), this program
hangs in pty_Popen.read, in os.read (see the line marked with # !!) -- it
never returns or raises an exception.  Why??

Perhaps I'm hitting some kind of system limit on pty's or something?
There are, at most, only a couple of relevant processes (mount, python,
losetup, etc) listed at any one time while this is running, so it doesn't
seem to be a process limit.


#!/usr/bin/env python
"""Crack off-by-one encrypted partition password.

pty_Popen is derived from code posted to comp.lang.python by Alex
Coventry.

Yes, I'm a fool for not writing my password down properly.
"""

import sys, os, pty, time

class pty_Popen:
    def __init__(self, command, args, delay=0.1):
        self._delay = delay
        self._cmd = command
        self._pid, self._child = pty.fork()
        if self._pid == 0:
            r = os.execv (command, [''] + args)
            os._exit(r)

    def wait(self):
        os.waitpid(self._pid, 0)

    def read(self, max_read):
        time.sleep(self._delay)
        ret = os.read(self._child, max_read)  # !!
        return ret

    def write(self, text):
        time.sleep(self._delay)
        return os.write(self._child, text)

    def response(self):
        while 1:
            try:
                response = self.read(1024).strip()
            except OSError:  # no output
                response = ""
                break
            if response:
                break
        return response

    def expect(self, expected, actual):
        if expected != actual:
            raise ValueError, "expected '%s', got '%s' from %s" % (
                expected, actual, self._cmd)

    def ok(self, expected, actual):
        if expected == actual: return 1
        else: return 0


class PswdIterator:
    min = 33
    max = 126
    def __init__(self, passwd):
        self.p = passwd
        self.i = 0
        self.cn = None
        self._new_char = 1

    def next(self):
        p = self.p
        if self.i >= len(p):
            return None
        if self._new_char:
            self.cn = self.min
            self._new_char = 0
        else:
            self.cn += 1
        if self.cn >= self.max:
            self.i += 1
            if self.i >= len(p):
                return None
            self._new_char = 1
        return p[:self.i] + chr(self.cn) + p[self.i+1:]


def crypton(crypt, device, cryptname, passwd):
    """Attempt to turn encrypted partition on, return 1 on success."""
    delay = 0.001
    p = pty_Popen("/sbin/losetup", ["-e", "serpent", device, crypt], delay)
    p.expect("Password :", p.response())
    p.write(passwd+"\n")
    p.expect("", p.response())
    p.wait()
    p2 = pty_Popen("/bin/mount", [device], delay)
    success = p2.ok("", p2.response())
    p2.wait()
    p3 = pty_Popen("/usr/local/bin/encoff", [cryptname], delay)
    r = p3.response()
    p3.expect("", r)
    p3.wait()
    if success:
        return 1

def crack():
    cryptname = "crypte"
    crypt = "/home/cd2/cryptfilee"
    passwd = "goeshere"
    device = "/dev/loop2"
    pwi = PswdIterator(passwd)
    while 1:
        print
        print "trying %s" % (passwd,)
        if crypton(crypt, device, cryptname, passwd):
            print "got it!"
            print passwd
            break
        passwd = pwi.next()
        if passwd is None: print "failed"

if __name__ == "__main__":
    t = time.time()
    crack()
    t = time.time() - t
    print t
    print t/60.0



Thanks for any help


John




More information about the Python-list mailing list