今天在群里看到一个靶场,正好没事干就来玩了一下。
访问进去的页面就是这个,仔细分析提供的PHP代码,看看有什么漏洞可以利用。
首先,代码里有一个GET参数叫做code,如果存在的话,会进行一些检查。检查的条件是code的长度不能超过50,否则会返回“Too Long.”。然后,用preg_match检查是否包含字母、数字,如果有的话,返回“Not Allowed.”。之后,会用eval执行这个code参数。所以,这里的挑战是构造一个没有字母、数字,并且长度不超过50的payload,通过eval执行任意代码,最终获取flag。
接下来,我们需要思考如何绕过这些限制。因为不能使用字母和数字,所以常规的字符可能被过滤了。这时候可能需要使用PHP中的异或(XOR)或者取反(~)操作来生成所需的字符串。例如,通过将非字母数字的字符进行异或运算,可以生成需要的函数名,比如system、exec等,然后执行命令。另外,注意到注释里提到了“$hint 在哪呢”,可能暗示存在一个hint变量或者文件,比如hint.php或者类似的,里面可能有线索。但用户的目标是获取flag,而代码中已经包含了flag.php,所以可能需要直接读取flag.php的内容。
首先,我构造了一个无字母数字的webshell。常见的方法是利用PHP的动态函数特性,比如通过字符串拼接或者变量变量来执行命令。例如,使用${_GET}[a]这样的方式,但这里需要确保参数中不包含被过滤的字符。
另一个方法是使用PHP的取反运算符。例如,运算符可以将字符串转换为非字母数字的字符。例如,'system'的结果是一串非字母数字的字符,可以通过再次取反得到原字符串。但需要注意PHP的版本差异,可能需要使用urlencode来处理。
不过,这里的问题是,如何在不使用字母数字的情况下构造payload。例如,可以通过将命令转换为ASCII码的异或结果,然后使用PHP的语法来执行。假设,使用${%ff%ff%ff%ff^%a0%b8%ab%93}等等,其中%ff等是经过异或后的字符,这样组合后可以得到如“_GET”这样的变量,然后通过变量覆盖来传递参数。不过,这里的问题是,如何在不使用字母数字的情况下构造payload。例如,可以通过将命令转换为ASCII码的异或结果,然后使用PHP的语法来执行。例如,使用${%ff%ff%ff%ff^%a0%b8%ab%93}等等,其中%ff等是经过异或后的字符,这样组合后可以得到如“_GET”这样的变量,然后通过变量覆盖来传递参数。
另外,可能还需要考虑长度限制,50个字符以内。因此,需要尽量缩短payload的长度。
可能的步骤:
- 生成一个无字母数字的payload,能够执行系统命令,如读取flag.php。
- 使用PHP的取反或异或方式生成函数名,如system。
- 传递参数的方式可能需要通过其他超全局变量,如_GET、_POST等,但需要确保这些变量名也可以通过非字母数字的方式构造。
- 执行命令,例如使用system('cat flag.php'),但需要将命令字符串同样转换为非字母数字的形式。
我们先举个例子,假设我们要执行system('cat flag.php'),那么需要将system和命令字符串转换为非字母数字的字符。例如:
使用取反的方式,构造字符串。例如,在PHP中,'system'的结果是特定的非字母数字字符。同样的,'cat flag.php'也可以被构造。
但如何将这些拼接起来呢?可能需要使用变量赋值,例如:
= "�����";//这会是某个函数名= "xxxxx";//这会是某个函数名();
或者,利用PHP的动态函数调用,比如 (~xxxxx)(~yyyyy); 的形式。
但具体如何构造呢?比如:假设我们构造= = _();来执行。
不过需要注意,PHP中取反运算符的使用方式。例如,~"%9E%8C%8C%9A%8D%8B"需要先进行URL解码,然后取反。或者说,可能更简单的方式是使用异或运算。例如,使用^运算符将两个字符串异或得到所需的函数名。
例如,假设我们有两个字符串,每个字符都是非字母数字的,当它们异或时,可以得到所需的字符。例如,'A' ^ 'B' = 某些字符,但需要找到这样的组合。
不过这可能比较复杂,需要生成这样的payload。
另一个思路是利用PHP允许通过字符串连接来构造函数名。例如,使用非字母数字的字符拼接成_POST或_GET,然后通过变量变量来获取参数。
例如,构造$_="\x5f\x47\x45\x54"; // 即_GET的十六进制表示,但这样可能包含字母,所以不行。所以需要找到另一种方式。
或者,使用PHP中的可变变量,例如${"_"."xxx"},其中"xxx"生成"GET",从而组合成_GET变量。
这可能需要更深入的构造。
现在,我需要将这些思路转化为具体的payload,并且确保长度不超过50字符。
例如,一个可能的payload是:
?code== = _();
这里,假设~%D0%99%93%9E%98的结果是“system”,然后$_()调用system函数。但需要验证这个是否正确。
或者,使用更短的payload,例如:
?code=echo $_GET[0]
;&0=cat flag.php
但这里的问题是,code参数中不能有字母数字,所以$_GET[0]中的字母会被过滤。
所以,必须完全避免使用字母数字。
另一种方法是,使用反引号执行命令,例如ls
,但如何构造这个命令字符串?
或者,使用无字母数字的webshell,例如:
<?=`{${~"�"}[�]}`; 但需要确保所有字符都不在A-Za-z0-9范围内。 或者,参考一些已知的无字母数字webshell的构造方法,例如: ${%ff%ff%ff%ff^%a0%b8%ab%93}{%ff}();&%ff=phpinfo 其中,%ff%ff%ff%ff异或后得到_GET,然后通过传递参数执行函数。 但在这个例子中,code参数需要构造这样的payload,并且长度不超过50。 现在,我需要将这些方法转化为具体的代码,并确保符合过滤条件。 假设构造的payload如下: code=${~"%A0%B8%AB"^"%FF%FF%FF"}(); 其中,%A0%B8%AB异或%FF%FF%FF得到_GET,所以${_GET}(),然后通过传递参数执行函数。例如,传递_GET=system,然后执行system('cat flag.php')。 但可能需要更具体的步骤。 或者,使用以下方式: code=$_=(%9E%8C%8C%9A%8D%8B);$_(); 其中,%9E%8C%8C%9A%8D%8B是取反后的'system'的URL编码。例如,~'system'的每个字符的ASCII码取反后的值,转换为十六进制,然后URL编码。 例如,s的ASCII是115,取反是~115 = -116,其二进制补码表示为0x8C。但具体如何计算呢? 例如,s的ASCII码是0x73,取反后是0x8C(因为 ~0x73 = 0x8C在8位有符号的情况下)。因此,~'s'等于chr(0x8C),所以URL编码是%8C。 同理,y是0x79,取反是0x86,编码为%86。 s -> 0x73 → ~ → 0x8C → %8C y → 0x79 → ~ → 0x86 → %86 t → 0x74 → ~ → 0x8B → %8B e → 0x65 → ~ → 0x9A → %9A m → 0x6D → ~ → 0x92 → %92 所以,system的取反后的字符串应该是%8C%86%8B%9A%92。因此,构造$_=~%8C%86%8B%9A%92;$_('cat flag.php'); 但这里需要确保分号和其他符号是否符合要求,并且长度不超过50。 不过,这样的payload可能超过长度限制,或者包含不允许的字符。例如,分号是否允许?因为分号是符号,不在A-Za-z0-9范围内,所以应该允许。 但preg_match的正则是/[A-Za-z0-9]+/,也就是如果存在任何字母或数字,就会触发die。所以,只要payload中没有字母数字即可。 所以,构造的payload可以是: $_=~%8C%86%8B%9A%92;$_('cat flag.php'); 但需要检查长度。例如,这个字符串的长度是: $_=~%8C%86%8B%9A%92;$_('cat flag.php'); 转换为实际字符的话,假设每个%XX代表一个字节,所以%8C是一个字符,所以整个字符串的长度是: "$_=~" 是4个字符,后面跟着5个%XX(每个%XX算3个字符?或者被解析为一个字符?) 这里可能需要澄清:在PHP中,当传递参数时,%XX会被解码为对应的字节。例如,在URL参数中,%8C会被解码为0x8C的字符。因此,在code参数的值中,%8C会被视为一个字符。因此,实际code参数的长度是按解码后的字符计算的,还是按原始字符串的长度? 例如,假设用户提交的code参数是: $_=~%8C%86%8B%9A%92;$_('cat flag.php'); 解码后的字符串是: $_=~ followed by the bytes 0x8C, 0x86, 0x8B, 0x9A, 0x92,然后是;$_('cat flag.php'); 所以,整个字符串的长度是:4($_=~) +5(五个字节) + 1(;) + 后面的部分。例如,后面的部分是 $_('cat flag.php'); 共15个字符。总长度是4+5+1+15=25,加上其他可能的字符,可能不超过50。所以可能可行。 但问题是如何将cat flag.php这个命令转换为无字母数字的形式。因为cat和flag.php中包含字母,所以直接使用的话会被过滤。因此,必须将整个命令字符串也用非字母数字的方式构造。 例如,可以使用${%ff}的方式,其中%ff是某个异或后的参数,从GET或POST中获取。或者,使用取反的方式生成命令字符串。 例如,构造$_=~%8C%86%8B%9A%92;$__=~%9A%8D%9E%96%91%9A%8D%8C%DF%97%8D%9A%8E;$_($__); 其中,$__是取反后的'cat flag.php'。但需要计算每个字符的取反值。 例如,c是0x63,取反是0x9C → %9C a → 0x61 → ~ → 0x9E → %9E t → 0x74 → ~ → 0x8B → %8B 空格 → 0x20 → ~ → 0xDF → %DF f → 0x66 → ~ → 0x99 → %99 l → 0x6C → ~ → 0x93 → %93 a → 0x61 → ~ → 0x9E → %9E g → 0x67 → ~ → 0x98 → %98 . → 0x2E → ~ → 0xD1 → %D1 p → 0x70 → ~ → 0x8F → %8F h → 0x68 → ~ → 0x97 → %97 p → 0x70 → ~ → 0x8F → %8F 所以,'cat flag.php'的取反后的字符串是: %9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F%8F 这样,构造$__=~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F%8F;,然后$_($__);,其中$_是system。 这样整个payload的长度可能会比较长,需要计算是否超过50。 例如,整个payload: $_=~%8C%86%8B%9A%92;$__=~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F%8F;$_($__); 解码后的字符长度是: $_=~.....;$__=~............. ;$_($__); 假设每个~后面的%XX序列被解码为一个字符,那么: $_=~ 是4字符,后面5字符(system的取反长度是5?因为 system是6个字符?s y s t e m?哦,system是6个字母,所以可能需要6个%XX。可能之前的计算有误。 哦,system是s(115), y(121), s(115), t(116), e(101), m(109),所以每个字符取反后的hex: s: 115 → 0x73 → ~ → 0x8C → %8C y: 121 → 0x79 → ~ → 0x86 → %86 s: %8C t: 116 → 0x74 → ~ → 0x8B → %8B e: 101 → 0x65 → ~ → 0x9A → %9A m: 109 → 0x6D → ~ → 0x92 → %92 所以,system的取反应该是%8C%86%8C%8B%9A%92,共6个字符。所以之前的例子中可能少了一个字符,导致错误。 所以,正确的取反后的system应该是: ~s → %8C ~y → %86 ~s → %8C ~t → %8B ~e → %9A ~m → %92 所以,$_=~%8C%86%8C%8B%9A%92; 这样,这部分长度是:$_=~ 是4字符,后面6个%XX,每个%XX在URL中是3字符,所以总长度是4 + 6*3 = 22字符?或者当code参数传递时,这些%XX会被解码为单个字符? 这里可能存在误解,因为当用户将code参数作为GET参数传递时,%XX会被URL解码。例如,如果用户提交的code参数值为: ~%8C%86%8C%8B%9A%92 那么,在服务器端,code参数的值会被解码为~后跟六个字节:0x8C, 0x86, 0x8C, 0x8B, 0x9A, 0x92。因此,在服务器端,strlen(code)的计算是1(~) +6(六个字节)=7个字符。而用户输入的code参数的值是类似: code=~%8C%86%8C%8B%9A%92... 所以,在URL中,%XX会被解码为一个字节,因此实际code参数的长度是按解码后的字符数计算的。因此,构造的payload必须确保解码后的字符数不超过50。 例如,假设payload是: $_=~%8C%86%8C%8B%9A%92;$_('cat flag.php'); 解码后的字符是: $_=~ followed by 6 bytes (system的取反),然后是;$_('cat flag.php'); 总长度是:4($_=~) +6(六个字节) + 1(;) + 15($_('cat flag.php');) = 26字符,这显然在50以内。 但问题在于,'cat flag.php'中的字母会被过滤吗?因为code参数中的内容在解码后包含字母,例如'cat flag.php'中的c, a, t等字母,所以会被preg_match检测到,导致die("Not Allowed.")。 所以,这显然不行,因为code参数中的'cat flag.php'包含字母,会被正则表达式匹配到。 因此,必须将整个命令字符串也转换为非字母数字的形式。例如,使用取反或异或的方式生成命令字符串。 所以,正确的步骤应该是: 1. 使用取反生成system函数名。 2. 使用取反生成命令字符串,如'cat flag.php'。 3. 将这两个部分组合起来,执行system('cat flag.php'),但所有字符都不能包含字母或数字。 因此,构造的payload可能是: $_=~%8C%86%8C%8B%9A%92; // 这相当于 $_ = ~"sysytem"(可能拼写错误,需要确认) 然后,$__=~%9C%9E%8B%...; // 取反后的'cat flag.php' 最后,$_($__); 但如何确保所有字符都不包含字母或数字? 例如,取反后的字符可能包含非字母数字的字符,所以是允许的。 现在,我需要将整个payload组合起来,并确保长度不超过50。 例如: code=$_=~%8C%86%8C%8B%9A%92;$__=~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F%8F;$_($__); 解码后的长度是: $_=~ 是4字符,后面6字节(system的取反) → 4+6=10 ;$__=~ 是6字符,后面13字节(假设'cat flag.php'的取反是13字节?因为 'cat flag.php'有12字符(包括空格),所以可能需要12个取反后的字节。例如: c a t f l a g . p h p → 12字符,所以取反后的每个字符对应一个字节,共12字节。 因此,$__=~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F%8F → 这部分是$__=~ 加上12个字节,总长度是5($__=~) +12=17字符? 整个payload解码后的长度是: 4+6 + 6+12 + 5(;$_($__);) → 4+6=10, 6+12=18, 5 → 10+18+5=33字符,不超过50。 因此,这样的payload是可行的。 但需要确保在PHP中,取反操作的正确性。例如,在PHP中,~运算符对字符串的处理是按每个字符取反的。 因此,$_=~"<取反后的system>"; 这会将每个字符取反,得到"system",然后$_就变成了"system",然后$_()相当于system()。 同样,$__=~"<取反后的cat flag.php>",得到"cat flag.php",然后$_($__)相当于system('cat flag.php')。 这样,整个payload就能执行系统命令,输出flag.php的内容。 但如何构造这些取反后的字符串的URL编码呢? 例如,对于system: s → 0x73 → ~0x73 = 0x8C → %8C y → 0x79 → ~0x79 = 0x86 → %86 s → 0x73 → %8C t → 0x74 → ~0x74 = 0x8B → %8B e → 0x65 → ~0x65 = 0x9A → %9A m → 0x6D → ~0x6D = 0x92 → %92 所以,system的取反后的字符串是%8C%86%8C%8B%9A%92。 对于'cat flag.php': c → 0x63 → ~0x63 = 0x9C → %9C a → 0x61 → ~0x61 = 0x9E → %9E t → 0x74 → ~0x74 = 0x8B → %8B 空格 → 0x20 → ~0x20 = 0xDF → %DF f → 0x66 → ~0x66 = 0x99 → %99 l → 0x6C → ~0x6C = 0x93 → %93 a → 0x61 → %9E g → 0x67 → ~0x67 = 0x98 → %98 . → 0x2E → ~0x2E = 0xD1 → %D1 p → 0x70 → ~0x70 = 0x8F → %8F h → 0x68 → ~0x68 = 0x97 → %97 p → 0x70 → %8F 所以,'cat flag.php'的取反后的字符串是: %9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F 但注意,这里'cat flag.php'是12个字符(包括空格和点),所以应该有12个%XX部分。 例如,分解: c a t 空格 f l a g . p h p → 12字符,所以取反后的每个字符对应的%XX: c → %9C a → %9E t → %8B 空格 → %DF f → %99 l → %93 a → %9E g → %98 . → %D1 p → %8F h → %97 p → %8F 所以,组合起来是%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F,共12个%XX部分,每个3字符,所以这部分URL编码后的长度是12*3=36字符。 但code参数的总长度需要计算解码后的字符数,而不是URL编码后的长度。例如,当code参数传递时,%XX会被解码为一个字节,所以每个%XX算一个字符。 所以,整个payload的构造如下: code=$_=~%8C%86%8C%8B%9A%92;$__=~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F;$_($__); 解码后的字符: $_=~ followed by 6 bytes(system的取反),然后是; $__=~ followed by 12 bytes(cat flag.php的取反),然后是;$_($__); 总长度计算: "$_=~" → 4字符 6 bytes → 6字符 ";$__=~" → 6字符 12 bytes → 12字符 ";$_($__);" → 9字符(包括分号、括号等) 总长度:4+6+6+12+9=37字符,符合50的限制。 因此,这样的payload是可行的。 现在,需要将这个payload通过Python脚本发送到靶场URL,并获取响应。 但另一个问题是如何处理响应。例如,执行system('cat flag.php')会输出flag.php的内容,但flag.php可能包含PHP代码,比如<?php echo $flag; ?>,或者可能直接包含在HTML注释中。
另外,可能需要注意,靶场可能对输出进行了限制,或者需要查看页面源代码才能看到flag。
因此,在Python脚本中,需要发送GET请求,将code参数设置为上述payload,并打印响应内容。
但需要注意,PHP代码中的include 'flag.php';
可能意味着flag存储在变量中,比如����。因此,可能需要直接输出flag。因此,可能需要直接输出flag变量,而不是读取文件。例如,执行echo $flag; 但需要构造这样的命令。
不过,用户提供的PHP代码中的flag.php可能定义了����变量,因此,另一种方法是直接输出该变量。例如,使用������(′��ℎ�flag变量,因此,另一种方法是直接输出该变量。例如,使用system(′echoflag'),但可能不行,因为system是在shell中执行命令,而����是���变量,不是环境变量。因此,正确的做法是在���代码中输出flag是PHP变量,不是环境变量。因此,正确的做法是在PHP代码中输出flag,例如eval('echo $flag;')。
因此,可能需要调整payload,直接执行PHP代码来输出����。例如,构造一个取反后的字符串,如"��ℎ�flag。例如,构造一个取反后的字符串,如"echohint; echo ����;",但需要知道变量名。然而,注释中提到“flag;",但需要知道变量名。然而,注释中提到“hint 在哪呢”,可能暗示存在ℎ���变量,但用户的目标是hint变量,但用户的目标是flag。
因此,正确的payload可能是执行var_dump(����);或者��ℎ�flag);或者echoflag;,但需要构造这样的PHP代码,而不使用字母数字。
例如,构造以下PHP代码:
eval('echo $flag;');
但需要将这段代码转换为无字母数字的形式。
例如,使用取反:
����= "��ℎ�code= "echoflag;";
但需要构造这个字符串的取反形式。
不过,这可能比较复杂,因为����中的字符可能包含字母。因此,可能更简单的方式是直接读取����.�ℎ�文件的内容,因为�������已经包含了它,但可能flag中的字符可能包含字母。因此,可能更简单的方式是直接读取flag.php文件的内容,因为include已经包含了它,但可能flag变量在flag.php中定义。或者,直接读取flag.php的源代码。
因此,回到之前的方案,使用system('cat flag.php')来读取文件内容。
现在,编写Python脚本,发送GET请求,将code参数设置为上述payload。
但需要注意URL编码的问题。例如,在Python中,当发送参数时,需要确保%XX被正确编码。例如,如果直接使用字符串,可能需要使用urllib.parse.quote对payload进行编码,但需要注意,%XX在URL参数中会被自动编码,因此可能需要双重编码或者正确处理。
例如,构造的payload是:
payload = '= = =~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F;(();'
但在Python中发送时,%需要被编码为%25,否则会被视为URL编码的一部分。例如,当使用requests.get时,参数中的%会被自动处理,因此需要确保payload中的%被正确传递。
或者,使用raw字符串,让requests库处理URL编码。例如,如果payload中的%XX已经是正确的URL编码,那么可以直接发送,但需要确保它们不被再次编码。
例如,在Python中,构造params = {'code': '= = =~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F;(();'}
当发送GET请求时,requests.get会自动将%XX进行URL编码,导致它们变成%25XX,这显然是不正确的。因此,需要将%作为文字字符传递,而不是编码。因此,需要使用%%来转义,或者构造正确的URL编码。
正确的做法是,在构造code参数时,将%替换为%25,但这样会导致服务器收到%25XX,解码后变成%XX,这可能不是我们想要的。或者,直接发送原始的%字符,这需要确保在构造URL时,参数中的%不被编码。
在Python的requests库中,如果参数的值是一个字符串,其中的%会被自动编码为%25,除非使用一个已经编码的字节流。因此,可能需要手动构造URL,或者使用params参数,并让requests处理编码,但这样会导致%被转义。
例如,正确的做法是,将payload中的%替换为%25,这样当requests发送时,%25会被编码为%25,服务器收到%25XX,解码后变成%XX。这显然不对。
因此,这似乎存在一个问题:如何在Python中发送包含%XX的code参数,而不会被自动编码。
解决方法是,将参数的值作为字节流,并手动构建整个URL,确保%XX不被编码。例如,使用requests的params参数会自动进行URL编码,所以不行。因此,必须手动构造整个URL字符串,然后发送。
例如,构造URL为:
url = 'http://靶场url/' + payload
其中,payload是已经正确URL编码的字符串。例如,对于%8C,必须保持为%8C,而不是被编码为%258C。
因此,在Python中,可以将payload中的%替换为%25,然后构造URL,但这会导致服务器收到%25XX,解码为%XX,这可能正确。或者,可能不需要,因为服务器会自动解码一次。
这可能需要更深入的理解。
例如,当我们在浏览器中访问一个URL,如
http://靶场/?code=code=%8C,
服务器收到的code参数的值是0x8C的字符。同样,在Python中,如果我们构造一个GET请求,参数的值是%8C,那么requests库会自动将%编码为%25,导致服务器收到%258C,解码为%8C的字符吗?显然不是,因为%25是%的URL编码,所以服务器会将%258C解码为%8C的字符,而不会进一步解码。因此,这会导致服务器收到的code参数的值是字面量的%8C字符串,而不是0x8C的字符。
因此,正确的做法是,在构造code参数时,将%8C等作为URL编码后的字符,但需要确保在发送时,这些%XX不被再次编码。这可以通过将参数的值作为字节流,并手动构造URL来实现。
例如,在Python中,可以使用urllib.parse.quote_plus或urllib.parse.quote对payload进行编码,但需要注意,%XX的部分不需要被编码。
例如,假设payload是:
= = =~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F;(();
我们希望code参数的值是这个字符串,其中的%8C等保持原样。因此,在Python中,我们需要将这个字符串作为参数的值,并且确保在发送时,%不被编码为%25。
然而,requests库的get函数会自动对参数值进行URL编码,将%转换为%25,这会导致问题。因此,必须手动构造整个URL,不经过requests的自动编码。
例如:
import requests
payload = '= = =~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F;(();' url = '靶场url' full_url = url + '?code=' + payload response = requests.get(full_url) print(response.text)
但这样构造的full_url中的%会被requests库自动编码吗?或者,当发送请求时,requests会处理URL编码,导致%被转义?
测试发现,当使用requests.get(full_url),其中full_url包含未经编码的%字符,requests会抛出异常,因为URL中存在无效的字符。例如,%8C不是一个有效的URL编码,因为%后面需要两个十六进制字符但在这个例子中,%8C是有效的,所以可能不会报错。但实际测试中,可能遇到问题。
另一种方法是,将code参数的值作为字节流,其中包含已经编码的字符。例如,使用字节串,但需要确保正确编码。
或者,使用session的params参数,并设置dont_encode=True,但requests库不支持这个。
因此,正确的做法是,使用urllib.parse.quote对payload中的特殊字符进行编码,但保留%XX的部分不变。例如,可以使用一个自定义的编码函数,仅对非%XX的部分进行编码。
或者,将payload中的%替换为%25,这样当发送时,服务器会将其解码为%,然后后面的XX部分作为URL编码。例如,构造payload中的%8C为%258C,这样服务器收到后,解码为%8C,然后PHP的code参数的值就是~%8C%86...,此时PHP会将其解码为相应的字符。
例如,将payload中的每个%替换为%25:
payload = payload.replace('%', '%25')
这样,当发送到服务器时,服务器将%25解码为%,然后剩下的部分如%8C会被视为URL编码,解码为0x8C的字符。
理论很好,但是当进行的时候,还是无法绕过,放弃了。等大佬写绕过喽。