メインコンテンツへスキップ

AlpacaHack Mirage writeup

    chal.cには次のように書かれていた。

    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    
    #define N 19
    
    uint8_t enc[N] = {
        0x31, 0x54, 0x6c, 0x2f, 0x04, 0x52, 0x22, 0x41, 0x3f, 0x59,
        0x27, 0x45, 0x67, 0x79, 0x1a, 0x4e, 0x78, 0x2d, 0x19
    };
    
    uint16_t step(uint16_t s) {
        uint16_t bit = ((s >> 0) ^ (s >> 2) ^ (s >> 3) ^ (s >> 5)) & 1;
        return (s >> 1) | (bit << 15);
    }
    
    int main(void) {
        setvbuf(stdout, NULL, _IONBF, 0);
        char buf[64];
        printf("enter the flag: ");
        if (!fgets(buf, sizeof(buf), stdin))
            return 1;
        buf[strcspn(buf, "\n")] = 0;
        if (strlen(buf) != N) {
            printf("wrong\n");
            return 1;
        }
        uint16_t state = 0xACE1;
        for (int i = 0; i < N; i++) {
            state = step(state);
            if (((uint8_t)buf[i] ^ (state & 0x7F)) != enc[i]) {
                printf("wrong\n");
                return 1;
            }
        }
        printf("correct!\n");
        return 0;
    }
    

    排他的論理和には次のような性質がある。
    A ^ B = Cの時、元の値AはA = C ^ Bで求められる。

    これを利用して次のようなコードを作成した。

    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    
    uint16_t step(uint16_t s) {
        uint16_t bit = ((s >> 0) ^ (s >> 2) ^ (s >> 3) ^ (s >> 5)) & 1;
        return (s >> 1) | (bit << 15);
    }
    
    int main(void){
      uint8_t enc[19] = {0x31, 0x54, 0x6c, 0x2f, 0x04, 0x52, 0x22, 0x41, 0x3f, 0x59,
        0x27, 0x45, 0x67, 0x79, 0x1a, 0x4e, 0x78, 0x2d, 0x19};
      uint16_t state = 0xACE1;
    
      uint8_t flag[20] = {0};
      for (int i = 0; i < 19; i++) {
             state = step(state);
             flag[i] = enc[i] ^ (state & 0x7F);
      }
      printf("flag: %s\n",flag);
      return 0;
    }
    

    このコードを実行すれば、flagが求められる。
    flag = Alpaca{mirrors_lie}

    あなたへのおすすめ