DVWA详解:AuthorisationBypass 篇(上)
前言:
在"DVWA_2.0.1"版本中,是没有"AuthorisationByPass"这个漏洞项目的,这是之后的版本新增加的;自然的,博主在很多年前玩DVWA时,也就没有攻破这个漏洞;简单的看了一下,说实话,还是挻失望的,没给博主带来什么惊喜;这个漏洞和"JavaScrip"漏洞类似,不同点是,"JavaScrip"漏洞更多的是在说"前端"方面的JS代码安全问题,而"AuthorisationBypass"更多的是从"后端"的角度去分析后端PHP代码中存在的问题~
博主不是很喜欢"AuthorisationBypass"篇的一个原因是,这个DVWA漏洞设计不太完美,解题过程中总感到难度并不是按层次的有序的递增的;不过,也许需要表现"后端在设计API应用程序接口时,由于安全意识不足,造成需管控的信息被绕过授权,被意外获取"这一个话题上,这样的漏洞实现手法,会相对简单一点;
废话也就不多说了,直接进入主题吧~~~
特别提示:如果你在实验过程中,直接复制本博客任意博文中的配置/代码,"空格"字符的前面将可能产生不可见的字符"M-BM-",从而造成文件不可用,这是字符编码的问题~若必需使用复制粘贴方式,请务必手动替换掉配置项中的所有空格!!!或尝试使用以下命令过滤掉所有"M-BM-"字符~
1 2 3 4 |
sed -i 's/\xc2\xa0/ /g' [文件名称] # LINUX下可使用以下命令查看不可见字符的情况 cat -A [文件名称] |
快速跳转:
《 DVWA详解:AuthorisationBypass 篇(下)》
环境需求:
测试需要部署DVWA环境,如果你会DOCKER,可以使用博主提供的文件快速部署一个可用的DVWA环境:下载"DVWA-2.3.tar.gz"压缩包,通过DOCKER-COMPOSE快速部署起DVWA的2.3版本:百度网盘(提取码:7s4q)--> [ 文件名称:DVWA/DVWA-2.3.tar.gz ];
博主在测试"DVWA 2.3"版本的"Authorisation Bypass"漏洞时,发现存在BUG(Github上的最新代码已修复);这个版本有两份文件的"IF条件判断中忘记了写'exit'语句",需要用户自己手动补充一下(见后文说明):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 注:在每次使用"docker-compose down"完全清除容器后,再次运行需要使用"./Readme.sh"文件(有配置文件复制至容器); $ tar -zxf DVWA-2.3.tar.gz $ cd DVWA $ ./Readme.sh # 其它命令 $ docker-compose down # 删除DVWA服务(再次创建服务需要使用"Readme.sh"脚本) $ docker-compose stop # 停止DVWA服务(在不删除DVWA容器时用本命令停止即可) $ docker-compose start # 启动DVWA服务(在不删除DVWA容器时用本命令启动即可) # ================================================================================================= # 其它补充: # 你可能在博文的截图中看到博主使用了"dvwa.domain.local"的域名,这是博主在浏览器的主机上使用了自定义的HOSTS解释; # > LINUX :上,你可以在"/etc/hosts"文件中自定义DNS解释 # > WINDOW :你可以在"c:\windows\system32\drivers\etc\hosts"文件中自定义DNS解释 |
使用博主的代码搭建DVWA环境的大概截图过程如下:
事前分析:
由于DVWA在"AuthorisationBypass"漏洞上设计得不太好,造成博主在写这篇博文时也无法遵从常规的"分析->解题"这样的过程去进行解说;从MEDIUM难度开始,直接没有了所谓的分析手段(使用"gordonb/abc123"的非管理员账户登录),因为从浏览器开发者工具中,压根就没有可用的可分析的东西,一切所谓的解题前提,均是已知;如果从更严格的角度来说,实际上LOW难度已经就是这样了,这也是为什么这段叫"事前分析";
在无法实时分析漏洞的情况下,我们应该如何理解这个漏洞,使其更加的贴近现实中的情况呢?博主在这里给读者模拟这么一个情境,读者可以将这个"AuthorisationBypass"的漏洞页面,当做一个"某个XX管理平台中的一个只能由管理员访问控制的页面"就行了,而这个"XX管理平台"卖给了多个公司,所以其资料也是公开状态;在这样的情境模拟下,下面关于一些解题信息的提前获取,也就变得合理了~
首先,以"admin/password"管理员身份登录DVWA,看一看"AuthorisationBypass"漏洞要我们做什么?"AuthorisationBypass"篇中表明"这个WEB页面被定义为只有管理员身份才可以访问",同时向我们提供了一个"gordonb/abc123"的非管理员账户;也就是说,如果你的身份不是"管理员",那么你不应该"看到或获取到这个页面上的各种数据",同样的"你也不应该能更改这些数据"!!!
从上面的各种提示,我们知道我们需要做的就是:以"gordonb/abc123"身份登录DVWA,如果我们能成功的"获取到这个页面的数据"或"更改到这个页面上的数据",就代表我们成功解题了;
前面的情境模拟说了,我们把"AuthorisationBypass"漏洞的页面当作"某个XX管理平台中的一个只能由管理员访问控制的页面"了,现在,我们以"管理员"的身份,去分析收集一下这个页面的信息吧~~
1、确定页面访问的URL(其实没必要从开发者工具中看,URL一眼便能看出来,从开发者工具中看,是想告诉读者,有其它需要关注的地方);另外,我们发现到该页面引用了一个名为"authbypass.js"的脚本文件,并且在加载完JS脚本后运行了一个"populate_form()"函数(从分析后面"authbypass.js"脚本的代码中,我们可以分析出这个函数用于更新HTML页面中表格的数据):
2、了解"authbypass.js"文件,由于这是"AuthorisationBypass"页面自动调用的JS脚本,我们需要研究这个脚本到底做了一些什么;研究"authbypass.js",我们可以发现两件重要的事:A、"submit_change()"函数,从名字可以看出其作是用于提交数据更新的,从函数的内部代码中,可以发现,其向一个名为"chang_user_details.php"页面发送 POST 请求以实现数据更新;B、名为"populate_form()"函数,结合前面的HTML页面分析,可以知道其用于刷新"AuthorisationBypass"页面中表格的数据的,另外可以发现,这些"数据"是通过向"get_user_data.php"发送 GET 请求获取的;
3、了解"get_user_data.php";可以看出只需要使用 GET 请求访问这个页面,其就会自动返回相关的"数据",而这些"数据"刚好是需要在HTML页面上需要展示的"数据";实际上,对于"get_user_data.php"的PHP源代码,官方应该需要给出的,因为只有这个PHP文件中的内容才可以体现出"MEDIUM"与"HIGH"难度之间的区别,可惜在DVWA的官方提示中,官方只是在注释中提示我们需要关注这个文件的源代码;后面我们需要自己找出这份文件查看PHP的源代码;
4、了解"change_user_details.php";为了在开发者工具中显示出这个页面,我们需要执行一次手动更新操作;可以看出当我们执行更新时,会向"change_user_details.php"发送一个 POST 请求,并以 JSON 格式附带上需要的数据进行更新操作;同样的,对于"change_user_details.php"的PHP源代码,官方应该需要给出而不是"仅仅只在注释中提示",因为只有这个PHP文件中的内容才可以体现出"MEDIUM"与"HIGH"难度之间的区别,后面我们需要自己找出这份文件查看PHP的源代码;
LOW:
现在以非管理员"gordonb/adc123"登录DVWA开始进行解题操作;在LOW难度下,当使用"gordonb"用户登录DVWA时,DVWA会将"Authorisation ByPass"漏洞页面给隐藏了起来,见下对比图:
如果你想知道这个菜单选项是怎么被隐藏起来的,你可以查看DVWA中的"/dvwa/includes/dvwaPage.inc.php"页面源代码(LOW等级的PHP源码中虽然没有有效的代码,但注释中特别重点提示了此文件),你可以发现以下代码,其通过'if (dvwaCurrentUser() == "admin")'代码判断是否显示'Authorisation Bypass'的菜单;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// 文件:dvwa/includes/dvwaPage.inc.php // > 其通过'if (dvwaCurrentUser() == "admin")'代码判断是否 // 显示'Authorisation Bypass'的菜单 // 省略前面的代码内容 ... if( dvwaIsLoggedIn() ) { $menuBlocks[ 'vulnerabilities' ] = array(); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'brute', 'name' => 'Brute Force', 'url' => 'vulnerabilities/brute/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'exec', 'name' => 'Command Injection', 'url' => 'vulnerabilities/exec/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'csrf', 'name' => 'CSRF', 'url' => 'vulnerabilities/csrf/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'fi', 'name' => 'File Inclusion', 'url' => 'vulnerabilities/fi/.?page=include.php' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'upload', 'name' => 'File Upload', 'url' => 'vulnerabilities/upload/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'captcha', 'name' => 'Insecure CAPTCHA', 'url' => 'vulnerabilities/captcha/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'sqli', 'name' => 'SQL Injection', 'url' => 'vulnerabilities/sqli/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'sqli_blind', 'name' => 'SQL Injection (Blind)', 'url' => 'vulnerabilities/sqli_blind/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'weak_id', 'name' => 'Weak Session IDs', 'url' => 'vulnerabilities/weak_id/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_d', 'name' => 'XSS (DOM)', 'url' => 'vulnerabilities/xss_d/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_r', 'name' => 'XSS (Reflected)', 'url' => 'vulnerabilities/xss_r/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'xss_s', 'name' => 'XSS (Stored)', 'url' => 'vulnerabilities/xss_s/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'csp', 'name' => 'CSP Bypass', 'url' => 'vulnerabilities/csp/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'javascript', 'name' => 'JavaScript', 'url' => 'vulnerabilities/javascript/' ); if (dvwaCurrentUser() == "admin") { $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'authbypass', 'name' => 'Authorisation Bypass', 'url' => 'vulnerabilities/authbypass/' ); } $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'open_redirect', 'name' => 'Open HTTP Redirect', 'url' => 'vulnerabilities/open_redirect/' ); $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Cryptography', 'url' => 'vulnerabilities/cryptography/' ); } // 省略后面的代码内容 ... |
在LOW等级下,虽然"Authorisation ByPass"菜单被隐藏了,但我们依然可以尝试通过直接访问"URL"的方式,去尝试访问"Authorisation ByPass"页面;当我们直接在地址栏中直接通过"http://dvwa.domain.local/vulnerabilities/authbypass/"地址进行访问时,我们发现成功访问到了"Authorisation ByPass"页面,查看到当中的"用户数据"并且能够进行"修改操作";然而实际上对于"gordonb"用户来说,这样的操作算是越权了;至此,LOW难度的解题完成;
MEDIUM:
查看MEDIUM等级的PHP源代码,如果此时你点击"Compare All Levels"比较"MEDIUM/HIGH/IMPOSSIBLE"等级中的源代码,你会发现其有效代码都是一样的,那么"MEDIUM/HIGH/IMPOSSIBLE"等级之间的区别是什么?"MEDIUM/HIGH/IMPOSSIBLE"等级之间的区别,重点就在它们相对应的"注释说明"中:
MEDIUM难度提示我们关注"get_user_data.php"与"change_user_details.php"两份文件,见下面代码说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 文件:vulnerabilities/authbypass/source/medium.php <?php // vulnerabilities/authbypass/get_user_data.php // vulnerabilities/authbypass/change_user_details.php // > MEDIUM难度的官方注释中,特别的提示要破解MEDIUM难度,需要关注 // "get_user_data.php"与"change_user_details.php"文件的PHP源代码; // > 两份文件的PHP源代码,官方并没有直接在源码页面上展示,这是不足; // 读者需要自己去相关的目录查看这两份文件的内容; // 下面这段代码,控制了非"admin"用户访问"/vulnerabilities/authbypass/"页面的权限; // 在LOW等级是没有这段代码的,所以LOW等级下非管理员用户也可以访问该页面; if (dvwaCurrentUser() != "admin") { print "Unauthorised"; http_response_code(403); exit; } ?> |
实际上,在MEDIUM难度下,"get_user_data.php"与"change_user_details.php"两份文件对"gordonb"用户来说均有使用权限(检查"权限"的"PHP代码语句"的是两份文件中的"IF条件判断语句");本节只解读"get_user_data.php"的PHP源码,而"change_user_details.php"将留在HIGH难度解读;
以下为"get_user_data.php"的PHP源码解读:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// 文件:vulnerabilities/authbypass/get_user_data.php <?php define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' ); require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php'; dvwaDatabaseConnect(); // 在LOW/MEDIUM等级时("gordonb"登录时) // > ((dvwaSecurityLevelGet() == "high" || dvwaSecurityLevelGet() == "impossible") && dvwaCurrentUser() != "admin") // 的判断结果为"Flase",IF内的代码不会被执行,所以"gordonb"用户在MEDIUN难度可以正常使用这个页面; // // 在HIGH/IMPOSSIBLE等级时("gordonb"登录时) // > ((dvwaSecurityLevelGet() == "high" || dvwaSecurityLevelGet() == "impossible") && dvwaCurrentUser() != "admin") // 的判断结果为"True",IF内的代码会被执行,所以"gordonb"用户无在HIGH难度使用这个页面; // // 任何难度等级时("admin"登录时) // > ((dvwaSecurityLevelGet() == "high" || dvwaSecurityLevelGet() == "impossible") && dvwaCurrentUser() != "admin") // 的判断结果总为"Flase"; // // 注意:"DVWA 2.3"版本的"exit;"语句缺失,需要手动修复(GitHub上最新代码已修复); // 缺失"exit;"语句影响的是"HIGH/IMPOSSIBLE"难度,会使"HIGH/IMPOSSIBLE"难度下本页面的漏洞依然生效; if ((dvwaSecurityLevelGet() == "high" || dvwaSecurityLevelGet() == "impossible") && dvwaCurrentUser() != "admin") { print json_encode (array ("result" => "fail", "error" => "Access denied")); exit; } // 之后的代码是"数据查询"操作了,但要执行这之后的代码,必需先通过前面的权限判断; $query = "SELECT user_id, first_name, last_name FROM users"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); $guestbook = ''; $users = array(); while ($row = mysqli_fetch_row($result) ) { if( dvwaSecurityLevelGet() == 'impossible' ) { $user_id = $row[0]; $first_name = htmlspecialchars( $row[1] ); $surname = htmlspecialchars( $row[2] ); } else { $user_id = $row[0]; $first_name = $row[1]; $surname = $row[2]; } $user = array ( "user_id" => $user_id, "first_name" => $first_name, "surname" => $surname ); $users[] = $user; } print json_encode ($users); exit; ?> |
另外特别提示一下,"DVWA 2.3"版本的"get_user_data.php"的PHP源代码的"IF条件判断语句"缺失了"exit;"语句(GitHub上最新代码已修复),你需要自己手动修复一下这个BUG;缺失"exit;"语句影响的是"HIGH/IMPOSSIBLE"难度,会使"HIGH/IMPOSSIBLE"难度下本页面的漏洞依然生效;
MEDIUM难度下,当们尝试以LOW的方式去攻击,将会得到"Unauthorised"的响应;而此时,假若我们直接在浏览器的地址栏中填写"http://dvwa.domain.local/vulnerabilities/authbypass/get_user_data.php"进行访问;我们可以发现,即使是"gordonb"用户,也能看到本应只能由管理员身份才能访问到的数据("管理员身份验证手段"被绕过了),至此,MEDIUM难度的解题完成了;
当然,此时我们也可以使用"change_user_details.php"页面进行数据更新操作,但这个内容更适合HIGH难度中解读,所以关于数据更新部分解读见HIGH篇~
结:
博主本想一篇博文写完三个难度等级的,但看了一下博文长度,好像太长了,于是,HIGH难度放在了下一篇的博文;见《DVWA详解:AuthorisationBypass 篇(下)》;
DVWA详解:AuthorisationBypass 篇(上):等您坐沙发呢!