New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new mixin for Nuuo models #11289
Conversation
@bcoles any non specific questions you have about these modules please post here. The older versions of CMS fail without specific VS 2005 redistributable DLLs. It's a pain to set those up. The newer ones install pretty cleanly. |
Fixed a bug in the library to allow more robust file download and upload. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address namespace on methods and method scoping where appropriate.
@jmartin-r7 changes made! |
lib/msf/core/exploit/remote/nuuo.rb
Outdated
@nucs_versions.shuffle.each do |version| | ||
@nucs_version = version | ||
data = login_nopass | ||
if data == nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conditional block:
if data == nil
next
else
@nucs_session = data
break
end
Might be cleaner using a guard clause:
next if data.nil?
@nucs_session = data
break
It's slightly easier to read, especially given that this block is already deeply buried in spaghetti.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Easier to read? I think exactly the opposite, your proposal is much more convoluted and less expressive. However if that's what you want I will make the change...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a suggestion. You're welcome to ignore it.
As a common code pattern, it's easy to read for readers familiar with Ruby.
Once familiar with right-hand conditionals, and their typical use case (guard clauses), this pattern is easier to read than nested conditionals. In this instance, the conditional is already nested two levels deep.
Part of the reason I find the existing implementation subjectively unnecessarily hard to read is due to code duplication.
Consider:
def nucs_login
if datastore['SESSION'] != nil
# since we're logged in, we don't need to guess the version any more
@nucs_session = datastore['SESSION']
return
end
@nucs_versions.shuffle.each do |version|
@nucs_version = version
if datastore['PASSWORD'].nil?
data = login_nopass
else
data = login_password
end
if data.nil?
next
else
@nucs_session = data
return # or break if you'd prefer
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bcoles I will implement your suggestions even if I don't agree with them 100%, it's your show anyway. I just don't like to make a lot of changes as I'm paranoid with QA, and this means I will have to retest all the exploits against a variety of target versions to ensure nothing gets broken.
I'll make all the required changes, submit again and wait for your feedback. Once you are happy with the results (for all the modules), I will just test all changes at once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not my show. My suggestions are suggestions. I'm primarily concerned with complexity for maintainability purposes.
Looking at the login logic, it could be boiled down even further, as the login_nopass
and login_password
methods are very similar, both private, and only ever invoked once.
I could be missing something, but I don't see the need for two methods. Perhaps it would be a good idea to merge both private login methods into a single private login method and move the if datastore['PASSWORD']
conditional there?
Co-Authored-By: pedrib <pedrib@gmail.com>
Co-Authored-By: pedrib <pedrib@gmail.com>
Co-Authored-By: pedrib <pedrib@gmail.com>
@bcoles while I believe in code re-use and generally follow the style guide, I believe most of your suggestions actually make the code harder to read. A more experienced Ruby programmer might find this easy to read:
However a less experienced Ruby programmer, or a programmer coming from C / Python / Java will think WTF for a few seconds before understanding. For this type of programmer, the code below is much more readable:
And an experienced Ruby programmer, being experienced, will not take longer to understand it either. This, as some of your golfed examples, look like to me, as an experienced programmer in other languages and a Ruby noob, as style over readability. Now I know you are just following the Ruby style guide, but looks like to me a clear case of the Ruby Style guide shooting itself in the foot and thinking "this is great". The more verbose, clearer structured methods will always make an easier read. Therefore, I am not incorporating your suggestions above besides the "more_data", which is effectively a bug as you pointed out. If this is a blocker for integration let me know and I'll change as suggested, otherwise I prefer to leave it as is. |
@bcoles what's the smart way to test all these branches at once? I'm asking this because I'm basically copying and pasting the individual files from each of these PR into my own local branch that has all 4 exploits plus the lib, then editing there, testing and finally pasting back here via the github interface. Yes, it's stupid... and this is cumbersome and prone to error. I'd like to leave my exploits well tested... how's your git magic? |
^ +1 |
Damn... I thought there was a better way. Please let me know when you are done reviewing all modules and I'll give them a good final shake together, against a variety of CMS versions I have installed. In the meantime, I will test the module changes individually to make sure any obvious stuff gets caught. |
One option is to create a temporary local branch off this one and merge each of PR to that branch locally. If all testing passes you are good, if not you will need to port any changes to the other PRs. Another it to rebase each of the other branches off this one and test each branch individually. You could then push the branches to the other PRs and |
@jmartin-r7 understood, the first one sounds like a good option. |
Hey guys, do you need anything else from me to get this show on the road? Let me know! |
There's should probably be some error handling following the Based on your previous patch to initialize break if !new_data || new_data.length == 0 Also, is there a reason This design decision introduces comparitively significant complexity throughout the majority of the library. Merging these methods, and updating the methods which depend on them, would effectively cut the size of this library in half. I offer the code below as a replacement for the following 5 methods:
I've attempted to maintain your style throughout, with the exception of Note that, if these changes are implemented, any instances of def nucs_login
if datastore['SESSION'] != nil
# since we're logged in, we don't need to guess the version any more
@nucs_session = datastore['SESSION']
return
end
@nucs_versions.shuffle.each do |version|
@nucs_version = version
res = nucs_send_msg(
[
"USERLOGIN",
"Version: #{@nucs_version}",
"Username: #{datastore['USERNAME']}",
"Password-Length: #{datastore['PASSWORD'].length}",
"TimeZone-Length: 0"
],
datastore['PASSWORD']
)
if res[0] =~ /User-Session-No: ([a-zA-Z0-9]+)/
@nucs_session = $1
break
end
end
end
##
# Sends a protocol message synchronously - sends and returns the result
##
def nucs_send_msg(msg, data='')
ctx = { 'Msf' => framework, 'MsfExploit' => self }
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => rport, 'Context' => ctx })
sock.write(format_msg(msg))
sock.write(data.to_s) unless data.to_s == ''
res = sock.recv(4096)
more_data = ''
if res =~ /Content-Length:([0-9]+)/
data_sz = $1.to_i
recv = 0
while recv < data_sz
new_data = sock.recv(4096)
break if !new_data || new_data.length == 0
more_data << new_data
recv += new_data.length
end
end
# socket cannot be closed, it causes exploits to fail...
#sock.close
return [res, more_data]
rescue
return ['', '']
end |
Ok after screwing up my local and remote branches, here is the final solution. I incorporated your changes with very small additions. Since all the changes are internal it seems they only really affect one module, the file upload one. I will push it to the other branch - this time manually to avoid this chaos. Check bae83e9 for the right commit |
btw there's a lot of crappy commits here - let me know if you want me to submit a new PR for this |
Guys anything else you need? |
Please squash the commits here. It looks like your testing of all branches merged together was pushed here and then you removed the files as additional commits. This will cause conflicts when trying to merge the other PRs as well. It might be reasonable to rebase the other PRs once the commits here are cleaned up. If you have enabled the |
@jmartin-r7 that is enabled, can you please lend a hand? Sorry, I'm pretty much a git noob. |
f9d6d22
to
733f784
Compare
# | ||
def initialize(info = {}) | ||
super(update_info(info, | ||
'Author' => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your evil plan there :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:) I'm not planning to dig deeper (for the moment), but pointing it out to whoever wants to look into it...
@wchen-r7 since I reworked the commit history on this you up for doing the final approach and landing procedure? |
Guys, before you land it, let me know you are done with all the reviewing - I will give it a good final shake across all the versions I have installed to make sure none of the recent changes have broken any of the exploits! |
@pedrib I'm working on moving some of the code to lib/rex. After I'm done with that I'll submit a PR to your branch so you can test it. |
@jrobles-r7 is currently working on this pull request and putting some of the code in Rex. I'm sure he'll reach out to @pedrib. Thanks for the heads up! |
Hello @pedrib, I update the modules. Could you test the updated modules as well? I'm still working on the rex/mixin stuff but I will PR that separately so we can get the PRs you submitted landed. |
Release NotesThis adds a mixin for the Nuuo NUCM protocol used for device and management software. |
This PR adds a new mixing that will be required for the next PR's that I will submit.
I will mention this in the new PRs and include more information there.
This adds functions that will be used by all four new modules.