首先说明一下,该篇章属于破坏认证以及会话管理,所以我就一起把它归结为访问控制篇了.
一.破坏认证
1.Forgotten Function
源代码如下所示:
<?php
$message = "";
if(isset($_POST["action"]))
{
$email = $_POST["email"];
if(!filter_var($email, FILTER_VALIDATE_EMAIL))//按照指定的过滤器过滤变量,这里的意思应该是输入正确的邮箱格式
{
$message = "<font color=\"red\">Please enter a valid e-mail address!</font>";
}
else
{
$email = mysqli_real_escape_string($link, $email);//防止sql注入
$sql = "SELECT * FROM users WHERE email = '" . $email . "'";
// Debugging
// echo $sql;
$recordset = $link->query($sql);
if(!$recordset)
{
die("Error: " . $link->error);//没查询到该用户,抛出错误
}
// Debugging
// echo "<br />Affected rows: ";
// printf($link->affected_rows);
$row = $recordset->fetch_object();
// If the user is present,如果用户邮箱名存在
if($row)
{
// Debugging
// echo "<br />Row: ";
// print_r($row);
$login = $row->login;//取出用户名
// Security level LOW
// Prints the secret
if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
{
$secret = $row->secret;
$message = "Hello " . ucwords($login) . "! Your secret: <b>" . $secret . "</b>";
//低等级的话直接显示用户名以及密码,ucwords是用于把单词首字母大写显示
}
// Security level MEDIUM
// Mails the secret
if($_COOKIE["security_level"] == "1")
{//中等级的话,就是把密码邮箱发给你,这个就比较常用了
if($smtp_server != "")
{
ini_set( "SMTP", $smtp_server);//先设置smtp服务器
// Debugging
// $debug = "true";
}
$secret = $row->secret;
// Sends a mail to the user
$subject = "bWAPP - Your Secret";
$sender = $smtp_sender;
$content = "Hello " . ucwords($login) . ",\n\n";
$content.= "Your secret: " . $secret . "\n\n";
$content.= "Greets from bWAPP!";
$status = @mail($email, $subject, $content, "From: $sender");
if($status != true)
{
$message = "<font color=\"red\">An e-mail could not be sent...</font>";
// Debugging
// die("Error: mail was NOT send");
// echo "Mail was NOT send";
}
else
{
$message = "<font color=\"green\">An e-mail with your secret has been sent.</font>";
}
}
// Security level HIGH
// Mails a reset code
if($_COOKIE["security_level"] == "2")
{
if($smtp_server != "")
{
ini_set( "SMTP", $smtp_server);
// Debugging
// $debug = "true";
}
// 'Reset code' generation
$reset_code = random_string();
$reset_code = hash("sha1", $reset_code, false);
// Debugging
// echo $reset_code;
// Sends a reset mail to the user
$subject = "bWAPP - Change Your Secret";
$server = $_SERVER["HTTP_HOST"];//修改密码的服务器
$sender = $smtp_sender;
$email_enc = urlencode($email);//email地址做url编码
$content = "Hello " . ucwords($login) . ",\n\n";
$content.= "Click the link to reset and change your secret: http://" . $server . "/bWAPP/secret_change.php?email=" . $email_enc . "&reset_code=" . $reset_code . "\n\n";
$content.= "Greets from bWAPP!";
$status = @mail($email, $subject, $content, "From: $sender");
if($status != true)
{
$message = "<font color=\"red\">An e-mail could not be sent...</font>";
// Debugging
// die("Error: mail was NOT send");
// echo "Mail was NOT send";
}
else//如果重置码成功发送,就直接更新用户重置的重置码
{
$sql = "UPDATE users SET reset_code = '" . $reset_code . "' WHERE email = '" . $email . "'";
// Debugging
// echo $sql;
$recordset = $link->query($sql);
if(!$recordset)
{
die("Error: " . $link->error);
}
// Debugging
// echo "<br />Affected rows: ";
// printf($link->affected_rows);
$message = "<font color=\"green\">An e-mail with a reset code has been sent.</font>";
}
}
}
else//如果用户不存在,执行这里的代码
{
if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
{
$message = "<font color=\"red\">Invalid user!</font>";//低等级,显示用户无效
}
else
{
$message = "<font color=\"green\">An e-mail with a reset code has been sent. Yeah right :)</font>";
//无论输入的邮箱有效还是无效都表示已发送,给攻击者少一点提示
}
}
}
}
?>
上面的代码都做了关键注释了,基本看懂PHP源码就没问题了.
后面上几张结果截图,对应不同的安全等级.
二.Insecure Login Forms
服务端源代码如下所示:
<?php
$bugs = file("bugs.txt");
if(isset($_POST["form_bug"]) && isset($_POST["bug"]))
{
$key = $_POST["bug"];
$bug = explode(",", trim($bugs[$key]));
//trim函数从字符串两端删除字符,explore用于把key对应的bug用逗号打散为两个数组元素
// Debugging
// print_r($bug);
header("Location: " . $bug[1]);//包含进来该文件
exit;
}
if(isset($_POST["form_security_level"]) && isset($_POST["security_level"]))
{
$security_level_cookie = $_POST["security_level"];
switch($security_level_cookie)
{
case "0" :
$security_level_cookie = "0";
break;
case "1" :
$security_level_cookie = "1";
break;
case "2" :
$security_level_cookie = "2";
break;
default :
$security_level_cookie = "0";
break;
}
if($evil_bee == 1)
{
setcookie("security_level", "666", time()+60*60*24*365, "/", "", false, false);
}
else
{
setcookie("security_level", $security_level_cookie, time()+60*60*24*365, "/", "", false, false);
}
header("Location: ba_insecure_login.php");
exit;
}
if(isset($_COOKIE["security_level"]))
{
switch($_COOKIE["security_level"])
{
case "0" :
$security_level = "low";
break;
case "1" :
$security_level = "medium";
break;
case "2" :
$security_level = "high";
break;
case "666" :
$security_level = "666";
break;
default :
$security_level = "low";
break;
}
}
else
{
$security_level = "not set";
}
$message = "";
if(isset($_POST["form"]))
{
if($_POST["login"] == "tonystark" && $_POST["password"] == "I am Iron Man")
{
$message = "<font color=\"green\">Successful login! You really are Iron Man :)</font>";
}
else
{
$message = "<font color=\"red\">Invalid credentials!</font>";
}
}
?>
这代码看完,一阵奇怪,有点蛇精病,和截获的报文完全不搭边.....
不信自己看看....好多该有的字段都没有...
然后就是源代码最后一段给了用户名和密码.....那这道题目的意义在哪里....
看不出意义在哪.....然后我看了一下答案,才知道....
Level Low:
想表达的是敏感信息泄露.....果然平时还是要养成看源代码习惯滴...
Level Medium:
然后调整为中等级,如图
给了用户名,没给密码,源代码查看一波.
点击以后就直接触发该函数,于是搜一波该js函数....
搜出来一大串,上代码块看一下把....
function unlock_secret()//js是从0开始计算起的.....
{
var bWAPP = "bash update killed my shells!"
//这里charat的意义在于取字符串里面第几位的字符出来
var a = bWAPP.charAt(0); var d = bWAPP.charAt(3); var r = bWAPP.charAt(16);
var b = bWAPP.charAt(1); var e = bWAPP.charAt(4); var j = bWAPP.charAt(9);
var c = bWAPP.charAt(2); var f = bWAPP.charAt(5); var g = bWAPP.charAt(4);
var j = bWAPP.charAt(9); var h = bWAPP.charAt(6); var l = bWAPP.charAt(11);
var g = bWAPP.charAt(4); var i = bWAPP.charAt(7); var x = bWAPP.charAt(4);
var l = bWAPP.charAt(11); var p = bWAPP.charAt(23); var m = bWAPP.charAt(4);
var s = bWAPP.charAt(17); var k = bWAPP.charAt(10); var d = bWAPP.charAt(23);
var t = bWAPP.charAt(2); var n = bWAPP.charAt(12); var e = bWAPP.charAt(4);
var a = bWAPP.charAt(1); var o = bWAPP.charAt(13); var f = bWAPP.charAt(5);
var b = bWAPP.charAt(1); var q = bWAPP.charAt(15); var h = bWAPP.charAt(9);
var c = bWAPP.charAt(2); var h = bWAPP.charAt(2); var i = bWAPP.charAt(7);
var j = bWAPP.charAt(5); var i = bWAPP.charAt(7); var y = bWAPP.charAt(22);
var g = bWAPP.charAt(1); var p = bWAPP.charAt(4); var p = bWAPP.charAt(28);
var l = bWAPP.charAt(11); var k = bWAPP.charAt(14);
var q = bWAPP.charAt(12); var n = bWAPP.charAt(12);
var m = bWAPP.charAt(4); var o = bWAPP.charAt(19);
var secret = (d + "" + j + "" + k + "" + q + "" + x + "" + t + "" +o + "" + g + "" + h + "" + d + "" + p);
//拼接出secret,可以看出作者是个美国佬
if(document.forms[0].passphrase.value == secret)
{
// Unlocked,若正确则解锁
location.href="/bWAPP/ba_insecure_login_2.php?secret=" + secret;
}
else
{
// Locked
location.href="/bWAPP/ba_insecure_login_2.php?secret=";
}
}
拼接出来的密码如下所示:
浩克粉碎的意思,应该是美国大片的吧....相比之下个人还是喜欢日剧一点...
hulk smash!,输入进去就成功了..
Level High:
高等级就是服务端进行校验认证了..
// Retrieves the LDAP connection settings
$login = $_SESSION["ldap"]["login"];
$password = $_SESSION["ldap"]["password"];
$server = $_SESSION["ldap"]["server"];
$dn = $_SESSION["ldap"]["dn"];
if(isset($_POST["form"]))
{
if($_POST["login"] == $login && $_POST["password"] == $password)
{
$message = "<font color=\"green\">Successful login!</font>";
}
else
{
$message = "<font color=\"red\">Invalid credentials!</font>";
}
}
这里用了LDAP访问协议.没啥破绽了
三.Logout Management
这道题目直接看代码就好
<a href="ba_logout_1.php" onclick="return confirm('Are you sure?');">here<div></div></a>
可以看到其实他只是点击登录以后就跳转,然后弹窗问你确定吗?问题的关键在于,并没有注销掉cookie,所以后面其实可以再利用cookie的,这样才导致了登录问题.
Level Medium的服务端代码如下:
switch($_COOKIE["security_level"])
{
case "0" :
// Do nothing
break;
case "1" :
// Destroys the session
session_destroy();
break;
}//session_destory()用于注销掉cookie
这样就没啥问题了.
四.Password Attacks
Level Low 的源代码如下:
if(isset($_POST["form"]))
{
if($_POST["login"] == $login && $_POST["password"] == $password)
{
$message = "<font color=\"green\">Successful login!</font>";
}
else
{
$message = "<font color=\"red\">Invalid credentials! Did you forgot your password?</font>";
}
}
这意思就是可以直接爆破了,没啥保护.
Level Medium:
中等级下查看源代码可以看到一些信息.
隐藏了一个盐值salt,所以就没啥了.
Level High:
if(isset($_SESSION["captcha"]) && ($_POST["captcha_user"] == $_SESSION["captcha"]))
用了验证码以及验证码登录一次换一个,不存在空验证码等情况,基本没啥问题了.
五. Weak Passwords
题目服务端的源代码如下:
<?PHP
$message = "";
$login = "test";
switch($_COOKIE["security_level"])
{
case "0" :
$password = "test";
break;
case "1" :
$password = "test123";
break;
case "2" :
$password = "Test123";
break;
default :
$password = "test";
break;
}
?>
好吧,就是考察弱密而已,没有其他了....
六.Administrative Portals
这个是管理门户没做好访问控制泄露了,可以被操纵
Level Low的管理门户进入点在URL中.
http://192.168.1.29/bWAPP/smgmt_admin_portal.php?admin=0
把admin设置为1就好了..
Level Medium的话就是管理门户进入点在cookies中.
操纵cookie就可以了.
七.Session Mgmt. - Cookies (HTTPOnly)
源代码如下所示:
<?PHP
switch($_COOKIE["security_level"])
{
case "0" :
//bool setcookie ( string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] )
//第一个是字符串名,第二个是值,第三个是时间戳(生存时间),第四个是Cookie 有效的服务器路径。 设置成 '/' 时,Cookie 对整个域名 domain 有效,第五个是Cookie 的有效域名/子域名,第六个是设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端,第七个是设置成 TRUE,Cookie 仅可通过 HTTP 协议访问。 这意思就是 Cookie 无法通过类似 JavaScript 这样的脚本语言访问。
// The cookie will be available within the entire domain
setcookie("top_security", "no", time()+3600, "/", "", false, false);
break;
case "1" :
// The cookie will be available within the entire domain
// Sets the Http Only flag
setcookie("top_security", "maybe", time()+3600, "/", "", false, true);
break;
case "2" :
// The cookie will be available within the entire domain
// The cookie expires at end of the session
// Sets the Http Only flag
setcookie("top_security", "yes", time()+300, "/", "", false, true);
break;
default :
// The cookie will be available within the entire domain
setcookie("top_security", "no", time()+3600, "/", "", false, false);
break;
}
?>
这样从源代码可以看出,相对而言中等级设置了httponly字段,高等级还缩减了cookie的生存时间.
低等级结果如下:
八.Session Mgmt. - Cookies (Secure)
服务端源代码如下:
<?PHP
$message = "";
// Deletes the cookies
setcookie("top_security_nossl", "", time()-3600, "/", "", false, false);
setcookie("top_security_ssl", "", time()-3600, "/", "", false, false);
switch($_COOKIE["security_level"])
{
case "0" :
$message.= "<p>Browse to another page to see if the cookies are protected over a non-SSL channel.</p>";
// The cookie will be available within the entire domain
// Sets the Http Only flag
setcookie("top_security", "no", time()+3600, "/", "", false, true);
break;
case "1" :
$message = "<p>This page must be accessed over a SSL channel to fully function!<br />";
$message.= "Browse to another page to see if the cookies are protected over a non-SSL channel.</p>";
// The cookie will be available within the entire domain
// Sets the Http Only flag and the Secure flag
setcookie("top_security", "maybe", time()+3600, "/", "", true, true);
break;
case "2" :
$message = "<p>This page must be accessed over a SSL channel to fully function!<br />";
$message.= "Browse to another page to see if the cookies are protected over a non-SSL channel.</p>";
// The cookie will be available within the entire domain
// The cookie expires at end of the session
// Sets the Http Only flag and the Secure flag
setcookie("top_security", "yes", time()+300, "/", "", true, true);
break;
default :
$message.= "<p>Browse to another page to see if the cookies are protected over a non-SSL channel</p>";
// The cookie will be available within the entire domain
// Sets the Http Only flag
setcookie("top_security", "no", time()+3600, "/", "", false, true);
break;;
}
?>
可以看到低等级只设置了httponly,中等级设置了需要通过https才能设置cookie,高等级则是再缩短了cookie生存期.
九.Session Mgmt. - Session ID in URL
源代码如下:
<?PHP
switch($_COOKIE["security_level"])
{
case "0" :
if(!(isset($_GET["PHPSESSID"])))
{
$session_id = session_id();
header("Location: smgmt_sessionid_url.php?PHPSESSID=". $session_id );
//在url中暴露了sessionid
exit;
}
break;
case "1" :
break;
case "2" :
break;
default :
if(!(isset($_GET["PHPSESSID"])))
{
$session_id = session_id();
header("Location: smgmt_sessionid_url.php?PHPSESSID=". $session_id );
exit;
}
break;
}
?>
低等级如下:
十.Session Mgmt. - Strong Sessions
源代码如下:
$message = "";
// Deletes the cookie
setcookie("top_security", "", time()-3600, "/", "", false, false);
switch($_COOKIE["security_level"])
{
case "0" :
$message = "<p>Click <a href=\"top_security.php\" target=\_blank\>here</a> to access our top security page.</p>";
// Deletes the cookies
setcookie("top_security_nossl", "", time()-3600, "/", "", false, false);
setcookie("top_security_ssl", "", time()-3600, "/", "", false, false);
break;
case "1" :
$message = "<p>Click <a href=\"top_security.php\" target=\_blank\>here</a> to access our top security page.</p>";
// Deletes the cookie
setcookie("top_security_ssl", "", time()-3600, "/", "", false, false);
if(!isset($_POST["form"]))
{
// Generates a non-SSL secured cookie
// Generates a random token
$token = uniqid(mt_rand(0,100000));
$token = hash("sha256", $token);
$_SESSION["top_security_nossl"] = $token;
// The cookie will be available within the entire domain
// Sets the Http Only flag
setcookie("top_security_nossl", $token, time()+3600, "/", "", false, true);
}
break;
case "2" :
$message = "<p>This page must be accessed over a SSL channel to fully function!<br />";
$message.= "Click <a href=\"top_security.php\" target=\_blank\>here</a> to access our top security page.</p>";
// Deletes the cookie
setcookie("top_security_nossl", "", time()-3600, "/", "", false, false);
if(!isset($_POST["form"]))
{
// Generates a non-SSL secured cookie
// Generates a random token
// $token = uniqid(mt_rand(0,100000));
// $token = hash("sha256", $token);
// $_SESSION["top_security_nossl"] = $token;
// The cookie will be available within the entire domain
// Sets the Http Only flag
// setcookie("top_security_nossl", $token, time()+3600, "/", "", false, true);
// Generates a SSL secured cookie
// Generates a random token
$token = uniqid(mt_rand(0,100000));
$token = hash("sha256", $token);
$_SESSION["top_security_ssl"] = $token;
// The cookie will be available within the entire domain
// Sets the Http Only flag and the Secure flag
setcookie("top_security_ssl", $token, time()+3600, "/", "", true, true);
}
break;
default :
$message = "<p>Click <a href=\"top_security.php\" target=\_blank\>here</a> to access our top security page.</p>";
// Deletes the cookies
setcookie("top_security_nossl", "", time()-3600, "/", "", false, false);
setcookie("top_security_ssl", "", time()-3600, "/", "", false, false);
break;
}
?>
看源代码就知道他是在cookie上面生成token作文章,所以比较一下token就可以了这题.
低等级都是直接使用setcookie就完成了,中等级top_security_nossl是自己生成了token,高等级是top_security_ssl自己生成了token.
至此就差不多结束该篇章了....
写点总结...
1.找回密码要采取邮箱点击重置认证的做法,不能直接把密码发回给用户.
2.密码验证必须放在后端,不能明文放在网页源码或者密码生成算法放在网页端.
3.登出必须清理cookie,不能只是简单跳转.
4.密码强度要足够强,不能把加密信息或者salt等放在前端(虽然会减低后端压力).
5.设置足够难度验证码加强密码破解难度.
6.做好管理门户的访问控制,不能由前端控制访问逻辑.
7.cookie要做好强度管理,最好加上httponly以及https下方可生成机制.
8.sessionid不能暴露在url中,防止会话固定攻击.
这里有一个会话固定的文章,整理一下
会话劫持就是偷别人的sessionid,然后自己用该sessionID来登录伪装合法用户.
防御思路就是:
A:更改sessionID的名称,其实就是做点伪装
B:关闭透明化sessionID,就是不要用URL来传递sessionID
C:设置httponly字段
会话固定攻击就是会话劫持的一种,但是相对而言就是除了劫持别人的sessionID之外,还可以是强迫受害者使用攻击者设定的一个有效会话,以此来获得用户的敏感信息.
攻击步骤如下:
1、 攻击者通过某种手段重置目标用户的SessionID,然后监听用户会话状态;
2、 目标用户携带攻击者设定的Session ID登录站点;
3、 攻击者通过Session ID获得合法会话。
防御手段如下:
A:每次用户登录时生成新的Session ID。
如果攻击者使用的会话标识符不是有效的,服务器将会要求用户重新登录。如果攻击者使用的是有效的Session ID,那么还可以通过校验的方式来避免攻击。
B:php.ini中一些设置SESSION安全的参数,session.use_cookies = 1
默认1,代表SessionId通过cookie来传递,否则会用Query_String传递.
整理一张思维导向图
最后最后我噶镇楼,希望技术早日飞升.