diff --git a/formatify.py b/formatify.py index 5c46acc..14ce9a5 100644 --- a/formatify.py +++ b/formatify.py @@ -141,7 +141,8 @@ def _buildUI(self): dropdownPanel = JPanel(FlowLayout(FlowLayout.CENTER)) self._conversionOptions = JComboBox([ "JavaScript Fetch", - "cURL Command", + "cURL Command (Linux)", + "cURL Command (Windows)", "Python Requests", "Python aiohttp", "Node.js Axios", @@ -150,7 +151,9 @@ def _buildUI(self): "FFUF Command", "Java OkHttp", "CSRF Payload Builder", - "CORS Exploit PoC" + "CORS Exploit PoC", + "Clickjacking PoC", + "Postman Collection" ]) self._conversionOptions.setPreferredSize(Dimension(200, 30)) self._conversionOptions.setFont(Font("SansSerif", Font.PLAIN, 13)) @@ -403,8 +406,10 @@ def _process_conversion(self, request_str, conversion_type): if conversion_type == "JavaScript Fetch": result = self._to_javascript_fetch(method, url, headers, body) - elif conversion_type == "cURL Command": + elif conversion_type == "cURL Command (Linux)": result = self._to_curl(method, url, headers, body) + elif conversion_type == "cURL Command (Windows)": + result = self._to_curl_windows(method, url, headers, body) elif conversion_type == "Python Requests": result = self._to_python_requests(method, url, headers, body) elif conversion_type == "Python aiohttp": @@ -423,6 +428,10 @@ def _process_conversion(self, request_str, conversion_type): result = self._to_csrf_payload(method, url, headers, body) elif conversion_type == "CORS Exploit PoC": result = self._to_cors_exploit(method, url, headers, body) + elif conversion_type == "Clickjacking PoC": + result = self._to_clickjacking_poc(method, url, headers, body) + elif conversion_type == "Postman Collection": + result = self._to_postman_collection(method, url, headers, body) else: result = "Conversion type not implemented" @@ -444,9 +453,7 @@ def run(self): SwingUtilities.invokeLater(OutputUpdater(self, text)) def _to_javascript_fetch(self, method, url, headers, body): - """ - Convert to JavaScript Fetch API - """ + """Convert to JavaScript Fetch API.""" headers_str = ",\n ".join(['"' + k + '": "' + v.replace('"', '\\"') + '"' for k, v in headers.items()]) content_type = headers.get("Content-Type", "") @@ -479,9 +486,7 @@ def _to_javascript_fetch(self, method, url, headers, body): return fetch_code def _to_curl(self, method, url, headers, body): - """ - Convert to cURL command - """ + """Convert to cURL command.""" # Build headers with proper escaping and ensure no truncation header_lines = [] for k, v in headers.items(): @@ -509,10 +514,30 @@ def _to_curl(self, method, url, headers, body): return curl_cmd + def _to_curl_windows(self, method, url, headers, body): + """Generate a Windows CMD-friendly cURL command (caret continuations, double quotes).""" + header_lines = [] + for k, v in headers.items(): + if k.lower() in ['accept-encoding', 'content-length', 'host']: + continue + escaped_value = str(v).replace('"', '""') + header_lines.append('-H "' + k + ': ' + escaped_value + '"') + + # Join headers with Windows continuation (caret at end of line) + headers_str = " ^\n ".join(header_lines) + + data_str = "" + if body and body.strip(): + # For CMD, prefer --data-raw with double-quoted string; escape internal quotes by doubling them + escaped_body = body.strip().replace('"', '""') + data_str = " ^\n --data-raw \"%s\"" % escaped_body + + curl_cmd = "curl -L --max-time 30 --connect-timeout 10 ^\n -X %s ^\n %s%s ^\n \"%s\"" % (method, headers_str, data_str, url) + + return curl_cmd + def _to_python_requests(self, method, url, headers, body): - """ - Convert to Python Requests - """ + """Convert to Python Requests.""" headers_str = ",\n ".join(['"' + k + '": "' + v.replace('"', '\\"') + '"' for k, v in headers.items()]) content_type = headers.get("Content-Type", "") @@ -552,9 +577,7 @@ def _to_python_requests(self, method, url, headers, body): return python_code def _to_python_aiohttp(self, method, url, headers, body): - """ - Convert to Python aiohttp - """ + """Convert to Python aiohttp.""" headers_str = ",\n ".join(['"' + k + '": "' + v.replace('"', '\\"') + '"' for k, v in headers.items()]) content_type = headers.get("Content-Type", "") @@ -594,9 +617,7 @@ async def main(): return aiohttp_code def _to_nodejs_axios(self, method, url, headers, body): - """ - Convert to Node.js Axios - """ + """Convert to Node.js Axios.""" headers_str = ",\n ".join(['"' + k + '": "' + v.replace('"', '\\"') + '"' for k, v in headers.items()]) content_type = headers.get("Content-Type", "") @@ -638,9 +659,7 @@ def _to_nodejs_axios(self, method, url, headers, body): return axios_code def _to_go_http(self, method, url, headers, body): - """ - Convert to Go http package - """ + """Convert to Go http package.""" headers_str = "\n\t".join(['req.Header.Add("' + k + '", "' + v.replace('"', '\\"') + '")' for k, v in headers.items()]) if body and body.strip(): @@ -701,9 +720,7 @@ def _to_go_http(self, method, url, headers, body): return go_code def _to_powershell(self, method, url, headers, body): - """ - Convert to PowerShell - """ + """Convert to PowerShell.""" headers_str = "\n".join(['$headers.Add("' + k + '", "' + v.replace('"', '\\"') + '")' for k, v in headers.items()]) if body and body.strip(): @@ -726,9 +743,7 @@ def _to_powershell(self, method, url, headers, body): return powershell_code def _to_ffuf(self, method, url, headers, body): - """ - Convert to FFUF command for fuzzing - """ + """Convert to FFUF command for fuzzing.""" # Create fuzz URL - add FUZZ parameter intelligently if "?" in url: fuzz_url = url + "&FUZZ=1" # Add as additional parameter @@ -768,9 +783,7 @@ def _to_ffuf(self, method, url, headers, body): return ffuf_cmd def _to_java_okhttp(self, method, url, headers, body): - """ - Convert to Java OkHttp - """ + """Convert to Java OkHttp.""" headers_str = "\n ".join(['.addHeader("' + k + '", "' + v.replace('"', '\\"') + '")' for k, v in headers.items()]) content_type = headers.get("Content-Type", "text/plain") @@ -808,9 +821,7 @@ def _to_java_okhttp(self, method, url, headers, body): return java_code def _to_csrf_payload(self, method, url, headers, body): - """ - Create a CSRF payload - """ + """Create a CSRF payload.""" form_fields = "" content_type = headers.get("Content-Type", "") @@ -879,9 +890,7 @@ def _to_csrf_payload(self, method, url, headers, body): return csrf_html def _to_cors_exploit(self, method, url, headers, body): - """ - Create a CORS exploit proof of concept - """ + """Create a CORS exploit proof of concept.""" # Build headers for the request request_headers = {} for k, v in headers.items(): @@ -988,5 +997,136 @@ def _to_cors_exploit(self, method, url, headers, body): """ % (url, url, method, headers_js, body_js) return cors_html + def _to_clickjacking_poc(self, method, url, headers, body): + """Create a Clickjacking proof of concept.""" + clickjack_html = """ + + + Clickjacking PoC + + + + +

