워드프레스 테마, 플러그인 등 워드프레스 전반에 걸쳐 취약점을 스캐닝할 수 있는 워드프레스 보안진단 툴인 WPScan 사용법을 정리해 보고, 이 스캔 결과를 이메일로 받아 볼 수 있는 방법에 대해 살펴봅니다.
워드프레스는 전 세계 CMS 사이트의 30%이상을 차지하는 가장 널리 사용되는 CMS 중 하나입니다. 그렇게 많이 사용하는만큼 해킹에 대한 시도가 끊이지 않는데요.
워드프레스 테마, 플러그인 그리고 워드프레스 코어 파일등이 멀웨어 감염되어 있는지 업데이트가 제대로 되어 있지 않은지 등을 워드프레스 보안 진단 툴인 WPScan으로 검사해 볼 수 있습니다.
여기서는 WPScan을 설치하고, 간단한 사용법을 토대로 정기적으로 워드프레스 취약점을 스캐닝하고 이 결과를 메일로 받아볼 수 있도록 만들어 보도록 하겠습니다.
WPScan이란
WPScan은 2011년 보안 전문가와 워드프레스 블로그 관리자들이 모여서 워드프레스 보안 취약성 데이타베이스를 구축하면서 시작했습니다.
WPScan는 워드프레스 취약점 데이타베이스를 API를 받아와 웓프레스 사이트를 스캐닝하면서 아래와 같은 사항을 점검합니다.
- 워드프레스 설치 버젼 체크 및 관련 취약성 점검
- 설치 플러그인 및 취약성 점검
- 설치 테마 및 취약성 점검
- 워드프레스 사용자 리스트
- 워드프레스 사용자중 암호화가 약한 암호를 가진 사용자 점검
- 백업 및 공개 액세스 가능한 파일이 있는지 점검
wp-config.php 파일 포함 - 공개 액세스 가능한 데이터베이스가 있는지 점검
- 워드프레스 플러그인으로 인한 오류 로그 노출 여부.
- 미디어 파일 리스트
- 취약한 Timthumb 파일 여부
- 워드프레스 readme 파일 존재 여부
- WP-Cron 활성화 여부
- 사용자 등록 활성화 여부
- 워드프레스 전체 경로
- 디렉터리 목록
WPScan 사용법에 대해서는 아래 사용자 매뉴얼을 참조해 보시기 바랍니다.
WPScan 설치
워드프레스에서 WPScan을 사용하는 방법은 가장 간단한 방법은 WPScan 플러그인을 사용하는 방업입니다.
WPScan – WordPress Security Scanner
아마 쟁쟁한 워드프레스 보안 플러그인들이 많기 때문에 WPScan 플러그인 사용자는 그리 많지는 않습니다.
워드프레스 테마, 플러그인 등 위약점 진단은 워드프레스 보안 플러그인의 여러 분야 중 하나이기 때문에 대부분 워드프레스 보안 플러그인에서 제공하고 있는 기능이기도 하기 때문입니다.
그러나 저는 플러그인보다는 서버에서 직접 스캐닝하는 것을 원하고, 더우기 서버에서 스캐닝 시 여러 개의 워드프레스 사이트를 동시에 스캐닝할 수 있기 때문에 서버에서 사용하려고 합니다.
우분투에서 WPScan 설치
우선 우분투 서버를 업데이트하고 WPScan 설치 및 운영에 필요한 제반 프로그램을 설치합니다.
sudo apt update
sudo apt install curl git libcurl4-openssl-dev make zlib1g-dev gawk g++ gcc libreadline6-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 autoconf libgdbm-dev libncurses5-dev automake libtool bison pkg-config ruby ruby-bundler ruby-dev -y libsqlite3-dev sqlite3 autoconf libgdbm-dev libncurses5-dev automake libtool bison pkg-config ruby ruby-bundler ruby-dev -y
Code language: PHP (php)
이제 WPScan을 설치합니다. WPScan은 Ruby로 작성되었기 때문에 Ruby의 gem 설치기를 사용합니다.
gem install wpscan
Code language: PHP (php)
CentOS 8/RHEL 8/Fedora에서 설치
먼저 ruby를 설치합니다.
sudo dnf install ruby
Code language: PHP (php)
WPScan 설치 및 운영에 필요한 제반 프로그램을 설치합니다.
sudo dnf group install "Development Tools"
sudo dnf install git gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel patch rpm-build
Code language: PHP (php)
WPScan을 설치합니다.
sudo gem install wpscan
Code language: PHP (php)
WPScan 사용법
먼저 데이타베이스를 업데이트합니다.
wpscan --update
Code language: PHP (php)
이러면 아래와 같은 메세지를 볼 수 있습니다.
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.2
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] Updating the Database ...
[i] Update completed.
Code language: PHP (php)
이 상태에서 바로 사이트 점검을 할 수 있습니다. “–url=” 다음에 사이트 주소를 넣어 스캔토록 합니다.
wpscan --url=https://happist.com
Code language: PHP (php)
그러면 이런 화면을 볼 수 있습니다.
______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.2
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[+] URL: https://happist.com/ [141.164.48.62]
[+] Started: Mon Jun 29 06:38:26 2020
Interesting Finding(s):
[+] Headers
| Interesting Entries:
| - server: nginx
| - x-ua-compatible: IE=edge
| - referrer-policy: origin
| - content-security-policy: script-src 'self' 'unsafe-inline' inicis.com ; frame-ancestors 'self';
| - access-control-allow-origin: *
| - x-debug-whats-going-on: on
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] https://happist.com/robots.txt
| Interesting Entries:
| - /wp-login.php
| - /xmlrpc.php
| Found By: Robots Txt (Aggressive Detection)
| Confidence: 100%
[+] The external WP-Cron seems to be enabled: https://happist.com/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 5.4.2 identified (Latest, released on 2020-06-10).
| Found By: Rss Generator (Passive Detection)
| - https://happist.com/feed/, <generator>https://wordpress.org/?v=5.4.2</generator>
| - https://happist.com/comments/feed/, <generator>https://wordpress.org/?v=5.4.2</generator>
[+] WordPress theme in use: generatepress
| Location: https://happist.com/wp-content/themes/generatepress/
| Latest Version: 2.4.2 (up to date)
| Last Updated: 2020-03-17T00:00:00.000Z
| Style URL: https://happist.com/wp-content/themes/generatepress/style.css
| Style Name: GeneratePress
| Style URI: https://generatepress.com
| Description: GeneratePress is a lightweight WordPress theme built with a focus on speed and usability. Performanc...
| Author: Tom Usborne
| Author URI: https://tomusborne.com
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| Version: 2.4.2 (80% confidence)
| Found By: Style (Passive Detection)
| - https://happist.com/wp-content/themes/generatepress/style.css, Match: 'Version: 2.4.2'
[+] Enumerating All Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)
[i] Plugin(s) Identified:
[+] content-views-query-and-display-post-page
| Location: https://happist.com/wp-content/plugins/content-views-query-and-display-post-page/
| Latest Version: 2.3.2 (up to date)
| Last Updated: 2020-03-27T08:24:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| Version: 2.3.2 (20% confidence)
| Found By: Query Parameter (Passive Detection)
| - https://happist.com/wp-content/plugins/content-views-query-and-display-post-page/public/assets/css/cv.css?ver=2.3.2
| - https://happist.com/wp-content/plugins/content-views-query-and-display-post-page/public/assets/js/cv.js?ver=2.3.2
[+] embed-any-document-plus
| Location: https://happist.com/wp-content/plugins/embed-any-document-plus/
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] gp-premium
| Location: https://happist.com/wp-content/plugins/gp-premium/
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] lazy-loading-responsive-images
| Location: https://happist.com/wp-content/plugins/lazy-loading-responsive-images/
| Latest Version: 6.0.1
| Last Updated: 2020-05-01T15:42:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] otter-blocks
| Location: https://happist.com/wp-content/plugins/otter-blocks/
| Latest Version: 1.5.5
| Last Updated: 2020-06-22T22:22:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] pt-content-views-pro
| Location: https://happist.com/wp-content/plugins/pt-content-views-pro/
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] sassy-social-share
| Location: https://happist.com/wp-content/plugins/sassy-social-share/
| Latest Version: 3.3.10 (up to date)
| Last Updated: 2020-05-14T06:16:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| Version: 3.3.10 (30% confidence)
| Found By: Query Parameter (Passive Detection)
| - https://happist.com/wp-content/plugins/sassy-social-share/public/css/sassy-social-share-public.css?ver=3.3.10
| - https://happist.com/wp-content/plugins/sassy-social-share/admin/css/sassy-social-share-svg.css?ver=3.3.10
| - https://happist.com/wp-content/plugins/sassy-social-share/public/js/sassy-social-share-public.js?ver=3.3.10
[+] searchwp-live-ajax-search
| Location: https://happist.com/wp-content/plugins/searchwp-live-ajax-search/
| Last Updated: 2020-04-23T12:09:00.000Z
| [!] The version is out of date, the latest version is 1.4.6.1
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| Version: 1.4.6 (10% confidence)
| Found By: Query Parameter (Passive Detection)
| - https://happist.com/wp-content/plugins/searchwp-live-ajax-search/assets/styles/style.css?ver=1.4.6
[+] stackable-ultimate-gutenberg-blocks-premium
| Location: https://happist.com/wp-content/plugins/stackable-ultimate-gutenberg-blocks-premium/
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| The version could not be determined.
[+] Enumerating Config Backups (via Passive and Aggressive Methods)
Checking Config Backups - Time: 00:00:01 <=============================> (21 / 21) 100.00% Time: 00:00:01
[i] No Config Backups Found.
[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up
[+] Finished: Mon Jun 29 06:38:47 2020
[+] Requests Done: 91
[+] Cached Requests: 7
[+] Data Sent: 17.227 KB
[+] Data Received: 792.266 KB
[+] Memory used: 188.879 MB
[+] Elapsed time: 00:00:20
Code language: PHP (php)
위 결과에 따르면 WP cron을 활성화되어 있어 60% 신뢰도를 보이고, sassy-social-share 플러그인는 업데이트가 필요하고, 30% 신뢰도를 보인다고 지적합니다.
저는 이 sassy-social-share 플러그인의 일부 파일을 수정해 한국 소셜 미디어를 추가했기 때문에 이런 지적이 나오는 것 같습니다.
단 주의할 점은 서버에서 사이트 주소를 리다이렉트했으면 리다이렉트한 주소를 입력해야 합니다.
워드프레스 요소별로 스캔하려면
워드프레스 전체가 아니라 요소별로 스캔하려면 아래와 같은 옵션을 사용합니다.
[Scan installed plugins]
wpscan --url https://happist.com --enumerate p
[Scan vulnerable plugins]
wpscan --url https://happist.com --enumerate vp
[Scan installed themes
wpscan --url https://happist.com --enumerate t
[Scan vulnerable themes]
wpscan --url https://happist.com --enumerate vt
[Scan user accounts:]
wpscan --url https://happist.com --enumerate u
[Scan vulnerable timthumb files:]
wpscan --url https://happist.com --enumerate tt
Code language: PHP (php)
WPVulnDB API 사용법
기본적으로 WPScan은 알려진 보안 취약성이 있는지 여부만 알려줍니다.
발견된 세부 취약점이 무엇인지를 알려면 WPVulnDB를 이용해야 합니다.
위에서 언급한대로 https://wpvulndb.com/users/sign_up에 등록하시면 일일 50건 요청이 가능한 무료 API 토큰을 받으실 수 있습니다.
여기서 계정을 등록 후 API 토큰을 발급받으면 아래와 같은 명령으로 WPScan 설정 파일에서 API 토큰을 등록할 수 있습니다.
nano ~/.wpscan/scan.yml
Code language: PHP (php)
이 설정 파일에서 아래 코드를 추가합니다.
cli_options:
api_token: 발급받은 API 토큰
Code language: PHP (php)
위에서도 설명했듯이 WPScan은 무료 및 비상업적 용도로 제공됩니다.
그러나 워드프레스 사이트 스캔 시 보다 자세한 취약점을 분석하려면 워드프레스 취약성 데이타베이스 API에 접속해서 보다 자세한 정보를 받아야 하는데요.
이 세부 취약성 데이타는 횟수에 따라서 과금하고 있습니다. 즉 하루 50회까지는 무료로 사용가능하며 그 이상 서비스를 원하는 경우 비용을 지불하는 시스템입니다. WPScan 팀 운영을 위해서는 어쩔 수 없는 일이 아닐까 합니다.
아마 사이트 보안을 위해 실시간으로 사이트를 점검한다면, 물론 이러려면 엄청난 시스템 자원이 필요하겠지만 점검 시간을 짧게 가져가려면 API 접속 횟수를 늘려야하기 때문에 유료 플랜 사용이 필요합니다.
수없이 등장하는 수많은 워드프레스 플러그인, 자주 업데이되는 워드프레스 코어 및 각종 테마들을 테스트하고 데이타베이스로 구축하는 것은 재능 기부로 해결할 수는 없을 듯합니다.
WPWatcher, 스캔 결과를 이메일로 받아보기
WPScan 결과를 이메일로 받아보려면 가장 간단하게는 위에서 설명한 워드프레스 플러그인을 설치하면 쉽습니다.
그러나 서버에서 작동시키는 것이 목적이기 때문에 우분투를 비롯한 리눅스 서버에서 메일로 보내줄 수 있는 방법이 필요합니다.
이러한 니즈를 잘 충족시키는 것이 바로 WPWatcher인데요. 여기서는 WPWatcher를 이용해서 이메일 송부 방법에 대해 살펴보도록 하겠습니다.
WPWatcher 설치 방법
WPWatcher를 설치, 사용하기 위해서는 당연히 WPScan이 필요하고, 파이썬 3가 필요합니다.
먼저 PyPi로 WPWatcher를 설치 및 업그레이드 합니다.
pip3 install wpwatcher
pip3 install wpwatcher --upgrade
Code language: PHP (php)
WPWatcher 설정
WPWatcher 설정을 위해서는 설정 파일을 복사해 옵니다.
wpwatcher --template_conf > ./wpwatcher.conf
Code language: PHP (php)
WPWatcher 설정 파일을 편집합니다.
nano ./wpwatcher.conf
Code language: PHP (php)
저는 아래와 같이 설정을 구성했습니다.
[wpwatcher]
wpscan_path=wpscan
wpscan_args=[ "--format", "json",
"--no-banner",
"--random-user-agent",
"--disable-tls-checks",
"--api-token", "API 토큰" ]
# Sites (--url or --urls)
wp_sites= [ {"url":"happist.com"}]
# Notifications
send_email_report=Yes
email_to=["받을 이메일 주소"]
send_infos=Yes
send_errors=Yes
send_warnings=Yes
attach_wpscan_output=Yes
resend_emails_after=1d
Code language: PHP (php)
# Email server settings
from_email=WordPressWatcher@happist.com
smtp_server=smtp.gmail.com:587
smtp_auth=Yes
smtp_user=email address
smtp_pass=password(gmail app password)
smtp_ssl=Yes
Code language: PHP (php)
# Sleep when API limit reached (--wait)
api_limit_wait=Yes
Code language: PHP (php)
제가 이전에 지메일을 활용한 메일 세팅에 대해 포스팅했는데요. 이를 참조하시면 좋을 것 같네요.
자동 수행을 위한 크론탭 설정
설정에 따라 일정 시간이 되면 자동으로 실행되도록 크론탭을 설정합니다.
crontab -e
Code language: PHP (php)
크론탭에 아래와 같은 명령을 추가합니다. WPWATCHER는 루트에서만 실행되기 때문에 먼저 cd 명령을 이용해 루트로 이동 후 wpwatcher를 실행토록 합니다.
40 3 * * * cd && wpwatcher --conf wpwatcher.conf --quiet
Code language: PHP (php)
원래 위와 같은 크롭탭 설정이 생각외로 작동하지 않아서 저는 조금 더 확실하게 스크립트 실행 파일(sh)을 만들어 작동하도록 만들었습니다.
cd /bin # /bin 폴더로 이동 장 확률이 높았기에.
nano wpwatcher.sh
Code language: PHP (php)
이 스크립트 파일에는 아래와 같은 내용을 추가합니다.
#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cd /root/
wpwatcher --conf wpwatcher.conf
Code language: PHP (php)
그리고 스크립트 파일이 실행 가능토록 만듭니다.
그 다음에는 이 파일에 권한을 부여합니다.
chmod +x wpwatcher.sh
Code language: PHP (php)
그 다음에는 크론에 이 파일 실행을 추가해야 겠죠?
이는 아시다시피 crontab -e 명령을 사용합니다.
crontab -e
Code language: PHP (php)
크랜탭에서 아래 내용을 추가해 줍니다. 매일 새벽 4시 40분과 오후 6시 35분에 정의한 wpwatcher.sh를 실행하라는 명령입니다.
40 04 * * * wpwatcher.sh
35 18 * * * wpwatcher.sh
Code language: PHP (php)
크론을 다시 시작합니다.
service cron restart
Code language: PHP (php)
크론이 제대로 작동하는지 한번 확인해 봅니다.
service cron status
Code language: PHP (php)
그러면 아래와 같이 크론이 active되고 있다고 나오면 OK입니다.
n# service cron status
● cron.service - Regular background program processing daemon
Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2020-07-12 13:12:24 KST; 7s ago
Docs: man:cron(8)
Main PID: 2732171 (cron)
Tasks: 1 (limit: 9451)
Memory: 384.0K
CGroup: /system.slice/cron.service
└─2732171 /usr/sbin/cron -f
Jul 12 13:12:24 fashionseoul.com systemd[1]: Started Regular background program processing daemon.
Jul 12 13:12:24 fashionseoul.com cron[2732171]: (CRON) INFO (pidfile fd = 3)
Jul 12 13:12:24 fashionseoul.com cron[2732171]: (CRON) INFO (Skipping @reboot
Code language: PHP (php)