総関西サイバーセキュリティLT大会(第43回)のハンズオン環境のメモ
ハンズオンで作った構成について
2024年8月17日(土)に開催されました 総関西サイバーセキュリティLT大会(第43回)でハンズオン環境のインフラ構築を行いましたので、その時に作った構成などをメモしておきます。(私は、講師ではなくて環境構築担当です!)
ハンズオンの後半の演習では、障害を発生させてハンズオン参加者に障害発生時の体験や、基礎的なWindowsコマンドを使って簡単に障害調査をやるような形式です。
これだけだと少し寂しいので、社内ネットワークのような環境でWebサービスをいくつか動かしておき、正常時はこれらが参照できる。というのを前提としました。
スイッチとかルータの構成
全体の雰囲気イメージ図

- 有線LANで接続できるためのL2スイッチ(Fujitsu SR-S318TL2)
- ゲートウェイを作るためのルータ(Cisco891FJ#1)
- 経路を切替してみて違いを見てもらうための経路ルータ(Cisco4221#1,Cisco1812J#1)
- サーバを収容するためのルータ(Cisco891FJ#2)
- ルータ間の制御は、ダイナミックルーティング(OSPF)で制御。
詳細の構成図(論理・物理・Zone)

KVMホスト+テザリングに接続するルータ
- 機器:HP Z240 SFF + 拡張ネットワークカード(1G×2本) + Wi-Fiアダプタ(USB)
- OS:ubuntu24.04
- KVMで仮想マシンをいくつか動作させる。
- ufwでNAT(IPマスカレード)してWi-Fi経由でインターネット接続する環境
DNSサーバ兼WEBサーバ(仮想マシン#1)
DBサーバ(仮想マシン#2)
- OS:ubuntu24.04
- Webサーバでで稼働するアプリのDBを動作
- Todoページ,トラフィック可視化サーバのDBを作成
ネットワーク遅延用サーバ(仮想マシン#3)
- OS:ubuntu24.04
- KVMホストの拡張NIC2本をブリッジでつなぎ、遅延を発生させる。
その他のメモ
環境構築で初なこと
- unbound使って内部用の権威DNSを立てる。
- pythonでflaskっていうフレームワークを使ってみた。参考URLのサンプルをほぼそのまま使わせてもらいました!勉強になりました。
- uWSGIを使う(nginxからアプリにソケット渡しするみたいなやつ?)
ハンズオンとして気をつけたこと
- DNSの設定でサーバの名前のTTLを60秒とした。(クライアントのキャッシュを早めにクリアさせたい)
- ルータ、L2スイッチについては、管理アクアスを特定IPからのみとした。(念のため)
- Linuxについても一部ufwなどでアクセス制限を実施した。(念のため)
ハンズオンで参加者が困ってた?こと
- Windows11のコンパネではない方のIP設定で、DNS指定なしだと設定がOKできないっぽい?
ハンズオン中に補助していたこと。
- ルータのARPテーブルを見て、固定IP設定ができてそうかを確認した。
- ProxyDNSのARPテーブルを見て、DNS設定をやれてそうかを確認した。
- 192.168.1.32 のARPが見えない→チームCの参加者2番目の人のPC設定が正しくないのでは?
もうちょっとやれたかも?と思ったこと。
- せっかくの物理環境でルータなどが動作している感じをわかるように、LEDとか見えるような置き方にすべきだったかも。(動いている感が大事!)
- とある障害発生時のL2SWの各ポートのトラフィックの推移を見せられたらよかったかも。
- Wi-Fi環境もあってもよかったかも。(運営用や演習前の資料配布などの用途)
参考URL
- Server World - KVM 他
- flask-todo-example ※ sqlite3をmysqlとしてほぼ流用させて頂きました。
- FlaskとMYSQLとSQLite3について
- Nginx+uWSGI+Flask+Ubuntuで作る本格サーバー(実装編)
- Network エミュレーション
- cacti
- 阿部寛 ※参考とさせて頂きました。
機材類
- 逸般の誤家庭(ライト勢)の機器を持ち込みました。

機材類
Writeup memo Pretty Raw (Forensics150) [SharifCTF 7]
SharifCTF 7の Pretty Raw (Forensics150) のWriteupメモ
- 問題文
Pretty Raw
What is this file?
http://ctf.sharif.edu/ctf7/api/download/17
- ファイルを確認
$ file pretty_raw pretty_raw: data
$ strings pretty_raw
---------------------------
IHDR
PLTELiq
1yy>
(略)
)+0IDBVG?KMQSajO{
IDATx
8/Sd
(略)
\70S
0r\o
IEND
---------------------------
IHDRとかIDATとかIENDとかあるのでPNGファイルが隠れているものと想定。
- binwalkで確認。
$ binwalk pretty_raw DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 116254 0x1C61E PNG image, 1434 x 1060, 8-bit colormap, non-interlaced
- foremostでファイルを抜き出し。
$ foremost pretty_raw Processing: pretty_raw |*|
output ディレクトリにファイルが生成される。
$ find output/ output/ output/audit.txt output/png output/png/00000227.png
⇒PNGファイル抜き出し。
- ファイルを見てみる。

flag.pngをexiftoolで見た結果の画像ファイル?
1570×74ピクセルのflag.pngというのがflagらしい。横長い画像。
foremostで出てきたPNGファイルがflagというわけではない。
- 問題ファイル「pretty_raw」をバイナリエディタで眺める。

下の方のノイジーなのが、PNGファイルで、上の方は黒(00)が多い。 何かしら前半のデータから、画像を生成するものと想定する。
- hexdumpで眺める。
$ hexdump -v pretty_raw 0000000 0000 0000 0000 0000 0000 0000 0000 0000 0000010 0000 0000 0000 0000 0000 0000 0000 0000 0000020 0000 0000 0000 0000 0000 0000 0000 0000 0000030 0000 0000 0000 0000 0000 0000 0000 0000 0000040 0000 0000 0000 0000 0000 0000 0000 0000 (略) 0002570 0000 0000 0000 0000 0000 0000 061b 1e1e 0002580 1e1e 141e 0000 0000 0000 0000 0000 0000 0002590 0000 0000 0000 0000 0000 1d08 1e06 1e1e 00025a0 1e1e 1e1e 1e1e 1e1e 0001 0000 0000 0000 00025b0 0000 0000 0000 0000 0000 0700 0302 1e09 (略)
なんとなく画像に見えてきたので(?)、PNGファイルのあった 116254 より前を切り出し。
$ dd if=pretty_raw count=116253 bs=1 of=pretty_raw_first.bin 116253+0 レコード入力 116253+0 レコード出力 116253 bytes (116 kB, 114 KiB) copied, 0.217263 s, 535 kB/s
- 文字数をカウント
hexdumpの出力結果のアドレス部・空白・改行を除いてカウント。
hexdump -v pretty_raw_first.bin | cut -c8- | tr -d '\n' | tr -d ' ' | wc
0 1 232508
⇒ 232508文字
$ python >>> 232508/74 3142 >>> 3142/2 1571 >>>
3140×74 (1570×2×74)となりそう。2文字=1ピクセルの画像。
- 3140行毎に改行入れたテキストの出力
hexdump -v pretty_raw_first.bin | cut -c8- | tr -d '\n' | tr -d ' ' | nkf -f3140-0 > flag.txt
テキストエディタで、flag.txt を見てみる。

(長い)
- ImageMagickでテキスト(flag.txt)を画像(flag.png)に画像にしてみる。
$ convert -pointsize 2 label:@flag.txt flag.png
※ ImageMagickの/etc/ImageMagick-6/policy.xmlで一時的に@を許可して実行しています。
$ cat -n /etc/ImageMagick-6/policy.xml
----------------------------------------------------------------------
68 <!-- policy domain="path" rights="none" pattern="@*" />
----------------------------------------------------------------------

- flag
SharifCTF{100ae53903cbb68ab523c8e858034988}
Writeup memo Memory Analysis (Forensics100) [SECCON 2016 Online CTF]
SECCON 2016 Online CTF の Forensics100点の「Memory Analysis」のWriteupメモ score-quals.seccon.jp
*問題文
Memory Analysis Find the website that the fake svchost is accessing. You can get the flag if you access the website!! memoryanalysis.zip (http://files.quals.seccon.jp/memoryanalysis.zip) The challenge files are huge, please download it first. Hint1: http://www.volatilityfoundation.org/ Hint2: Check the hosts file password: fjliejflsjiejlsiejee33cnc
メモリ解析をやりましょうという問題。
- メモリダンプのイメージ情報を出力
volatility.exe imageinfo -f forensic_100.raw ----------------------------------------------------------------------------------------------------------- Volatility Foundation Volatility Framework 2.5 INFO : volatility.debug : Determining profile based on KDBG search... Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86) AS Layer1 : IA32PagedMemoryPae (Kernel AS) AS Layer2 : FileAddressSpace (D:\hogehoge\memoryanalysis\forensic_100.raw) PAE type : PAE DTB : 0x34c000L KDBG : 0x80545ce0L Number of Processors : 1 Image Type (Service Pack) : 3 KPCR for CPU 0 : 0xffdff000L KUSER_SHARED_DATA : 0xffdf0000L Image date and time : 2016-12-06 05:28:47 UTC+0000 Image local date and time : 2016-12-06 14:28:47 +0900 -----------------------------------------------------------------------------------------------------------
⇒ 「WinXPSP2x86」or 「WinXPSP3x86」らしい。
- ヒントにあるhostsファイルの格納位置を調査
volatility.exe --profile=WinXPSP3x86 -f forensic_100.raw filescan ----------------------------------------------------------------------------------------------------------- (略) 0x000000000217b748 1 0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts (略) -----------------------------------------------------------------------------------------------------------
- ファイルを指定して出力
volatility.exe --profile=WinXPSP3x86 -f forensic_100.raw dumpfiles -Q 0x000000000217b748 --name -D .\ ----------------------------------------------------------------------------------------------------------- => file.None.0x819a3008.hosts.dat -----------------------------------------------------------------------------------------------------------
- hostsファイルの中身を確認
type file.None.0x819a3008.hosts.dat
-----------------------------------------------------------------------------------------------------------
(略)
127.0.0.1 localhost
153.127.200.178 crattack.tistory.com
-----------------------------------------------------------------------------------------------------------
- IEのヒストリでそれらしいサイトを確認
volatility.exe -f forensic_100.raw --profile=WinXPSP2x86 iehistory ----------------------------------------------------------------------------------------------------------- (略) Process: 380 IEXPLORE.EXE Cache type "URL " at 0x76be00 Record length: 0x180 Location: http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd Last modified: 2016-12-06 03:39:11 UTC+0000 Last accessed: 2016-12-06 05:28:40 UTC+0000 File Offset: 0x180, Data Offset: 0xac, Data Length: 0xd0 File: Data-Science-import-pandas-as-pd[1] Data: HTTP/1.1 200 OK Content-Type: application/octet-stream Content-Length: 42 ETag: "584632df-2a" ~U:system (略) -----------------------------------------------------------------------------------------------------------
- 上記URLをIP指定でアクセス
curl -H "Host:crattack.tistory.com" "http://153.127.200.178/entry/Data-Science-import-pandas-as-pd"
-----------------------------------------------------------------------------------------------------------
SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}
-----------------------------------------------------------------------------------------------------------
タイムライン整理していろいろ眺めるともっと面白い何かもあるのかも。
サービス監視用スクリプト(bash,やっつけ)
やっつけなので注意☆
基本的な考え方
- 監視スクリプト本体 : check-XXXX.sh
- 監視対象のリストファイル : list-XXX.txt
- 監視スクリプトから利用されるコマンドファイル : cmd-XXXX.txt
- 動作ディレクトリ : /usr/local/tools/monitor
- ログ保存ディレクトリ : /usr/local/tools/monitor/logs
- テンポラリファイル : /tmp/XXXX-ng.txt
想定環境
CentOS6系
check ping
check-ping.sh
#!/bin/bash # # check ping script. # ver 0.1 2016/05/28 # export LANG=C CHECK=ping DIR=/usr/local/tools/monitor LOG=/usr/local/tools/monitor/logs/${CHECL}.log LIST=/usr/local/tools/monitor/list-${CHECK}.txt TEMP=/tmp/ping-ng.txt MAIL_TO=user1@sXX.hogehoge.local cat ${LIST}| while read DEST do ping -c 2 -w 2 ${DEST} > /dev/null if [ $? == 0 ] ; then echo `date +%F' '%X` "${DEST} ${CHECK} : OK" >> ${LOG} else echo `date +%F' '%X` "${DEST} ${CHECK} : NG" > ${TEMP} cat ${TEMP} >> ${LOG} cat ${TEMP} | mail -s "alert [${DEST}] ${CHECK} NG!" ${MAIL_TO} fi done
list-ping.txt
192.168.1.1 192.168.1.2 192.168.1.3
check web
check-web.sh
#!/bin/bash # # check web script. # ver 0.1 2016/05/28 export LANG=C CHECK=web #PORT=80 DIR=/usr/local/tools/monitor LOG=${DIR}/logs/${CHECK}.log LIST=${DIR}/list-${CHECK}.txt REMOTE_CMD=${DIR}/cmd-${CHECK}.txt TEMP=/tmp/${CHECK}-ng.txt MAIL_TO=user1@sXX.hogehoge.local cat ${LIST}| while read DEST do SITE=`echo ${DEST}| awk -F"/" '{print $3}'` curl -f ${DEST} > /dev/null 2>&1 if [ $? == 0 ] ; then echo `date +%F' '%X` "${DEST} ${CHECK} : OK" >> ${LOG} else echo `date +%F' '%X` "${DEST} ${CHECK} : NG" > ${TEMP} cat ${TEMP} >> ${LOG} cat ${TEMP} | mail -s "alert [${SITE}] ${CHECK} NG!" ${MAIL_TO} fi done
list-web.txt
http://www1.sXX.hogehoge.local/ http://www2.sXX.hogehoge.local/
check smtp
check-smtp.sh
#!/bin/bash +x # check smtp script. # ver 0.1 2016/05/28 export LANG=C CHECK=smtp PORT=25 DIR=/usr/local/tools/monitor LOG=${DIR}/logs/${CHECK}.log LIST=${DIR}/list-${CHECK}.txt REMOTE_CMD=${DIR}/cmd-${CHECK}.txt TEMP=/tmp/${CHECK}-ng.txt RESULT="221 2.0.0 Bye" MAIL_TO=user1@sXX.hogehoge.local cat ${LIST}| while read DEST do cat ${REMOTE_CMD} | nc ${DEST} ${PORT} | tail -1 | grep "${RESULT}" > /dev/null 2>&1 if [ $? == 0 ] ; then echo `date +%F' '%X` "${DEST} ${CHECK} : OK" >> ${LOG} else echo `date +%F' '%X` "${DEST} ${CHECK} : NG" > ${TEMP} cat ${TEMP} >> ${LOG} cat ${TEMP} | mail -s "alert [${DEST}] ${CHECK} NG!" ${MAIL_TO} fi done
list-smtp.txt
192.168.1.3
cmd-smtp.txt
ehlo test quit
2016年06月 Hardening Project 2016 / Hardening 100 Value x Value 参加した。
2016年06月某日。とあるチームで参加。
内容は下記。
特徴
与えられた競技環境である、ECサイトと関連するシステムを守り切り、売り上げの最大化を目指す。
採点について、今回の大会では下記のようなパラメータにて各チームが評価された。
・見込み販売力 (Sales Potential)
・技術点 (Technical Merit)
・顧客点 (Customer Impression)
・対応点 (Incident Response)
・経済点 (Market Creation)
・協調点 (Information Sharing)
各チームのスコア(結果)は、下記より参照できる。
ルール上ではまり易い点
前日に配布された資料の十分な読み込みが必要。
競技後の評価や不慮の事故や調査等で運営者から利用されるアカウントのについては、下記のようなルールがある。
・該当アカウントでのログオン可能にしておくこと
・該当アカウントでのsshを許可しておくこと (※)
・該当アカウントの sudo の設定値を変更しないこと。
・パスワードを変えないこと(sshのキーでログインしているっぽいので関係ないかも。)
※ sshを許可しておくこと = 最終的に競技環境のどこかしらから運営者がsshでログオンするため、その経路をFirewall等で止めてしまうとNG。
外部向けのFirewallの設定では、競技環境のDMZのサーバがすべて1:1のStaticNATで外部に公開されている。一般的に考えると、公開サイトは、NAT公開されてて良いとは思うが、dbやlogを管理するサーバ、proxyなどは、NAT公開が必須ではないし、外部への不要な通信(例えば、C&Cサイトへアクセスしてしまうなど)を排除すべく外部へのNAT公開や、IPマスカレードでの外向けアクセスを停止する方が本来は正しいとは思う。
仮想基盤特有の留意点
競技者達は、StarBED内に構築された、仮想のネットワーク環境、仮想マシンで競技します。それらは、各チーム毎にそれぞれに比較的フェアな条件で構築されており、それなりのスペックの仮想マシンが動作している。しかしながら、ディスク構成としては、チーム内の仮想化マシン間でシェアしているため、特定の仮想マシンのIO負荷が上がってしまうと、同じディスク(同じRAID Group)に属している別の仮想マシンのIOに影響が出てしまう。
例えば、webサーバでディスクにランダムアクセスが集中しているような場合に、同じRAID Groupにある、dbサーバのIOパフォーマンスが出ないといったことが発生する。
同一RAID GROUP内の仮想マシン達でIO負荷が集中するような処理をcronで回す場合には、処理時間をずらすなどの考慮が必要となるのかもしれない。
運用監視
サイトの監視を行い、改ざんされたり、サイトが停止していたりすることを把握する必要がある。サービス監視、プロセス監視などが必要となる。
8時間という限られた時間である点と、発生するインシデントが頻繁に襲ってくるような競技の特性があるため、サポート端末(Windows)のブラウザより、F5でのサイト監視が最も有効な説有。tail -f とかで 各サービスのログを監視しておけば、それでもわかるのかも。
もしかしたら、ChromeのAuto Refresh プラグインを動かして監視とかがいいのかも。
尚、競技用に作成したが、それほど役に立たなかった監視ツールを一応置いておく。
dnsが死んだ場合には、postfixの設定次第で、メールの送信ができないケースもあると思われるため注意が必要。/etc/postfix/main.cf の設定で、MTAに向ける設定がIP指定か、ホスト指定か、それともMXで動くのかなどにより監視サーバのメールの設定周りにも注意が必要。
改ざん検知
aideを使った。CentOS6.x でrpmで入れられてサクッと動かせるので便利。
一般的な運用とは異なり、頻繁にチェックが必要となると思われる。チームでは30分単位で動作。
8時間という競技上、改ざんを本当に確認すべきか、さっさとバックアップからコンテンツを戻す方が早いのかが結構悩ましいところではある。
各サーバからメールで通知する場合、DNSが死ぬと役に立たないケースがあるので、postfixの設定なども気を付けた方が良い。
pcap のノード毎振り分け
環境
virtualbox / ubuntu1604LTS / mem 4GB / 2cores
tshark version 2以降
前提
/NFS/work/pcap 配下にpcapファイルがたくさんある
ipv6非対応
RAMDISK作成
sudo vi /etc/fstab
tmpfs /ramdisk tmpfs rw,size=1G,x-gvfs-show 0 0
NFS上のpcapファイルを各ノード(Endpoint)で別ファイルに分割
(テンポラリとしてRAMDISK利用)
touch ~/bin/capbynode.sh chmod +x ~/bin/capbynode.sh
vi ~/bin/capbynode.sh
#!/bin/bash # ./capbynode.sh # for tshark ver2 INPUTDIR=/NFS/work/pcap OUTDIR=/NFS/work/pcap/nodes RAMDISK=/ramdisk LIST_PCAP=${RAMDISK}/list_pcap.txt LIST_ENDPOINTS=${RAMDISK}/list_endpoints.txt # output pcap file list ls -1tr ${INPUTDIR}/*.pcap > ${LIST_PCAP} cat ${LIST_PCAP} | while read FILE_PCAP do # clear RAMDISK pcap file rm -f ${RAMDISK}/*pcap # copy from INPUTDIR to RAMDISK echo "---- FILE_PCAP = ${FILE_PCAP} ----" cp -v ${FILE_PCAP} ${RAMDISK}/ cd ${RAMDISK} INPUT_FILE=`ls -1tr *pcap | tail -1` # output endpoints echo "`date -R` : output endpoints start FILE=${INPUT_FILE}" tshark -r ${INPUT_FILE} -q -z endpoints,ipv4 | grep ^[0-9] | awk '{print $1}' > ${LIST_ENDPOINTS} echo "`date -R` : output endpoints complete FILE=${INPUT_FILE}" echo "${LIST_ENDPOINTS} : `cat ${LIST_ENDPOINTS} | wc -l` lines" cat ${LIST_ENDPOINTS} | while read IPADDR do echo "`date -R` : input_file = ${INPUTFILE} ,ipaddr = ${IPADDR} ###" tcpdump -r ${INPUT_FILE} -w ${OUTDIR}/${INPUT_FILE}_${IPADDR}.pcap host ${IPADDR} > /dev/null 2>&1 done done
NFS上の各ノード毎のpcapファイルから任意のアドレスのpcapをマージ
touch ~/bin/merge-nodes.sh chmod +x ~/bin/merge-nodes.sh
vi ~/bin/merge-nodes.sh
#!/bin/bash # mergecap by nodes # merge-nodes.sh [ip-address] INPUTDIR="/NFS/work/pcap/nodes" IPADDR=$1 INFILES=`ls -1tr ${INPUTDIR}/*_${IPADDR}.pcap | tr -s '\n' ' '` mergecap -w ./merge_${IPADDR}.pcap ${INFILES}


