# Automatic Rejection MachineThis is a classical flag checker but its an Aarch64 ELF.Since qemu is a pain in the ass and I have no usable device to run the executable, we just reversed the binary and re-implemented it in Rust.
The binary basically takes the flag and apply some operations on it, and then it checks that the result matches some magic values. To solve it we just brute-force the value using the number of magic values matched as a """""side-channel"""".```rustuse std::collections::HashMap;
const SBOX: [i16; 30] = [    0x0, 0x2, 0xB, 0x6, 0x4, 0x5, 0x3, 0x7, 0x8, 0x9, 0xA, 0x1, 0xC, 0x16, 0x18, 0xF, 0x11, 0x10, 0x12, 0x13, 0x17, 0x14, 0xD, 0x15, 0xE, 0x1D, 0x1C, 0x1B, 0x1A, 0x19];
fn shuffle_flag(mut flag: Vec<u8>) -> Vec<u8> {    let mut sbox = SBOX.to_vec();    for i in 0..0x1E {        let mut j = i;        while sbox[j] > -1 {            flag.swap(i, sbox[j] as usize);            let tmp = sbox[j];            sbox[j] -= 0x1E;            j = tmp as usize;        }    }    flag}
const WTF: [u64; 6] = [    0x9e3779b917181920,    0x9e3779b912881288,    0xdeadbeeffeedbeef,    0x1badb002facecafe,    0xFEEDFACE08920892,    0xCAFEFEED12401240,];
fn f1(flag: Vec<u8>) -> Vec<u64> {    let mut wtf = WTF.to_vec();    let mut res = Vec::new();
    for i in 0..(flag.len() - 2) {        wtf[0] =             (flag[i + 2] as u64) << 0x10 |            (flag[i + 1] as u64) << 8 |            flag[i] as u64 |            0xaabbccdd11000000;        let (a, b) = f2(&wtf);        res.push(a);        res.push(b);    }
    res}
fn f2(wtf: &Vec<u64>) -> (u64, u64) {    let mut res1 = wtf[0];    let mut res2 = wtf[1];    let mut c = wtf[2..].to_vec();
    for i in 0..0x10 {        c[i & 3] =             c[0] + c[1] + (                c[2] + c[3] ^ c[0] << (c[2 & 0x3F])            );        let tmp = c[i & 3];        res1 += (tmp + res2) * 0x200 ^ tmp - res2 ^ (tmp + res2) >> 0xe;        res2 += (tmp + res1) * 0x200 ^ tmp - res1 ^ (tmp + res1) >> 0xe;    }
    (res1, res2)}
