天天看點

Writeup-北郵新生賽MRCTF-Web題:套娃

這道題名副其實,果真是套娃,一層一層把我頭都繞暈了

原題位址:https://merak-ctf.site/challenges#%E5%A5%97%E5%A8%83

Writeup-北郵新生賽MRCTF-Web題:套娃

從題目已經看出他的套路了,打開題目位址一看,标準的開場沒有什麼意外

Writeup-北郵新生賽MRCTF-Web題:套娃

右鍵檢視源碼,發現有一段注釋

Writeup-北郵新生賽MRCTF-Web題:套娃

可以觀察出來又是一道if套娃語句,需要一層一層解

同樣先将這段代碼格式化

//1st
$query = $_SERVER['QUERY_STRING'];

 if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
    die('Y0u are So cutE!');
}
 if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
    echo "you are going to the next ~";
}           

複制

首先将

$_SERVER['QUERY_STRING']

的值賦給變量

$query

關于

$_SERVER['QUERY_STRING']

擷取的值:

1,http://localhost/aaa/ (打開aaa中的index.php)

結果:

$_SERVER['QUERY_STRING'] = "";

$_SERVER['REQUEST_URI'] = "/aaa/";

$_SERVER['SCRIPT_NAME'] = "/aaa/index.php";

$_SERVER['PHP_SELF'] = "/aaa/index.php";

2,http://localhost/aaa/?p=222 (附帶查詢)

結果:

$_SERVER['QUERY_STRING'] = "p=222";

$_SERVER['REQUEST_URI'] = "/aaa/?p=222";

$_SERVER['SCRIPT_NAME'] = "/aaa/index.php";

$_SERVER['PHP_SELF'] = "/aaa/index.php";

3,http://localhost/aaa/index.php?p=222&q=333

結果:

$_SERVER['QUERY_STRING'] = "p=222&q=333";

$_SERVER['REQUEST_URI'] = "/aaa/index.php?p=222&q=333";

$_SERVER['SCRIPT_NAME'] = "/aaa/index.php";

$_SERVER['PHP_SELF'] = "/aaa/index.php";

由執行個體可知:

$_SERVER["QUERY_STRING"] 擷取查詢 語句,執行個體中可知,擷取的是?後面的值

$_SERVER["REQUEST_URI"] 擷取 http://localhost 後面的值,包括/

$_SERVER["SCRIPT_NAME"] 擷取目前腳本的路徑,如:index.php

$_SERVER["PHP_SELF"] 目前正在執行腳本的檔案名

此段原文位址:https://www.cnblogs.com/mitang/p/3874291.html

感謝大佬的測試

然後我們再來看第一層判斷條件為

if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 )           

複制

這段代碼表示需要滿足"或"語句

而其中的substr_count函數是用于計算子串在字元串中出現的次數

再看看第二層判斷條件

if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t']))           

複制

我們需要同時滿足兩個條件,其中preg_match函數用于比對正規表達式,這裡需要通過get送出參數b_u_p_t,但是參照第一層提到的substr_count函數,是以get參數不能帶下劃線,這時我們可以用點來代替下劃線,同時用%0a來進行過濾正規表達式的條件,最終get傳遞的參數為?b.u.p.t=23333%0a

Writeup-北郵新生賽MRCTF-Web題:套娃

根據提示進入secrettw.php,仍然是标準套路,提示需要本地才能通路

Writeup-北郵新生賽MRCTF-Web題:套娃

右鍵檢視源碼,發現一大堆注釋,乍一看像亂碼,實際上ctf裡的注釋大家也都知道是怎麼回事,肯定不是毫無意義的,百度一查,發現是一種叫jother的編碼,直接複制粘貼到浏覽器控制台即可解碼

Writeup-北郵新生賽MRCTF-Web題:套娃

執行後彈出了一段alert資訊

Writeup-北郵新生賽MRCTF-Web題:套娃

根據提示用hackbar通過POST送出一個Merak參數

