vhost context phpIniOverride not being enforced

#1
Was last working and tested in openlitespeed in 2022-05-28 and lsphp74 7.4.29

In current one 1.7.16(build 1 or 2) which fixes the CVE's it looks like now the vhost context php phpIniOverride stuff is ignored and it just allows whatever the global php.ini doesn't have disabled.

Not sure is this is related to some side effects of the "fixes" silently slipped into OpenLitespeed "1.7.16" as "1.7.16.1" https://thehackernews.com/2022/11/multiple-high-severity-flaw-affect.html?m=1


basically we have hardened the stack and it should NOT allow the phpinfo function which can be seen as disabled in Local but not in Master but it clearly works which is nuts...... Cause it would appear at first glance it is disabled, but its not when you check for functions that should be clearly disabled.
Screenshot from 2022-11-13 18-31-28.png


Also like shell_exec should be disabled but its not either. this pretty much means the local overrides are not working which is a huge deal as this was extensively tested before and I was very pleased about how well it worked as it did not allow user to override the vhost based phpIniOverride via local file and bypass the settings. Now the settings appear fine in php.ini but are not being enforced and this is HUGE security risk. We never needed to put the same settings in the global php.ini version in addition to the vhost for stuff to work..

I also checked the last few versions of openlitespeed and the php.ini default shows same value of
```
disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
```

So its not like the defaults were more strict before and changed.

I tried digging through recent stuff on openlitespeed github for clues but not seeing anything immediately obvious not sure if this is an lsphp bug or openlitespeed...

According to this though it should be overriding the global one. Not being just ignored for whatever the global setting is.
https://openlitespeed.org/kb/change...ide_Global_phpini_through_virtual_host_config

All the common steps were done between testing to kill detached processes this is definitely a reproducible bug.

Setup a site with vhost config with those override settings:
```
phpIniOverride {
### Insert common phpIni
php_admin_flag engine on
php_admin_flag log_errors On
php_admin_value error_log logs/php_error_log
php_admin_value open_basedir "/var/www/testols.wizardassistant.com/html:/tmp/"
php_admin_value disable_functions "dl, exec, fpassthru, getmypid, getmyuid, highlight_file, link, opcache_get_configuration, passthru, pcntl_exec, pcntl_get_last_error, pcntl_setpriority, pcntl_strerror, pcntl_wifcontinued, phpinfo, popen, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, source, system, virtual"
php_admin_flag allow_url_fopen Off
php_admin_value session.use_strict_mode 1
php_admin_value session.cookie_httponly 1
php_admin_value session.use_cookies 1
php_admin_value session.use_only_cookies 1
php_admin_value session.use_trans_sid 0
php_admin_value memory_limit 128M
php_admin_value post_max_size 25M
php_admin_value upload_max_filesize 25M
php_admin_value max_execution_time 7200
}

```

The above directives should disable phpinfo and shell_exec so you can easily confirm if it works if you can even see the phpinfo test page load after restarting lsws and killall -9 lsphp are done.



