Training: Register Globals (Exploit, PHP, Training)
题目描述
This challenge is a relict of old PHP times, where register globals has been enabled by default, which often lead to security issues.
Again, your job is to login as admin, and you are given the sourcecode as well as highlighted version.Here is the link to the vulnerable script.
I have also setup a test account: test:testEnjoy!
这个问题是旧时代PHP遗留下来的,在PHP时代默认启用了注册全局变量,这通常会导致安全问题。
同样,您的工作是以管理员身份登录,您将获得源代码和高亮显示的版本。
下面是漏洞脚本的链接。
我还设置了一个测试帐户:test:test
享受吧!
解
查看php源码
<?php
chdir('../../../../');
define('GWF_PAGE_TITLE', 'Training: Register Globals');
require_once('challenge/html_head.php');
if (false === ($chall = WC_Challenge::getByTitle(GWF_PAGE_TITLE))) {
$chall = WC_Challenge::dummyChallenge(GWF_PAGE_TITLE, 2, 'challenge/training/php/globals/index.php');
}
$chall->showHeader();
GWF_Debug::setDieOnError(false);
GWF_Debug::setMailOnError(false);
# EMULATE REGISTER GLOBALS = ON
foreach ($_GET as $k => $v) { $$k = $v; }
# Send request?
if (isset($_POST['password']) && isset($_POST['username']) && is_string($_POST['password']) && is_string($_POST['username']) )
{
$uname = GDO::escape($_POST['username']);
$pass = md5($_POST['password']);
$query = "SELECT level FROM ".GWF_TABLE_PREFIX."wc_chall_reg_glob WHERE username='$uname' AND password='$pass'";
$db = gdo_db();
if (false === ($row = $db->queryFirst($query))) {
echo GWF_HTML::error('Register Globals', $chall->lang('err_failed'));
} else {
# Login success
$login = array($_POST['username'], (int)$row['level']);
}
}
if (isset($login))
{
echo GWF_HTML::message('Register Globals', $chall->lang('msg_welcome_back', array(htmlspecialchars($login[0]), htmlspecialchars($login[1]))));
if (strtolower($login[0]) === 'admin') {
$chall->onChallengeSolved(GWF_Session::getUserID());
}
}
else
{
?>
<form action="globals.php" method="post">
<table>
<tr>
<td><?php echo $chall->lang('th_username'); ?>:</td>
<td><input type="text" name="username" value="" /></td>
</tr>
<tr>
<td><?php echo $chall->lang('th_password'); ?>:</td>
<td><input type="password" name="password" value="" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="send" value="<?php echo $chall->lang('btn_send'); ?>" /></td>
</tr>
</table>
</form>
<?php
}
# EMULATE REGISTER GLOBALS = OFF
foreach ($_GET as $k => $v) { unset($$k); }
require_once 'challenge/html_foot.php';
?>
在第13-14行,有关键代码,可以修改全局变量
# EMULATE REGISTER GLOBALS = ON
foreach ($_GET as $k => $v) { $$k = $v; }
通过GET传入的键名被引用成参数变量了,首先要知道$_GET 变量是一个数组,内容是由 HTTP GET 方法发送的变量名称和值,比如GET传入一个a=1,b=2等可以通过键名查询对应的值。
echo $_GET["a"]
#1
echo $_GET["b"]
#2
然后$$k = $v 可以修改全局变量(键名=变量名),看似传入a=1、b=2其实,实现效果为
$a = 1
$b = 2
在第32行-38行,有挑战成功的判定
if (isset($login))
{
echo GWF_HTML::message('Register Globals', $chall->lang('msg_welcome_back', array(htmlspecialchars($login[0]), htmlspecialchars($login[1]))));
if (strtolower($login[0]) === 'admin') {
$chall->onChallengeSolved(GWF_Session::getUserID());
}
}
可以知道成功条件是 strtolower($login[0]) === ‘admin’,通过GET修改$login[0]为admin(大小写任意)即可。
解题链接:
/globals.php?login[0]=admin
/globals.php?login[0]=ADMIN
都行