mame82 / duckencoder.py

Python port of infamous duckencoder for RubberDucky
136 stars 49 forks source link

duckencoder.py is unable to work on piped stream by design #9

Open doublehp opened 6 years ago

doublehp commented 6 years ago

I am piping live stream from keyboard into duckencoder.py; this is PITA because duckencoder.py is designed to work on closed stream, and not live pipe. Issue lays in both methods -r and -p, due to the use of

                        for line in sys.stdin:
                                source += line

This means the code is waiting for EOF before starting further work. Same issue happens further in the code:

        if rawpassthru:
                # parse raw ascii data
                result = ""
                keyboard = DuckEncoder.readResource(script_dir + "/resources/keyboard.properties")
                language = DuckEncoder.readResource(script_dir + "/resources/" + lang + ".properties")
                for line in source:
                        for c in line:
                                keydata = DuckEncoder.ASCIIChar2USBBytes(c, keyboard, language)
                                if len(keydata) > 0:
                                        result += keydata
        else:
                # parse source as DuckyScript
                result = DuckEncoder.generatePayload(source, lang)

        if ofile is None:
                # print to stdout
                # print(result)
                sys.stdout.write(result)
        else:
                # write to ofile
                with open(ofile, "w") as f:
                        f.write(result)

This whole section does things in two seperate steps: 1, it converts data, and when convertion is done, it tries to output it.

The way to fix for line in sys.stdin: is given in man python, in section for option -u. Fixing the rest needs a complete rewrite of the end of the source.

My workaround is to parse input data, and process it byte after byte, and call duckencoder.py once for each byte; this is overkilling, since it requires to reparse and recompile the python script for every single byte sent; the host can usually stand it because the initial input is a human typing on a keyboard, so it can hardly exceed 10 bytes per second for longer than 10mn ...

mame82 commented 6 years ago

This is inteded behavior. I've done per char encoding in P4wnP1's HID backdoor, if I remember correctly, for the commans sending key (uses duckencoder.py module).

In an early phase of development, I recognized that an USB keyboard is able to send non-ASCII chars, like German 'ü'.

One of the ideas was to provide Input as UTF8, which would conflict with bytewise conversion. Implementing this woild need some kind of look-ahead, as a single UTF8 char could consume multiple bytes.

Anyway, I never implemented this and trued to stay DuckyScript compatible for P4wnP1, which wasn't one of my best decissions (it is fairly limited, if you try to use loops , branches are impossible).

doublehp commented 6 years ago

The work around I am looking for since a few hours would to convert my raw input into duck-script, before sending it over the network; then, I would be able to feed duckencoder with a script, and not raw bytes; but I don't find the script generator in the documentations ...