https://alpacahack.com/daily/challenges/lets-shut-down-linux

コードの必要部分

chal.c

chal.c:50:69

/* 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;
}

chal.c:80:87

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");

server.py:22:25

print(f"[server.py] {p.returncode = }")
if p.returncode == 0 and b"Power down" in output:
    flag = os.getenv("FLAG", "Alpaca{REDACTED}")
    print(f"[server.py] Linux has been shut down properly! FLAG: {flag}")

:thinking:

上のコードのように Linux に Power down と出力させればよいが、そのためにシステムコールを実行する必要がある。 ところで、my_syscall_4 とほぼ動作が等しい syscall() の引数は以下の通りである。 (my_syscall_4() はアセンブリを用いてそのまま syscall を呼び出す)

int syscall(SYS_reboot, int magic, int magic2, int op, void *arg);

https://man7.org/linux/man-pages/man2/reboot.2.html

である。これを読むと、引数の説明は以下であることがわかる

This system call fails (with the error EINVAL) unless magic equals LINUX_REBOOT_MAGIC1 (that is, 0xfee1dead) and magic2 equals LINUX_REBOOT_MAGIC2 (that is, 0x28121969).

... (中略) ... The op argument can have the following values: 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. (後略) ...

すなわち、 magic = 0xfee1dead かつ magic2 = 0x28121969 であれば再起動が呼び出され、 op = 0x4321fedc であれば Power down と出力されシャットダウンが呼び出されることがわかる。

ところで my_read_uint32() を読むと、なにか頑張って 0 ~ 9 の10進数を uint32_t に変換していることがわかるので、入力は10進数でなければならない。 よって、適当に Windows の電卓の「プログラマー」タブを使うか (ただし、コピーするときは DEC にフォーカスを合わせ Ctrl + C する必要がある)、 単に以下の Python スクリプトの出力をそのまま入れればよい。

Solve

magic = 0xfee1dead
magic2 = 0x28121969
op = 0x4321fedc

print(int(magic))
print(int(magic2))
print(int(op))

以上の結果より、以下を順番に入力すればよい。