基於 Echo Shorthand Tags 的 PHP Webshell

駭客在入侵網站後, 通常都會放入網頁後門程式(Webshell), 用以確保控制權不容易因為弱點被修復而消失.

下方是常見的簡短 Webshell (一句話木馬)

<?php system($_GET[0]);

最近發現了另一種簡短的 Webshell, 利用了 PHP shorthand tag, 寫法如下

<?=`ls`;

其效果等價於

<?php echo system('ls');

很多管理員認為預設不開啟 short tags 就可以避開這種後門, 但事實並非如此

在 php.ini 中掌管 short tag 的參數為

short_open_tag = Off

官方對於 short_open_tag 的說明中有提到 <?= 並不包含其中, 因此在做後門探測的時候, 記得也要針對這類型的後門進行檢查

偉哉PHP

Laravel 常見問題: Specified key was too long

Laravel 在 5.4 版之後為了支援 emoji , 因此將資料編碼改為 utf8mb4. 由於 utf8mb4 的儲存空間需求膨脹了4倍, 導致預設長度無法正常寫入資料庫.

這個問題會在 MySQL 5.7.6 以下與 MariaDB 的環境中出現以下錯誤

[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

在 Migrate 過程中出現這個問題的解決方法有兩種

  1. 更新到 MySQL 5.7.7 以上版本
  2. 調整 Laravel 的預設資料長度

升級 MySQL 的方法就不細說了, 接下來主要說明調整 Laravel 預設值的方法

首先, 編輯專案目錄下的 app/Providers/AppServiceProvider.php

新增一個引用

use Illuminate\Support\Facades\Schema;

接著修改 boot function, 將預設長度定為 191

public function boot()
{
    Schema::defaultStringLength(191);
}

重新執行 php artisan migrate 就不會有問題了

最後附上完整的 AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Linux 設定修改時區

Linux 上時間分成兩個部分, Universal Time 與 Local Time, Universal Time 一直會維持為 UTC 時間, 而 Local Time 則是使用者所在的時區時間, 通常我們在安裝 Linux 的時候就會完成時區的設定, 但是在 Cloud 上預設都維持在 UTC +0 時區, 當我們機房跨足不同時區時可能會有同步的問題, 因此正確的設定時區是非常重要的.

檢查時區

當主機還沒有設定時區時, 輸入指令 date 系統返回的時間會是 UTC, 若主機已經有設定時區 UTC 會變成其他時區

$ date
Sat Jun 17 15:28:00 UTC 2017

設定時區

我們可以透過以下指令進行時區設定

sudo dpkg-reconfigure tzdata

系統會跳出視窗要求你選擇所在的地理區

接著選擇時區

當設定完成後, 系統會顯示目前的設定

Current default time zone: 'Asia/Taipei'
Local time is now:      Sat Jun 17 23:51:12 CST 2017.
Universal Time is now:  Sat Jun 17 15:51:12 UTC 2017.

指令 date 所顯示的時間變成帶有時區的時間了!

Sat Jun 17 23:51:55 CST 2017

這樣一來就完成時區的設定了, 若要修改時區只要把上面的步驟在做一次就可以了.

Electron – Cannot find module ‘app’

最近將舊版的 electron 升級到最新版, 結果所有程式都不能啟動了, 全部回傳 Error: Cannot find module 'app', 在翻閱新版手冊發找到了解決辦法

問題

升級到新版 Electron 出現 Error: Cannot find module 'app'

成因

Electron 新版將 app 模組整合到 electron 內

解決辦法

舊版手冊的範例寫法如下

var app = require('app');
var BrowserWindow = require('browser-window'); 

由於 app 被整合到 electron 內了, 因此只要改寫成下方的寫法就可以正常運作了

var electron = require('electron');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;

Electron – Uncaught ReferenceError: $ is not defined

最近因為需要將新的 Web App 封裝成應用程式, 團隊決定使用 Github Electron 進行封裝, 但封裝後的程式無法運作, 本來以為是 VUE 造成的, 直到在 Console 看到了 Uncaught ReferenceError: $ is not defined 才確定是 jQuery 造成的, 但說也奇怪, VUE 正常而 jQuery 卻沒辦法註冊, 粗略看起來應該不是 js 沒有載入的問題, 經過幾番研究後確定了問題成因, 這邊做一個小筆記紀錄一下.

問題

Electron 出現 Uncaught ReferenceError: $ is not defined 錯誤

成因

Electron 的 Render 使用了 Nodejs, 並且掛入 require 到全域變數, 導致 jQuery 註冊的 $ 被覆蓋了

解決辦法

jQuery 實際上是有正確被載入的, 因此我們只需要透過下面的方法重新註冊 $ 就可以了

try {$ = jQuery = module.exports;} catch(e) {}

如此一來, jQuery 重新綁定回 $, 系統就可以正常運作了

Apache .htaccess 沒有效果

我們知道在 Apache 中可以使用 .htaccess 來針對當下目錄做相關設定, 但時常發生 .htaccess 無效的狀況, 這邊分享一下一些常見的原因與排除方法

沒有複寫權限

Apache 根目錄預設是禁止複寫設定的, 可以透過編輯 httpd.conf 當中的設定開啟複寫功能

編輯 httpd.conf

sudo vim /etc/apache/httpd.conf

找到相關目錄設定(這邊以內建路徑為例)

<Directory "/Library/WebServer/Documents">
    Options FollowSymLinks Multiviews
    MultiviewsMatch Any

        AllowOverride None

        Require all granted
</Directory>

將 AllowOverride 修改為 All

<Directory "/Library/WebServer/Documents">
    Options FollowSymLinks Multiviews
    MultiviewsMatch Any

        AllowOverride All

        Require all granted
</Directory>

重新啟動 Apache 即可

檔案名稱錯誤

Apache 可以修改 .htaccess 的名稱, 可能因為某些原因名稱被修改了
可以尋找設定檔中的參數 AccessFileName 來確認正確名稱

模組無效

很多時候其實 .htaccess 有生效, 只是是因為 .htaccess 中有進行模組是否存在的相關檢查, 以至於我們以為沒有生效

.htaccess 可能有類似的內容

<IfModule mod_rewrite.c>
    .......
</IfModule>

上述的 .htaccess 會檢查 Apache 是否有 rewrite 這個模組, 若有才執行, 這種狀況變成要啟動該模組才會正常運行

編輯 httpd.conf, 找到下面的內容並將前方的 # 移除

#LoadModule rewrite_module libexec/apache2/mod_rewrite.so

將 MAC 內建的 PHP 5.6 升級到 PHP 7

在 MAC 上進行開發時使用的是 MAC 內建 PHP 5.6, 但 PHP 7 實在是很好用, 決定把 MAC 的 PHP 5.6 升級成 PHP 7, Mac 上要升級到 PHP 7非常簡單, 國外已經有人提供編譯好的版本與安裝腳本, 使用起來非常容易

相關資料

官方網站 php-macosx

安裝 PHP 7

選擇一個想要安裝的 PHP 版本, 目前支援 PHP 7.0 與 PHP 7.1

選擇 PHP 7.0

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.0

選擇 PHP 7.1

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.1

測試結果

接著寫入一個 phpinfo

<?php phpinfo();

看到下面這個畫面就代表我們成功升級為 PHP 7 了!

調整 Apache 設定

由於 MAC 預設使用 PHP 5, MAC 內建的 Apache 的 PHP 解釋器預設是連結到 libphp5.so, 當安裝新的 PHP 7 之後會產生衝突, 因此我們必須關閉舊版的模組, Apache 才能正常運作

關閉 PHP 5 模組

編輯 httpd.conf

sudo vim /etc/apache2/httpd.conf

找到原先的 libphp5.so 模組

LoadModule php5_module libexec/apache2/libphp5.so

在前面加上 # 將其註解

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

Laravel 電話長度與選填欄位的實作筆記

最近在處理計畫的網站, 計畫的網站當中有一個選填電話的欄位, 在使用 Laravel 內建 Validation 進行長度檢查時意外踩到坑, 仔細查閱手冊後才發現 Max, Min 的行為與心中所有有所差距, 因此做個筆記避免往後夥伴踩到一樣的坑

Laravel 的 Validation 非常強大, 若要讓欄位選填並且只有在有填寫內容時才進行其他驗證, 可以使用內建的 nullable 達到效果, 而不需要使用 required

$rules = [ 'phone'=>'nullable' ];

針對數字的部分可以用 numeric 來達到驗證

$rules = [ 'phone'=>'nullable|numeric' ];

在長度檢查的部分我一開始是用了 min 與 max 來檢查, 結果無論如何都會觸發長度過長的錯誤, 仔細看過手冊後發現 Laravel 會去猜輸入的型別, 如果猜測結果是數字則 min, max 會變成比大小(min < x < max) 而不是預期的長度檢查, 正確長度檢查要使用 digits_between 這個規則才對

$rules = [ 'phone'=>'nullable|numeric|digits_between:10,12' ];

調整 Mysql/MariaDB Table 名稱大小寫不敏感

MySQL 與 MaraiDB 預設對於 table 的名稱是大小寫敏感的, 也就是 case sensitive, 但最近遇到客戶要求要將表名稱設定為大小寫不敏感, 設定上十分容易, 步驟如下

注意: 請先檢查是否有任何 Table 名稱在改為小寫後會重複的 Table, 若發生衝突 MySQL 會崩潰

編輯 MySQL/MariaDB 設定檔(不同作業系統可能會在不同目錄)

sudo vim /etc/mysql/my.cnf

找到 [mysqld] 這個 section 下方加入

lower_case_table_names = 1

接著重新啟動 MySQL/MariaDB 即可

sudo service mysql restart

不用懶人包在 MAC 上安裝 Apache, PHP, MySQL

當我們需要在 Mac 下進行網站開發時, 時常會用到 Apache, PHP, MySQL (AMP) 組合, 在 Windows 下常見的懶人包有 XAMPP, Appserv…等, 雖然 Mac 也有懶人包像是 MAMP, 但實際上 MAC 已經內建了 Apache 與 PHP , 並不需要用到懶人包, 我們只需要設定一下就可以啟動他們.

提醒

由於許多操作涉及管理員權限, 因此指令都有加上 sudo, 過程中如有詢問密碼若無特別說明則為您的 mac 使用者密碼

啟動 Apache

啟動內建的 Apache

sudo apachectl start

當我們啟動 Apache 後, 便可以訪問一下 http://127.0.0.1 檢查一下是否有正常運作

如果畫面上出現 It Works 就代表我們成功啟動 Apache 了!

整合 PHP

由於 Mac 已經內建 PHP 模組, 我們只要在 Apache 中將他啟用就可以了

使用編輯器編輯 Apache 設定檔

/etc/apache/httpd.conf

找到下面這行將前面的 # 刪除

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

步驟做完了, 當然要驗證一下 PHP 是否有如期運作, 透過下面指令建立一個測試用的 php 檔案

echo "<?php phpinfo();" | sudo tee /Library/WebServer/Documents/info.php

接著我們就可以瀏覽 http://127.0.0.1/info.php 檢查一下結果

如果出現如上圖的畫面就代表 PHP 已經正常啟動了!(PHP Info 可能會因為版本不同而有些微差異)

安裝 MySQL

由於 Mac 並沒有內建 MySQL, 因此我們需要自己從官方網站下載來安裝
https://dev.mysql.com/downloads/mysql/

使用 DMG 封裝的版本進行安裝

點選下載後會出現要你登入的頁面, 但其實可以直接點選下面的 No thanks, just start my download. 直接進行下載

安裝過程的最後一步會跳出一個臨時密碼的視窗, 我們要記住這個密碼, 後續設定會用到

接著打開 Mac 的系統設定, 左下角會多出一個 MySQL 的選項, 點開 MySQL 進行設定

剛安裝完成 MySQL 並不會啟動, 我們需要手動點選 Start MySQL Server(爾後電腦重開會自動啟動)

當狀態轉變為 running 就代表啟動成功

啟動 Mysql 後, 接著要修改 root 密碼

/usr/local/mysql/bin/mysqladmin -uroot -p password '新的密碼'

指令執行期間會提示輸入 root 密碼, 這時候要輸入的密碼是安裝完成後出現的那組臨時密碼

這樣 Apache + PHP + MySQL (AMP) 的開發環境就建立完成啦!

工作目錄權限調整

Mac 的 Apache 預設工作目錄為

/Library/WebServer/Documents/

由於預設的擁有者是 root, 這會導致我們無法直接寫入檔案, 可以透過以下指令將所有權變成你的

sudo chown -R 你的mac使用者 /Library/WebServer/Documents/