xortool.py ==================== A tool to do some xor analysis: - guess the key length (based on count of equal chars) - guess the key (base on knowledge of most frequent char) **Notice:** xortool is now only running on Python 3. The old Python 2 version is accessible at the `py2` branch. The **pip** package has been updated. ## Installation ```bash $ pip3 install xortool ``` For development or building this repository, [poetry](https://python-poetry.org/) is needed. ```bash poetry build pip install dist/xortool*.whl ``` Usage --------------------- ``` xortool A tool to do some xor analysis: - guess the key length (based on count of equal chars) - guess the key (base on knowledge of most frequent char) Usage: xortool [-x] [-m MAX-LEN] [-f] [-t CHARSET] [FILE] xortool [-x] [-l LEN] [-c CHAR | -b | -o] [-f] [-t CHARSET] [-p PLAIN] [-r PERCENT] [FILE] xortool [-x] [-m MAX-LEN| -l LEN] [-c CHAR | -b | -o] [-f] [-t CHARSET] [-p PLAIN] [-r PERCENT] [FILE] xortool [-h | --help] xortool --version Options: -x --hex input is hex-encoded str -l LEN, --key-length=LEN length of the key -m MAX-LEN, --max-keylen=MAX-LEN maximum key length to probe [default: 65] -c CHAR, --char=CHAR most frequent char (one char or hex code) -b --brute-chars brute force all possible most frequent chars -o --brute-printable same as -b but will only check printable chars -f --filter-output filter outputs based on the charset -t CHARSET --text-charset=CHARSET target text character set [default: printable] -p PLAIN --known-plaintext=PLAIN use known plaintext for decoding -r PERCENT, --threshold=PERCENT threshold validity percentage [default: 95] -h --help show this help Notes: Text character set: * Pre-defined sets: printable, base32, base64 * Custom sets: - a: lowercase chars - A: uppercase chars - 1: digits - !: special chars - *: printable chars Examples: xortool file.bin xortool -l 11 -c 20 file.bin xortool -x -c ' ' file.hex xortool -b -f -l 23 -t base64 message.enc xortool -b -p "xctf{" message.enc xortool -r 80 -p "flag{" -c ' ' message.enc ``` Example 1 --------------------- ```bash # xor is xortool/xortool-xor tests $ xor -f /bin/ls -s "secret_key" > binary_xored tests $ xortool binary_xored The most probable key lengths: 2: 5.0% 5: 8.7% 8: 4.9% 10: 15.4% 12: 4.8% 15: 8.5% 18: 4.8% 20: 15.1% 25: 8.4% 30: 14.9% Key-length can be 5*n Most possible char is needed to guess the key! # 00 is the most frequent byte in binaries tests $ xortool binary_xored -l 10 -c 00 ... 1 possible key(s) of length 10: secret_key # decrypted ciphertexts are placed in ./xortool_out/Number_ # ( have no better idea ) tests $ md5sum xortool_out/0_secret_key /bin/ls 29942e290876703169e1b614d0b4340a xortool_out/0_secret_key 29942e290876703169e1b614d0b4340a /bin/ls ``` The most common use is to pass just the encrypted file and the most frequent character (usually 00 for binaries and 20 for text files) - length will be automatically chosen: ```bash tests $ xortool tool_xored -c 20 The most probable key lengths: 2: 5.6% 5: 7.8% 8: 6.0% 10: 11.7% 12: 5.6% 15: 7.6% 20: 19.8% 25: 7.8% 28: 5.7% 30: 11.4% Key-length can be 5*n 1 possible key(s) of length 20: an0ther s3cret \xdd key ``` Here, the key is longer then default 32 limit: ```bash tests $ xortool ls_xored -c 00 -m 64 The most probable key lengths: 3: 3.3% 6: 3.3% 9: 3.3% 11: 7.0% 22: 6.9% 24: 3.3% 27: 3.2% 33: 18.4% 44: 6.8% 55: 6.7% Key-length can be 3*n 1 possible key(s) of length 33: really long s3cr3t k3y... PADDING ``` So, if automated decryption fails, you can calibrate: - (`-m`) max length to try longer keys - (`-l`) selected length to see some interesting keys - (`-c`) the most frequent char to produce right plaintext Example 2 --------------------- We are given a message in encoded in Base64 and XORed with an unknown key. ```bash # xortool message.enc The most probable key lengths: 2: 12.3% 4: 13.8% 6: 10.5% 8: 11.5% 10: 8.6% 12: 9.4% 14: 7.1% 16: 7.8% 23: 10.4% 46: 8.7% Key-length can be 4*n Most possible char is needed to guess the key! ``` We can now test the key lengths while filtering the outputs so that it only keeps the plaintexts holding the character set of Base64. After trying a few lengths, we come to the right one, which gives only 1 plaintext with a percentage of valid characters above the default threshold of 95%. ```bash $ xortool message.enc -b -f -l 23 -t base64 256 possible key(s) of length 23: \x01=\x121#"0\x17\x13\t\x7f ,&/\x12s\x114u\x170# \x00<\x130"#1\x16\x12\x08~!-\'.\x13r\x105t\x161" \x03?\x103! 2\x15\x11\x0b}".$-\x10q\x136w\x152! \x02>\x112 !3\x14\x10\n|#/%,\x11p\x127v\x143 \x059\x165\'&4\x13\x17\r{$("+\x16w\x150q\x134\' ... Found 1 plaintexts with 95.0%+ valid characters See files filename-key.csv, filename-char_used-perc_valid.csv ``` By filtering the outputs on the character set of Base64, we directly keep the only solution. Information --------------------- Author: hellman License: [MIT License](https://opensource.org/licenses/MIT)