1. 程式人生 > >遇到一個有趣的邏輯漏洞

遇到一個有趣的邏輯漏洞

遇到個有趣的邏輯漏洞,和大家分享一下。 

某系統資料庫是mysql。user表有個code欄位,型別是int(11),這個欄位是儲存一個隨機數,用來找回密碼的時候做驗證,預設值是0。 

找回密碼時候的步驟是,首先填寫自己郵箱,接收重置密碼的郵件,點選連結,訪問如下程式碼: 

if (!empty($_GET['email']) && !empty($_GET['code'])) 
{ 
    if (!$db->count('user',"email='{$_GET['email']}' AND code='{$_GET['code']}'")) 
        die('error'); 
    $_SESSION['email'] = $_GET['email']; 
    ... 
}

在資料庫中查詢email=$_GET['email']並且code=$_GET['code']的行數,如果行數為0則die出去,否則設定$_SESSION['email'] = $_GET['email']; 

最後就以$_SESSION['email']記憶體儲的郵箱重置密碼。 

看似似乎沒問題,只有當email為你的email,並且你知道他的隨機code的時候,才能不die,才能獲得$_SESSION['email']

但關鍵問題就是:code的預設值是0,也就是說所有使用者只要沒有重置過密碼,他的code就是0,所以等於說我知道了所有使用者的code,那我不就可以重置所有使用者的密碼了嗎? 

不不,等下,我們看到這行程式碼: 

if (!empty($_GET['email']) && !empty($_GET['code'])) 

必須要!empty($_GET['code'])的時候,才可能進入這個if語句。熟悉php的人都知道,empty(0)是返回真的。所以說,如果$_GET['code']=0的話,根本進不來這個if語句。 

那怎麼辦? 

又涉及到mysql一個tip,很容易犯錯的點。 

我之前說了,code這個欄位的型別是整型int(11)。而在mysql裡面,當欄位型別為整型,而where語句中的值不為整型的時候,會被轉換成整型才放入查詢。也就是說,如果where code='xxx'

,xxx不為整型的話,則會先將xxx轉換成整數,才放入查詢。 

也就是說,如果我們傳入的字串為0aaa,則會轉換成0,再執行。 

我們可以來做個試驗, 

0015.jpg

上圖大家可以看到,select count(*) from `user` where `id`='0a';select count(*) from `user` where `id`='0';得到的結果都是1。 

所以通過這個tip,就可以繞過if (!empty($_GET['email']) && !empty($_GET['code'])),只要我們傳入的$_GET['code']=0xxx,就可以進入if語句,並且讓select count(*)語句返回1,最後找回任意使用者密碼,不需要爆破。