zip-rs / zip-old

Zip implementation in Rust
MIT License
731 stars 204 forks source link

Why it does not panic when wrong password are used? #379

Closed miaobuao closed 1 year ago

miaobuao commented 1 year ago

version == 0.6

reduf commented 1 year ago

It should return an error, though in some cases it's impossible to know the wrong password is used with the legacy encryption scheme. If you can elaborate, I might be able to give more context/information to your problem.

miaobuao commented 1 year ago

Here's the code snippet that should well describe my issue. When I remove the comments, this code runs fine, but when I keep the comments, it outputs the wrong password:

use zip::ZipArchive;
use std::fs::File;
use std::io::Read;
use itertools::{Itertools};

pub fn key_generator(
    seed: &[u8], 
    min_length: Option<usize>, 
    max_length: Option<usize>
) -> impl Iterator<Item = Vec<u8>> + '_ 
{
    (if let Some(le) = min_length {
        if let Some(ri) = max_length {
             le ..= ri
        } else {
            le ..= seed.len()
        }
    } else {
        1 ..= seed.len()
    }).flat_map(move |length| seed.to_vec().into_iter().permutations(length))
}

fn main() {
    let path = String::from("/home/meo/dev/proj/rcrack/test/data/flag.zip");
    let seed = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+-=[{}]\\|;:,<.>/?'\" ";

    let file = File::open(path).unwrap();
    let mut archive = ZipArchive::new(file).unwrap();
    for k in key_generator(seed.as_bytes(), None, None) {
        if let Ok(mut res) = archive
            .by_index_decrypt(0, k.as_slice())
            .unwrap() {
                // let mut buffer = Vec::new();
                // if let Ok(_) = res.read_to_end(&mut buffer) {
                    println!("{:?}", String::from_utf8(k).unwrap());
                // }
            }
    }
}
reduf commented 1 year ago

Is the zip encrypted with traditional PKWARE encryption (I think sometime named ZipCrypto)? If yes, you can't generally know if the password is incorrect, because the check is done with only 2 bytes. From the spec:

After the header is decrypted, the last 1 or 2 bytes in Buffer SHOULD be the high-order word/byte of the CRC for the file being decrypted, stored in Intel low-byte/high-byte order. Versions of PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is used on versions after 2.0. This can be used to test if the password supplied is correct or not.

reduf commented 1 year ago

Also, since you seems to be doing a ctf, wouldn't you be able to test the first few bytes of the data for the sign of a flag? They often start with prefix{.

miaobuao commented 1 year ago

Thank you, man. I think that's probably the problem :)