0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Daily AlpacaHack 9/3-4 Let's Shut Down Linuxのwriteup

0
Posted at

先月に引き続きsyscall。思ったんですけど、AlpacaHackが毎日じゃなくなったことでwriteupを書く余裕が生まれたんですよね。いろいろ書けるといいな

Let's Shut Down Linux

rebootシステムコールに3個の引数を指定して、Linuxをシャットダウンしましょう!

※Dockerfileのビルド中に、Linuxイメージをビルドするために、100MB以上のデータのダウンロードや並列ビルドを行います。そのため、Dockerイメージのビルドに数分かかることがあります。

chal、chal.c、compose.yaml、Dockerfile、Makefile、server.pyが渡されます。実際にサーバにいるlinuxをshutdownする問題みたいですね。chal.cを見てみます。

#include <stddef.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <unistd.h>

/* Run a system call using 4 arguments. */
/* __attribute__((unused)) are used to disable warnings when build */
uint64_t __attribute__((naked))
my_syscall_4(__attribute__((unused)) uint64_t syscall_number,
             __attribute__((unused)) uint64_t arg1,
             __attribute__((unused)) uint64_t arg2,
             __attribute__((unused)) uint64_t arg3,
             __attribute__((unused)) uint64_t arg4) {
  asm("mov %rdi, %rax\n"
      "mov %rsi, %rdi\n"
      "mov %rdx, %rsi\n"
      "mov %rcx, %rdx\n"
      "mov %r8,  %r10\n"
      "syscall\n"
      "ret\n");
}

/* Run a system call using 3 arguments. */
uint64_t my_syscall_3(uint64_t syscall_number, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
  return my_syscall_4(syscall_number, arg1, arg2, arg3, 0);
}

/* Run a system call using 1 argument. */
uint64_t my_syscall_1(uint64_t syscall_number, uint64_t arg1) {
  return my_syscall_4(syscall_number, arg1, 0, 0, 0);
}

/* Write a string to stdout. */
ssize_t my_write(const char *s) {
  size_t size = 0;
  while (s[size]) {
    ++size;
  }

  return my_syscall_3(SYS_write, STDOUT_FILENO, (uint64_t)s, size);
}

/* Write a string and exit. */
void __attribute__((noreturn)) my_fatal(const char *message) {
  my_write(message);
  my_syscall_1(SYS_exit, 1);
  __builtin_unreachable();
}

/* Read a string from stdin, then parse it as decimal number. */
uint32_t my_read_uint32() {
  char buf[64] = {};
  ssize_t size = (ssize_t)my_syscall_3(SYS_read, STDIN_FILENO, (uint64_t)buf, sizeof(buf) - 1);
  if (size <= 0) {
    my_fatal("Failed to read...\n");
  }

  uint32_t result = 0;
  for (int i = 0; buf[i] && buf[i] != '\n'; ++i) {
    char c = buf[i];
    if ('0' <= c && c <= '9') {
      result *= 10;
      result += (c - '0');
    } else {
      my_fatal("Characters should be digits...\n");
    }
  }
  return result;
}

/* An entry point function. */
int _start() {
  my_write(" _         _   _       ____  _           _     ____                        _     _                  \n");
  my_write("| |    ___| |_( )___  / ___|| |__  _   _| |_  |  _ \\  _____      ___ __   | |   (_)_ __  _   ___  __\n");
  my_write("| |   / _ \\ __|// __| \\___ \\| '_ \\| | | | __| | | | |/ _ \\ \\ /\\ / / '_ \\  | |   | | '_ \\| | | \\ \\/ /\n");
  my_write("| |__|  __/ |_  \\__ \\  ___) | | | | |_| | |_  | |_| | (_) \\ V  V /| | | | | |___| | | | | |_| |>  < \n");
  my_write("|_____\\___|\\__| |___/ |____/|_| |_|\\__,_|\\__| |____/ \\___/ \\_/\\_/ |_| |_| |_____|_|_| |_|\\__,_/_/\\_\\\n");

  my_write("Specify arg1, arg2, and arg3 in decimal to be used in the reboot system call to shut down Linux.\n");
  my_write("arg1: ");
  uint32_t arg1 = my_read_uint32();
  my_write("arg2: ");
  uint32_t arg2 = my_read_uint32();
  my_write("arg3: ");
  uint32_t arg3 = my_read_uint32();
  my_write("Running a reboot system call!\n");
  my_syscall_4(SYS_reboot, arg1, arg2, arg3, (uint64_t)"A constant string");
  my_fatal("Failed to shut down. Kernel panic will occur...\n");
}

AAがいいですね。
数字を3つ渡すとrebootのsyscallに渡してくれて、shutdownに成功するとflagがもらえるみたいです。rebootに引数なんてあったかな〜と思いながらまたChromiumのドキュメントを見てみます。chalをfileコマンドしてみたところ、x86-64だと判明したので、またx86-64のテーブルを見てみます。

169	reboot	man/ cs/	0xa9	int magic1	int magic2	unsigned int cmd	void *arg

最後のvoid *argはチャレンジに書かれている"A constant string"ですね。確かにほかにintの引数が3つ必要みたいです。magic1 magic2ってなんだろう〜ということで、「reboot int magic」でググってみたところ、ばにらびいんず(鳥)さんのブログが引っかかりました。
どうやらmagic1は0xfee1dead、magic2は0x28121969ほか3つが指定されているそうです。magic2は、Linuxカーネルの父Linus Torvaldsの誕生日と娘さんたちの誕生日だそう。へえ〜〜
じゃあ次のcmdってなんだ?となります。読んでいると、

    /* Instead of trying to make the power_off code look like
     * halt when pm_power_off is not set do it the easy way.
     */
    if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off())
        cmd = LINUX_REBOOT_CMD_HALT;

となっていました。
これはLINUX_REBOOT_CMD_POWER_OFFが分かればOKということで、検索したところ、linux manualのrebootのページに

      LINUX_REBOOT_CMD_POWER_OFF
              (RB_POWER_OFF, 0x4321fedc; since Linux 2.1.30).  The
              message "Power down." is printed, the system is stopped,
              and all power is removed from the system, if possible.  If
              not preceded by a sync(2), data will be lost.

と記述がありました。
よって、全部10進数に直して(magic2はご本人の誕生日にしました)

4276215469
672274793
1126301404

これでフラグゲット。

rebootに引数があることに気がついていませんでした。安全装置みたいな感じかな。今後linuxトリビアとして披露していきたいですね。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?