xss漏洞总结

发布于:2025-07-23 ⋅ 阅读:(27) ⋅ 点赞:(0)

跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!

xss分类

1.反射性xss 反射型XSS 是非持久性、参数型的跨站脚本。反射型XSS 的JS 代码在Web 应用的参数(变量)中,如搜索框的反射型XSS。在搜索框中,提交PoC[scriptalert(/xss/)/script],点击搜索,即可触发反射型XSS。 注意到,我们提交的poc 会出现在search.php 页面的keywords 参数中。

2.存储型xss

存储型XSS 是持久性跨站脚本。持久性体现在XSS 代码不是在某个参数(变量)中,而是写进数据库或文件等可以永久保存数据的介质中。存储型XSS 通常发生在留言板等地方。我们在留言板位置留言,将恶意代码写进数据库中。此时,我们只完成了第一步,将恶意代码写入数据库。因为XSS 使用的JS 代码,JS 代码的运行环境是浏览器,所以需要浏览器从服务器载入恶意的XSS 代码,才能真正触发XSS。此时,需要我们模拟网站后台管理员的身份,查看留言。

3.DOM的xss

DOM XSS 比较特殊。owasp 关于DOM 型号XSS 的定义是基于DOM 的XSS 是一种XSS 攻击,其中攻击的payload由于修改受害者浏览器页面的DOM 树而执行的。其特殊的地方就是payload 在浏览器本地修改DOM 树而执行, 并不会传到服务器上,这也就使得DOM XSS 比较难以检测。

xss-labs

下载xss-labs

将他转移到xp的www目录下

然后

在xp上创建网站

需要访问时打开apchi和mysql,访问

http://127.0.0.1/xss-labs

level-1网页源代码

这里能看到网页源码里是有个alert函数的,只要触发这个函数就可以到下一关

这里输入

< svg οnclick="alert(1)" >
SVG(可缩放矢量图形)的根标签,用于定义矢量图形。
οnclick="alert(1)"事件属性,意思是当用户点击这个 SVG 元素时,会执行alert(1)这个 JavaScript 代码,弹出一个显示数字 “1” 的提示框。level-2第二关是有一个input输入框的输入内容就是test,我们要做的就是payload逃出这个引号内容,然后调用这个alert函数 

" οnclick="alert(1)
是将图中test替换为以上内容,后再input里用onclick
οnclick="alert(1)" 是 HTML 中的一个内联事件处理属性,用于在元素被点击时触发 JavaScript 代码

这里用onclick所以我们这里点击input的输入框就会调用alert函数进入下一关level-3这个和上一关差不多,先用上一关方法试试

' οnfοcus='alert(1)' autofocus='
onfocus 是 HTML 中的事件属性,当元素获得焦点时会触发后面的脚本;
autofocus 则是让元素自动获得焦点的属性。
两者结合后,页面加载时元素会因 autofocus 自动聚焦,进而触发 onfocus 中的脚本执行,这是典型的利用 HTML 属性注入脚本的 XSS 攻击模式,可能被用于窃取用户信息、篡改页面内容等恶意行为。

成功了,而且不需要点击输入框。level-4这一关也是有个输入框,继续上一关方法试试,感觉这次不太行了 ``` " οnfοcus="alert(1)" autofocus=" ```level-5

这个关也是差不多

还用那个方法试试

这次不行了

他在我们o后面加了个_,把我们的方法破坏了

我们换个方法

"><a href=javascript:alert(1)>下一关</a>
 <a href=javascript:alert(1)> 是创建了一个超链接,其href属性使用了javascript:伪协议,当用户点击该链接时,会执行alert(1)这个 JavaScript 代码,弹出内容为1的对话框。level-6依旧输入框试试上一关方法href被过滤了

不行了在我们r后面加_了

onfocus+autofocus也不行也被过滤我们试试将href中的re换成大写

"><a hREf=javascript:alert()>下一关</a>
level-7先试试上一关方法

"><a href=javascript:alert()>下一关</a>

它吧我们的href和script给删掉了"><a hrhrefef=javasscriptcript:alert()>下一关</a>

把被删了的字段放进原本的字段里,它让刚开始检查不出来,把第一个href和script删掉时,我们直接形成了第二个href和script。成功过关

原型链污染

原型和原型链都是来源于对象而服务于对象的概念,所以我们要先明确一点: JavaScript中一切引用类型都是对象,对象就是属性的集合。 Array类型、Function类型、Object类型、Date类型、RegExp类型等都是引用类型。 也就是说 数组是对象、函数是对象、正则是对象、对象还是对象。