Full Example from the live site
vhconf.conf
```
docRoot $VH_ROOT/html
vhDomain $VH_DOMAIN
vhAliases www.$VH_DOMAIN
adminEmails admin@testols.wizardassistant.com
enableGzip 1
enableBr 1

errorlog $VH_ROOT/html/logs/$VH_NAME.error_log {
useServer 0
logLevel ERROR
rollingSize 10M
keepDays 35
compressArchive 1
}

accesslog $VH_ROOT/html/logs/$VH_NAME.access_log {
useServer 0
logFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i""
logHeaders 7
rollingSize 10M
keepDays 35
compressArchive 1
}

index {
useServer 0
indexFiles index.php, index.html
}

scripthandler {
add lsapi:lsphp74 php
}

expires {
enableExpires 1
}

phpIniOverride {
### Insert common phpIni
php_admin_flag engine on
php_admin_flag log_errors On
php_admin_value error_log logs/php_error_log
php_admin_value open_basedir "/var/www/testols.wizardassistant.com/html:/tmp/"
php_admin_value disable_functions "dl, exec, fpassthru, getmypid, getmyuid, highlight_file, link, opcache_get_configuration, passthru, pcntl_exec, pcntl_get_last_error, pcntl_setpriority, pcntl_strerror, pcntl_wifcontinued, phpinfo, popen, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, source, system, virtual"
php_admin_flag allow_url_fopen Off
php_admin_value session.use_strict_mode 1
php_admin_value session.cookie_httponly 1
php_admin_value session.use_cookies 1
php_admin_value session.use_only_cookies 1
php_admin_value session.use_trans_sid 0
php_admin_value memory_limit 128M
php_admin_value post_max_size 25M
php_admin_value upload_max_filesize 25M
php_admin_value max_execution_time 7200
}

accessControl {
allow *
}

realm Default {
note Default password protected realm

userDB {
location $SERVER_ROOT/conf/vhosts/$VH_NAME/htpasswd
}

groupDB {
location $SERVER_ROOT/conf/vhosts/$VH_NAME/htgroup
}
}
bubbleWrap 1

extprocessor lsphp74 {
type lsapi
address uds://tmp/lshttpd/$VH_NAME.sock
maxConns 35
env PHP_LSAPI_MAX_REQUESTS=5000
env PHP_LSAPI_CHILDREN=35
env PHP_INI_SCAN_DIR=:$VH_ROOT/html
initTimeout 600
retryTimeout 0
persistConn 1
respBuffer 0
autoStart 1
path /usr/local/lsws/lsphp74/bin/lsphp
backlog 100
instances 1
runOnStartUp 1
priority 0
memSoftLimit 2047M
memHardLimit 2047M
procSoftLimit 400
procHardLimit 500
}

context exp:error_log|wp-config-sample.php|\.pl|\.cgi|\.lua|\.perl|\.sql|\.sh|wp-config.php|php.ini|\.log {
location $DOC_ROOT/$0
allowBrowse 0
note Block access to scripts and files we don't want executed

rewrite {

}
addDefaultCharset off

phpIniOverride {

}
}

context /logs/ {
location logs/
allowBrowse 0
note Deny public access to logs directory

rewrite {

}
addDefaultCharset off

phpIniOverride {

}
}

context / {
allowBrowse 1
note Default Context Headers
extraHeaders <<<END_extraHeaders
# Headers go below this line
X-XSS-Protection "1; mode=block" always;
X-Frame-Options "SAMEORIGIN";
Referrer-Policy no-referrer, strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# Headers go above this line
END_extraHeaders


rewrite {
enable 1
}

addDefaultCharset off

phpIniOverride {

}
}

rewrite {
enable 1
autoLoadHtaccess 1
logLevel 0
RewriteRule ^/wp-content/uploads/.*\.php$ - [F]
RewriteRule ^/wp-content/files/.*\.php$ - [F]
RewriteRule ^/wp-content/updraft/.*$ - [F,L]
RewriteRule "(^|/)\.(?!well-known\/)" - [F]
}

vhssl {
keyFile /etc/letsencrypt/live/$VH_NAME/privkey.pem
certFile /etc/letsencrypt/live/$VH_NAME/fullchain.pem
certChain 1
ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
enableECDHE 1
renegProtection 1
sslSessionCache 1
enableSpdy 15
enableQuic 1
enableStapling 1
ocspRespMaxAge 86400
}

```

Please fix and let us know when it is fixed so we can update ASAP....
 
Last edited:

Cold-Egg

Administrator
#2
Hi,
May I know if it works if you downgrade to the previous version v1.7.15?
Code:
/usr/local/lsws/admin/misc/lsup.sh -v 1.7.15
I saw you have a "PHP_INI_SCAN_DIR " setup. I put the 'disable_functions = "phpinfo"' in the document root's php.ini file and it works in my test env, does it work in your server?
 
#3
I just tried this.

Downgraded to v 1.7.15. Saw the same behavior - the site-specific (local) vhconf.conf directives do not work for phpIniOverride disable_functions.

But if using the php.ini in the PHP_INI_SCAN_DIR then it works.

Removing the PHP_INI_SCAN_DIR directive still does not allow the site-specific (local ) vhconf.conf directive to work.

Curious if you can make it work in the site-specific (local) vhconf.conf file.
 
Last edited:
#4
@Cold-Egg - is there anything I can do to get someone from the OLS team to take a closer look at this behavior asap?

I don't believe that this behavior matches the documentation (which says that php directives in the local vhconf.conf file should work).

But the real urgency is that it also leaves a possible security hole since folks likely expect that security related directives (such as the disable_functions directive ) in the local/site vhconf.conf file will work.
 
#5
@Cold-Egg

really starting to feel bad about recommending ols and lsws to people if this is the kinda vague delayed stuff I should expect

