picoCTF 2018 – webExploitation 上

題目: Inspect Me

打開網頁檢視原始碼

<!doctype html>
<html>
  <head>
    <title>My First Website :)</title>
    <link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="mycss.css">
    <script type="application/javascript" src="myjs.js"></script>
  </head>

  <body>
    <div class="container">
      <header>
    <h1>My First Website</h1>
      </header>

      <button class="tablink" onclick="openTab('tabintro', this, '#222')" id="defaultOpen">Intro</button>
      <button class="tablink" onclick="openTab('tababout', this, '#222')">About</button>

      <div id="tabintro" class="tabcontent">
    <h3>Intro</h3>
    <p>This is my first website!</p>
      </div>

      <div id="tababout" class="tabcontent">
    <h3>About</h3>
    <p>These are the web skills I've been practicing: <br/>
      HTML <br/>
      CSS <br/>
      JS (JavaScript)
    </p>
    <!-- I learned HTML! Here's part 1/3 of the flag: picoCTF{ur_4_real_1nspe -->
      </div>

    </div>

  </body>
</html>

很快就發現了flag, 不過這邊說只有1/3的flag

檢視網頁碼的時候有看到其它連結, 一一點過去看看

就可以發現另外兩個部份的Flag

I learned HTML! Here’s part 1/3 of the flag: picoCTF{ur_4_real_1nspe

/* I learned CSS! Here’s part 2/3 of the flag: ct0r_g4dget_098df0d0} */

/* I learned JavaScript! Here’s part 3/3 of the flag: */

所以flag就是picoCTF{ur_4_real_1nspect0r_g4dget_098df0d0}

題目: Client Side is Still Bad

進入網站後的畫面長這樣

credentials: 資格;資格證書,資質證明

他要你輸入你的驗證通過

打開原始碼看看

<html>
<head>
<title>Super Secure Log In</title>
</head>
<body bgcolor="#000000">
<!-- standard MD5 implementation -->
<script type="text/javascript" src="md5.js"></script>

<script type="text/javascript">
  function verify() {
    checkpass = document.getElementById("pass").value;
    split = 4;
    if (checkpass.substring(split*7, split*8) == '}') {
      if (checkpass.substring(split*6, split*7) == '0594') {
        if (checkpass.substring(split*5, split*6) == 'd_04') {
         if (checkpass.substring(split*4, split*5) == 's_ba') {
          if (checkpass.substring(split*3, split*4) == 'nt_i') {
            if (checkpass.substring(split*2, split*3) == 'clie') {
              if (checkpass.substring(split, split*2) == 'CTF{') {
                if (checkpass.substring(0,split) == 'pico') {
                  alert("You got the flag!")
                  }
                }
              }

            }
          }
        }
      }
    }
    else {
      alert("Incorrect password");
    }
  }
</script>
<div style="position:relative; padding:5px;top:50px; left:38%; width:350px; height:140px; background-color:red">
<div style="text-align:center">
<p>Welcome to the Secure Login Server.</p>
<p>Please enter your credentials to proceed</p>
<form action="index.html" method="post">
<input type="password" id="pass" size="8" />
<br/>
<input type="submit" value="Log in" onclick="verify(); return false;" />
</form>
</div>
</div>
</body>
</html>

substring用法
stringObject.substring(start,stop)
用來提取字串介於兩個指定index下之間的string

舉個例子

<!DOCTYPE html>
<html>
<body>

<p>Click the button to extract characters from the string.</p>

<button onclick="myFunction()">Try it</button>

<p id="demo"></p>

<script>
function myFunction() {
  var str = "Hello world!";
  var res = str.substring(1, 4);
  document.getElementById("demo").innerHTML = res;
}
</script>

</body>
</html>

以上的程式會顯式ell
因為ell是”Hello world!”中介於(1,4)的字串
注意!!包括 start 處的string,但不包括 stop 處的string

所以我們可以推出密碼就是
picoCTF{client_is_bad_040594}

不過是也沒必要去登入…畢竟都拿到Flag了

題目: Logon

到指定的連結
http://2018shell.picoctf.com:6153/

Hint的部分說沒有check任何人的密碼, 除了admins

實際登入發現
隨便輸入甚麼帳號密碼都可以成功登入
只是沒有flag

可是如果用admin帳號登入
會顯示以下內容

查看一下網頁原始碼

看不出有甚麼問題

在F12的console下
輸入

document.cookie

可以看到登入成功的時候有記錄一個cookie

"_ga=GA1.2.96357746.1553694410; _gid=GA1.2.745085609.1554817848; admin=False; password=111; username=111"

試著把 admin = False改成True
直接輸入

document.cookie = "admin=True"

再按F5重新整理, Flag就出現啦~

網站左上角

可以查看在這網頁用了甚麼cookie

也可以到browser的設定

查看cookies

輸入網域名稱搜尋

也可以用EditThisCookie之類的工具修改cookie
或是用python寫一個程式request並且夾帶cookie,自行設定參數

還有一個地方可以看到cookie
就是按F12後, 到Application
左方會有cookies 可以看到cookie存取的Name跟Value

題目: Irish Name Repo

http://2018shell.picoctf.com:59464/

查看原始碼…

查看到登入的原始碼的時候發現

<!doctype html>
<html>
<head>
    <title>Login</title>
    <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-primary" style="margin-top:50px">
                <div class="panel-heading">
                    <h3 class="panel-title">Log In</h3>
                </div>
                <div class="panel-body">
                    <form action="login.php" method="POST">
                        <fieldset>
                            <div class="form-group">
                                <label for="username">Username:</label>
                                <input type="text" id="username" name="username" class="form-control">
                            </div>
                            <div class="form-group">
                                <label for="password">Password:</label>
                                <div class="controls">
                                    <input type="password" id="password" name="password" class="form-control">
                                </div>
                            </div>
                            <input type="hidden" name="debug" value="0">

                            <div class="form-actions">
                                <input type="submit" value="Login" class="btn btn-primary">
                            </div>
                        </fieldset>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

帳密輸入用input

在support的地方發現有提到SQL

嘗試看看用SQL injection登入

假設網站的登入資料庫查詢代碼如下

SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');

我們只要想辦法使執行代碼變成

"SELECT * FROM users;"

就可以不用帳密也能成功登入

這題輸入
userName輸入”1′ OR 1=1;
passWord輸入”1′ OR 1=1;

就可以讓SQL判別 1=1
always True 這樣就成功登入
取得flag

題目: Mr.Robots

http://2018shell.picoctf.com:10157/

題目是這樣說的:
網站有甚麼地方是網站開發者不想讓你看到的?

robots.txt這個檔案
是一種存放於網站根目錄下的ASCII編碼的文字檔案,
它通常告訴網路搜尋引擎的漫遊器,
此網站中的哪些內容是不應被搜尋引擎的漫遊器取得的。
https://zh.wikipedia.org/wiki/Robots.txt

直接用網址目錄攻擊
更改網址如下

http://2018shell.picoctf.com:10157//robots.txt

發現一個有趣的東西

User-agent: *
Disallow: /143ce.html

貼上url
http://2018shell.picoctf.com:10157/143ce.html
成功拿到flag

題目: No Login

http://2018shell.picoctf.com:52920/

如果點選sign in
顯示還沒開始執行

查看cookies

加入username跟password值等於admin
還有也要加入admin = True

就成功取得flag

題目: Secret Agent

http://2018shell.picoctf.com:3827/

題目說這個網頁還沒完全完成, 不過google可以得到你的info

Hint部分說要怎麼假裝Browser

點Flag得到這樣的回應

意思就是你登入的browser不是他要的那種
You’re not google! Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36

先說一下怎麼看自己請求頭的browser
按F12, Network左方點一個檔案 看右方的下面
這個爬蟲常會用到

查詢google的user agent

知道要改user agent
但其實我也不知道該改那一個
就隨便先選一個

這題的一個解法是用工具Burp suite
https://portswigger.net/burp
官網有免費版可以下載,有簡易功能

Burp Suite的Proxy預設127.0.0.1 port為8080

到browser的設定中

開啟proxy

設定好按確認之後, 重新整理ctf的網頁
可以看到Burp這邊有資訊
將user agent修改成剛剛查到的
按forward送出
請求成功後會得到一個response在broswer
上面就顯示Flag

題目: Buttons

http://2018shell.picoctf.com:44730/
網頁中只有個按鈕

得到一串訊息

FORM DISABLED. THIS INCIDENT HAS BEEN LOGGED AND REPORTED TO /dev/null

Hint部分說兩個按鈕有甚麼不同?

從code來看

<!doctype html>
<html>
<head>
    <title>Buttons!</title>
    <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-primary" style="margin-top:50px">
                <div class="panel-heading">
                    <h3 class="panel-title">BUTTON1</h3>
                </div>
                <div class="panel-body">
                    <form action="button1.php" method="POST">
                        <input type="submit" value="PUSH ME! I am your only hope!"/>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>
<!doctype html>
<html>
<head>
    <title>Buttons!</title>
    <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<div>
    You did it! Try the next button: <a href="button2.php">Button2</a>
</div>
</body>
</html>

看起來…
第一個有用到method=”POST”, 第二個就是網頁連結

<form action="button1.php" method="POST">

<a href="button2.php">Button2</a>

我們看一下第二個按鈕後出現的網頁的網頁code
其中

<form action="button2.php" method="POST">
                        FORM DISABLED. THIS INCIDENT HAS BEEN LOGGED AND REPORTED TO /dev/null                  
</form>
Now the hint was to look at the difference between the two buttons.

1. The first button was form pointing to button1.php with a POST method
2. The second button was a link, meaning clicking it send a GET request
3. In the error page there is a form that points to button2.php with a POST method


This seems to indicate that we should try sending a POST requests to button2.php

看起來是說
button2的php不應該用網頁連結方式要用POST方法

我的做法是在按下第一個按鈕之後的頁面
開啟proxy 一樣是用Burp
重新整理後 burp會收到資訊
查看headers的地方我把button1改成2
再按Forward送出,成功得到回傳的Flag

題目: The Vault

題目說要你想辦法登入
http://2018shell.picoctf.com:53261/

提到登入當然馬上先試試看SQL injection
不過有防禦,所以跳出以下訊息

登入的下方有php code

<?php
  ini_set('error_reporting', E_ALL);
  ini_set('display_errors', 'On');

  include "config.php";
  $con = new SQLite3($database_file);

  $username = $_POST["username"];
  $password = $_POST["password"];
  $debug = $_POST["debug"];
  $query = "SELECT 1 FROM users WHERE name='$username' AND password='$password'";

  if (intval($debug)) {
    echo "<pre>";
    echo "username: ", htmlspecialchars($username), "\n";
    echo "password: ", htmlspecialchars($password), "\n";
    echo "SQL query: ", htmlspecialchars($query), "\n";
    echo "</pre>";
  }

  //validation check
  $pattern ="/.*['\"].*OR.*/i";
  $user_match = preg_match($pattern, $username);
  $password_match = preg_match($pattern, $username);
  if($user_match + $password_match > 0)  {
    echo "<h1>SQLi detected.</h1>";
  }
  else {
    $result = $con->query($query);
    $row = $result->fetchArray();

    if ($row) {
      echo "<h1>Logged in!</h1>";
      echo "<p>Your flag is: $FLAG</p>";
    } else {
      echo "<h1>Login failed.</h1>";
    }
  }

?>

PHP htmlspecialchars 函數的功能是用來轉換 HTML 特殊符號為僅能顯示用的編碼,舉例來說,HTML 的大於(>)小於(<)符號、單引號(’)或雙引號(””)都可以轉換為僅能閱讀的 HTML 符號

接著
注意到有段內容是

  if($user_match + $password_match > 0)  {
    echo "<h1>SQLi detected.</h1>";
  }
  else {
  .....

所以說要讓user_match 跟 password_match 相加小於0

往前看

$pattern ="/.*['\"].*OR.*/i";
$user_match = preg_match($pattern, $username);
$password_match = preg_match($pattern, $username);

本來以為會跟fetchArray()有關之類的…

仔細再看清楚上面的內容

發現user_match跟password_match其實都只有針對username做比對

所以根本就沒有過濾密碼XD

嘗試帳號輸入admin
密碼’ or ‘1’=’1

通過 得到flag

題目: Artisinal Handcrafted HTTP 3

這題要先了解一下關於HTTP protocl
https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview

:::danger
An example HTTP request:

:::

:::danger
An example response:

:::

所以我們知道一個HTTP request 要有下列格式的內容

{METHOD} {PATH} {PROTOCOL_VERSION}
{HEADERS}

{BODY}

solution
https://www.youtube.com/watch?v=Ftnoff0KQSQ

創一個connet.sh檔案

nano connect.sh

:::success
nano是一個字符終端的文本編輯器,有點像DOS下的editor程序。
它比vi /vim要簡單得多,比較適合Linux初學者使用。
某些Linux發行版的默認編輯器就是nano。
:::
nano指令用法可以參考
https://www.vpser.net/manage/nano.html
http://man.linuxde.net/nano
ctrl+O 存檔
ctrl+X 離開

chmod +x connect.sh 

讓檔案可以執行
然後執行檔案連線
:::danger
目前解題困難! nc沒有回應
:::

20191207重新再看這題

curl -A "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36" http://2018shell.picoctf.com:57775 

20201116重新再看 終於可以成功連線XD

nc 2018shell.picoctf.com 57775

詳細看清楚題目

We found a hidden flag server hiding behind a proxy,
but the proxy has some... 
_interesting_ ideas of what qualifies someone to make HTTP requests.  
Looks like you'll have to do this one by hand.  
Try connecting via nc 2018shell.picoctf.com 57775,
and use the proxy to send HTTP requests to `flag.local`.  
We've also recovered a username and a password 
for you to use on the login page:
`realbusinessuser`/`potoooooooo`.

我們可以利用proxy送出請求
連線過去 成功答對問題後 連線沒有斷開
我們可以送出HTTP的請求

可以發現得到回應

透過這個回應資訊我們可以知道裡面有個登入頁面 路徑在/login
所以接著下一個連線我們就連過去

由以下的回應 得知登入頁面的帳號密碼欄位名稱是user跟pass

下一步就是要利用POST發送表單
成功登入後得到了一個set-cookie

下次連線過去 帶著cookie 得到flag

要求我們對flag.local送出請求
並且利用這組帳戶realbusinessuser:potoooooooo

得到一個set-cookies
用來當下次請求的cookie
PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D

GET / HTTP/1.1
Host: flag.local
Cookie: real_business_token=PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D

得到flag
picoCTF{0nLY_Us3_n0N_GmO_xF3r_pR0tOcol5_2e14}

這題很棒 對於學習HTTP 還有了解整個HTTP流程 如何利用手動完成瀏覽器的動作

題目: Flaskcards

發現了一個釣魚網站可能有點問題,請看看這個網站

釣魚網站連結: http://2018shell.picoctf.com:23547/

Hints部分
(1)檢查看是否有任何基本的backend vulnerabilities
(2)filtering doesn’t get applied?
(2)Database會reverted每兩小時

write-up
https://kawing-ho.github.io/2018/picoctf18-flaskcards/

:::danger
這題也是真的猜不透這個解題思路…
:::

首先進入網站後有看到可以register跟login

先在有input的地方嘗試使用SQL injection
不過後來發現沒有用

好, 接著我們先註冊一個帳號登入看看
username: username0000
password: password

登入後可以看到有
create card, list cards, admin

在create輸入的內容會顯示在list cards

所以這個功能我們可以嘗試以下兩種攻擊

  • Cross Site Scripting (XSS)
  • Server-Side Template Injection (SSTI)

首先我們使用stored-XSS

沒有跳出任何alert, 所以網站有作xss的防禦

接著嘗試SSTI
https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/

我們輸入{{3*3}} 跟 {{3+3}} , 結果list顯示的是9跟6

表示SSTI攻擊有效

接著輸入conig
可以看到它顯示了詳細內容
裡面也包含了flag

這邊也可以輸入config.items(),

we get a bunch of information about the server,
as well as the ‘SECRET_KEY’, which contains the flag.

題目: fancy-alive-monitoring

連線至 http://2018shell.picoctf.com:43316

有一個應用程式可以輸入IP

可以看一下source code

前端做了一次簡單的IP格式確認 如果正確就發送到後端
後端也做了一次IP檢查 稍微比較複雜一些

IP驗證過了會執行

exec('ping -c 1 '.$ip, $cmd_result);

接著返回結果
hint的第一點說雖然client與server端都有做驗證 可是server端似乎有問題
第二點說你必須在server上的shell監聽

<html>
<head>
    <title>Monitoring Tool</title>
    <script>
    function check(){
        ip = document.getElementById("ip").value;
        chk = ip.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
        if (!chk) {
            alert("Wrong IP format.");
            return false;
        } else {
            document.getElementById("monitor").submit();
        }
    }
    </script>
</head>
<body>
    <h1>Monitoring Tool ver 0.1</h1>
    <form id="monitor" action="index.php" method="post" onsubmit="return false;">
    <p> Input IP address of the target host
    <input id="ip" name="ip" type="text">
    </p>
    <input type="button" value="Go!" onclick="check()">
    </form>
    <hr>

<?php
$ip = $_POST["ip"];
if ($ip) {
    // super fancy regex check!
    if (preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/',$ip)) {
        exec('ping -c 1 '.$ip, $cmd_result);
        foreach($cmd_result as $str){
            if (strpos($str, '100% packet loss') !== false){
                printf("<h3>Target is NOT alive.</h3>");
                break;
            } else if (strpos($str, ', 0% packet loss') !== false){
                printf("<h3>Target is alive.</h3>");
                break;
            }
        }
    } else {
        echo "Wrong IP Format.";
    }
}
?>
<hr>
<a href="index.txt">index.php source code</a>
</body>
</html>

我們先來了解一下server端坐的regex

/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/
^是開頭
[1-9] 表示這個字源符合1-9之間任意 
?在[1-9]跟[0-9]之間
表示中間這個不管 隨便甚麼都行
[0-9]|1 這個|表示or

因為語法太多 需要考慮優先權
因為 | 是最低 所以我們要最後看

所以前面的我們可以這樣看
^((A | B | C | D ).)
符合ABCD四個其中一個的都可以

其實最後問題點就是少了一個$而已
所以沒有規定結尾要以甚麼結束
我們可以在match完IP之後 
輸入shell command

取得flag
picoCTF{n3v3r_trust_a_b0x_c4a9b715}

發佈留言

Close Menu