備忘録なるもの

X-masCTFのWriteUp

こんにちは。グレープ粗茶です。今回は、x-masCTFに参加しました。

[web]Sequel Fun

Sequel Fun 25 Points SOLVED  So I found this login page, but I forgot the credentials :(

Remote server: http://challs.xmas.htsp.ro:11006 Author: Milkdrop

貼り付け元 https://xmas.htsp.ro/challenges?category=web-exploitation

この問題では、まずchromeなどのデベロッパツールからhtmlのソースを閲覧すると、サーバーサイドのソースを見る方法が記されている。

index.php

 <?php
if (isset ($_GET['source'])) {
  show_source ("index.php");
  die ();
}
?>

<head>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="container">

<?php
include ("config.php");
if (isset ($_GET['user']) && isset ($_GET['pass'])) {
  $user = $_GET['user'];
  $pass = $_GET['pass'];
  if (strpos ($user, '1') === false && strpos ($pass, '1') === false) {
    $conn = new mysqli ($servername, $username, $password, $dbname);
    $result = mysqli_query ($conn, "SELECT * FROM users WHERE user='" . $user . "' AND pass='" . $pass . "'", MYSQLI_STORE_RESULT); // TO-DO: Remove elf:elf account

    if ($result === false) {
      echo "<b>Our servers have run into a query error. Please try again later.</b>";
    } else {
      if ($result->num_rows !== 0) {
        $row = mysqli_fetch_array ($result, MYSQLI_ASSOC);

        echo "<h1>You are logged in as: " . $row["user"] . "</h1><br>";

        echo "<b class='flag'>";
        if ($row ["uid"] === "0")
          echo $flag;
        else
          echo "Welcome elf!";
        echo "</b>";

      } else {
        echo "<b>Login fail.</b>";
      }
    }
  } else {
    echo "<b>I don't like the number 1 :(</b>";
  }
} else {
  echo '<form class="center">
    <h1>Santa Login:</h1>
    <label>Username:</label> <input type="text" name="user" autocomplete="off"><br>
    <label>Password:</label> <input type="password" name="pass" autocomplete="off"><br>
    <input type="submit" value="Connect">
  </form>';
}
?>

</div>
<br>

<script src="/js/snow.js"></script>

<!-- ?source=1 -->

</body>

貼り付け元  <http://challs.xmas.htsp.ro:11006/?source

 これらから、SQLを操作しているソースであることが確認でき、sqlinjectionの問題と判断する。

   "SELECT * FROM users WHERE user='" . $user . "' AND pass='" . $pass . "'", 

シングルコーテーションの数が合うように設定すると、ペイロードは、
?user=aa&pass=aa' OR 'a'='a となる。

[web]Roboworld 

Roboworld 50 Points SOLVED  A friend of mine told me about this website where I can find secret cool stuff. He even managed to leak a part of the source code for me, but when I try to login it always fails :(

Can you figure out what's wrong and access the secret files?

Remote server: http://challs.xmas.htsp.ro:11000 Files: leak.py Author: Reda

貼り付け元 https://xmas.htsp.ro/challenges?category=web-exploitation

leak.py

from flask import Flask, render_template, request, session, redirect
import os
import requests
from captcha import verifyCaptchaValue
app = Flask(__name__)
@app.route('/')
def index():
    return render_template("index.html")
@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('user')
    password = request.form.get('pass')
    captchaToken = request.form.get('captcha_verification_value')
privKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" #redacted
    r = requests.get('http://127.0.0.1:{}/captchaVerify?captchaUserValue={}&privateKey={}'.format(str(port), captchaToken, privKey))
    #backdoored ;)))
    if username == "backd00r" and password == "catsrcool" and r.content == b'allow':
        session['logged'] = True
        return redirect('//redacted//')
    else:
        return "login failed"
@app.route('/captchaVerify')
def captchaVerify():
    #only 127.0.0.1 has access
    if request.remote_addr != "127.0.0.1":
        return "Access denied"
token = request.args.get('captchaUserValue')
    privKey = request.args.get('privateKey')
    #TODO: remove debugging privkey for testing: 8EE86735658A9CE426EAF4E26BB0450E from captcha verification system
    if(verifyCaptchaValue(token, privKey)):
        return str("allow")
    else:
        return str("deny")

index.html

<head>
    <script>
        function captchaGenerateVerificationValue()
        {
            //Devnote:
            //Oops I broke the captcha verification function
            //so it will just generate random stuff for the verification value
            //hope no one notices :O

            var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            var charactersLength = characters.length;
            result = ""
            for ( var i = 0; i < 10; i++ ) {
                result += characters.charAt(Math.floor(Math.random() * charactersLength));
            }

            document.getElementById("captcha").value = result
        }
    </script>
</head>

Login:

<form method="post" action="/login">
    Username: <input type="text" name="user" /><br>
    Password: <input type="password" name="pass" /><br>
    Captcha: <input id="captcha" onchange="captchaGenerateVerificationValue()" type="checkbox" name="captcha_verification_value" value="" /> I am not a robot <br>
    <input type="submit" value="Login" /><br>

認証サイトのバイパス方法

leak.pyの認証処理内にはif文が三つあり、これらを抜ける必要がある。

  1. 検索しているとどうやら何をしても127.0.0.1と解釈してしまう事象が発生してしまうようだった。 (※引用) 試しにしたのURLへとアクセスしてみると、'deny'と表示される。 これはleak.py一つ目のif文をすでに通過している事が分かる。 http://challs.xmas.htsp.ro:11000/captchaVerify

  2. Leak.pyに記述されているデバック用のプライベートキーを利用して先ほどのサイトにゲットパラメータとして送信してみる。 http://challs.xmas.htsp.ro:11000/captchaVerify?privateKey=8EE86735658A9CE426EAF4E26BB0450E

すると、'allow'が返ってくる。

解答ペイロード

まずleak.py内で認証サイトにアクセスするのは以下の文となる。

      r = requests.get('http://127.0.0.1:{}/captchaVerify?captchaUserValue={}&privateKey={}'.format(str(port), captchaToken, privKey))

確認としてユーザがブラウザから値を指定できるのはchapchaToken,のみとなる。

つまり、このcapchaToken内に"デバッグ用のprivateKey"を指定してあげればよい。

なので、ブラウザのデベロッパもしくはburp suite,などのプロキシツールを利用して、capchaTokenが代入される"capcha_verification_value"内に攻撃文を入れる。
つまり

     Value="&privateKey=8EE86735658A9CE426EAF4E26BB0450E#"

とすれば、最終的にprivatekeyが理想の場所に入ってくれる。f:id:grapesoda204:20191221205055p:plain 注意点(´;ω;`)

問題を解くことに集中してケアレスミスしないでね(自戒)

上のペイロードと一緒にusernameとpassも指定しないとログインできません。

backdoored ;))) if username == "backd00r" and password == "catsrcool" and r.content == b'allow':

これでログインすると、フラグが記載された動画を閲覧することができます。

一番最初dirbなどで探そうとしたのはダメでした。 ディレクトリ名が"単語_ランダムな文字列"で構成されてました(笑)

以降解けなかった問題

[web]Execute No Evil 50 Points

2 hours, 54 minutes, 56 seconds remaining (1) New Message: "Hey dude. So we have this database system at work and I just found an SQL injection point. I quickly fixed it by commenting out all the user input in the query. Don't worry, I made the query so that it responds with boss's profile, since he is kind of the only person actively using this database system, and he always looks up his own name, lol. Anyway, guess we'll go with this til' the sysadmin comes and fixes the issue."

Huh, so hear no evil, see no evil, ... execute no evil?

Remote server: http://challs.xmas.htsp.ro:11002 Author: Milkdrop

貼り付け元 https://xmas.htsp.ro/challenges?category=web-exploitation

こちらも?Source=1と入力することでソースファイルを閲覧することができた。 しかしながら、getで名前を受け取るもそれをすべてコメントアウトしているという状況であった。 これをどう回避するのか全く分からなかった

(追伸) writeup曰く、mysqlにはコメントを用いてバージョンの場合分けを書けるらしい。

dev.mysql.com

図作成

いままでフローチャートなどを作ったことが無かったので、試しに作ってみました。   www.draw.io