原生JS文件上传
JS实现文件上传
<!-- 表单用于文件上传,指定了上传的目标地址为 "upload.php",使用 POST 方法提交,并设置 enctype 为 "multipart/form-data" --> <form action="upload.php" method="POST" enctype="multipart/form-data"> <!-- 为文件上传输入框添加标签 --> <label for="file">选择文件:</label> <br> <!-- 这是一个包含文件上传输入框的 HTML 代码,并且在用户选择文件时触发 CheckFileExt 函数 --> <input type="file" id="file" name="f" onchange="CheckFileExt(this.value)"> <br> <!-- 提交按钮 --> <button type="submit">上传文件</button> </form>
|
<script> function CheckFileExt(filename){ var flag = false; var exts = ['png', 'gif', 'jpg']; var index = filename.lastIndexOf('.'); var ext = filename.substr(index + 1);
for (var i = 0; i < exts.length; i++) { if (ext === exts[i]) { flag = true; alert('文件后缀名正确'); break; } }
if (!flag) { alert('文件后缀错误!') location.reload(true); } } </script>
|
直接写在html代码中,前端JS验证
安全问题
禁用JS或删除过滤代码绕过
删除过滤代码:
将页面源代码复制下来,在本地创建,并删除检验代码的函数调用onchange=”CheckFileExt(this.value)”
将调用的文件上传地址,切换为使用网址路由的样式http://192.168.137.1:84/js/upload.php
成功绕过文件检验,上传成功1.exe
在本地源代码文件中实现远程文件上传,使用调用的文件上传地址
JS导入库开发
后端php实现账户判断,前端JS实现登录处理
val() 是 jQuery 的一个方法,用来获取或设置表单元素的值
JS实现登录验证
$.ajax()是一个用于执行异步HTTP请求的jQuery函数。它允许您通过JavaScript代码向服务器发送请求,并在不刷新整个页面的情况下接收和处理响应。
下面是一个基本的$.ajax()用法示例:
$.ajax({ url: "example.com/data", // 请求的URL method: "GET", // HTTP请求方法(GET、POST等) data: { // 发送到服务器的数据(可选) param1: "value1", param2: "value2" }, success: function(response) { console.log("请求成功!"); console.log(response); }, error: function(xhr, status, error) { console.log("请求失败!"); console.log(error); } });
|
<div class="login"> <h2>后台登录</h2> <label for="username">用户名:</label> <input type="text" name="username" id="username" class="user"> <label for="password">密码:</label> <input type="password" name="password" id="password" class="pass"> <button>登录</button> </div>
** <script src="js/jquery-1.12.4.js"></script>**
<script> $("button").click(function (){ $.ajax({ type: 'POST', url: 'logincheck.php', data: { myuser: $('.user').val(), mypass: $('.pass').val() }, success: function (res){ console.log(res); if(res['infoCode'] == 1){ alert('登录成功'); } else { alert('登录失败'); } }, dataType: 'json', }); }); </script>
|
<?php $user = $_POST['myuser']; $pass = $_POST['mypass'];
** $success = array('msg' => 'ok');**
if ($user == 'xiaodi' && $pass == '123456') { $success['infoCode'] = 1; } else { $success['infoCode'] = 0; }
**
echo json_encode($success);**
|
安全问题
登陆成功后的处理操作写在JS里
if(res['infoCode'] == 1){ alert('登录成功'); }
|
我们直接抓包修改infoCode的值为1,可以绕过登录


前提是仅仅通过infoCode这一参数来校验是否登录成功
当成功后的操作如跳转到其他页面写在PHP中,相对安全
前端js只起到判断作用,无法执行跳转等逻辑
逻辑购买
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>商品购买</title> </head> <body> <img src="iphone.jpg" width="300" height="300" alt=""><br> 金钱:10000<br> 商品价格:8888<br> 数量:<input type="text" name="number" class="number"> <button>购买</button> </body> </html>
<script src="js/jquery-1.12.4.js"></script>
<script> $("button").click(function (){ **$.ajax({ type: 'POST', url: 'shop.php', data: { num: $('.number').val(), }, success: function (res){ console.log(res); if(res['infoCode'] == 1){ alert('购买成功'); } else { alert('购买失败'); } }, dataType: 'json', });** }); </script>
|
<?php $num = $_POST['num'];
$success = array('msg' => 'ok');
** if (10000 >= ($num * 8888)) { $success['infoCode'] = 1; } else { $success['infoCode'] = 0; }
echo json_encode($success);** ?>
|
将抓到的包,设置其返回包也抓取,并将访问失败返回包的改为1发送,后购买成功。
当成功后的操作如购买成功后的逻辑到其他页面写在js中,不安全
DOM树
DOM:文档操作对象
浏览器提供的一套专门用来操作网页代码内容的功能,实现自主或用户交互动作反馈
演示操作:
当点击按钮的时候会进行图片替换,要获取该图片的对象,获取对象的src属性,替换src属性
获取对象
获取对象三种方法
1.标签:直接写
2.Class:加上符号.
i3.id:加上符号#
<!-- 这是标题 --> <h1 id="myHeader" onclick="getValue()">这是标题</h1>
<!-- 选择第一个 h1 元素 --> document.querySelector('h1')
<!-- 选择所有具有 'id' 类的元素 --> document.querySelector('.id')
<!-- 选择具有 'myHeader' id 的元素 --> document.querySelector('#myHeader')
|
console.log(): 是一个用于在控制台输出信息的方法。它是由浏览器或其他 JavaScript 运行环境提供的调试工具。通过调用 console.log(),您可以在控制台中输出消息、变量的值、调试信息等,以便在开发过程中进行调试和测试。
例如: console.log("Hello, world!"); 这行代码将在控制台输出字符串 "Hello, world!"。
|
获取对象属性
<img src="1.jpg" width="300" height="300" > <button onclick="update()">刷新</button>
<script> function update(){ const s=document.querySelector('img') console.log(s) }
</script>
|
每次点击刷新按钮,控制台都会输入img标签的内容

操作元素数据
innerText 不解析后续代码
<h1 onclick="update1()">这是标题</h1> <img src="1.jpg" width="300" height="300" > <button onclick="update()">刷新</button>
<script> function update(){ const s=document.querySelector('img') console.log(s) } function update1(){ const s=document.querySelector('h1') console.log(s.innerText) } </script>
|
每次点击“这是标题”,控制台都会打印一遍

当吧update1中获得的h1标签的数据先赋值给一个变量,在更改这个变量的内容,最后打印数据,h1标签的数据就会被改变
function update1(){ const s=document.querySelector('h1') const str=s.innerText="这是hx" console.log(str) }
|

innerHTML 解析后续代码
<h1 onclick="update1()">这是标题</h1> <img src="1.jpg" width="300" height="300" > <button onclick="update()">刷新</button>
<script> function update(){ const s=document.querySelector('img') console.log(s) } function update1(){ const s=document.querySelector('h1') const str=s.innerText="这是hx<br>" console.log(str) } </script>
|
当我们使用innerText,后面的html标签不会被解析

使用innerHTML
<h1 onclick="update1()">这是标题</h1> <img src="1.jpg" width="300" height="300" > <button onclick="update()">刷新</button>
<script> function update(){ const s=document.querySelector('img') console.log(s) } function update1(){ const s=document.querySelector('h1') s.innerHTML="这是hx<Hr>" console.log(s.innerHTML) } </script>
|
当点击标题,
标签被执行,页面更改

操作元素属性
实现点击按钮更换图片
<h1 onclick="update1()">这是标题</h1> <img src="1.jpg" width="300" height="300" > <button onclick="update()">刷新</button>
<script> function update(){ const s=document.querySelector('img') s.src='2.png' console.log(s.src) } </script>
|
当我们点击刷新,图片被更新为2.png

安全问题
本身的前端代码通过DOM技术实现代码的更新修改,但是更新修改如果修改的数据可以由用户来指定,就会造成DOM-XSS攻击

在用户可控输入的地方构造xss语句

闭合标签
网易云翻译:可以使用带外dns,造成数据库ip泄露


正向翻译有过滤,当鼠标放在右边被翻译的文字,正向没有翻译出来再次尝试翻译,反向翻译没有过滤,执行构造的
,被解析,成功带外查询
典型的DOM-XSS
编码加密&逆向调试
编码加密
通过js导入库来实现对数据的md5、AES、SHA1等加密
没有实现..存在遗留问题
逆向调试
首先找到相应的源码内容位置

找到表单的name属性的值
CTRL+SHIFT+F在调试器中全局搜索name的值,找相应的加密函数

Login.js
审计代码,找到相应的加密函数

找到加密逻辑
根据相应的加密函数,将payload加密,构成有效payload
如果加密格式不显示出来,怎样判断加密的方式是什么?
可以借助检查的控制台,尝试输入获取加密后的密码值,再和提交表单的加密值进行比对,若一致则证明识别出。(一般安全防护比较强的,不会把运行的所以东西全加载到浏览器上)
断点调试
当我们找到了相应的加密函数
logindata.UserName = encodeURI(encrypt.encrypt(numMobile)); logindata.Mobile = encodeURI(encrypt.encrypt(numMobile));;
logindata.Password = encodeURI(encrypt.encrypt(numPassword));
|
采用之前的方式在控制台中输入相应的代码encodeURI(encrypt.encrypt(numPassword)),报错encrypt is not defined,原因是:有一些文件只在服务器本地执行,不会加载到浏览器中

必须采用调试断点的方式来,通过服务器获取其执行文件,然后修改对应的返回密文即可
对应地方(加密函数那一行代码)打上断点,点击登录,进入断点调试,发现右侧出现输入的账号密码内容

再次打开控制台,并输入encodeURI(encrypt.encrypt(numPassword))发现成功回显加密后的密码

我们在控制台构造payload并用加密函数进行加密,将加密后的有效payload提交,进行测试
NodeJS
NodeJS教程
NodeJS是运行在服务器的JS,与传统JS不同(传统JS运行在前端浏览器,通过查看源代码可以看到完整JS代码),而NodeJS运行结果,查看源代码只能查看运行结果

访问之后当我们查看源代码,只有输出结果hello world

实现用户登录
前端登录页面
<div class="login"> <h2>后台登录</h2> <form action="http://127.0.0.1:3001/login" method="post"> <label for="username">用户名:</label> <input type="text" name="username" id="username" class="user"> <label for="password">密码:</label> <input type="password" name="password" id="password" class="pass"> <button>登录</button> </div>
|
const express = require('express'); const bodyParser = require('body-parser');
const app = express(); 创建一个用于解析 URL 编码的 bodyParser 中间件实例 const urlencodedParser = bodyParser.urlencoded({ extended: false });
app.get('/login', function(req, res) { const u = req.query.username; const p = req.query.password;**
console.log(u); console.log(p);
if (u === 'admin' && p === '123456') { res.send('欢迎进入后台管理页面'); } else { res.send('登录用户或密码错误'); } });
app.post('/login', urlencodedParser, function(req, res) { const u = req.body.username; const p = req.body.password;**
console.log(u); console.log(p);
if (u === 'admin' && p === '123456') { res.send('欢迎进入后台管理页面'); } else { res.send('登录用户或密码错误'); } });
app.get('/', function(req, res) { res.sendFile(__dirname + '/' + 'sql.html'); });
const server = app.listen(3001, function() { console.log('Web 服务器已经启动,监听端口 3001!'); });
|
req.query 用于处理 URL 查询字符串参数(GET请求),而 req.body 用于处理 (POST 请求)中的表单数据
POST请求
还需要下载const bodyParser = require(‘body-parser’); 相关库 npm i body-parser
并且post请求还需要创建一个解析URL编码的bodyParser (中间件实例)
sql.js里同时写了get和post处理逻辑,当sql.html里方法属性为get时则使用get处理逻辑
<form action="http://127.0.0.1:3001/login" method="post">
|
成功登录


连接数据库
导入mysql ,npm i mysql下载相关依赖
const mysql = require('mysql');
|
导入 mysql 模块
var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', database : 'dome01' });
|
文件操作
导入fs
const fs=require('fs');
fs.readdir('./',function(error,files){ console.log(files); })
|

启用服务器
const fs = require('fs'); const express = require('express'); const app = express();
app.get('/file', function (req, res) { const dir = req.query.dir; console.log(dir);
filemanage(dir); });
var server = app.listen(3000, function () { console.log('Web应用已启动在3000端口!'); });
function filemanage(dir) { fs.readdir(dir, function (error, files) { console.log(files); }); }
|
传参

命令执行
const rce=require('child_process')
eval("require('child_process').exec('calc')")
|
exec & spawnSync 调用系统命令
eval调用代码命令执行,将字符串当做代码解析
安全问题
SQL注入、文件操作、RCE、
实战测试NodeJS安全:
判断:参考前期的信息收集
黑盒:通过对各种功能和参数进行payload测试
白盒:通过对代码中写法安全进行审计分析
原型链污染
如果攻击者控制并修改了一个对象的原型,(proto)
那么将可以影响所有和这个对象来自同一个类、父祖类的对象。
let foo = {bar: 1}
console.log(foo.bar)
foo.__proto__.bar = '2'
console.log(foo.bar)
let zoo = {}
console.log(zoo.bar)
|
我们并没有对zoo赋值,但zoo.bar输出为2,是因为继承了foo.bar父类的赋值2

利用原型链污染调用计算器
let foo = {bar: 1};
console.log(foo.bar);
foo.__proto__.bar = 'require(\'child_process\').execSync(\'calc\');';
console.log(foo.bar);
let zoo = {};
console.log(eval(zoo.bar));
|
yapi漏洞
yapi token注入漏洞-CSDN博客
webpack
为什么使用webpack
function test(){ console.log('test'); }
|
<!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 src="src/2.js"></script> <script src="src/1.js"></script> </body> </html>
|
由于函数要先声明再调用,所以要先引用1.js,在引用2.js
如果我们先写2再写1会产生报错,而在正常的业务中可能会有很多js文件,按顺序处理过于麻烦
Webpack是一个模块打包器。在Webpack中会将前端的所有资源文件都作为模块处理。它将根据模块的依赖关系进行分析,生成对应的资源
使用
1.先创建js文件

export default function count(x,y){ return x-y; }
|
export default function sum(x,y){ return x+y; }
|
import count from "./count.js"; import sum from "./sum.js";
console.log(sum(1,2)); console.log(count(1,2));
|
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="main.js"></script> </body> </html>
|

2.创建webpack配置文件 webpack.config.js(名称不能修改)
const path = require('path');
module.exports = { entry: './src/main.js',
output: { path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true, },
mode: "development", };
|
entry: 指定入口文件,即Webpack从哪个文件开始构建依赖关系图。
output: 指定输出的目录和文件名,以及是否在每次构建前清理输出目录。
mode: 指定打包的模式,可以是 ‘development’ 或 ‘production’。
development 模式下会启用一些开发工具,容易造成源码泄露
production 模式下会进行代码优化,代码极简化。
3.运行webpack打包命令:npx webpack


4.打包成功后,我们将html里的代码换成打包后的包文件

5.启用调试html文件,控制台成功输出结果

源代码中可以看到打包的文件已经源文件

安全问题
WebPack源码泄漏-模式选择
development 模式下会启用一些开发工具,容易造成源码泄露
production 模式下会进行代码优化,代码极简化。
当我们在打包的时候选择(webpack.config.js文件配置)development模式,会将源码文件泄露,前端可以直接看到文件内容


JQuery
jQuery是一个快速、简洁的JavaScript框架,是一个丰富的JavaScript代码库。设计目的是为了写更少的代码,做更多的事情。它封装JavaScript常用功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互
Javascript框架库漏洞验证-CSDN博客