ISPConfig 多 PHP 版本環境下應對 CVE-2026-115560 漏洞:全域修復與服務重啟實戰

在現今複雜的網頁寄存環境中,主機控制面板通常需要同時支援多個不同的 PHP 版本(從舊版的 PHP 5.4、5.6 到現代的 PHP 7.x、8.x),以滿足不同客戶或網站系統的相容性需求。然而,當突發重大安全漏洞(如針對 session.upload_progress 的 CVE-2026-115560 遠端程式碼執行漏洞)降臨孤立或多版本並存的伺服器時,管理員如何在不破壞多 PHP 架構的前提下進行一次性全域快速止血,就成為了一門重要的技術課題。

本文將以實際在 ISPConfig 伺服器上的防護經驗為例,分享如何利用 Shell Script 精準修復多版本 php.ini 並安全重啟服務。

一、 挑戰所在:ISPConfig 多 PHP 架構的配置特點

以採用 Remi 套件庫並透過 ISPConfig 管理多 PHP 版本的 Linux 伺服器為例:

  • 路徑分散:系統中往往同時存在多個獨立的 PHP 運行環境,其設定檔並非集中在單一的 /etc/php/ 目錄,而是散落于 /opt/remi/、/etc/opt/remi/ 或 /etc/ 等自訂路徑中。
  • 版本眾多:從 PHP 5.4 一直到 PHP 8.3 共存,若手動逐一打開每個版本的 php.ini 進行修改,不僅耗時費力,還極容易遺漏高風險版本。

二、 實戰演練:一次性全域修改 php.ini

為了精準切斷 CVE-2026-115560 的漏洞觸發路徑(即關閉 session.upload_progress.enabled 且不影響正常的檔案上傳功能),我們不需要「一刀切」禁止所有上載,而是可以直接在伺服器端執行一段迴圈腳本,自動掃描並更新所有版本的 php.ini。

1. 執行自動掃描與批次修改指令

透過以下 Shell 命令,系統會自動在 /opt/、/etc/ 及 /usr/local/ 中尋找所有的 php.ini 檔案:

  • 若檔案中已存在該參數,則自動將其設定為 0;
  • 若不存在,則在檔案結尾自動追加 session.upload_progress.enabled = 0。

Bash

for ini in $(find /opt/ /etc/ /usr/local/ -type f -name "php.ini" 2>/dev/null); do
    if grep -q "session.upload_progress.enabled" "$ini"; then
        sed -i 's/^[# \t]*session\.upload_progress\.enabled\s*=.*/session.upload_progress.enabled = 0/' "$ini"
    else
        echo "session.upload_progress.enabled = 0" >> "$ini"
    fi
    echo "已更新: $ini"
done

執行後,終端機會清晰列出所有被成功加固的 php.ini 路徑,確保無一遺漏。

三、 批次重啟 PHP-FPM 與網頁伺服器

設定檔修改完成後,必須重啟對應的 PHP-FPM 服務與網頁伺服器(以 Apache / httpd 為例),才能使全域修改正式生效。

1. 迴圈重啟各版本 PHP-FPM 服務

Bash

for s in php54-php-fpm php56-php-fpm php70-php-fpm php72-php-fpm php73-php-fpm php74-php-fpm php81-php-fpm php83-php-fpm; do
    systemctl restart $s 2>/dev/null
    echo "已重啟: $s"
done

2. 重啟網頁伺服器

Bash

systemctl restart httpd

四、 總結與防護建議

透過這套自動化處理方案,系統管理員能在短短數分鐘內完成整台 ISPConfig 多 PHP 版本伺服器的漏洞防護加固:

  1. 精準 surgical 級別防禦:關閉 session.upload_progress.enabled 有效阻斷了 RCE 攻擊途徑。
  2. 業務零中斷:完整保留了網站正常的檔案上傳與互動功能,避免粗暴禁止上傳所帶來的業務癱瘓。
  3. 高效維運:利用 Shell 迴圈完美解決了多版本、分散式路徑的管理難題。

建議各位主機維護團隊在面對新型自動化攻擊浪潮時,優先採用這類結構化、自動化的指令碼來提升應變效率,保障伺服器的絕對安全。

How to test a POP server by using telnet

Source : http://www.anta.net/misc/telnet-trouble … /pop.shtml

How to test a POP server by using telnet

What you need

The host name of the POP server (for use in the telnet command)
The POP user name (for use in the USER command)
The user’s POP password (for use in the PASS command)

Encryption

For added security, you can encrypt your POP connection. This requires that your server supports SSL or TLS and that you have access to an SSL/TLS client program, for example OpenSSL, to use instead of telnet.

As the port number normally is 995, an example OpenSSL command would be openssl s_client -connect pop.example.com:995 -quiet. (If you would like to see the public key of the server, as well as some other encryption-related information, omit -quiet.) The server should then start a POP session, displaying a greeting such as the +OK InterMail POP3 server ready example below.

What to do

The DELE command flags messages for deletion. Use it only if you want to delete mail.

The initial telnet: > symbolises your shell prompt.

