From bdbf6ea9bb4b6de0f7d0f9cbe3e1afebd6cda86d Mon Sep 17 00:00:00 2001 From: nmonkee Date: Tue, 6 Nov 2012 21:16:32 +0000 Subject: [PATCH 01/10] SAP NI Proxy Support (SAProuter) - see http://labs.mwrinfosecurity.com/blog/2012/09/13/sap-smashing-internet-windows --- lib/rex/socket/comm/local.rb | 75 ++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index bd9be1ce04..4f3bc5b38c 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -1,4 +1,3 @@ -# -*- coding: binary -*- require 'singleton' require 'rex/socket' require 'rex/socket/tcp' @@ -346,9 +345,79 @@ class Rex::Socket::Comm::Local end def self.proxy(sock, type, host, port) - - #$stdout.print("PROXY\n") case type.downcase + when 'ni' + packet_type = 'NI_ROUTE' + route_info_version = 2 + ni_version = 39 + num_of_entries = 2 + talk_mode = 1 # ref: http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm + num_rest_nodes = 1 + route_length = 0 + current_position = 0 + routes = {} + route_data = '' + + array = sock.peerinfo.split(":") + + shost = array[0] + sport = array[1] + + routes = {shost => sport.to_s, host => port.to_s} + + ni_packet = packet_type << [0].pack('c*') << [route_info_version].pack('c*') << [ni_version].pack('c*') << [num_of_entries].pack('c*') << [talk_mode].pack('c*') << [0].pack('c*') << [0].pack('c*') << [num_rest_nodes].pack('c*') + + first = 'False' + + routes.each do|host,port| + route_item = host + [0].pack("C") + port + [0, 0].pack("c*") + if first == "False" + route_data = route_data << [route_item.length].pack('N') << route_item + first = "True" + else + route_data = route_data << route_item + end + end + + ni_packet << [route_data.length - 4].pack('N') << route_data + + ni_packet = [ni_packet.length].pack('N') << ni_packet + + size = sock.put(ni_packet) + + if (size != ni_packet.length) + raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller + end + + begin + ret_len = sock.recv(4).unpack('H*')[0] + if ret_len !=0 + ret = sock.recv(ret_len.to_i) + end + rescue IOError + raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller + end + + if (ret.nil? or ret.length < 4) + raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller + end + + if (ret =~ /NI_RTERR/) + if (ret =~ /timed out/) + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out") + elsif (ret =~ /refused/) + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed") + elsif (ret =~ /denied/) + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") + else + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + end + elsif (ret =~ /NI_PONG/) + $stdout.print("[*] remote native connection to #{host}:#{port} established\n") + else + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + end + when 'http' setup = "CONNECT #{host}:#{port} HTTP/1.0\r\n\r\n" size = sock.put(setup) From f04dc587b6fe8323efd03c88168dd2ddd6a4d617 Mon Sep 17 00:00:00 2001 From: nmonkee Date: Thu, 15 Nov 2012 00:13:06 +0000 Subject: [PATCH 02/10] made requested changes --- lib/rex/socket/comm/local.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index 4f3bc5b38c..cbf0617e1e 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -367,25 +367,25 @@ class Rex::Socket::Comm::Local ni_packet = packet_type << [0].pack('c*') << [route_info_version].pack('c*') << [ni_version].pack('c*') << [num_of_entries].pack('c*') << [talk_mode].pack('c*') << [0].pack('c*') << [0].pack('c*') << [num_rest_nodes].pack('c*') - first = 'False' + first = false routes.each do|host,port| route_item = host + [0].pack("C") + port + [0, 0].pack("c*") - if first == "False" + if first route_data = route_data << [route_item.length].pack('N') << route_item - first = "True" + first = true else - route_data = route_data << route_item + route_data << route_item end end - ni_packet << [route_data.length - 4].pack('N') << route_data - + ni_packet << [route_data.length - 4].pack('N') + ni_packet << route_data ni_packet = [ni_packet.length].pack('N') << ni_packet size = sock.put(ni_packet) - if (size != ni_packet.length) + if size != ni_packet.length raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller end @@ -398,22 +398,22 @@ class Rex::Socket::Comm::Local raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller end - if (ret.nil? or ret.length < 4) + if ret or ret.length < 4 raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller end - if (ret =~ /NI_RTERR/) - if (ret =~ /timed out/) + if ret =~ /NI_RTERR/ + if ret =~ /timed out/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out") - elsif (ret =~ /refused/) + elsif ret =~ /refused/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed") - elsif (ret =~ /denied/) + elsif ret =~ /denied/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") else raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") end - elsif (ret =~ /NI_PONG/) - $stdout.print("[*] remote native connection to #{host}:#{port} established\n") + elsif ret =~ /NI_PONG/ + print_good("[*] remote native connection to #{host}:#{port} established\n") else raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") end From 088d20c5a914819fb96aa47c729a0056f4ca926b Mon Sep 17 00:00:00 2001 From: nmonkee Date: Thu, 22 Nov 2012 09:28:50 +0000 Subject: [PATCH 03/10] Made requested changes --- lib/rex/socket/comm/local.rb | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index cbf0617e1e..df1051c8d5 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -398,22 +398,23 @@ class Rex::Socket::Comm::Local raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller end - if ret or ret.length < 4 + if ret and ret.length < 4 raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller end - + case if ret =~ /NI_RTERR/ - if ret =~ /timed out/ - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out") - elsif ret =~ /refused/ - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed") - elsif ret =~ /denied/ - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") - else - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") - end + case ret + when =~ /timed out/ + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out") + when =~ /refused/ + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed") + when =~ /denied/ + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") + else + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + end elsif ret =~ /NI_PONG/ - print_good("[*] remote native connection to #{host}:#{port} established\n") + # would like to print this "[*] remote native connection to #{host}:#{port} established\n" else raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") end From 79c050707700a7c95b725d3b5df875df6d3a883f Mon Sep 17 00:00:00 2001 From: nmonkee Date: Thu, 22 Nov 2012 09:43:16 +0000 Subject: [PATCH 04/10] Fix syntax errors --- lib/rex/socket/comm/local.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index df1051c8d5..c35a0cb741 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -404,11 +404,11 @@ class Rex::Socket::Comm::Local case if ret =~ /NI_RTERR/ case ret - when =~ /timed out/ + when /timed out/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out") - when =~ /refused/ + when /refused/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed") - when =~ /denied/ + when /denied/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") else raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") From 937e49378c7093d308d95206f679d10649c31d7c Mon Sep 17 00:00:00 2001 From: nmonkee Date: Thu, 22 Nov 2012 09:57:08 +0000 Subject: [PATCH 05/10] Syntax fix Doh, missed one. --- lib/rex/socket/comm/local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index c35a0cb741..3552dee3cd 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -401,7 +401,7 @@ class Rex::Socket::Comm::Local if ret and ret.length < 4 raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller end - case + if ret =~ /NI_RTERR/ case ret when /timed out/ From 4002759fcfe0cd5ae9f0adc3d1730183ffaf2729 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Fri, 28 Dec 2012 14:14:49 -0600 Subject: [PATCH 06/10] Bring some sanity to the Array#packs --- lib/rex/socket/comm/local.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index 3552dee3cd..25c7394d7f 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -365,20 +365,31 @@ class Rex::Socket::Comm::Local routes = {shost => sport.to_s, host => port.to_s} - ni_packet = packet_type << [0].pack('c*') << [route_info_version].pack('c*') << [ni_version].pack('c*') << [num_of_entries].pack('c*') << [talk_mode].pack('c*') << [0].pack('c*') << [0].pack('c*') << [num_rest_nodes].pack('c*') + ni_packet = [ + packet_type, + 0, + route_info_version, + ni_version, + num_of_entries, + talk_mode, + 0, + 0, + num_rest_nodes + ].pack("A8c7") first = false - routes.each do|host,port| - route_item = host + [0].pack("C") + port + [0, 0].pack("c*") + routes.each do |host,port| + route_item = [host, 0, port, 0, 0].pack("A*CA*CC") if first - route_data = route_data << [route_item.length].pack('N') << route_item + route_data = [route_data, route_item.length, route_item].pack("A*NA*") first = true else route_data << route_item end end + # TODO: This is really hard to follow ni_packet << [route_data.length - 4].pack('N') ni_packet << route_data ni_packet = [ni_packet.length].pack('N') << ni_packet From 7a0a230e92d5518b8f0418b8e4a7e63d827d27f4 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Fri, 28 Dec 2012 14:16:56 -0600 Subject: [PATCH 07/10] Put the coding: binary magic comment back --- lib/rex/socket/comm/local.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index 25c7394d7f..4b6e120266 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -1,3 +1,4 @@ +# -*- coding: binary -*- require 'singleton' require 'rex/socket' require 'rex/socket/tcp' From 8cd7c2783e5ed5730ab3c6688e8c2cc5d9cd9a97 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Fri, 28 Dec 2012 14:36:06 -0600 Subject: [PATCH 08/10] Indentation fixes --- lib/rex/socket/comm/local.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index 4b6e120266..3b82e85954 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -381,14 +381,14 @@ class Rex::Socket::Comm::Local first = false routes.each do |host,port| - route_item = [host, 0, port, 0, 0].pack("A*CA*CC") - if first - route_data = [route_data, route_item.length, route_item].pack("A*NA*") - first = true - else - route_data << route_item - end - end + route_item = [host, 0, port, 0, 0].pack("A*CA*CC") + if first + route_data = [route_data, route_item.length, route_item].pack("A*NA*") + first = true + else + route_data << route_item + end + end # TODO: This is really hard to follow ni_packet << [route_data.length - 4].pack('N') @@ -402,9 +402,9 @@ class Rex::Socket::Comm::Local end begin - ret_len = sock.recv(4).unpack('H*')[0] - if ret_len !=0 - ret = sock.recv(ret_len.to_i) + ret_len = sock.recv(4).unpack('H*')[0] + if ret_len !=0 + ret = sock.recv(ret_len.to_i) end rescue IOError raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller @@ -427,10 +427,10 @@ class Rex::Socket::Comm::Local end elsif ret =~ /NI_PONG/ # would like to print this "[*] remote native connection to #{host}:#{port} established\n" - else - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + else + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") end - + when 'http' setup = "CONNECT #{host}:#{port} HTTP/1.0\r\n\r\n" size = sock.put(setup) From f5b00512e006084189f9b2433f6e70d7b967cffa Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 13 Jun 2013 17:15:48 -0500 Subject: [PATCH 09/10] Fix sap ni proxy, hopefully --- lib/rex/socket/comm/local.rb | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index 3b82e85954..bb65e19d69 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -347,16 +347,13 @@ class Rex::Socket::Comm::Local def self.proxy(sock, type, host, port) case type.downcase - when 'ni' + when 'sapni' packet_type = 'NI_ROUTE' route_info_version = 2 ni_version = 39 num_of_entries = 2 talk_mode = 1 # ref: http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm num_rest_nodes = 1 - route_length = 0 - current_position = 0 - routes = {} route_data = '' array = sock.peerinfo.split(":") @@ -376,15 +373,15 @@ class Rex::Socket::Comm::Local 0, 0, num_rest_nodes - ].pack("A8c7") + ].pack("A8c8") - first = false + first = true routes.each do |host,port| - route_item = [host, 0, port, 0, 0].pack("A*CA*CC") + route_item = [host, 0, port, 0, 0].pack("A*CA*cc") if first - route_data = [route_data, route_item.length, route_item].pack("A*NA*") - first = true + route_data = [route_item.length, route_item].pack("NA*") + first = false else route_data << route_item end @@ -402,9 +399,9 @@ class Rex::Socket::Comm::Local end begin - ret_len = sock.recv(4).unpack('H*')[0] - if ret_len !=0 - ret = sock.recv(ret_len.to_i) + ret_len = sock.get_once(4, 30).unpack('L>')[0] + if ret_len and ret_len != 0 + ret = sock.get_once(ret_len, 30) end rescue IOError raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller @@ -423,12 +420,13 @@ class Rex::Socket::Comm::Local when /denied/ raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL") else - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)") end elsif ret =~ /NI_PONG/ + # success case # would like to print this "[*] remote native connection to #{host}:#{port} established\n" else - raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed - #{ret}\n\n#{ni_packet}") + raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)") end when 'http' From 1aff778a792d68737b584088f80ece11bf979f24 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 18 Jun 2013 09:06:44 -0500 Subject: [PATCH 10/10] Fix unpack --- lib/rex/socket/comm/local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index bb65e19d69..1e955c567e 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -399,7 +399,7 @@ class Rex::Socket::Comm::Local end begin - ret_len = sock.get_once(4, 30).unpack('L>')[0] + ret_len = sock.get_once(4, 30).unpack('N')[0] if ret_len and ret_len != 0 ret = sock.get_once(ret_len, 30) end