原型和原型链到底是什么呢,我学的时候,也懵逼了好长时间。 定义:每个 JavaScript 函数(构造函数)都有一个 prototype 属性,指向一个对象(原型对象)。 作用就是为了共享属性和方法,所有通过该构造函数创建的实例都能访问原型上的属性和方法。

这里的原型对象是什么,实例对象有是什么?

我们看一个例子

function Person(name) {
  this.name = name; // 实例属性(每个实例独立)
}

const person1 = new Person("Alice"); // person1 是实例对象
const person2 = new Person("Bob");   // person2 是另一个实例对象

实例对象就是这么简单,那原型对象呢

function Animal(name) {
  this.name = name;
}
Animal.prototype.color = 'white';

var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');

cat1.color // 'white'
cat2.color // 'white'

这个例子里cat1和cat2是实例对象,图中的animal的prototype就是cat1和cat2的原型对象 JavaScript 规定,每个函数都有一个prototype属性,指向一个对象。就是object

cat1.color--->Animal.prototype---->aaaaaaa.prototype------>xxxxx.------->Object.prototype---->null

如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOftoString方法的原因,因为这是从Object.prototype继承的。 那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是nullnull没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null

prototype和__proto__和constructor 有什么区别呢

1,prototype

每个函数(Function)默认拥有的属性,指向一个对象(原型对象)。

当函数被用作构造函数(通过 new 调用)时,新创建的对象会继承原型对象的属性和方法。

后面将他和其他两个结合起来说

2.proto

每个对象(包括数组、函数)默认拥有的属性,指向创建它的构造函数的 prototype 对象。

JavaScript 通过 proto 实现原型链查找,当访问一个对象的属性时,引擎会先查找对象本身,再通过 proto 逐级向上查找。

const person = new Person("Alice");
console.log(person.__proto__ === Person.prototype); // true

3.constructor

每个原型对象默认拥有的属性,指向创建该原型的构造函数 用于标识对象的 “类型”,或通过它创建新实例。

prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。

function P() {}
P.prototype.constructor === P // true

由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。

function P大() {}
var p小 = new P大();

//应该有这个属性吗
p小.constructor === P大 // true

p小.constructor === P大.prototype.constructor // true

这个还是非常清晰的

上面代码中,p是构造函数P的实例对象,但是p自身没有constructor属性,该属性其实是读取原型链上面的P.prototype.constructor属性。

constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。

constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。

function Person(name) {
  this.name = name;
}

Person.prototype.constructor === Person // true

Person.prototype = {
  method: function () {}
};

Person.prototype.constructor === Person // false
Person.prototype.constructor === Object // true

上面代码中,构造函数Person的原型对象改掉了,但是没有修改constructor属性,导致这个属性不再指向Person。由于Person的新原型是一个普通对象,而普通对象的constructor属性指向Object构造函数,导致Person.prototype.constructor变成了Object。 应该能看拿出来哪里修改了原型对象吧,Person.prototype = { method 这里修改了(我就不写玩了OVO),这个看懂了后面都清晰的。

所以,修改原型对象时,一般要同时修改constructor属性的指向。

C.prototype.method1 = function (...) { ... };

这个方法比较好,建议用这个,这个比较清晰,易于理解

//定义基类animal
function Animal(type) {
  this.type = type;
}
Animal.prototype.move = function() {
  console.log(`${this.type} is moving`);
};
//定义子类dog
function Dog(name) {
  this.name = name;
  Animal.call(this, "Dog"); // 继承属性
}
// 设置 Dog 的原型为 Animal 的实例
Dog.prototype = Object.create(Animal.prototype);
// 修复 constructor
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
  console.log("Woof!");
};

const dog = new Dog("Buddy");
dog.move(); // 输出: Dog is moving(通过原型链访问 Animal.prototype)
dog.bark(); // 输出: Woof!
console.log(dog.constructor === Dog); // true

Animal 构造函数:创建对象时设置 type 属性(如 Dog、Cat)。

Animal.prototype.move:所有 Animal 实例共享的方法,通过原型链访问。

Dog 构造函数: 设置 name 属性(如 "Buddy")。 通过 Animal.call(this, "Dog") 调用父类构造函数,将 type 设置为 "Dog"。 效果:每个 Dog 实例都有 name 和 type 属性。

Object.create(Animal.prototype): 创建一个新对象,其 proto 指向 Animal.prototype。 将该对象赋值给 Dog.prototype,使 Dog 实例可以访问 Animal.prototype 的方法(如 move())。 原型链结构: dog.proto ---> Dog.prototype ---> Animal.prototype ---> Object.prototype。


网站公告

今日签到

点亮在社区的每一天
去签到