Clickjacking Proof of Concept

+
+ This PoC overlays a nearly transparent iframe pointing to %s beneath a visible lure button. + If the site is vulnerable (no X-Frame-Options and frame-ancestors not set), clicking the button will actually click + the underlying control in the framed site. +
+ +
+
+ + +
+
+ Tip: Adjust the iframe size and the lure button position (top/left) to align over a sensitive action (e.g., Delete, Transfer, Approve). +
+ If the frame is blocked (blank or console shows frame-ancestors / X-Frame-Options), the application may not be vulnerable. +
+
+ + +""" % (url, url) + return clickjack_html + + def _to_postman_collection(self, method, url, headers, body): + """Generate a Postman Collection JSON for the current request.""" + # Build headers array for Postman + pm_headers = [] + for k, v in headers.items(): + # Skip headers that are auto-managed by clients + if k.lower() in ['content-length']: + continue + pm_headers.append({ + "key": k, + "value": v + }) + + # Determine body mode + content_type = headers.get("Content-Type", "") + body_obj = None + if body and body.strip(): + if "application/json" in content_type.lower(): + body_obj = { + "mode": "raw", + "raw": body, + "options": {"raw": {"language": "json"}} + } + elif "application/x-www-form-urlencoded" in content_type.lower(): + try: + form_params = [] + for part in body.split("&"): + if "=" in part: + name, value = part.split("=", 1) + else: + name, value = part, "" + form_params.append({"key": name, "value": value, "type": "text"}) + body_obj = {"mode": "urlencoded", "urlencoded": form_params} + except: + body_obj = {"mode": "raw", "raw": body} + else: + body_obj = {"mode": "raw", "raw": body} + + # Build request object + request_obj = { + "method": method, + "header": pm_headers, + "url": url + } + if body_obj: + request_obj["body"] = body_obj + + # Build minimal collection + collection = { + "info": { + "name": "Formatify Export", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_postman_id": "00000000-0000-0000-0000-000000000000" + }, + "item": [ + { + "name": method + " " + url, + "request": request_obj + } + ] + } + + return json.dumps(collection, indent=2) + # Made with Love by Sid Joshi # Find me at Linkedin: https://www.linkedin.com/in/sid-j0shi/