const MAGIC: [u64; 60] = [    0xb4d8846071ac9ee5,    0x1e1ff00814e134fe,    0x6b198e7941b7002e,    0xbc6fa839efe36443,    0xc3c71ad9a664b6c3,    0x5692a2f09c98d986,    0xf084a1a59cd01e68,    0xbc52e78a7e4df2df,    0xda219d93290b91a8,    0x5703d0286fa5d32f,    0x6274b1b118da82b2,    0xa746ebfb0954ebbc,    0x5f6df7bd4f1967a2,    0x16d5b5bdee98cf8e,    0x52e8b6df7e62e39a,    0x99f9455fb0c8d933,    0x5ffd82d53af933d,    0xff9084a16ff0141c,    0xe17c5f0781d52f9b,    0x1a0f4431548e51d1,    0xf2e8573d8f0f01dd,    0x250039177f4def91,    0x8851491ecbc7af7c,    0xad427c6695b91d24,    0x5e0071d97d98d094,    0x264dda52b0c37b03,    0xa5811271d6d7c428,    0xe0133fc719f34136,    0xe508ace2412b2633,    0x74321a3e9face34c,    0xff5b8a59e8ebf70b,    0x76275a516f88c986,    0x1604d76f74599cc4,    0xf744bcd8f2016f58,    0xa0b6a7a0239e4ea7,    0xf1efc57f15cb9ab4,    0xb0d1ad4fb4ed946a,    0x81ca31324d48e689,    0xe6a9979c51869f49,    0xa666637ee4bc2457,    0x6475b6ab4884b93c,    0x5c033b1207da898f,    0xb66dc7e0dec3443e,    0xe4899c99cfa0235c,    0x3b7fd8d4d0dcaf6b,    0xb1a4690db34a7a7c,    0x8041d2607129adab,    0xa6a1294a99894f1a,    0xdde37a1c4524b831,    0x3bc8d81de355b65c,    0x6c61ab15a63ad91e,    0x8fa4e37f4a3c7a39,    0x268b598404e773af,    0x74f4f040ae13f867,    0x4df78e91fd682404,    0xabe1fc425a9a671a,    0x1bb06615c8a31dd5,    0x9f56e9aef2fa5d55,    0x239dcf030b3ce09b,    0x24556a34b61ca99,];
const INV_SBOX: [usize; 30] = [0, 11, 1, 6, 4, 5, 3, 7, 8, 9, 10, 2, 12, 22, 24, 15, 17, 16, 18, 19, 21, 23, 13, 20, 14, 29, 28, 27, 26, 25];
fn main() {    // start from a plausible input this is important because the f1 function    // depends on the next 3 chars in the flag (once shuffled) so we need the `p` and the `m``    // to be already right otherwise the bruteforcing won't work.    let mut input = b"ptm{EFGHIJKLMNOPQRSTUVWXYZabc}".to_vec();     // for each carachter    for i in 1..30 {        let mut tests = HashMap::new();         // bruteforce the next carachter        for c in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\\'()*+,-./:;<=>?@[\\]^_`{|}~".bytes() {            // set the current carachter             input[INV_SBOX[i]] = c;             // simlate the binary            let clone_input = input.clone();            let flag = shuffle_flag(input.clone());            let flag = f1(flag);             // count how many magic values the current input matches            let mut count = 0;            for i in 0..56 {                if flag[i] == MAGIC[i] {                    count += 1;                }            }             // save it into the possible solutions map            tests.insert(clone_input, count);        }         // extract the input which matches the most magics        let (new_input, count) = tests.iter().max_by(|(_flag1, count1), (_flag2, count2)| count1.cmp(count2)).unwrap();         // print it and use it for the next iteration        println!("{} {}", String::from_utf8(new_input.clone()).unwrap(), count);        input = new_input.clone();     }}```Which give the result:```$ time cargo run --releaseptm{EFGHIJKuMNOPQRSTUVWXYZabc} 2ptm{EFGHIJKuMNOPQRSTUVWXYZabc} 2ptm{EF0HIJKuMNOPQRSTUVWXYZabc} 4ptm{5F0HIJKuMNOPQRSTUVWXYZabc} 6ptm{5m0HIJKuMNOPQRSTUVWXYZabc} 10ptm{5m0HIJKuMNOPQRSTUVWXYZabc} 10ptm{5m0lIJKuMNOPQRSTUVWXYZabc} 12ptm{5m0l_JKuMNOPQRSTUVWXYZabc} 14ptm{5m0l_cKuMNOPQRSTUVWXYZabc} 16ptm{5m0l_chuMNOPQRSTUVWXYZabc} 20ptm{5m0l_chuMNOPQRSTUVWXYZabc} 20ptm{5m0l_chunNOPQRSTUVWXYZabc} 22ptm{5m0l_chunNOPQRSTUV3XYZabc} 24ptm{5m0l_chunNOPQRSTUV3XuZabc} 26ptm{5m0l_chunNO_QRSTUV3XuZabc} 28ptm{5m0l_chunNO_QmSTUV3XuZabc} 30ptm{5m0l_chunNO_5mSTUV3XuZabc} 32ptm{5m0l_chunNO_5m0TUV3XuZabc} 34ptm{5m0l_chunNO_5m0lUV3XuZabc} 36ptm{5m0l_chunNO_5m0lU53XuZabc} 38ptm{5m0l_chunNO_5m0lU53cuZabc} 40ptm{5m0l_chunkO_5m0lU53cuZabc} 42ptm{5m0l_chunkO_5m0l_53cuZabc} 44ptm{5m0l_chunk5_5m0l_53cuZabc} 48ptm{5m0l_chunk5_5m0l_53cuZabc} 48ptm{5m0l_chunk5_5m0l_53cuZaby} 50ptm{5m0l_chunk5_5m0l_53cuZa7y} 52ptm{5m0l_chunk5_5m0l_53cuZ17y} 54ptm{5m0l_chunk5_5m0l_53cur17y} 56cargo run --release  0.07s user 0.01s system 98% cpu 0.073 total```