Closed vah13 closed 7 years ago
I used requests :-) sorry for that )
Hi! Thanks, this is great as always!
As this is in the HTTP interface, I don't see a fit for having it available on pysap
more than for using it through a SAPRouter. Even in that case that can be easily done using router_portfw.py
, but it might be worth a try.
Can you make this work using plain sockets instead of requests
? If so you can make it use the SAPRoutedStreamSocket
and have it routing the traffic as in https://github.com/CoreSecurity/pysap/blob/master/examples/enqueue_dos_exploit.py.
Hi Martin, We have a question.
We changed script but in testing time got HTTP request, from SAP Router, with package length like this 00000008GET /ABC
can you say, how we can fix it (to router don't send packages with length of data)?
thank you
In order to the stream socket not append the NI layer you should use the NI_RAW_IO
talk mode, like doing:
conn = SAPRoutedStreamSocket.get_nisocket(host, port, route, talk_mode=1)
Hi Martin,
yes router_portfw.py
method is working fine, now trying to achieve the same result within the exploit via SAPRoutedStreamSocket
with your mention is failing. Consider following POC to showcase that talk_mode
doesn't seems to be taken into account:
from pysap.SAPRouter import SAPRoutedStreamSocket
route = '/H/yoursaprouter/S/3299'
host = 'desthttpmsgserver'
port = '8101'
conn = SAPRoutedStreamSocket.get_nisocket(host, port, route, talk_mode=1)
conn.send('ABCD')
conn.close()
That will spit the following packet from the 'yoursaprouter' host:
13:18:45.002289 IP yoursaprouter.52658 > desthttpmsgserver.8101: P 1:9(8) ack 1 win 115 <nop,nop,timestamp 2180275605 16712324>
0x0000: 000c 29a7 eeb7 000c 29eb 8e69 0800 4500 ..).....)..i..E.
0x0010: 003c 9ebb 4000 4006 2341 xxxx xxxx xxxx .<..@.@.#A......
0x0020: xxxx xxxx 1fa5 ab5e c32e 6be6 6f85 8018 .......^..k.o...
0x0030: 0073 78ee 0000 0101 080a 81f4 5d95 00ff .sx.........]...
0x0040: 0284 0000 0004 4142 4344 ......ABCD
As you can see the NI layer is still used (with length being prepended)
I've got finally a working POC with:
router = yoursaprouter
dest = desthttpmsgserver
destport = '8101'
router_sock = SAPNIStreamSocket.get_nisocket(router, 3299, keep_alive=True)
# Route description to our destination
router_string = [SAPRouterRouteHop(hostname=router, port=3299),
SAPRouterRouteHop(hostname=dest, port=destport)]
# Forge SAPRouter packet to enable the route
router_string_lens = list(map(len, list(map(str, router_string))))
p = SAPRouter(type=SAPRouter.SAPROUTER_ROUTE,
route_entries=len(router_string),
route_talk_mode=1,
route_rest_nodes=1,
route_length=sum(router_string_lens),
route_offset=router_string_lens[0],
route_string=router_string)
resp = router_sock.sr(p)
# And now send our raw TCP payload to final destination
router_sock.ins.send("ABCD")
The important detail seems to be using the ins
(or outs
) members of SimpleSocket object for bypassing NI layer.
NB: My previous example after doing a pull didn't work anymore by spitting this:
DEBUG:pysap.sapni:To send 24 bytes
DEBUG:pysap.sapni:To receive 222 bytes
DEBUG:pysap.sapni:Received 222 bytes
DEBUG:pysap.saprouter:Requesting route to desthttpmsgserver:8101 using mode 1 (NI_RAW_IO)
DEBUG:pysap.sapni:To send 66 bytes
Traceback (most recent call last):
File "./pysap_streamsocket_debug.py", line 19, in <module>
conn = SAPRoutedStreamSocket.get_nisocket(host, port, route, talk_mode=1)
File "build/bdist.linux-x86_64/egg/pysap/SAPRouter.py", line 673, in get_nisocket
File "build/bdist.linux-x86_64/egg/pysap/SAPRouter.py", line 551, in __init__
File "build/bdist.linux-x86_64/egg/pysap/SAPRouter.py", line 584, in route_to
File "build/bdist.linux-x86_64/egg/pysap/SAPNI.py", line 162, in sr
File "build/bdist.linux-x86_64/egg/pysap/SAPRouter.py", line 614, in recv
File "build/bdist.linux-x86_64/egg/pysap/SAPNI.py", line 122, in recv
socket.error: (100, 'Underlying stream socket tore down')
About my last remark, I pointed out that get_router_version()
is not working as supposed.
By forcing router_version
like: conn = SAPRoutedStreamSocket.get_nisocket(host, port, route, talk_mode=1, router_version=40)
will fix the situation, so that you can investigate why talk_mode
is not taken into account.
About my last point, I pointed out that get_router_version() is not working as supposed. By forcing router_version like: conn = SAPRoutedStreamSocket.get_nisocket(host, port, route, talk_mode=1, router_version=40) will fix the situation, so that you can investigate why talk_mode is not taken into account.
Yes, I broke it in d2f0424a42c5154a5204bc9a18a40bca3a958ee4! Fixing right now!
Check it out and let me know how it goes now! Missed out that send
method was not even imlpemented in SAPRoutedStreamSocket
and thus adding the NI layer even when talk mode was set to raw
.
yeah that fixes everything, and simplifies the Router part of the POC as you advised ins issuecomment-280381063 :+1:
Thanks man! Will check and merge ASAP!
Find out that this approach doesn't work for non routed connections, as the NI layer is still added. I'm changing the behaviour of SAPRoutedStreamSocket.get_ni_socket
to support this scenario.
Can you check it's working fine without routing on the msdos
branch?
yes, without a route, I don't see the length field in the payload sent to the destination. c33e720 seems to work properly.
... ok with further testing I see incompatibilities:
talk_mode=1
when route=None
and you specify a base_cls
on the get_nisocket()
call: base_cls
is passed via kwargs
to StreamSocket
that is not happy about itSAPRoutedStreamSocket.recv()
in this special case, we don't have basecls
field set in our StreamSocket
, so again crash when StreamSocket.recv()
is doing a pkt = self.basecls(pkt)
Attempt to fix that issue (but hard to know what will be the consequences in others scenarios):
diff --git a/pysap/SAPRouter.py b/pysap/SAPRouter.py
index 45e97fe..c492426 100644
--- a/pysap/SAPRouter.py
+++ b/pysap/SAPRouter.py
@@ -22,7 +22,7 @@ import re
import logging
from socket import error as SocketError
# External imports
-from scapy.layers.inet import TCP
+from scapy.layers.inet import TCP, Raw
from scapy.packet import Packet, bind_layers
from scapy.supersocket import socket, StreamSocket
from scapy.fields import (ByteField, ShortField, ConditionalField, StrField,
@@ -608,6 +608,7 @@ class SAPRoutedStreamSocket(SAPNIStreamSocket):
# need the NI layer anymore. Just use the plain socket inside the
# NIStreamSockets.
if self.routed and self.talk_mode == 1:
+ if not self.base_cls: self.basecls = Raw
return StreamSocket.recv(self)
# If the route was not accepted yet or we're working on non-native talk
# mode, we need the NI layer.
@@ -675,6 +676,7 @@ class SAPRoutedStreamSocket(SAPNIStreamSocket):
# NI layer completely
if talk_mode == 1:
sock = socket.create_connection((host, port))
+ if 'base_cls' in kwargs: kwargs.pop('base_cls')
return StreamSocket(sock, **kwargs)
# Otherwise use the standard SAPNIStreamSocket get_nisocket method
I made my try by adapting your patch a little bit: if instead of pop'ing the base class we force it to be Raw
we don't need to check it in send
/recv
methods.
Merged in ab307119c9466d472600254389845499607937a4, thanks guys!
Hi. We found a DoS vulnerability in Message Server (all kernel versions)
May can you add functionality for SAP route in send_crash function? I requested CVE and think will get for 24 hours.