Writeup-北郵新生賽MRCTF-Web題:套娃

傳回了一段代碼,應該是secrettw.php的部分源碼高亮

Writeup-北郵新生賽MRCTF-Web題:套娃

源碼如下

Flag is here~But how to get it? <?php 
error_reporting(0); 
include 'takeip.php';
ini_set('open_basedir','.'); 
include 'flag.php';

if(isset($_POST['Merak'])){ 
    highlight_file(__FILE__); 
    die(); 
} 


function change($v){ 
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission!  Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>            

複制

可以簡單的分析出secrettw.php的作用

首先用if(isset($_POST['Merak']))函數檢測是否存在參數名為Merak的POST資料,如果不存在則執行下面的語句,如果存在則執行if中的highlight_file函數高亮顯示源碼

我們已經通過POST送出Merak知道了源碼,後面就不用再送出POST了,不然會被highlight_file函數截斷,繼續看下面的語句,中間的change函數暫時不管,是轉換字元用的,後面會提到

後面的$ip = getIp();應該是使用了頭部的takeip.php中的函數來擷取用戶端ip,再将擷取到的ip指派給變量$ip

如果滿足$ip!='127.0.0.1'則執行該if内的語句,但是這段語句沒什麼用,是以我們不用管,第二個if内的語句才是我們需要執行的

第二個if的判斷條件為

if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' )           

複制

也就是說需要滿足兩個條件

第一個條件$ip === '127.0.0.1',這個很容易滿足,隻要讓get_ip擷取到的值為127.0.0.1就行了,一般隻有XFF和Client-ip這兩種方法,我們可以用burpsuite來送出

Writeup-北郵新生賽MRCTF-Web題:套娃

第二個條件

file_get_contents($_GET['2333']) === 'todat is a happy day'

首先通過file_get_content函數将整個資料讀入一個字元串中,但是後面的值使用的單引号,并且中間使用===來判斷全等,是以,經過到百度上各種CTF技巧的查找,發現這裡可以使用data:// 來進行轉換,具體用法可以參考:https://www.php.cn/manual/view/285.html

格式為

data://text/plain;base64,

将todat is a happy day進行base64編碼得到dG9kYXQgaXMgYSBoYXBweSBkYXk=,是以需要通過get送出一個名為2333的參數,值為

data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=

第二個if内的語句

echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file']));           

複制

還用到了一個名為file的get參數,用于傳回檔案内容,我們需要知道flag.php的内容,是以這裡需要file_get_content的檔案是flag.php

但是這裡要注意file_get_content函數不是直接使用的

$_GET['file']

的值,而是用到了上面說到的change函數來轉換,我們來看一下change函數的作用

function change($v){ 
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}           

複制

首先定義用法,然後将變量進行base64解碼(這說明後面POST參數file的值必須先進行base64編碼),然後通過一段for循環,這段for循環的作用是先将字元轉換為ASCII碼,再将ASCII碼逐漸+i*2,i初始值為0,然後再轉回字元其中strlen函數作用是計算字元的數目,chr是把ASCII轉成字元,ord是把字元轉成ASCII數字經過對照ASCII碼表和計算,我們需要傳遞到file參數的值為“fj]a&fb(flag.php經過change函數轉換為fj]a&fb)”的base64值,也就是ZmpdYSZmXGI=

順帶一提,takeip.php經過change函數變換,我們需要送出的值為“t_g_af"bXp^”,不過我們用不上,有興趣的可以自己試一試

是以,我們最終送出的兩個get參數為

Writeup-北郵新生賽MRCTF-Web題:套娃

注意别忘了将ip改為127.0.0.1,這裡get_ip用到的方法為Client-ip

Writeup-北郵新生賽MRCTF-Web題:套娃

burpsuite改包放行後傳回頁面,右鍵檢視源碼

Writeup-北郵新生賽MRCTF-Web題:套娃

得到flag:

MRCTF{c323e009-6f72-410a-9dff-96686b411977}