how much should we bet this probably affects litespeed Enterprise as well?

I guess I should go check all mine and clients with Enterprise litespeed too.

this is crazy big to silently break and then not address mission critical security features that worked previously.
 

Cold-Egg

Administrator
#6
HI @meramsey and @forumblues, thanks for pointing out the issue.
I have discussed this internally to check the issue. And it turns out the change has nothing to do with the web server but the PHP engine, some configs may not support the override. Once I confirmed all the parameters, will update the document.
 
#7
Hey @Cold-Egg - just wanted to check in to see if there was any progress on this. I assume when you say 'php engine' you mean lsphpxx and not the PHP language itself? If so, would be nice to get a timeline on a fix or a confirmation that it's not going to be fixed.

Or maybe there is there someone better at lightspeedtech that we should try to escalate this to since I'm aware that this might not be within your purview in this forum?

Thanks.
 
#8
HI

So, I tried to find out what the issue is by launching an old image that has old LSPHP with Server API 7.9 and OLS v1.7.14, but the test result is the same(phpinfo is still loadable if you want to override it from the virtual host config). It seems nothing changed from my test.

Also, https://www.php.net/manual/en/ini.core.php#ini.disable-functions mentioned,
disable_functions string
This directive allows you to disable certain functions. It takes on a comma-delimited list of function names.

Only internal functions can be disabled using this directive. User-defined functions are unaffected.

This directive must be set in php.ini For example, you cannot set this in httpd.conf.
 
#9
OLS shows the changes but doesn’t implement it
For context inf.php contains
Code:
<?php
phpinfo()
?>
Extest.php contains
Code:
<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>
Adding the following to vhconf directly or inside context /
Code:
phpIniOverride  {
  php_admin_value disable_functions= "dl, exec, fpassthru, getmypid, getmyuid, highlight_file, link, opcache_get_configuration, passthru, pcntl_exec, pcntl_get_last_error, pcntl_setpriority, pcntl_strerror, pcntl_wifcontinued, popen, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, source, system, virtual"
php_admin_flag allow_url_fopen Off
php_admin_flag allow_url_include Off
}
This results in these being shown correctly
1669322027134.png

However, the shell_exec function still works ????
1669322044675.png

However, on the Nginx end if we add the following to the site’s pool file it overrides both local and default (it’s isolated, even a site with the same PHP version doesn’t get its default values changed )
Code:
php_admin_value[disable_functions] = dl, exec, fpassthru, getmypid, getmyuid, highlight_file, link, opcache_get_configuration, passthru, pcntl_exec, pcntl_get_last_error, pcntl_setpriority, pcntl_strerror, pcntl_wifcontinued, popen, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, source, system, virtual

The phpinfo
1669322063017.png
and the result
1669322077238.png

Still would like to know why the reason this stopped working. The above clearly shows that its not PHP issue, its only your PHP’s issue

Reference material if you want to also deep dive:
https://openlitespeed.org/kb/change...ocal_phpini_through_Virtual_Host_external_app
https://openlitespeed.org/kb/setup-per-directory-file-php/
https://openlitespeed.org/kb/change-php-settings-by-vhost-and-user/

Litespeeds has some more detail but its pretty much equivalent for both in how they work from what I found
https://docs.litespeedtech.com/lsws/cp/cpanel/php-user-ini/#per-domain-phpini
https://www.litespeedtech.com/support/wiki/doku.php/litespeed_wiki:php:per-user-php-ini
 
Last edited:
#10
Hi,

As the PHP document states, it must be set in php.ini, and it indeed works with OpenLiteSpeed. We cannot override via the php_admin_value, and even if the local value is changed, PHP won't do anything. It is the way how PHP engine works.

The PHP-FPM pool setting is equivalent to setting it in php.ini, that's why it works in your test with Nginx.
 
#11
If it isn’t supposed to work at all, phpinfo shouldn’t be showing incorrect info

Secondly I tried it with fastcgi params instead of pool file to confim

Code:
fastcgi_param PHP_VALUE "disable_functions=dl, exec, fpassthru, getmypid, getmyuid, highlight_file, link, opcache_get_configuration, passthru, pcntl_exec, pcntl_get_last_error, pcntl_setpriority, pcntl_strerror, pcntl_wifcontinued, popen, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, show_source, source, system, virtual";
this works perfectly fine
 
Top