telnet: > telnet pop.example.com pop3
telnet: Trying 192.0.2.2...
telnet: Connected to pop.example.com.
telnet: Escape character is '^]'.
server: +OK InterMail POP3 server ready.
client: USER MyUsername
server: +OK please send PASS command
client: PASS MyPassword
server: +OK MyUsername is welcome here
client: LIST
server: +OK 1 messages
server: 1 1801
server: .
client: RETR 1
server: +OK 1801 octets
server: Return-Path: sender@example.com
server: Received: from client.example.com ([192.0.2.1])
server: by mx1.example.com with ESMTP
server: id <20040120203404.CCCC18555.mx1.example.com@client.example.com>
server: for <recipient@example.com>; Tue, 20 Jan 2004 22:34:24 +0200
server: From: sender@example.com
server: Subject: Test message
server: To: recipient@example.com
server: Message-Id: <20040120203404.CCCC18555.mx1.example.com@client.example.com>
server:
server: This is a test message.
server: .
client: DELE 1
server: +OK
client: quit
server: +OK MyUsername InterMail POP3 server signing off.

Dynamic DNS updates with nsupdate and BIND 9

Ref: Grig Gheorghiu(2012), http://agiletesting.blogspot.hk/2012/03 … e-and.html

I first saw nsupdate mentioned on the devops-toolchain mailing list as a tool for dynamically updating DNS zone files from the command line. Since this definitely beats manual editing of zone files, I’d thought I’d give it a try. My setup is BIND 9 on Ubuntu 10.04. I won’t go into the details of setting up BIND 9 on Ubuntu — see a good article about this here.

It took me a while to get nsupdate to work. There are lots of resources out there, but as usual it’s hard to separate the grain from the chaff. When everything was said and done, the solution was relatively simple. Here it is.

Generate TSIG keys

# dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 512 -n HOST myzone.com

This generates 2 files of the form:

-rw——- 1 root bind 122 2012-03-21 15:47 Kmyzone.com.+157+02058.key
-rw——- 1 root bind 229 2012-03-21 15:47 Kmyzone.com.+157+02058.private

Note that I specified /dev/urandom as the source of randomness, which may not meet your security requirements. When I didn’t specify the -r /dev/urandom parameter, the dnssec-keygen command appeared to hang.

Also note that the type of the key needs to be HOST (specified via -n HOST).

Add key to DNS master server configuration and allow updates

I modified /etc/bind/named.conf.local and added a ‘key’ section:

key “myzone.com.” {
algorithm hmac-md5;
secret “JKlA76FvmGboEQ8R2yoc9AtpFqkIncH5yf2mXY+s8m6a/RRC0thUVGnqrJSO1QKhzlnkbxTjmArap+WuVW9iLQ==”;
};

The key name can be anything you want. The secret is the actual key, which can be found in both of the files generated by dnssec-keygen.

I also added an allow-update directive to the zone that I wanted to modify via nsupdate. This is still in /etc/bind/named.conf.local:

zone “myzone.com” {

type master;
file “/var/lib/bind/myzone.com.db”;
allow-update { key “myzone.com.”; };
};

I then restarted bind9 on the master DNS server via ‘service bind9 restart’. I checked /var/log/daemon.log to make sure there were no errors during the restart.

Note that you can use a more finely grained control over which operations you allow for the updates. See the ‘Allowing Updates’ section in this ‘Secure DDNS Howto’ document.

Use nsupdate to do remote updates

On a remote trusted host of your choice, copy the private file generated by dnssec-keygen, and create a file containing the desired updates to the zone file on the master. This file is of the form:

# cat nsupdate.txt
server master.dns.server.myzone.com
debug yes
zone myzone.com.
update add testnsupdate.myzone.com. 86400 CNAME ns1
show
send

Then run nsupdate and specify the kddey and the file you just created:

# nsupdate -k Kmyzone.com.+157+02058.private -v nsupdate.txt

If everything goes well, you should see something like this in the debug output of nsupdate (because we specified ‘debug yes’ in the nsupdate.txt file):

;; UPDATE SECTION:

testnsupdate.myzone.com. 86400 IN CNAME ns1

;; TSIG PSEUDOSECTION:

myzone.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1332788750 300 16 UxiMG7+X2RejWzQ9rkuPaQ== 3305 NOERROR 0

Reply from update query:

;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 3305

;; flags: qr ra ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1

;; TSIG PSEUDOSECTION:

myzone.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1332788857 300 16 KBubhEggwBHnPlbmlQ7iTw== 3305 NOERROR 0

On the master DNS server, you should see something like this in /var/log/daemon.log:

Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.133#58265: signer “myzone.com” approved

Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.133#58265: updating zone ‘myzone.com/IN’: adding an RR at ‘testnsupdate.myzone.com’ CNAME

Mar 26 12:07:37 dns01 named[14952]: zone myzone.com/IN: sending notifies (serial 2012032104)

Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.121#50790: transfer of ‘myzone.com/IN’: IXFR started

Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.121#50790: transfer of ‘myzone.com/IN’: IXFR ended

One other important note: the modifications made with nsupdate take effect immediately on the DNS master server (and they also get pushed from there to slave servers), but they are not written immediately to the actual DNS zone file on disk on the master server. Instead, a journal file is used, in the same directory as the zone file. The journal entries get applied periodically to the main zone file. If you restart bind9, the journal entries also get applied.

That’s about it. If everything went well, you now have an API of sorts into your Bind 9 server. Now go automate all the things!