1+ #
2+ # Author: MM - https://github.com/1modm
3+ #
4+ # Most of the Penetration/Exploit/Hijacking Tools use the HTTP methods to try to inject
5+ # or execute code into the attacked server, also this tools usually have a well known
6+ # "hardcoded" User-Agent, URI or request content.
7+ #
8+ # So if the original scanner is not modified can be detected. This is a PoC in order to generate
9+ # simple rules to detect and identified some of the most commons Penetration/Exploit/Hijacking Tools.
10+ #
11+ # Some of the most commons tools source and information:
12+ #
13+ # Nmap
14+ # User-Agent header by default it is "Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)".
15+ # https://nmap.org/nsedoc/lib/http.html
16+ #
17+ # OpenVAS
18+ # http://www.openvas.org/src-doc/openvas-libraries/nasl__http_8c_source.html
19+ # User-Agent header by default: #define OPENVAS_USER_AGENT "Mozilla/5.0 [en] (X11, U; OpenVAS)"
20+ #
21+ # MASSCAN
22+ # https://github.com/robertdavidgraham/masscan
23+ #
24+ # Morpheus
25+ # https://github.com/r00t-3xp10it/morpheus
26+ # https://latesthackingnews.com/2016/12/19/morpheus-automated-ettercap-tcpip-hijacking-tool/
27+ #
28+ # DataCha0s Web Scanner
29+ # http://eromang.zataz.com/2011/05/23/suc026-datacha0s-web-scannerrobot/
30+ # https://blogs.harvard.edu/zeroday/2006/06/12/data-cha0s-connect-back-backdoor/
31+ #
32+ # HNAP (Home Network Administration Protocol)
33+ # https://nmap.org/nsedoc/scripts/hnap-info.html
34+ #
35+ # ZmEu Scanner
36+ # https://en.wikipedia.org/wiki/ZmEu_(vulnerability_scanner)
37+ # http://linux.m2osw.com/zmeu-attack
38+ # https://code.google.com/archive/p/caffsec-malware-analysis/wikis/ZmEu.wiki
39+ # https://ensourced.wordpress.com/2011/02/25/zmeu-attacks-some-basic-forensic/
40+ # http://philriesch.com/computersecurity_zmeu.html
41+ #
42+ # Jorgee Scanner
43+ # http://www.skepticism.us/2015/05/new-malware-user-agent-value-jorgee/
44+ # https://www.checkpoint.com/defense/advisories/public/2016/cpai-2016-0214.html
45+ # https://blog.paranoidpenguin.net/2017/04/jorgee-goes-on-a-rampage/
46+
47+ import re
48+ import util
49+ import dshell
50+ import datetime
51+ import colorout
52+ from httpdecoder import HTTPDecoder
53+
54+ class DshellDecoder (HTTPDecoder ):
55+
56+ def __init__ (self ):
57+ HTTPDecoder .__init__ (self ,
58+ name = 'peht' ,
59+ description = 'Penetration/Exploit/Hijacking Tool detector' ,
60+ longdescription = """
61+ The Penetration/Exploit/Hijacking Tool detector will identify the tool used to scan or exploit a server using the
62+ User agent, URI or HTTP content.
63+
64+ General usage:
65+ decode -d peht <pcap>
66+
67+ Detailed usage:
68+ decode -d peht --peht_showcontent <pcap>
69+
70+ Output:
71+
72+ Request Timestamp (UTC): 2017-07-16 02:41:47.238549
73+ Penetration/Exploit/Hijacking Tool: Open Vulnerability Assessment System
74+ User-Agent: Mozilla/5.0 [en] (X11, U; OpenVAS 8.0.9)
75+ Request Method: GET
76+ URI: /scripts/session/login.php
77+ Source IP: 1.2.3.4 - Source port: 666 - MAC: 50:b4:02:39:24:56
78+ Host requested: example.com
79+
80+ Response Timestamp (UTC): 2017-07-16 02:41:48.238549
81+ Response Reason: Not Found
82+ Response Status: 404
83+ Destination IP: 192.168.1.1 - Destination port: 80 - MAC: a4:42:ab:56:b6:23
84+
85+
86+ Detailed Output:
87+
88+ Request Timestamp (UTC): 2017-07-16 02:41:47.238549
89+ Penetration/Exploit/Hijacking Tool: Arbitrary Remote Code Execution/injection
90+ User-Agent: Wget(linux)
91+ Request Method: POST
92+ URI: /command.php
93+ Source IP: 1.2.3.4 - Source port: 666 - MAC: 50:b4:02:39:24:56
94+ Host requested: example.com
95+
96+ cmd=%63%64%20%2F%76%61%72%2F%74%6D%70%20%26%26%20%65%63%68%6F%20%2D%6E%65%20%5C%5C%78%33%6B%65%72%20%3E%20%6B%65%72%2E%74%78%74%20%26%26%20%63%61%74%20%6B%65%72%2E%74%78%74
97+
98+ Response Timestamp (UTC): 2017-07-16 02:41:48.238549
99+ Response Reason: Found
100+ Response Status: 302
101+ Destination IP: 192.168.1.1 - Destination port: 80 - MAC: a4:42:ab:56:b6:23
102+
103+ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
104+ <html><head>
105+ <title>302 Found</title>
106+ </head><body>
107+ <h1>Found</h1>
108+ <p>The document has moved <a href="https://example.com/command.php">here</a>.</p>
109+ </body></html>
110+
111+ """ ,
112+ filter = 'tcp and (port 80 or port 81 or port 8080 or port 8000)' ,
113+ filterfn = lambda ((sip , sp ), (dip , dp )): sp in (
114+ 80 , 81 , 8000 , 8080 ) or dp in (80 , 81 , 8000 , 8080 ),
115+ author = 'mm' ,
116+ optiondict = {
117+ 'showcontent' : {'action' : 'store_true' , 'default' : False , 'help' : 'Display the request and response body content.' }
118+ }
119+ )
120+
121+ self .out = colorout .ColorOutput ()
122+ self .direction = None
123+ self .request_ioc = None
124+ self .request_method = None
125+ self .request_user_agent = None
126+ self .request_host = None
127+ self .request_rangestr = None
128+ self .request_body = None
129+ self .request_referer = None
130+ self .response_content_type = None
131+ self .response_body = None
132+ self .response_contentencoding = None
133+ self .response_status = None
134+ self .response_contentlength = None
135+ self .response_reason = None
136+
137+ def preModule (self ):
138+ if 'setColorMode' in dir (self .out ):
139+ self .out .setColorMode ()
140+
141+ def check_payload (self , payloadheader , payloaduri , requestbody ):
142+
143+ ET_identified = None
144+
145+ r = re .compile (r'\bbash\b | \bcmd\b | \bsh\b | \bwget\b' , flags = re .I | re .X )
146+ if r .findall (requestbody ):
147+ ET_identified = 'Arbitrary Remote Code Execution/injection'
148+
149+ if payloadheader .has_key ('content-type' ):
150+ struts_ioc = ['cmd' , 'ProcessBuilder' , 'struts' ]
151+ #Will return empty if all words from struts_ioc are in payloadheader['content-type']
152+ struts_check = list (filter (lambda x : x not in payloadheader ['content-type' ], struts_ioc ))
153+ if not struts_check :
154+ ET_identified = 'Apache Struts Content-Type arbitrary command execution'
155+
156+ if payloadheader .has_key ('user-agent' ):
157+ if 'Jorgee' in payloadheader ['user-agent' ]:
158+ ET_identified = 'Jorgee Scanner'
159+ elif 'Nmap' in payloadheader ['user-agent' ]:
160+ ET_identified = 'Nmap'
161+ elif 'masscan' in payloadheader ['user-agent' ]:
162+ ET_identified = 'Mass IP port scanner'
163+ elif ('ZmEu' in payloadheader ['user-agent' ] and 'w00tw00t' in payloaduri ):
164+ ET_identified = 'ZmEu Vulnerability Scanner'
165+ elif 'immoral' in payloadheader ['user-agent' ]:
166+ ET_identified = 'immoral'
167+ elif 'chroot' in payloadheader ['user-agent' ]:
168+ ET_identified = 'chroot'
169+ elif 'DataCha0s' in payloadheader ['user-agent' ]:
170+ ET_identified = 'DataCha0s Web Scanner'
171+ elif 'OpenVAS' in payloadheader ['user-agent' ]:
172+ ET_identified = 'Open Vulnerability Assessment System'
173+ elif ('bash' or 'sh' or 'cmd' or 'wget' ) in (payloadheader ['user-agent' ]):
174+ ET_identified = 'Arbitrary Remote Code Execution/injection'
175+
176+ if 'muieblackcat' in payloaduri :
177+ ET_identified = 'Muieblackcat Web Scanner/Robot'
178+ if '/HNAP1/' in payloaduri :
179+ ET_identified = 'Home Network Administration Protocol'
180+
181+ return ET_identified
182+
183+
184+
185+ def HTTPHandler (self , conn , request , response , requesttime , responsetime ):
186+
187+ if not request :
188+ return
189+
190+ # Obtain the response content
191+ try :
192+ if 'gzip' in util .getHeader (response , 'content-encoding' ):
193+ self .response_body = self .decompressGzipContent (response .body )
194+ if self .response_body == None :
195+ self .response_body = '(gunzip failed)\n ' + response .body
196+ else :
197+ self .response_body = '(gzip encoded)\n ' + self .response_body
198+ else :
199+ self .response_body = response .body
200+ except AttributeError as e :
201+ self .response_body = None
202+
203+ # Obtain the request content
204+ try :
205+ if 'gzip' in util .getHeader (request , 'content-encoding' ):
206+ self .request_body = self .decompressGzipContent (request .body )
207+ if self .request_body == None :
208+ self .request_body = '(gunzip failed)\n ' + request .body
209+ else :
210+ self .request_body = '(gzip encoded)\n ' + self .request_body
211+ else :
212+ self .request_body = request .body
213+ except AttributeError as e :
214+ self .request_body = None
215+
216+ # Identify the Exploit/Hijacking Tool
217+ self .request_ioc = self .check_payload (request .headers , request .uri , self .request_body )
218+
219+ if self .request_ioc :
220+
221+ # REQUEST
222+ if request .method in ('GET' , 'POST' , 'HEAD' ):
223+ self .direction = "sc"
224+ self .request_method = request .method
225+ self .request_user_agent = request .headers .get ('user-agent' )
226+ self .request_host = util .getHeader (request , 'host' )
227+ self .request_rangestr = util .getHeader (request ,'range' )
228+ self .request_body = request .body
229+ self .request_referer = util .getHeader (request , 'referer' )
230+
231+ if request .headers .has_key ('user-agent' ):
232+ self .request_user_agent = request .headers ['user-agent' ]
233+
234+ self .out .write ("\n Request Timestamp (UTC): {0} \n Penetration/Exploit/Hijacking Tool: {1}\n User-Agent: {2}\n Request Method: {3}\n URI: {4}\n Source IP: {5} - Source port: {6} - MAC: {7}\n Host requested: {8}\n Referer: {9}\n " .format (datetime .datetime .utcfromtimestamp (
235+ requesttime ), self .request_ioc , self .request_user_agent , self .request_method , request .uri , conn .sip , conn .sport , conn .smac , self .request_host , self .request_referer ), formatTag = "H2" , direction = self .direction )
236+
237+ # Show request body content
238+ if self .showcontent :
239+ self .out .write ("\n {0}\n " .format (self .request_body ), formatTag = "H2" , direction = self .direction )
240+
241+ if not response :
242+ self .direction = "cs"
243+ self .out .write ('\n No response\n ' , formatTag = "H2" , direction = self .direction )
244+
245+ # RESPONSE
246+ else :
247+ self .direction = "cs"
248+ self .response_content_type = util .getHeader (response , 'content-type' )
249+ self .response_contentencoding = util .getHeader (response , 'content-encoding' )
250+ self .response_status = response .status
251+ self .response_reason = response .reason
252+
253+ self .out .write ("\n Response Timestamp (UTC): {0} \n Response Reason: {1}\n Response Status: {2}\n Destination IP: {3} - Destination port: {4} - MAC: {5}\n " .format (datetime .datetime .utcfromtimestamp (
254+ responsetime ), self .response_reason , self .response_status , conn .dip , conn .dport , conn .dmac ), formatTag = "H2" , direction = self .direction )
255+
256+ # Show response body content
257+ if self .showcontent :
258+ self .out .write ("\n {0}\n " .format (self .response_body ), formatTag = "H2" , direction = self .direction )
259+
260+ if __name__ == '__main__' :
261+ dObj = DshellDecoder ()
262+ print dObj
263+ else :
264+ dObj = DshellDecoder ()
0 commit comments