大学の授業で、「暇だったらCTFの問題作って」と言われました。そこで、yum info パッケージ名
などと入力したらパッケージの情報とともにフラッグが表示されるという問題はどうかな?と思いましたので、それを作ってみました。
コードは下記でアップしてますので、ご確認ください。
https://github.com/fum1h1to/ctfYumRPM
構成
今回は画像のように、RPMパッケージをインストールするクライアントコンテナと、Yumリポジトリを持ちRPMパッケージを提供するサーバコンテナをDockerで構築し、クライアント側でyum info -y ctfYumRPM
と入力するとサーバ側からctfYumRPMをインストールできるようにします。
ちなみにパッケージの名前は、ctfYumRPM
となっています。特に理由はありません。
手順
1. RPMパッケージを作成する
RPMパッケージの作成は、後に作るクライアントコンテナ、サーバコンテナとは別の環境で作成しても問題ありません。
自分は、新たにDocker上にcentosの環境を準備しそこでRPMパッケージを作成しました。
$ docker pull centos:centos7
$ docker run -it -d -name centos7 centos:centos7
$ docker exec -it centos7 /bin/bash
なお、RPMパッケージを作成する手順については、下記を参考にさせていただきました。
1. RPMパッケージの作成に必要なツールをインストール
$ yum groupinstall -y 'Development tools'
$ yum install -y rpmdevtools yum-utils
2. RPM作成用の環境を生成
$ rpmdev-setuptree
ホームディレクトリにrpmbuild
というディレクトリができます。
3. SOURCES
ディレクトリにソースコードを入れる
#include <stdio.h>
int main() {
printf("flag{This_is_Fake}\n");
printf("sorry:(\n");
return 0;
}
ctfYumRPM.c
などとして~/rpmbuild/SOURCES
に入れます。
これは、クライアント側で自作パッケージをインストールした後に実行できるようになるプログラムです。
今回は簡単な内容で、fakeのフラッグを出力するようにします。
4. SPECS
フォルダにspecファイルを入れる
specファイルについては詳しく説明しませんが、ここに書く情報が後にyum info ctfYumRPM
とした際に表示されるため、ここに本当のフラッグを書いておきます。
%define name ctfYumRPM
%define version 1.0
%define release 1
Name: %{name}
Version: %{version}
Release: %{release}
Source0: ctfYumRPM.c
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
Summary: Where is flag???
License: flag{This_is_real_flag_Congrats}
%description
Where is flag?????????????????????????????????????
%prep
rm -rf %{buildroot}
%build
gcc /root/rpmbuild/SOURCES/ctfYumRPM.c -o /root/rpmbuild/BUILD/ctfYumRPM
%install
mkdir -p %{buildroot}/usr/bin/
install -m 755 /root/rpmbuild/BUILD/ctfYumRPM %{buildroot}/usr/bin/ctfYumRPM
%clean
rm -rf %{buildroot}
%files
/usr/bin/ctfYumRPM
ctfYumRPM.spec
などとして~/rpmbuild/SPECS
に入れます。
5. パッケージをビルドする
$ rpmbuild -bb ~/rpmbuild/SPECS/ctfYumRPM.spec
6. パッケージに署名する
-
必要なパッケージをインストール
$ yum install -y gpg
-
鍵の生成
$ gpg --gen-key
この際、様々なことを聞かれますが、エンターで大丈夫です。
パスワードについては、拒否するような選択をしても何度も入力しろと言われますが、そのうち諦めてくれます。生成した鍵を確認するときは下記コマンドです。
$ gpg --list-key
-
鍵のexport
$ gpg -export -a '鍵の作成時に指定した本名' > '鍵ファイル名'
自分は、
$ gpg -export -a 'fumihito' > 'ctfYumRPM.pgp'
としました。
-
鍵ファイルをRPMのデータベースに登録する
$ rpm -import '鍵ファイル名'
-
~/.rpmmacros
に内容を追加.rpmmacros%_signature gpg %_gpg_name <鍵の所有者名>
鍵の所有者名は、鍵の作成時に指定した本名の事です。つまり自分の場合、
fumihito
です。 -
RPMファイルに署名をする
$ rpm -addsign ~/rpmbuild/RPMS/x86_64/ctfYumRPM-1.-1.x86_64.rpm
path内の
x86_64
については環境によっては異なる可能性があります。RPMファイルを検証してみましょう。
$ rpm -checksig ~/rpmbuild/RPMS/x86_64/ctfYumRPM-1.0-1.x86_64.rpm /root/rpmbuild/RPMS/x86_64/ctfYumRPM-1.0-1.x86_64.rpm: rsa sha1 (md5) pgp md5 OK
OKと出れば成功です。
以上で、RPMパッケージの作成は終了です。
作成したctfYumRPM-1.0-1.x86_64.rpm
とctfYumRPM.gpg
は後に必要となります。
2. Yumのリポジトリを作成する
作成にあたって、ディレクトリ構造は下記のような形になっています。
│ docker-compose.yml
│
├─client
│ │ dockerfile
│ │
│ └─file
│ ctfYumRPM.gpg
│ fumihito.repo
│
└─server
│ dockerfile
│
└─file
ctfYumRPM-1.0-1.x86_64.rpm
サーバコンテナを用意する
Dockerでサーバを構築します。
今回RPMファイルを転送するためにHTTPを使うため、ApacheでHTTPサーバを用意します。
FROM centos:centos7
RUN yum install -y httpd
RUN yum install -y createrepo
RUN mkdir -p /var/www/html/repos/RPMS
ADD ./server/file/ctfYumRPM-1.0-1.x86_64.rpm /var/www/html/repos/RPMS
RUN createrepo /var/www/html/repos
EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
dockerfileでは、
httpdとcreaterepoをインストール
↓
RPMを格納するディレクトリを作成
↓
ホスト側から用意したRPMパッケージをコンテナ内に取り込む
↓
リポジトリを作成
↓
httpdを起動
という流れを行っています。
これで、自分の作成したRPMパッケージを提供するYumリポジトリを持ったサーバの完成です。
3. クライアント側でインストールできるようにする
クライアントコンテナを作成するわけですが、クライアント側で自作のRPMパッケージをyumでインストールするためには、以下2つを行う必要があります。
- RPMパッケージを作成する際に作った鍵ファイルの登録
-
/etc/yum.repos.d/
配下に自前のYumリポジトリの情報を追加
dockerfileはこのようになりました。
FROM centos:centos7
ADD ./client/file/ctfYumRPM.gpg /root/
ADD ./client/file/fumihito.repo /etc/yum.repos.d/
RUN rpm -import /root/ctfYumRPM.gpg
fumihito.repo
は下記です。
#fumihito's yum repository
[fumihito]
name=fumihito RPM packages
baseurl=http://web:80/repos/
baseurl=http://web:80/repos/
の箇所はDockerでなければ、YumリポジトリがあるサーバのIPアドレスを記入するのですが、今回はDocker上に構成するので、serviceの名前を書いています。
4. docker-compose.yml
の作成
最後にdocker-compose.ymel
を作成してクライアントコンテナとサーバコンテナの起動を楽にします。
version: "3"
services:
web:
tty: true
build:
context: .
dockerfile: ./server/dockerfile
container_name: ctfYumRPM_repo
ports:
- 8080:80
client:
tty: true
build:
context: .
dockerfile: ./client/dockerfile
container_name: ctfYumRPM_client
これで、docker-compose up -d
とコマンドで入力することで、コンテナが起動するようになります。
そして、クライアント側に入り、ctfYumRPM
をインストール出来たら成功です。
$ docker exec -it ctfYumRPM_client
$ yum install -y ctfYumRPM
確認で下記コマンドを打つと、しっかりとfakeのフラッグが出てくるはずです。
$ ctfYumRPM
flag{This_is_Fake}
sorry:(
CTFの答えとなってしまいますが、パッケージの情報を出すと本当のフラッグも出てくるはずです。
$ yum info ctfYumRPM
最後に
CTFの問題としてはすごく簡単な問題ですが、問題の環境を構築するのは大変でした。でも、Dockerってすごく便利ですね。今後も何かCTFの問題を作ってみたいです。
また、RPMやYum、Dockerについて自分の知識が浅い中で作ったので、何かおかしな点がありましたらご指摘していただきたいです。