LoginSignup
0
0

More than 3 years have passed since last update.

TSG CTF Recorded [Misc] write-up

Posted at

以下のスクリプトを使ってinputを解読した。

#include <assert.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <sys/time.h>

int main(void)
{
  int fd = open("input", O_RDWR);
  assert(fd != -1);

  for (;;) {
    struct input_event event;
    assert(read(fd, &event, sizeof(event)) == sizeof(event));
    if (event.type == 0x1 && event.value == 0x1) {
      switch (event.code) {
        case KEY_1:
          putchar('1');
          break;
        case KEY_2:
          putchar('2');
          break;
        case KEY_3:
          putchar('3');
          break;
        case KEY_4:
          putchar('4');
          break;
        case KEY_5:
          putchar('5');
          break;
        case KEY_6:
          putchar('6');
          break;
        case KEY_7:
          putchar('7');
          break;
        case KEY_8:
          putchar('8');
          break;
        case KEY_9:
          putchar('9');
          break;
        case KEY_0:
          putchar('0');
          break;
        case KEY_MINUS:
          putchar('-');
          break;
        case KEY_EQUAL:
          putchar('=');
          break;
        case KEY_Q:
          putchar('q');
          break;
        case KEY_W:
          putchar('w');
          break;
        case KEY_E:
          putchar('e');
          break;
        case KEY_R:
          putchar('r');
          break;
        case KEY_T:
          putchar('t');
          break;
        case KEY_Y:
          putchar('y');
          break;
        case KEY_U:
          putchar('u');
          break;
        case KEY_I:
          putchar('i');
          break;
        case KEY_O:
          putchar('o');
          break;
        case KEY_P:
          putchar('p');
          break;
        case KEY_LEFTBRACE:
          putchar('(');
          break;
        case KEY_RIGHTBRACE:
          putchar(')');
          break;
        case KEY_ENTER:
          putchar('\n');
          break;
        case KEY_A:
          putchar('a');
          break;
        case KEY_S:
          putchar('s');
          break;
        case KEY_D:
          putchar('d');
          break;
        case KEY_F:
          putchar('f');
          break;
        case KEY_G:
          putchar('g');
          break;
        case KEY_H:
          putchar('h');
          break;
        case KEY_J:
          putchar('j');
          break;
        case KEY_K:
          putchar('k');
          break;
        case KEY_L:
          putchar('l');
          break;
        case KEY_SEMICOLON:
          putchar(';');
          break;
        case KEY_APOSTROPHE:
          putchar('\'');
          break;
        case KEY_GRAVE:
          putchar('`');
          break;
        case KEY_BACKSLASH:
          putchar('\\');
          break;
        case KEY_Z:
          putchar('z');
          break;
        case KEY_X:
          putchar('x');
          break;
        case KEY_C:
          putchar('c');
          break;
        case KEY_V:
          putchar('v');
          break;
        case KEY_B:
          putchar('b');
          break;
        case KEY_N:
          putchar('n');
          break;
        case KEY_M:
          putchar('m');
          break;
        case KEY_COMMA:
          putchar(',');
          break;
        case KEY_DOT:
          putchar('.');
          break;
        case KEY_SLASH:
          putchar('/');
          break;
        case KEY_SPACE:
          putchar(' ');
          break;
        case KEY_LEFTSHIFT:
          printf("<shift>");
          break;
        case KEY_TAB:
          printf("<tab>");
          break;
        case KEY_BACKSPACE:
          printf("<bs>");
          break;
        default:
          printf("<%d>", event.code);
      }
      //printf(": %lu\n", event.time.tv_sec);
    }
  }
  close(fd);
}

結果は以下の通り。

rm /dev/ura<tab>
rm /dev/ra<tab>
<shift>lang-c date --utc <shift>. /dev/random
echo nyan <shift>.. /dev/ra<tab>
curl -<shift>o https'//www.openssl.org/source/openssl-1.1.1b.tar.gz
tar xzvf ope<tab>
cd ope<tab><tab>
vim cry<tab>ra<tab>rand<shift><89>unix.c
637<shift>gd17d621<shift>gd2d603<shift>gdd480<shift>gd30d'wq
vim cr<tab>ra<tab>ra<tab><shift><89>li<tab>
250<shift>gd2d'wq
./co<tab>
make -j 4
cd ..
<shift>ld<89>library<89>path-./ope<tab> ./ope<tab>app<tab>ope<tab>genrsa 1024 <shift>. key.pem
<shift>ld<89>library<89>path-./ope<tab> ./ope<tab>ap<tab>ope<tab>rsautl -encrypt -inkey key.<tab>-in fl<tab>-out encrypted
fd<bs>g 1

guessしながら結果を整形した。

rm /dev/ura<tab>
rm /dev/ra<tab>
LANG=C date --utc > /dev/random (enter key tv_sec = 1556368668)
echo nyan >> /dev/ra<tab>
curl -O https://www.openssl.org/source/openssl-1.1.1b.tar.gz
tar xzvf ope<tab>
cd ope<tab><tab>
vim cry<tab>ra<tab>rand_unix.c
637Gd17d621Gd2d603Gdd480Gd30d:wq
vim cr<tab>ra<tab>ra<tab>_li<tab>
250Gd2d:wq
./co<tab>
make -j 4
cd ..
LD_LIBRARY_PATH=./ope<tab> ./ope<tab>app<tab>ope<tab>genrsa 1024 > key.pem (enter key tv_sec = 1556368884)
LD_LIBRARY_PATH=./ope<tab> ./ope<tab>ap<tab>ope<tab>rsautl -encrypt -inkey key.<tab>-in fl<tab>-out encrypted
fg 1
^C

与えられたDockerfileを使ってproblemイメージを生成しproblem上でコンテナを開始した。
コンテナの中で、以下のコマンドで/dev/urandom/dev/randomを削除し/dev/randomを再生成した。

# rm /dev/urandom
# rm /dev/random
# LANG=C date --utc --date="@1556368668" > /dev/random
# echo nyan >> /dev/random

解読結果に従って改造されたOpenSSLバイナリを作った。しかし、crypto/rand/rand_unix.cの中のget_time_stamp()を以下のように再改造した。

static uint64_t get_time_stamp(void)
{
    return 1556368884;
}

OpenSSLのソースコードを読んでkey.pem生成をランダム化する3つの因子があることを理解した。それは、/dev/random、生成時刻、生成するプロセスのIDであった。
解読結果から正しい/dev/randomと正しい生成時刻を知った。しかし、正しいPIDは分からないままだった。
したがって、encryptedをコンテナの中へコピーし、以下のコマンドで総当たり攻撃を行った。

# for ((i = 0; i < 40000; i++)); do LD_LIBRARY_PATH=./openssl-1.1.1b ./openssl-1.1.1b/apps/openssl genrsa 1024 > key.pem && LD_LIBRARY_PATH=./openssl-1.1.1b ./openssl-1.1.1b/apps/openssl rsautl -decrypt -inkey key.pem -in encrypted -out flag-${i}.txt; done
# ls -lS | more

こうして、flagを見つけた。

# cat flag-2936.txt 
TSGCTF{openssl_genrsa_is_hardly_predictable}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0