├── libs ├── __init__.py ├── ssl │ ├── mitmproxy-ca-cert.p12 │ ├── mitmproxy-dhparam.pem │ ├── mitmproxy-ca-cert.cer │ ├── mitmproxy-ca-cert.pem │ └── mitmproxy-ca.pem ├── func.py ├── models.py ├── proxy.py ├── action.py └── wyproxy.py ├── .gitignore ├── pics ├── https1.png ├── index1.png ├── vuln1.png ├── vuln2.png ├── https_cmd.png ├── key_trust.png ├── showlog1.png ├── showtask1.png ├── showtask2.png ├── showtask3.png ├── key_manager.png └── https_showtask.png ├── static ├── images │ ├── logo.png │ ├── onError.gif │ ├── onFocus.gif │ ├── onShow.gif │ ├── tab-thbg.png │ ├── onCorrect.gif │ └── login │ │ └── admin-login-btnbg.gif ├── fonts │ ├── icomoon.eot │ ├── icomoon.ttf │ ├── icomoon.woff │ └── icomoon.svg ├── js │ ├── myjs │ │ ├── main.js │ │ └── function.js │ └── libs │ │ └── modernizr.min.js └── css │ ├── main.css │ ├── admin_login.css │ └── common.css ├── config.xml ├── CHANGELOG.md ├── test.log ├── templates ├── left.html ├── login.html ├── header.html ├── showtask.html ├── index.html ├── status.html ├── startask.html ├── insert.html └── info.html ├── README.md ├── foxscan.sql └── views.py /libs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .pyc 3 | -------------------------------------------------------------------------------- /pics/https1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/https1.png -------------------------------------------------------------------------------- /pics/index1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/index1.png -------------------------------------------------------------------------------- /pics/vuln1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/vuln1.png -------------------------------------------------------------------------------- /pics/vuln2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/vuln2.png -------------------------------------------------------------------------------- /pics/https_cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/https_cmd.png -------------------------------------------------------------------------------- /pics/key_trust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/key_trust.png -------------------------------------------------------------------------------- /pics/showlog1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/showlog1.png -------------------------------------------------------------------------------- /pics/showtask1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/showtask1.png -------------------------------------------------------------------------------- /pics/showtask2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/showtask2.png -------------------------------------------------------------------------------- /pics/showtask3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/showtask3.png -------------------------------------------------------------------------------- /pics/key_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/key_manager.png -------------------------------------------------------------------------------- /pics/https_showtask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/pics/https_showtask.png -------------------------------------------------------------------------------- /static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/logo.png -------------------------------------------------------------------------------- /static/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/fonts/icomoon.eot -------------------------------------------------------------------------------- /static/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/fonts/icomoon.ttf -------------------------------------------------------------------------------- /static/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/fonts/icomoon.woff -------------------------------------------------------------------------------- /static/images/onError.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/onError.gif -------------------------------------------------------------------------------- /static/images/onFocus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/onFocus.gif -------------------------------------------------------------------------------- /static/images/onShow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/onShow.gif -------------------------------------------------------------------------------- /static/images/tab-thbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/tab-thbg.png -------------------------------------------------------------------------------- /static/images/onCorrect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/onCorrect.gif -------------------------------------------------------------------------------- /libs/ssl/mitmproxy-ca-cert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/libs/ssl/mitmproxy-ca-cert.p12 -------------------------------------------------------------------------------- /static/images/login/admin-login-btnbg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengxuangit/Fox-scan/HEAD/static/images/login/admin-login-btnbg.gif -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 127.0.0.1 4 | root 5 | 123480 6 | 3306 7 | foxscan 8 | utf8 9 | 10 | 11 | http://127.0.0.1:8775 12 | 13 | 14 | .php,.asp,.aspx,.jsp,.jspx 15 | .ico,.flv,.js,.css,.jpg,.png,.jpeg,.gif,.pdf,.ss3,.txt,.rar,.zip,.avi,.mp4,.swf,.wmi,.exe,.mpeg 16 | 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.0.1 (2016-09-05) 4 | 5 | ### BUG FIX 6 | - 修复不能实时刷新新数据问题 7 | 8 | ### FEATURE 9 | - 添加自动保存成功数据功能 10 | 11 | 12 | ## v0.0.2 (2016-09-06) 13 | 14 | ### FEATURE 15 | - 任务展示页点击LOG按钮显示扫描日志功能 16 | 17 | 18 | ## v0.0.3 (2016-09-14) 19 | 20 | ### BUGFIX 21 | - 修复windows路径报错问题 22 | - 修复需要ipdb第三方包的问题 23 | - 修复root密码为空报错问题 24 | 25 | 26 | ## v0.1.0 (2016-10-04) 27 | 28 | ### BUGFIX 29 | - 修复爬虫网页同网站获取失败的问题 30 | - 修复停止任务无效的问题 31 | 32 | ### FEATURE 33 | - 将左侧task status连接到action/showtask 34 | - 添加HTTPS代理工具,支持https代理资源获取和检测 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test.log: -------------------------------------------------------------------------------- 1 | Fri, 05 Aug 2016 22:58:48 _internal.py[line:87] WARNING * Debugger is active! 2 | Fri, 05 Aug 2016 22:58:48 _internal.py[line:87] INFO * Debugger pin code: 322-285-974 3 | Fri, 05 Aug 2016 23:11:3Fri, 05 Aug 2016 23:11:33 _internal.py[line:87] INFO * Restarting with stat 4 | Fri, 05 Aug 2016 23:11:39 _internal.py[line:87] INFO * Restarting with stat 5 | Fri, 05 Aug 2016 23:11:45 _internal.py[line:87] INFO * Restarting with stat 6 | Fri, 05 Aug 2016 23:11:50 _internal.py[line:87] INFO * Restarting with stat 7 | Fri, 05 Aug 2016 23:11:55 _internal.py[line:87] INFO * Restarting with stat 8 | Fri, 05 Aug 2016 23:11:58 _internal.py[line:87] INFO * Restarting with stat 9 | Fri, 05 Aug 2016 23:12:03 _internal.py[line:87] INFO * Restarting with stat 10 | Fri, 05 Aug 2016 23:12:10 _internal.py[line:87] INFO * Restarting with stat 11 | -------------------------------------------------------------------------------- /libs/ssl/mitmproxy-dhparam.pem: -------------------------------------------------------------------------------- 1 | 2 | -----BEGIN DH PARAMETERS----- 3 | MIICCAKCAgEAyT6LzpwVFS3gryIo29J5icvgxCnCebcdSe/NHMkD8dKJf8suFCg3 4 | O2+dguLakSVif/t6dhImxInJk230HmfC8q93hdcg/j8rLGJYDKu3ik6H//BAHKIv 5 | j5O9yjU3rXCfmVJQic2Nne39sg3CreAepEts2TvYHhVv3TEAzEqCtOuTjgDv0ntJ 6 | Gwpj+BJBRQGG9NvprX1YGJ7WOFBP/hWU7d6tgvE6Xa7T/u9QIKpYHMIkcN/l3ZFB 7 | chZEqVlyrcngtSXCROTPcDOQ6Q8QzhaBJS+Z6rcsd7X+haiQqvoFcmaJ08Ks6LQC 8 | ZIL2EtYJw8V8z7C0igVEBIADZBI6OTbuuhDwRw//zU1uq52Oc48CIZlGxTYG/Evq 9 | o9EWAXUYVzWkDSTeBH1r4z/qLPE2cnhtMxbFxuvK53jGB0emy2y1Ei6IhKshJ5qX 10 | IB/aE7SSHyQ3MDHHkCmQJCsOd4Mo26YX61NZ+n501XjqpCBQ2+DfZCBh8Va2wDyv 11 | A2Ryg9SUz8j0AXViRNMJgJrr446yro/FuJZwnQcO3WQnXeqSBnURqKjmqkeFP+d8 12 | 6mk2tqJaY507lRNqtGlLnj7f5RNoBFJDCLBNurVgfvq9TCVWKDIFD4vZRjCrnl6I 13 | rD693XKIHUCWOjMh1if6omGXKHH40QuME2gNa50+YPn1iYDl88uDbbMCAQI= 14 | -----END DH PARAMETERS----- 15 | -------------------------------------------------------------------------------- /templates/left.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 『豪情』后台管理 6 | 7 | 8 | 9 |
10 |

后台管理

11 | 30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /libs/ssl/mitmproxy-ca-cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDoTCCAomgAwIBAgIGDWubM1FQMA0GCSqGSIb3DQEBCwUAMCgxEjAQBgNVBAMM 3 | CW1pdG1wcm94eTESMBAGA1UECgwJbWl0bXByb3h5MB4XDTE2MTAwMjExNDcyOVoX 4 | DTE5MTAwNDExNDcyOVowKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAlt 5 | aXRtcHJveHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsDKN/Wt6E 6 | YpcTpokZ2egsY+vX9aexEOc7qiZLwwcqkOxyaXaPnOJJ3zeDT21kWk4BljMvxbpM 7 | qCZJGSuE+xFdI8aj6D2EuJnwTkwfVeGDQbalpF9I2ZBECC1+nSL/c8uIPRkbqzDz 8 | 1hv0IXCpxF9awbgYmcvYNRGIWuYfkz72xrZMKl9TdZpGzWwi2g3tZ26EssFfGSD2 9 | xztldyTTUxS9RtC5V9pdCJPGXbLYCK0kVcNggGMQO5cp/dOZfgLoUdxACef42u6u 10 | ZMfBshsOZ5B8qubgi2qnMrgTr5GkguZ8CoudvDJRYK+0q5SZmpoa2X8nW2foKM5J 11 | ulvJcXgpVhBxAgMBAAGjgdAwgc0wDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhC 12 | AQEEBAMCAgQweAYDVR0lBHEwbwYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcD 13 | BAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQBgjcCARYGCisGAQQBgjcKAwEG 14 | CisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG+EIEATAOBgNVHQ8BAf8EBAMC 15 | AQYwHQYDVR0OBBYEFHfMOdsSAvHo3EPk8JlGEonN9F9jMA0GCSqGSIb3DQEBCwUA 16 | A4IBAQConUdOn5s+TgM4o7J9xWTxiG3l6Zi1VpRc/rTDRBrFrVX8Io8MwZigBLnu 17 | xd/cDiX1IwPOKvPGICyzI6mly9JeiegXw39nsVmHCu3Gsjvt17XBiSEK1g8dekXm 18 | X6uubNGpQ1W63JBJ8NmOmmw8mLvs+BCRw4ZBOyVDP0o8nbErF8UG0UQH1A2ijyo9 19 | AeAHdpkWfgNYZQMVL5GKDyEEU8lOZvZKrnlypPDCI7lQXQKcnn/aFJK0hJ7Kv8q5 20 | faNI6Ol2060penOeQ0gC5FzcvxosSp3NYJfw1cW3Ftpv5DSiHd6QItx6vcWuM8fl 21 | PwQ07WwOaw+Vpf/OFmd2EXhxz5bT 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /libs/ssl/mitmproxy-ca-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDoTCCAomgAwIBAgIGDWubM1FQMA0GCSqGSIb3DQEBCwUAMCgxEjAQBgNVBAMM 3 | CW1pdG1wcm94eTESMBAGA1UECgwJbWl0bXByb3h5MB4XDTE2MTAwMjExNDcyOVoX 4 | DTE5MTAwNDExNDcyOVowKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAlt 5 | aXRtcHJveHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsDKN/Wt6E 6 | YpcTpokZ2egsY+vX9aexEOc7qiZLwwcqkOxyaXaPnOJJ3zeDT21kWk4BljMvxbpM 7 | qCZJGSuE+xFdI8aj6D2EuJnwTkwfVeGDQbalpF9I2ZBECC1+nSL/c8uIPRkbqzDz 8 | 1hv0IXCpxF9awbgYmcvYNRGIWuYfkz72xrZMKl9TdZpGzWwi2g3tZ26EssFfGSD2 9 | xztldyTTUxS9RtC5V9pdCJPGXbLYCK0kVcNggGMQO5cp/dOZfgLoUdxACef42u6u 10 | ZMfBshsOZ5B8qubgi2qnMrgTr5GkguZ8CoudvDJRYK+0q5SZmpoa2X8nW2foKM5J 11 | ulvJcXgpVhBxAgMBAAGjgdAwgc0wDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhC 12 | AQEEBAMCAgQweAYDVR0lBHEwbwYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcD 13 | BAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQBgjcCARYGCisGAQQBgjcKAwEG 14 | CisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG+EIEATAOBgNVHQ8BAf8EBAMC 15 | AQYwHQYDVR0OBBYEFHfMOdsSAvHo3EPk8JlGEonN9F9jMA0GCSqGSIb3DQEBCwUA 16 | A4IBAQConUdOn5s+TgM4o7J9xWTxiG3l6Zi1VpRc/rTDRBrFrVX8Io8MwZigBLnu 17 | xd/cDiX1IwPOKvPGICyzI6mly9JeiegXw39nsVmHCu3Gsjvt17XBiSEK1g8dekXm 18 | X6uubNGpQ1W63JBJ8NmOmmw8mLvs+BCRw4ZBOyVDP0o8nbErF8UG0UQH1A2ijyo9 19 | AeAHdpkWfgNYZQMVL5GKDyEEU8lOZvZKrnlypPDCI7lQXQKcnn/aFJK0hJ7Kv8q5 20 | faNI6Ol2060penOeQ0gC5FzcvxosSp3NYJfw1cW3Ftpv5DSiHd6QItx6vcWuM8fl 21 | PwQ07WwOaw+Vpf/OFmd2EXhxz5bT 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FuckSQLi 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

后台管理

18 | 22 |
23 |
24 | 29 |
30 |
31 |
-------------------------------------------------------------------------------- /templates/showtask.html: -------------------------------------------------------------------------------- 1 | {% include "header.html" %} 2 | 3 | {% include "left.html" %} 4 | 5 | 10 |
11 |
12 |
HOME>TASK Distribute
13 |
14 |
15 |
16 |
17 |

Site information

18 |
19 |
20 |
21 | {# #} 22 | 23 |
24 |
25 |
26 |
27 |
28 | 关闭 29 |
30 | 遮罩层。 31 |
32 |
33 | 34 | 35 |
36 | 37 |
38 |
39 |
40 |
41 |
42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /static/js/myjs/main.js: -------------------------------------------------------------------------------- 1 | function ShowDiv(show_div, bg_div) { 2 | document.getElementById(show_div).style.display = 'block'; 3 | document.getElementById(bg_div).style.display = 'block'; 4 | var bgdiv = document.getElementById(bg_div); 5 | bgdiv.style.width = document.body.scrollWidth; 6 | // bgdiv.style.height = $(document).height(); 7 | $("#" + bg_div).height($(document).height()); 8 | }; 9 | //关闭弹出层 10 | function CloseDiv(show_div, bg_div) { 11 | document.getElementById(show_div).style.display = 'none'; 12 | document.getElementById(bg_div).style.display = 'none'; 13 | }; 14 | 15 | function ShowLog(taskid){ 16 | $.ajax({ 17 | url : '/action/showtask?type=log&taskid=' + taskid, 18 | dataType : "json", 19 | timeout: 10000, 20 | error : function(XMLHttpRequest, textStatus, errorThrown){ 21 | ShowLogDetail("Nothing here"); 22 | }, 23 | success : function (data) { 24 | ShowLogDetail(data); 25 | } 26 | }); 27 | } 28 | var close_html = "

" + 29 | "关闭
"; 30 | 31 | function ShowLogDetail(data) { 32 | $('#hides').empty(); 33 | $('#hides').append(close_html); 34 | var html = ""; 35 | $.each(data['log'], function(n, value){ 36 | for (var key in value){ 37 | html += "" + key + "" + ": " + value[key] + " "; 38 | } 39 | html += "
\n"; 40 | $('#hides').append(html); 41 | }); 42 | ShowDiv('hides','shows'); 43 | 44 | } 45 | 46 | function showdatadetail(data){ 47 | $('#hides').empty(); 48 | $('#hides').append(close_html); 49 | var html = ""; 50 | if (data['data'] == []){ 51 | return; 52 | } 53 | // alert(); 54 | $.each(data['data'][0]['value'][0]['data'], function(n, value){ 55 | for (var key in value){ 56 | html += "" + key + " " + ": " + value[key] + " "; 57 | } 58 | html += "
\n"; 59 | $('#hides').append(html); 60 | }); 61 | ShowDiv('hides','shows'); 62 | } 63 | 64 | 65 | function ShowPayload(taskid) { 66 | $.ajax({ 67 | url : '/action/showtask?type=payload&taskid=' + taskid, 68 | dataType : "json", 69 | timeout: 10000, 70 | error : function(XMLHttpRequest, textStatus, errorThrown){ 71 | ShowLogDetail("Nothing here"); 72 | }, 73 | success : function (data) { 74 | showdatadetail(data); 75 | } 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /libs/func.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #!-*- coding:utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import logging 7 | import json 8 | import base64 9 | import requests 10 | import urllib2 11 | import ssl 12 | from urlparse import urlparse 13 | # from models import MySQLHander 14 | import re 15 | import xml.etree.cElementTree as ET 16 | from requests.adapters import HTTPAdapter 17 | from requests.packages.urllib3.poolmanager import PoolManager 18 | 19 | 20 | SPIDER_HEADER = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko)" \ 21 | " Version/6.0 Mobile/10A5376e Safari/8536.25"} 22 | 23 | JSON_HEADER={'Content-Type': 'application/json'} 24 | 25 | 26 | def getrootpath(): 27 | return os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) 28 | 29 | def getrootdomain(domain): 30 | return urlparse(domain).netloc 31 | 32 | 33 | class XMLDOM(object): 34 | def __init__(self): 35 | xml = ET.parse("{0}{1}config.xml".format(getrootpath(), os.path.sep)) 36 | self.tree = xml.getroot() 37 | 38 | def GetElementByName(self, name): 39 | return self.tree.find(name).text 40 | 41 | #ensure HTTPAdapter to spider https 42 | class MyAdapter(HTTPAdapter): 43 | def init_poolmanager(self, connections, maxsize, block=False): 44 | self.poolmanager = PoolManager(num_pools=connections, 45 | maxsize=maxsize, 46 | block=block, 47 | ssl_version=ssl.PROTOCOL_TLSv1) 48 | class Tools: 49 | ''' 50 | 将request请求对象转换为SQLMAP的设置值 51 | ''' 52 | @staticmethod 53 | def do_sqlmap_options(request): 54 | options = {} 55 | for key in request.keys(): 56 | if request[key] == "True": 57 | options[key] = request[key] 58 | return options 59 | 60 | @staticmethod 61 | def dict2base64(dictobj): 62 | return base64.b64encode(json.dumps(dictobj)) 63 | 64 | @staticmethod 65 | def base642json(string): 66 | return json.loads(base64.b64decode(string)) 67 | 68 | @staticmethod 69 | def getjsondata(url, data=None): 70 | if data == None: 71 | try: 72 | text = json.loads(requests.get(url,None, headers=JSON_HEADER).text) 73 | return text 74 | except: 75 | return None 76 | else: 77 | try: 78 | text = json.loads(requests.post(url,data=data, headers=JSON_HEADER).text) 79 | return text 80 | except: 81 | return None 82 | 83 | 84 | if __name__ == '__main__': 85 | print getrootdomain("http://www.108js.com/article/article1/10025.html?id=58") 86 | 87 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% include "header.html" %} 2 | 3 | {% include "left.html" %} 4 | 5 |
6 |
7 |
Welcome to Use 。
8 |
9 |
10 |
11 |

快捷操作

12 |
13 |
14 |
15 | new target 16 | settings 17 | 20 |
21 |
22 |
23 |
24 |
25 |

系统基本信息

26 |
27 |
28 |
    29 |
  • 30 | fengxuan 31 |
  • 32 |
  • 33 | Apache/2.2.21 (Win64) PHP/5.3.10 34 |
  • 35 |
  • 36 | apache2handler 37 |
  • 38 |
  • 39 | v0.1 40 |
  • 41 |
42 |
43 |
44 | 59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /libs/models.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #!-*- coding:utf-8 -*- 3 | 4 | import os 5 | import MySQLdb 6 | import sys 7 | 8 | from func import XMLDOM 9 | 10 | class MySQLHander(object): 11 | def __init__(self): 12 | xml = XMLDOM() 13 | host = xml.GetElementByName('mysql/host').strip() 14 | username = xml.GetElementByName('mysql/username').strip() 15 | if xml.GetElementByName('mysql/password') == None: 16 | password = "" 17 | else: 18 | password = xml.GetElementByName('mysql/password').strip() 19 | port = xml.GetElementByName('mysql/port').strip() 20 | database = xml.GetElementByName('mysql/database').strip() 21 | charset = xml.GetElementByName('mysql/charset').strip() 22 | try: 23 | self._conn = MySQLdb.connect(host=host, 24 | port=int(port), 25 | user=username, 26 | passwd=password, 27 | db=database, 28 | charset=charset) 29 | except MySQLdb.Error, e: 30 | self.error_code = e.args[0] 31 | error_msg = 'MySQL error! ', e.args[0], e.args[1] 32 | print error_msg 33 | sys.exit() 34 | self._cur = self._conn.cursor() 35 | self._instance = MySQLdb 36 | 37 | 38 | def query(self,sql): 39 | try: 40 | self._cur.execute("SET NAMES utf8") 41 | result = self._cur.execute(sql) 42 | except MySQLdb.Error, e: 43 | self.error_code = e.args[0] 44 | print "DATABASE ERROR: ",e.args[0],e.args[1] 45 | result = False 46 | return result 47 | 48 | def update(self,sql): 49 | try: 50 | self._cur.execute("SET NAMES utf8") 51 | result = self._cur.execute(sql) 52 | self._conn.commit() 53 | except MySQLdb.Error, e: 54 | self.error_code = e.args[0] 55 | print "DATABASE ERROR: ",e.args[0],e.args[1] 56 | result = False 57 | return result 58 | 59 | def insert(self,sql): 60 | try: 61 | self._cur.execute("SET NAMES utf8") 62 | self._cur.execute(sql) 63 | self._conn.commit() 64 | return self._conn.insert_id() 65 | except MySQLdb.Error, e: 66 | self.error_code = e.args[0] 67 | print "DATABASE ERROR: ",e.args[0],e.args[1] 68 | return False 69 | 70 | def fetchAllRows(self): 71 | return self._cur.fetchall() 72 | 73 | def fetchOneRow(self): 74 | return self._cur.fetchone() 75 | 76 | def getRowCount(self): 77 | return self._cur.rowcount 78 | 79 | def commit(self): 80 | self._conn.commit() 81 | 82 | def rollback(self): 83 | self._conn.rollback() 84 | 85 | def __del__(self): 86 | try: 87 | self._cur.close() 88 | self._conn.close() 89 | except: 90 | pass 91 | 92 | def close(self): 93 | self.__del__() 94 | 95 | class SqlMapTask(object): 96 | pass 97 | -------------------------------------------------------------------------------- /libs/ssl/mitmproxy-ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCsDKN/Wt6EYpcT 3 | pokZ2egsY+vX9aexEOc7qiZLwwcqkOxyaXaPnOJJ3zeDT21kWk4BljMvxbpMqCZJ 4 | GSuE+xFdI8aj6D2EuJnwTkwfVeGDQbalpF9I2ZBECC1+nSL/c8uIPRkbqzDz1hv0 5 | IXCpxF9awbgYmcvYNRGIWuYfkz72xrZMKl9TdZpGzWwi2g3tZ26EssFfGSD2xztl 6 | dyTTUxS9RtC5V9pdCJPGXbLYCK0kVcNggGMQO5cp/dOZfgLoUdxACef42u6uZMfB 7 | shsOZ5B8qubgi2qnMrgTr5GkguZ8CoudvDJRYK+0q5SZmpoa2X8nW2foKM5JulvJ 8 | cXgpVhBxAgMBAAECggEBAIYYB6owIbQev08ygjLi0oEek+eq8DsiSIcJM3XjGIfF 9 | knQN3LlL9lbLIhI26rTHaXr1HQoD2xL6D3TzqCaqJDtqsdx4GtKBqoFQFSZrIivS 10 | IM/zT8yQvU847HR9dpSRJLYXoKUfBTVW0Eyzb4Lxqbwrthd+bxEhM3wKFMfRVMay 11 | jE7v1M9DStBwYqFJGbQ+xVHMzwsghJZUKG3CJIKstGXClU/QbUdDwIFh8SRBD46w 12 | JczSmjd6vspzaEJYmvrhwdKWA+UacexE8lH8WHOFdN2BGrqrRP4zAnKDFSBYWRGf 13 | MQSEdbY6m56T17xi2CoeiNJfVkNwhgVtfcFdCNK7Da0CgYEA28S247fk+ik5IBEd 14 | YeHUgc7A2qCWwYHwwtaGFtaWsWyBQKkHbR5p9//2kXnGt8LPMzCtz1853H6CvLi1 15 | YpTiJ5iudL5Yf+VfuAuLQhKDX+xrAheYdY6G6nqlCkpyY+2L7SycrI4dmQfdSbEe 16 | 99tPr/XAn7yd5xflrPqqSZmx4KMCgYEAyGnzYFkIPiU2GWQjWYna4HqdM7OM8bzk 17 | 84yoirukFxVBlJo7Pb+4MfMBiuqp2FBC5VfcNFh/bg2EOjfCik5zbQr0EspApGNq 18 | UVZDBaFQEVW590zCtH8RbhgxqHKpBfoz7eBF/055dnxLOzcEANjRKxTV+T9HwdJS 19 | kH3nKVmW19sCgYEAtGq34hZT6nLxLLwgLP0iYjaD6Hexi8bLCojmp9Ue/SUgrx6U 20 | tCYlxKzjlOYuFyncxB+QcQ+yBqvtVFUmw3mKeAtGHR0utkBt5j/D4UglhhgmeR85 21 | 0Dhj1hc9akdXxWV8XAcl0BsTfVARgK/hxoTK1J+htQE5eEAME4ftSGLevpUCgYBM 22 | UbShoyX1bHw+jRi9Fzcntum4b46j2/ggGxdvxWcGd0zDBzy6FhFRzCVxPk2xl1by 23 | OVQdBvp38WPCO8u0mY1xH/O0WBrnvwgUs1HQig6Qm2G3IB8hVyZPE52NdSSSpyYx 24 | Vu+w+rRcf5aylQ/MNsTosAWP5h4wXCSe66Mk5v3/cwKBgQDICPMtI/BZsdqc3E2g 25 | HfLEgzQxkzExdyLdkfzvehjdqfPQMqNhrenG9tzZfIK+V3DDWIBVNuRfPREs9Iam 26 | Vps+drZyy0Ho+/Bn9t6s8za6sH2ppFSRvDkeei3JY+rvei1xXpBUEIFej0hMi/J4 27 | v1xONK/C23QLcHVDlK4Daah/QA== 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDoTCCAomgAwIBAgIGDWubM1FQMA0GCSqGSIb3DQEBCwUAMCgxEjAQBgNVBAMM 31 | CW1pdG1wcm94eTESMBAGA1UECgwJbWl0bXByb3h5MB4XDTE2MTAwMjExNDcyOVoX 32 | DTE5MTAwNDExNDcyOVowKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAlt 33 | aXRtcHJveHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsDKN/Wt6E 34 | YpcTpokZ2egsY+vX9aexEOc7qiZLwwcqkOxyaXaPnOJJ3zeDT21kWk4BljMvxbpM 35 | qCZJGSuE+xFdI8aj6D2EuJnwTkwfVeGDQbalpF9I2ZBECC1+nSL/c8uIPRkbqzDz 36 | 1hv0IXCpxF9awbgYmcvYNRGIWuYfkz72xrZMKl9TdZpGzWwi2g3tZ26EssFfGSD2 37 | xztldyTTUxS9RtC5V9pdCJPGXbLYCK0kVcNggGMQO5cp/dOZfgLoUdxACef42u6u 38 | ZMfBshsOZ5B8qubgi2qnMrgTr5GkguZ8CoudvDJRYK+0q5SZmpoa2X8nW2foKM5J 39 | ulvJcXgpVhBxAgMBAAGjgdAwgc0wDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhC 40 | AQEEBAMCAgQweAYDVR0lBHEwbwYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcD 41 | BAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQBgjcCARYGCisGAQQBgjcKAwEG 42 | CisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG+EIEATAOBgNVHQ8BAf8EBAMC 43 | AQYwHQYDVR0OBBYEFHfMOdsSAvHo3EPk8JlGEonN9F9jMA0GCSqGSIb3DQEBCwUA 44 | A4IBAQConUdOn5s+TgM4o7J9xWTxiG3l6Zi1VpRc/rTDRBrFrVX8Io8MwZigBLnu 45 | xd/cDiX1IwPOKvPGICyzI6mly9JeiegXw39nsVmHCu3Gsjvt17XBiSEK1g8dekXm 46 | X6uubNGpQ1W63JBJ8NmOmmw8mLvs+BCRw4ZBOyVDP0o8nbErF8UG0UQH1A2ijyo9 47 | AeAHdpkWfgNYZQMVL5GKDyEEU8lOZvZKrnlypPDCI7lQXQKcnn/aFJK0hJ7Kv8q5 48 | faNI6Ol2060penOeQ0gC5FzcvxosSp3NYJfw1cW3Ftpv5DSiHd6QItx6vcWuM8fl 49 | PwQ07WwOaw+Vpf/OFmd2EXhxz5bT 50 | -----END CERTIFICATE----- 51 | -------------------------------------------------------------------------------- /templates/status.html: -------------------------------------------------------------------------------- 1 | {% include "header.html" %} 2 | 3 | {% include "left.html" %} 4 | 5 |
6 | 7 |
8 | 9 |
10 |
11 |
12 |
13 | 14 | 15 | 16 | 22 | 23 | 24 | 25 | 26 |
选择分类: 17 | 21 | 关键字:
27 |
28 |
29 |
30 |
31 |
32 |
33 | Domain settings 34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | 55 | 59 | 60 |
IDurlstatuspayloadtimeoperation
58本地代理 … 51 | 127.0.0.1:8445Off2013-12-30 22:34:00 56 | update 57 | delete 58 |
61 |
1 item 1/1 page
62 |
63 |
64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | .sidebar-wrap{float: left;width: 189px;min-height:700px;background: #f2f2f2;border-right:1px solid #ccc;/*cursor:e-resize;*/} 2 | .main-wrap{margin-left: 190px;min-height:100%;} 3 | .sidebar-title{height: 40px;line-height: 40px;text-indent:1em;font-size: 24px;text-align: left;} 4 | .sidebar-title h1{font-weight: normal;} 5 | .sidebar-content{padding-top: 5px;} 6 | .sidebar-list li{border:1px solid #e5e5e5;border-width:1px 0;} 7 | .sidebar-list li .icon-font{margin-right: 5px;color: #888;font-size: 14px;} 8 | .sidebar-list li a{padding: 0 16px 0 20px;display: block;height: 38px;line-height: 38px;color: #333;} 9 | .sidebar-list li a:hover{background: #fff;color: #1963AA;} 10 | .sub-menu{border-top: 1px solid #e5e5e5;background: #fff;} 11 | .sub-menu li{padding-left: 21px;} 12 | .sub-menu li.on{background: #1963AA;} 13 | .sub-menu li.on a{background: #1963AA;color: #fff;} 14 | .sub-menu li.on .icon-font{color: #fff;} 15 | .sub-menu .icon-font{font-size: 11px;} 16 | .options-font{font-size: larger;font-family: "Microsoft YaHei";} 17 | /* main */ 18 | .crumb-wrap{height: 40px;line-height: 39px;border-bottom: 1px solid #e5e5e5;background: #f5f5f5;} 19 | .crumb-list{padding-left: 12px;} 20 | .crumb-list .icon-font{margin-right: 5px;} 21 | .crumb-step{margin: 0 5px;color: #b2c2e0;font-family: serif;} 22 | .search-wrap{padding: 15px 0;border-bottom: 1px solid #e5e5e5;} 23 | .search-tab tr{line-height: 35px;} 24 | .search-tab th{text-align: right;padding-right:10px;font-weight: normal;} 25 | .search-tab td{padding: 0 5px;} 26 | .common-text{height: 23px;line-height: 23px;padding: 2px 4px;border: 1px solid #ccc;background: #fff;border-radius:5px;} 27 | .result-wrap{padding:10px 20px;border-bottom: 1px solid #e5e5e5;} 28 | .result-title{line-height: 35px;padding-bottom: 5px;overflow: hidden;} 29 | .comment-title{line-height: 35px;margin-bottom: 10px;overflow: hidden;} 30 | .result-list a{margin-right: 15px;} 31 | .result-list i{padding-right: 5px;} 32 | .result-tab{border-collapse:collapse;border: 1px solid #ddd;} 33 | .result-tab th{font-weight: normal;font-size: 15px;text-align: left;background: url(../images/tab-thbg.png) #f9f9f9 0 bottom repeat-x;} 34 | .result-tab th,.result-tab td{padding:5px;border-bottom: 1px solid #ddd;border-right: 1px solid #e1e1e1;} 35 | .result-tab tr{line-height:35px;} 36 | .result-tab th.tc,.result-tab td.tc{text-align: center;} 37 | .result-tab tr:nth-child(odd){background: #f9f9f9;} 38 | .result-tab tr:hover{background: #f1f1f1;} 39 | .result-tab tr.even-tr{background: #e9fff2;} 40 | .comment-tab{border-bottom: 1px solid #ddd;padding-left: 15px;margin-bottom: 10px;} 41 | .comment-tab a{float: left;} 42 | .comment-tab a.on{padding: 0 15px;background: #49afcd;color: #fff;border-radius:5px 5px 0 0;} 43 | /* config */ 44 | .config-items{margin-bottom: 25px;} 45 | .config-title{margin-bottom: 10px;} 46 | .config-title h1{font-size: 14px;font-weight: normal;} 47 | .config-title h1 i{margin-right: 5px;font-size: 12px;} 48 | .columns-title{padding: 10px 0;height: 35px;line-height: 35px;overflow: hidden;} 49 | /*.columns-title .comment-tab{padding-left: 0;}*/ 50 | .visitor-img{float: left;} 51 | .visitor-info{float: left;padding-left: 10px;line-height:23px;} 52 | .visitor-email{color: #aaa;} 53 | .short-wrap a{margin-right: 20px;} 54 | .short-wrap a i{margin-right: 5px;} 55 | .res-lab{display: inline-block;width: 150px;padding-right: 10px;text-align: right;} 56 | .sys-info-list li{line-height: 35px;border-bottom: 1px dashed #eaeaea;} 57 | .res-lab{color: #909090;} 58 | .res-info{font-size: 15px;} 59 | .sort-input{width: 25px;text-align: center;} 60 | 61 | -------------------------------------------------------------------------------- /static/js/myjs/function.js: -------------------------------------------------------------------------------- 1 | String.prototype.format=function(){ 2 | if(arguments.length==0) return this; 3 | for(var s=this, i=0; i" 12 | 13 | var ChildDemo = "

" + 14 | "" + 15 | "" + 16 | "" + 17 | "
*Domain:
*Operator: " + 18 | " {3} " + 19 | "" + 20 | "" + 21 | "" + 22 | "
"; 23 | 24 | function setSelectUserNo(radioObj){ 25 | var radioCheck= radioObj.value; 26 | if("True"==radioCheck){ 27 | $(radioObj).attr("checked",false); 28 | $(radioObj).val("False"); 29 | }else{ 30 | $(radioObj).attr("checked", true); 31 | $(radioObj).val("True"); 32 | } 33 | } 34 | 35 | function AppendChildStatus(data, $obj){ 36 | var child = ChildDemo.concat(); 37 | //当返回的任务数大于现在的数据时候才改变. 38 | $('#tasknum').html(data['number']); 39 | if (taskid_dict.indexOf(data['taskid']) == -1) 40 | taskid_dict.push(data['taskid']); 41 | $obj.empty(); 42 | var targetlist = []; 43 | $.each(data['data'], function(n, value){ 44 | targetlist.push(value); 45 | }); 46 | targetlist.sort(function (a, b) { 47 | if(a.success > b.success){ 48 | return -1; 49 | }else if (a.success > b.success){ 50 | return 0; 51 | }else{ 52 | return 1; 53 | } 54 | }); 55 | var str = ""; 56 | for (var i=0;i< targetlist.length; i++){ 57 | // $obj.append() 58 | var value = targetlist[i]; 59 | if (value['success'] == 1){ 60 | str = child.format(value['target'], value['taskid'], " red_table", value['status']); 61 | }else{ 62 | str = child.format(value['target'], value['taskid'], "", value['status']); 63 | } 64 | $obj.append(str); 65 | } 66 | } 67 | 68 | 69 | function ajaxGetjson($obj){ 70 | $.ajax({ 71 | url : '/action/showtask?action=refresh', 72 | dataType : "json", 73 | success : function (jdata) { 74 | AppendChildStatus(jdata, $obj); 75 | } 76 | }); 77 | } 78 | 79 | function STOPTASK(taskid="") { 80 | if (taskid == ""){ 81 | for (var i =0;i 25 | 26 | 127.0.0.1 27 | root 28 | 123480 29 | 3306 30 | foxscan 31 | utf8 32 | 33 | 34 | http://127.0.0.1:8775 35 | 36 | 37 | .php,.asp,.aspx,.jsp,.jspx 38 | 39 | .ico,.flv,.js,.css,.jpg,.png,.jpeg,.gif,.pdf,.ss3,.txt,.rar,.zip,.avi,.mp4,.swf,.wmi,.exe,.mpeg 40 | 41 | 42 | 43 | 44 | sqlmap标签为你的sqlmap地址,typelist类型设置为黑名单和白名单设置,用于爬虫用。默认可以不用改。 45 | 46 | ###DATABASE 47 | 48 | CREATE DATABASE `foxscan` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 49 | 50 | source foxscan.sql 51 | 52 | ##Run 53 | 54 | 1 首先运行sqlmapapi.py 55 | 56 | ``` 57 | python sqlmapapi.py -s 58 | ``` 59 | 60 | 2 运行本程序WEB界面 61 | 62 | ``` 63 | python views.py 64 | ``` 65 | 66 | 3 打开浏览器输入控制台提示的访问地址(这里是http://127.0.0.1:8775) 在这里配置你的目标网站,sqlmap的地址,爬虫的过滤类型以及代理地址。 67 | 68 | 1. 这里的Domain,即代表爬虫的时候不会获取这个根域名之外的网站链接,同一时刻只能添加一次目标 69 | 2. 需要更改目标的话需要重新进入这个界面配置,但是会删除之前的所有在跑的任务 70 | 71 | 72 | ![index1page](pics/index1.png) 73 | 74 | 4 在配置完任务信息后,可以进入到libs目录中,运行 75 | 76 | ``` 77 | python proxy.py 8081 78 | ``` 79 | 启动本地代理服务器,然后再配置浏览器代理,即可达到被动扫描的效果 80 | 例如: 81 | 82 | ![vuln1](pics/vuln1.png) 83 | 84 | 写了一个很简单的POST登录框。 85 | 控制台输出这样的字样后代表加入队列扫描 86 | 87 | ![vuln2](pics/vuln2.png) 88 | 89 | 如果没有,说明是第三方网站或者访问的是静态文件资源,则不会加入到扫描队列中! 90 | 91 | 92 | 5 配置完成之后点击FUCK IT按钮,就会提示你成功添加一个目标,进入到任务详情页。 93 | 这里会显示说有在跑的任务,使用AJAX请求每3秒刷新一次。 94 | 95 | ![showtask1](pics/showtask1.png) 96 | 97 | 如果有成功的目标,就会显示为红色 98 | 99 | ![successtask](pics/showtask2.png) 100 | 101 | 可以看到我们刚才的POST注入已经扫描完成。 102 | 103 | ![successtask2](pics/showtask3.png) 104 | 105 | 点击LOG按钮可以查看扫描日志。 106 | ![showlog](pics/showlog1.png) 107 | 108 | 109 | 6 程序会自动有一个异步非阻塞追踪线程,如果发现有成功的目标,就会把目标和payload防到`successlist` 表中 110 | 111 | 112 | 7 HTTPS资源获取 (2016/10/04) 113 | 114 | 这里使用libs/wyproxy.py脚本,这里是借鉴猪猪侠的代理工具简化开发了一下https://github.com/ring04h/wyproxy 115 | 116 | 在此感谢猪哥的轮子 117 | 118 | 1. Mac OS X 安装配置 SSL 证书 并信任 119 | 120 | `$ wget https://raw.githubusercontent.com/fengxuangit/Fox-scan/master/libs/ssl/mitmproxy-ca.pem` 121 | 122 | 在Finder中双击运行mitmproxy-ca.pem 123 | 124 | 进入钥匙串访问工具, 选择mitmproxy的证书 125 | 126 | ![key_manage](./pics/key_manager.png) 127 | 128 | 选择始终信任该证书, 即可生效, 便能成功捕捉所有HTTPS的流量 129 | 130 | ![key_trust](./pics/key_trust.png) 131 | 132 | 运行libs/wyproxy.py 133 | 134 | python libs/wyproxy.py -p 8888 135 | 136 | ![https_cmd](./pics/https_cmd.png) 137 | 138 | 浏览器上添加公钥信任 139 | 140 | ![https_web](./pics/https1.png) 141 | 142 | 后台就会检测https的网页了 143 | 144 | ![https_scan](./pics/https_showtask.png) 145 | 146 | 147 | 148 | 149 | 150 | ##TODO 151 | 基本可以使用,但是还是有一些BUG。 152 | 153 | BUG: 154 | 155 | 1. AJAX刷新有时候不能正确实时展示。(fixed) 156 | 2. 代理功能有时候在数据库不支持长链接的情况下会报错(fixed) 157 | 158 | 还有一些功能未能实现 159 | 160 | FEATURE: 161 | 162 | 1. 点击LOG,可以查看扫描日志 (done) 163 | 2. 添加PAYLOAD选项,可以查看到PAYLOAD(done) 164 | 3. 添加Command按钮,可以生成注入成功的sqlmap命令 165 | 166 | ##CHANGELOG 167 | 168 | * CHANGELOG 169 | 170 | ##License 171 | 172 | > + fengxuan - ***mOon Security Team*** 2016/09/03 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /foxscan.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.7.9, for osx10.9 (x86_64) 2 | -- 3 | -- Host: 127.0.0.1 Database: foxscan 4 | -- ------------------------------------------------------ 5 | -- Server version 5.7.10 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `settings` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `settings`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!40101 SET character_set_client = utf8 */; 25 | CREATE TABLE `settings` ( 26 | `id` int(11) NOT NULL AUTO_INCREMENT, 27 | `server` varchar(100) DEFAULT NULL, 28 | `proxyaddr` varchar(100) DEFAULT NULL, 29 | `writelist` text, 30 | `blacklist` text, 31 | `rootdomain` varchar(100) DEFAULT NULL, 32 | `blackdomain` text, 33 | PRIMARY KEY (`id`) 34 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 35 | /*!40101 SET character_set_client = @saved_cs_client */; 36 | 37 | -- 38 | -- Dumping data for table `settings` 39 | -- 40 | 41 | LOCK TABLES `settings` WRITE; 42 | /*!40000 ALTER TABLE `settings` DISABLE KEYS */; 43 | INSERT INTO `settings` VALUES (1,'http://127.0.0.1:8775','http://127.0.0.1:8081','php,asp,aspx,jsp,jspx','ico,flv,.js,css,jpg,png,jpeg,gif,pdf,ss3,txt,rar,zip,avi,mp4,swf,wmi,exe,mpeg','fengxuan.com','127.0.0.1:5000'); 44 | /*!40000 ALTER TABLE `settings` ENABLE KEYS */; 45 | UNLOCK TABLES; 46 | 47 | -- 48 | -- Table structure for table `successlist` 49 | -- 50 | 51 | DROP TABLE IF EXISTS `successlist`; 52 | /*!40101 SET @saved_cs_client = @@character_set_client */; 53 | /*!40101 SET character_set_client = utf8 */; 54 | CREATE TABLE `successlist` ( 55 | `id` int(11) NOT NULL AUTO_INCREMENT, 56 | `target` varchar(100) DEFAULT NULL, 57 | `request_body` text, 58 | `data` text, 59 | PRIMARY KEY (`id`) 60 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 61 | /*!40101 SET character_set_client = @saved_cs_client */; 62 | 63 | -- 64 | -- Dumping data for table `successlist` 65 | -- 66 | 67 | LOCK TABLES `successlist` WRITE; 68 | /*!40000 ALTER TABLE `successlist` DISABLE KEYS */; 69 | /*!40000 ALTER TABLE `successlist` ENABLE KEYS */; 70 | UNLOCK TABLES; 71 | 72 | -- 73 | -- Table structure for table `task` 74 | -- 75 | 76 | DROP TABLE IF EXISTS `task`; 77 | /*!40101 SET @saved_cs_client = @@character_set_client */; 78 | /*!40101 SET character_set_client = utf8 */; 79 | CREATE TABLE `task` ( 80 | `id` int(11) NOT NULL AUTO_INCREMENT, 81 | `target` text, 82 | `taskid` varchar(45) DEFAULT NULL, 83 | `server` varchar(100) DEFAULT NULL, 84 | `user` varchar(45) DEFAULT NULL, 85 | `data` text, 86 | `status` varchar(45) DEFAULT NULL, 87 | `success` int(11) DEFAULT 0, 88 | `action` int(11) DEFAULT '0', 89 | PRIMARY KEY (`id`) 90 | ) ENGINE=InnoDB AUTO_INCREMENT=527 DEFAULT CHARSET=utf8; 91 | /*!40101 SET character_set_client = @saved_cs_client */; 92 | 93 | -- 94 | -- Dumping data for table `task` 95 | -- 96 | 97 | LOCK TABLES `task` WRITE; 98 | /*!40000 ALTER TABLE `task` DISABLE KEYS */; 99 | /*!40000 ALTER TABLE `task` ENABLE KEYS */; 100 | UNLOCK TABLES; 101 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 102 | 103 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 104 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 105 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 106 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 107 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 108 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 109 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 110 | 111 | -- Dump completed on 2016-09-03 19:53:09 112 | -------------------------------------------------------------------------------- /static/css/admin_login.css: -------------------------------------------------------------------------------- 1 | result-content@charset "utf-8"; 2 | /******************************** 3 | * @autor: haoqing 4 | * @time : 2011-03 5 | * @link : jikeytang@gmail.com 6 | * @info : admin-css 7 | *******************************/ 8 | *{margin:0;padding:0;} 9 | body{font:14px/1.5 '微软雅黑';background:#f9f9f9;} 10 | a{color:#00007F;text-decoration:none;} 11 | a:hover{color:#bd0a01;text-decoration:underline;} 12 | .admin_login_wrap{margin:140px auto 0;width:312px;} 13 | .admin_login_wrap h1{font-family:'微软雅黑';font-weight: normal;font-size:20px;margin-bottom:15px;} 14 | .adming_login_border{box-shadow:1px 2px 3px #ccc;border:1px solid #eee;background:#fff;padding:0 5px 15px;overflow:hidden;} 15 | .admin_input{margin:15px auto 0;width:280px;} 16 | .admin_items li{line-height:28px;margin-bottom: 5px;list-style:none;clear: both;} 17 | .admin_input label{display:block;margin-bottom:5px;} 18 | .admin_input_style{border:1px solid #e6e6e6;background:#fff;padding:3px;height:30px;line-height:30px;font-family:Arial;color:#666;border-radius:5px;transition-duration:0.3s;} 19 | .admin_input_style:focus{border-color: rgba(82, 168, 236, 0.8);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);background:#f8f8f8;} 20 | .btn{display:inline-block;*display:inline;padding:12px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#ffffff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ffffff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#ffffff,#e6e6e6);background-image:-o-linear-gradient(top,#ffffff,#e6e6e6);background-image:linear-gradient(to bottom,#ffffff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbbbbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);} 21 | .btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9;} 22 | .btn:active,.btn.active{background-color:#cccccc \9;} 23 | .btn:first-child{*margin-left:0;} 24 | .btn:hover{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} 25 | .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} 26 | .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);} 27 | .btn-primary{width: 100%;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#0044cc;background-image:-moz-linear-gradient(top,#0088cc,#0044cc);background-image:-webkit-gradient(linear,0 0,0 100%,from(#0088cc),to(#0044cc));background-image:-webkit-linear-gradient(top,#0088cc,#0044cc);background-image:-o-linear-gradient(top,#0088cc,#0044cc);background-image:linear-gradient(to bottom,#0088cc,#0044cc);background-repeat:repeat-x;border-color:#0044cc #0044cc #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);} 28 | .btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;} 29 | .btn-primary:active,.btn-primary.active{background-color:#003399 \9;} 30 | .admin_copyright{color:#585858;margin-top:10px;font-family:Arial;text-align:center;} 31 | .admin_copyright a:link,.admin_copyright a:visited{color:#f90;} 32 | .admin_copyright a:hover{color:#f90;} 33 | -------------------------------------------------------------------------------- /views.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #!-*- coding:utf-8 -*- 3 | 4 | import json 5 | import threading 6 | import multiprocessing 7 | import requests 8 | from flask import Flask,render_template,request,session,jsonify,redirect 9 | 10 | from libs.action import SqlMapAction,Spider_Handle,Save_Success_Target 11 | from libs.func import Tools 12 | from libs.models import MySQLHander 13 | from libs.action import Action 14 | from libs.proxy import run_proxy 15 | 16 | app = Flask(__name__) 17 | 18 | mysql = MySQLHander() 19 | 20 | app.config.update(dict( 21 | DEBUG=True, 22 | SECRET_KEY="546sdafwerxcvSERds549fwe8rdxfsaf98we1r2" 23 | )) 24 | 25 | app.config.from_envvar('AUTOSQLI_SETTINGS', silent=True) 26 | 27 | app.secret_key = "34$#4564dsfaWEERds/*-()^=sadfWE89SA" 28 | 29 | SqlMap = SqlMapAction() 30 | 31 | @app.route('/') 32 | def index(): 33 | return render_template('index.html') 34 | 35 | @app.route('/index') 36 | def settings_views(): 37 | return render_template('index.html') 38 | 39 | @app.route('/settings', methods=['GET', 'POST']) 40 | def settings_settings_info(): 41 | return render_template('info.html') 42 | 43 | #TODO user=session['user'] 44 | @app.route('/action/startask', methods=['GET', 'POST']) 45 | def action_startask(): 46 | if request.method == 'GET': 47 | return render_template('startask.html') 48 | else: 49 | #删除之前的任务 50 | SqlMap.DeleteAllTask() 51 | #转换为sqlmap的设置 52 | options = Tools.do_sqlmap_options(request.form) 53 | #更新整体的设置 54 | SqlMap.update_settings(request) 55 | #线程启动任务,后台运行,没有join 56 | t = threading.Thread(target=Spider_Handle,args=(request.form['target'],options,)) 57 | t.start() 58 | t = threading.Thread(target=Save_Success_Target,args=()) 59 | t.start() 60 | return redirect('/action/showtask') 61 | return "" 62 | return "" 63 | 64 | @app.route('/action/showtask', methods=['GET']) 65 | def action_showtask(): 66 | data = {"number":0, "data":[]} 67 | if request.args.has_key('action') and request.args['action'] == "refresh": 68 | mysql = MySQLHander() 69 | sql = "select taskid,target,success,status from task" 70 | mysql.query(sql) 71 | source = mysql.fetchAllRows() 72 | #获取正在扫描的URL 73 | num = 0 74 | for line in source: 75 | num += 1 76 | data['data'].append({"taskid":line[0], "target":line[1], "success":line[2], "status":line[3]}) 77 | data['number'] = num 78 | mysql.close() 79 | return json.dumps(data) 80 | if request.args.has_key('type'): 81 | if request.args['type'] == "log": 82 | sqlaction = SqlMapAction() 83 | server = sqlaction._get_server() 84 | url = "{0}/scan/{1}/log".format(server, request.args['taskid']) 85 | return json.dumps(Tools.getjsondata(url)) 86 | if request.args['type'] == "payload": 87 | sqlaction = SqlMapAction() 88 | server = sqlaction._get_server() 89 | url = "{0}/scan/{1}/data".format(server, request.args['taskid']) 90 | return json.dumps(Tools.getjsondata(url)) 91 | return render_template('showtask.html') 92 | 93 | @app.route('/action/showdetail', methods=['GET']) 94 | def action_showjson(): 95 | data = {"target":"", "data":"", "success":0, "status":"running"} 96 | if request.args.has_key('taskid'): 97 | taskid = request.args['taskid'] 98 | sql = "select target,data,success,status where taskid = '{0}'".format(taskid) 99 | mysql = MySQLHander() 100 | mysql.query(sql) 101 | resource = mysql.fetchOneRow() 102 | data = {"target":resource[0], "data":resource[1], "success":resource[2], "status":resource[4]} 103 | return json.dumps(data) 104 | 105 | 106 | @app.route('/action/stoptask') 107 | def action_status(): 108 | if request.args['taskidlist'] != "": 109 | taskidlist = [] 110 | if request.args['taskidlist'].find(",") > 0: 111 | taskidlist = request.args['taskidlist'].split(',') 112 | else: 113 | taskidlist.append(request.args['taskidlist']) 114 | return json.dumps({"status":SqlMap.StopTask(taskidlist)}) 115 | return json.dumps({"error":"no taskid"}) 116 | 117 | 118 | if __name__ == '__main__': 119 | app.run() -------------------------------------------------------------------------------- /templates/startask.html: -------------------------------------------------------------------------------- 1 | {% include "header.html" %} 2 | 3 | {% include "left.html" %} 4 | 5 | 9 |
10 |
11 |
HOME>TASK Distribute
12 |
13 |
14 | 15 |
16 |
17 |

Site information

18 |
19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 60 | 61 | 62 | 63 | 67 | 68 | 69 | 70 | 85 | 86 | 87 | 88 | 92 | 93 |
*Domain:
*Mode: 32 | 34 | 35 | 37 |
SqlMap address: 42 | 44 |
Write List: 49 | 51 |
Black List: 56 | 59 |
Proxy Address: 64 | 66 |
*Options: 71 | 72 | 73 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
89 | 90 | 91 |
94 |
95 |
96 |
97 |
98 |
99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /templates/insert.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 后台管理 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |

后台管理

15 | 19 |
20 |
21 | 26 |
27 |
28 |
29 |
30 | 60 | 61 |
62 | 63 |
64 |
首页>作品管理>新增作品
65 |
66 |
67 |
68 |
69 | 70 | 71 | 72 | 78 | 79 | 80 | 81 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 103 | 104 |
*分类: 73 | 77 |
*标题: 82 | 83 |
作者:
*缩略图:
内容:
100 | 101 | 102 |
105 |
106 |
107 |
108 | 109 |
110 | 111 |
112 | 113 | -------------------------------------------------------------------------------- /templates/info.html: -------------------------------------------------------------------------------- 1 | {% include "header.html" %} 2 | 3 | {% include "left.html" %} 4 | 5 |
6 | 7 |
8 | 9 |
10 | 30 |
31 | 32 | 39 |
40 |
41 | Proxy settings 42 |
43 |
44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 61 | 62 | 63 | 67 | 68 |
IDaddress messageproxy addressproxy statusupdate timeoperation
58本地代理 … 59 | 127.0.0.1:8445Off2013-12-30 22:34:00 64 | update 65 | delete 66 |
69 |
1 item 1/1 page
70 |
71 | 72 |
73 |
74 | 77 |
78 |
79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | 96 | 97 | 100 | 101 |
TypeSuffixOperation
White List 87 | 90 | update 91 |
Black List 95 | 98 | update 99 |
102 |
1 item 1/1 page
103 | 104 | 105 |
106 |
107 |
108 | SQLMAP Address 109 |
110 |
111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 121 | 122 | 126 | 127 |
IDsqlmap addressOperation
White List 120 | 123 | update 124 | delete 125 |
128 |
1 item 1/1 page
129 | 130 |
131 |
132 |
133 | 134 |
135 | 136 | -------------------------------------------------------------------------------- /libs/proxy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #!-*- coding:utf-8 -*- 3 | # 4 | # Simple asynchronous HTTP proxy with tunnelling (CONNECT). 5 | # 6 | # GET/POST proxying based on 7 | # http://groups.google.com/group/python-tornado/msg/7bea08e7a049cf26 8 | # 9 | # Copyright (C) 2012 Senko Rasic 10 | # 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documentation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | 29 | import logging 30 | import os 31 | import sys 32 | import socket 33 | import threading 34 | from urlparse import urlparse 35 | from Queue import Queue 36 | 37 | import tornado.httpserver 38 | import tornado.ioloop 39 | import tornado.iostream 40 | import tornado.web 41 | import tornado.httpclient 42 | import tornado.httputil 43 | 44 | from action import ProxyHander 45 | 46 | logger = logging.getLogger('tornado_proxy') 47 | 48 | __all__ = ['ProxyHandler', 'run_proxy'] 49 | 50 | class BackProxyHandle(threading.Thread): 51 | def __init__(self, queue): 52 | threading.Thread.__init__(self) 53 | self.queue = queue 54 | 55 | def run(self): 56 | print "\n" 57 | while self.queue.empty() == False: 58 | print "[*] Waiting for Queue..." 59 | request = self.queue.get() 60 | if request['uri'].find('127.0.0.1')>=0: 61 | continue 62 | print request['uri'] 63 | print "[*] Process Queue" 64 | ProxyHander(request) 65 | 66 | def get_proxy(url): 67 | url_parsed = urlparse(url, scheme='http') 68 | proxy_key = '%s_proxy' % url_parsed.scheme 69 | return os.environ.get(proxy_key) 70 | 71 | 72 | def parse_proxy(proxy): 73 | proxy_parsed = urlparse(proxy, scheme='http') 74 | return proxy_parsed.hostname, proxy_parsed.port 75 | 76 | 77 | def fetch_request(url, callback, **kwargs): 78 | proxy = get_proxy(url) 79 | if proxy: 80 | logger.debug('Forward request via upstream proxy %s', proxy) 81 | tornado.httpclient.AsyncHTTPClient.configure( 82 | 'tornado.curl_httpclient.CurlAsyncHTTPClient') 83 | host, port = parse_proxy(proxy) 84 | kwargs['proxy_host'] = host 85 | kwargs['proxy_port'] = port 86 | req = tornado.httpclient.HTTPRequest(url, **kwargs) 87 | client = tornado.httpclient.AsyncHTTPClient() 88 | client.fetch(req, callback, raise_error=False) 89 | 90 | 91 | class ProxyHandler(tornado.web.RequestHandler): 92 | SUPPORTED_METHODS = ['GET', 'POST', 'CONNECT'] 93 | queue=Queue() 94 | def compute_etag(self): 95 | return None # disable tornado Etag 96 | 97 | @tornado.web.asynchronous 98 | def get(self): 99 | logger.debug('Handle %s request to %s', self.request.method, 100 | self.request.uri) 101 | 102 | def handle_response(response): 103 | if (response.error and not 104 | isinstance(response.error, tornado.httpclient.HTTPError)): 105 | self.set_status(500) 106 | self.write('Internal server error:\n' + str(response.error)) 107 | else: 108 | self.set_status(response.code, response.reason) 109 | self._headers = tornado.httputil.HTTPHeaders() # clear tornado default header 110 | 111 | for header, v in response.headers.get_all(): 112 | if header not in ('Content-Length', 'Transfer-Encoding', 'Content-Encoding', 'Connection'): 113 | self.add_header(header, v) # some header appear multiple times, eg 'Set-Cookie' 114 | 115 | if response.body: 116 | self.set_header('Content-Length', len(response.body)) 117 | self.write(response.body) 118 | self.finish() 119 | 120 | body = self.request.body 121 | if not body: 122 | body = None 123 | try: 124 | if 'Proxy-Connection' in self.request.headers: 125 | del self.request.headers['Proxy-Connection'] 126 | fetch_request( 127 | self.request.uri, handle_response, 128 | method=self.request.method, body=body, 129 | headers=self.request.headers, follow_redirects=False, 130 | allow_nonstandard_methods=True) 131 | proxy_dict={} 132 | proxy_dict['uri']=self.request.uri 133 | proxy_dict['method']=self.request.method 134 | proxy_dict['headers']=self.request.headers 135 | proxy_dict['body']=body 136 | self.queue.put(proxy_dict) 137 | BackProxyHandle(self.queue).start() 138 | 139 | except tornado.httpclient.HTTPError as e: 140 | if hasattr(e, 'response') and e.response: 141 | handle_response(e.response) 142 | else: 143 | self.set_status(500) 144 | self.write('Internal server error:\n' + str(e)) 145 | self.finish() 146 | 147 | @tornado.web.asynchronous 148 | def post(self): 149 | return self.get() 150 | 151 | @tornado.web.asynchronous 152 | def connect(self): 153 | logger.debug('Start CONNECT to %s', self.request.uri) 154 | host, port = self.request.uri.split(':') 155 | client = self.request.connection.stream 156 | 157 | def read_from_client(data): 158 | upstream.write(data) 159 | 160 | def read_from_upstream(data): 161 | client.write(data) 162 | 163 | def client_close(data=None): 164 | if upstream.closed(): 165 | return 166 | if data: 167 | upstream.write(data) 168 | upstream.close() 169 | 170 | def upstream_close(data=None): 171 | if client.closed(): 172 | return 173 | if data: 174 | client.write(data) 175 | client.close() 176 | 177 | def start_tunnel(): 178 | logger.debug('CONNECT tunnel established to %s', self.request.uri) 179 | client.read_until_close(client_close, read_from_client) 180 | upstream.read_until_close(upstream_close, read_from_upstream) 181 | client.write(b'HTTP/1.0 200 Connection established\r\n\r\n') 182 | 183 | def on_proxy_response(data=None): 184 | if data: 185 | first_line = data.splitlines()[0] 186 | http_v, status, text = first_line.split(None, 2) 187 | if int(status) == 200: 188 | logger.debug('Connected to upstream proxy %s', proxy) 189 | start_tunnel() 190 | return 191 | 192 | self.set_status(500) 193 | self.finish() 194 | 195 | def start_proxy_tunnel(): 196 | upstream.write('CONNECT %s HTTP/1.1\r\n' % self.request.uri) 197 | upstream.write('Host: %s\r\n' % self.request.uri) 198 | upstream.write('Proxy-Connection: Keep-Alive\r\n\r\n') 199 | upstream.read_until('\r\n\r\n', on_proxy_response) 200 | 201 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 202 | upstream = tornado.iostream.IOStream(s) 203 | 204 | proxy = get_proxy(self.request.uri) 205 | if proxy: 206 | proxy_host, proxy_port = parse_proxy(proxy) 207 | upstream.connect((proxy_host, proxy_port), start_proxy_tunnel) 208 | else: 209 | upstream.connect((host, int(port)), start_tunnel) 210 | 211 | 212 | def run_proxy(port, start_ioloop=True): 213 | """ 214 | Run proxy on the specified port. If start_ioloop is True (default), 215 | the tornado IOLoop will be started immediately. 216 | """ 217 | app = tornado.web.Application([ 218 | (r'.*', ProxyHandler), 219 | ]) 220 | app.listen(port) 221 | ioloop = tornado.ioloop.IOLoop.instance() 222 | if start_ioloop: 223 | ioloop.start() 224 | 225 | if __name__ == '__main__': 226 | port = 8888 227 | if len(sys.argv) > 1: 228 | port = int(sys.argv[1]) 229 | 230 | print ("Starting HTTP proxy on port %d" % port) 231 | try: 232 | run_proxy(port) 233 | except KeyboardInterrupt,e: 234 | print "[*] over" 235 | sys.exit() -------------------------------------------------------------------------------- /libs/action.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #!-*- coding:utf-8 -*- 3 | import json 4 | import time 5 | import sys 6 | import requests 7 | import re 8 | import urllib2 9 | import base64 10 | import threading 11 | import multiprocessing 12 | from urlparse import urlparse 13 | from func import XMLDOM,Tools,SPIDER_HEADER,getrootdomain 14 | from bs4 import BeautifulSoup 15 | from models import MySQLHander 16 | 17 | HEADER={'Content-Type': 'application/json'} 18 | 19 | 20 | #threading锁 21 | lock = threading.Lock() 22 | 23 | #taskid的队列 24 | taskid_thread_Dict=[] 25 | 26 | class SqlMapAction(object): 27 | def __init__(self): 28 | xml = XMLDOM() 29 | self.db = MySQLHander() 30 | self.address = xml.GetElementByName('sqlmap').strip() 31 | 32 | def _get_server(self): 33 | sql = "select server from settings where id = 1" 34 | self.db.query(sql) 35 | server = self.db.fetchOneRow()[0] 36 | if server == None: 37 | return False 38 | return server 39 | 40 | def NewTaskId(self, **kwargs): 41 | url = "{0}/task/new".format(self.address) 42 | response = json.loads(requests.get(url).text) 43 | if response['success']: 44 | db = MySQLHander() 45 | taskid = response['taskid'] 46 | sql = "insert into task(`target`, `taskid`, `server`) VALUES (\"{0}\", \"{1}\", \"{2}\")"\ 47 | .format(kwargs['target'], taskid, self.address) 48 | if db.insert(sql) == 0L: 49 | print "Apply New TaskId Success!" 50 | else: 51 | print "Apply New Task Fail" 52 | del db 53 | return taskid 54 | else: 55 | return False 56 | 57 | def Set_Options(self, **kwargs): 58 | server = self._get_server() 59 | if server == False: 60 | return False 61 | url = "{0}/option/{1}/set".format(server, kwargs['taskid']) 62 | if "options" in kwargs: 63 | data = json.dumps(kwargs['options']) 64 | else: 65 | data = json.dumps({}) 66 | response = json.loads(requests.post(url, data=data, headers=HEADER).text) 67 | if response['success']: 68 | message = "{0} Set Options successfully".format(time.strftime("[*%H:%M:%S]")) 69 | print(message) 70 | return True 71 | else: 72 | return False 73 | 74 | def update_settings(self, kwargs): 75 | mysql = MySQLHander() 76 | sql = "update settings set server=\"{0}\", writelist=\"{1}\", blacklist=\"{2}\", proxyaddr=\"{3}\"," \ 77 | "rootdomain=\"{4}\", blackdomain = \"{5}\" where id=1 ".format(kwargs.form['sqlmapaddr'], \ 78 | kwargs.form['writelist'],kwargs.form['blacklist'],\ 79 | kwargs.form['proxyaddr'], getrootdomain(kwargs.form['target']), getrootdomain(kwargs.url)) 80 | mysql.update(sql) 81 | mysql.close() 82 | 83 | def start_scan(self, taskid, target): 84 | server = self._get_server() 85 | url = "{0}/scan/{1}/start".format(server, taskid) 86 | data = json.dumps({"url":target}) 87 | response = json.loads(requests.post(url,data=data, headers=HEADER).text) 88 | if response['success'] == True: 89 | print "[!] start task {0} sucess".format(taskid) 90 | t = multiprocessing.Process(target=Thread_Handle,args=(taskid,target,)) 91 | taskid_thread_Dict.append(taskid) 92 | t.start() 93 | return True 94 | else: 95 | return False 96 | 97 | def StopTask(self, tasklist): 98 | if isinstance(tasklist, list) == False: 99 | return False 100 | return True 101 | flag = True 102 | for taskid in tasklist: 103 | server = self._get_server() 104 | url = "{0}/scan/{1}/stop".format(server, taskid) 105 | response = json.loads(requests.get(url,None).text) 106 | print "-----------\n",response 107 | if requests['success'] == True: 108 | print "[!] stop task {0} ok!".format(taskid) 109 | else: 110 | flag = False 111 | print "[!] stop task {0} failed!".format(taskid) 112 | return flag 113 | 114 | def Start_Spider(self, taskid, target): 115 | t = threading.Thread(target=Spider_Handle,args=(taskid,target,)) 116 | t.start() 117 | 118 | def DeleteAllTask(self): 119 | mysql = MySQLHander() 120 | sql = "select target,data from task where success=1" 121 | mysql.query(sql) 122 | slist = mysql.fetchAllRows() 123 | for line in slist: 124 | sql = "insert into successlist(`target` ,`data`) values (\"{0}\")".format(line[0], line[1]) 125 | mysql.insert(sql) 126 | sql = "delete from task" 127 | mysql.update(sql) 128 | mysql.close() 129 | print "[!] task schedule has been clear!" 130 | 131 | class Action: 132 | @staticmethod 133 | def SaveData(target, data): 134 | sql = "" 135 | mysql = MySQLHander() 136 | if len(data['data']) == 0: 137 | sql = "update task set success=0 where target=\"{0}\"".format(target) 138 | else: 139 | sql = "update task set data=\"{0}\",success=1 where target=\"{1}\"".format(\ 140 | Tools.dict2base64(data['data'][0]['value'][0]['data']), target) 141 | mysql.update(sql) 142 | mysql.close() 143 | return 144 | 145 | @staticmethod 146 | def GetStatusInfo(taskid): 147 | ''' 148 | :param taskid: 149 | :return: status,success 150 | ''' 151 | mysql = MySQLHander() 152 | sql = "select target,status,success from task where taskid=\"{0}\" ".format(taskid) 153 | mysql.query(sql) 154 | data = mysql.fetchOneRow() 155 | result = {"target":data[0], "status":data[1], "success":data[2]} 156 | mysql.close() 157 | return result 158 | 159 | @staticmethod 160 | def GetTaskidList(): 161 | return taskid_thread_Dict 162 | 163 | @staticmethod 164 | def GetStatus(): 165 | data = [] 166 | for taskid in taskid_thread_Dict: 167 | result = Action.GetStatusInfo(taskid) 168 | data.append(result) 169 | return data 170 | 171 | 172 | class Spider(object): 173 | def __init__(self): 174 | mysql = MySQLHander() 175 | sql = "select writelist,blacklist,rootdomain,blackdomain from settings where id=1" 176 | mysql.query(sql) 177 | resource = mysql.fetchOneRow() 178 | self.writelist,self.blacklist,self.rootdomain,self.blackdomain = list(resource) 179 | mysql.close() 180 | 181 | #如果以http开头就返回整个链接,否则就拼接URL 182 | def geturl(self, url, href): 183 | url = urlparse(url) 184 | if href.startswith('http'): 185 | return href 186 | return "{0}://{1}/{2}/{3}".format(url.scheme, url.netloc, url.path, href) 187 | 188 | def SpiderGetLink(self, url): 189 | content = requests.get(url, headers=SPIDER_HEADER).text 190 | #得到设置信息表 191 | result = set() 192 | soup = BeautifulSoup(content, "lxml") 193 | for a in soup.find_all('a'): 194 | #将a标签中的值挨个取出来 195 | href = a['href'] 196 | domain = self.geturl(url, href) 197 | data = self.Analysis(domain) 198 | if data != None: 199 | result.add(data) 200 | return result 201 | 202 | def Analysis(self, url): 203 | #判断是否是同源网站 204 | def fuckotherdomain(href, rootdomain, blackdomain): 205 | #如果找到不需要匹配的域名就退出 206 | if href.find(blackdomain) >= 0: 207 | return None 208 | if href.find(rootdomain) >= 0: 209 | return href 210 | return None 211 | if url.startswith('http'): 212 | #判断是否同欲 213 | if fuckotherdomain(url, self.rootdomain, self.blackdomain) != None: 214 | pass 215 | else: 216 | return None 217 | else: 218 | return None 219 | flag = False 220 | link = urlparse(url) 221 | #Matching white list first 首先匹配白名单,如果匹配到那么就优先添加 222 | for types in self.writelist.split(','): 223 | if link.path.find(types) >= 0: 224 | return url 225 | #Matching white list Second 首先匹配黑名单 226 | for types in self.blacklist.split(','): 227 | if link.path.find(types) >=0: 228 | flag = True 229 | #if match blacklist then continue 匹配到黑名单就推出 230 | if flag: 231 | return None 232 | return url 233 | 234 | 235 | def Thread_Handle(taskid, target): 236 | lock.acquire() 237 | sql = SqlMapAction() 238 | server = sql._get_server() 239 | url_status = "{0}/scan/{1}/status".format(server, taskid) 240 | url_log = "{0}/scan/{1}/log".format(server, taskid) 241 | url_data="{0}/scan/{1}/data".format(server, taskid) 242 | mysql = MySQLHander() 243 | response_status = json.loads(requests.get(url_status,None).text)['status'] 244 | while response_status != "terminated" and response_status!="deleting": 245 | time.sleep(2) 246 | response_status = json.loads(requests.get(url_status,None).text)['status'] 247 | sql = "update `task` set status = \"{0}\" where taskid=\"{1}\"".format(response_status, taskid) 248 | mysql.update(sql) 249 | response_data = json.loads(requests.get(url_data, None).text) 250 | if response_data==None: 251 | return False 252 | Action.SaveData(target, response_data) 253 | mysql.close() 254 | lock.release() 255 | return True 256 | 257 | def Spider_Handle(target, options={}): 258 | result = set() 259 | spider = Spider() 260 | #得到页面的链接 261 | result = spider.SpiderGetLink(target) 262 | result.add(target) 263 | saction = SqlMapAction() 264 | for url in result: 265 | taskid = saction.NewTaskId(target=url) 266 | if taskid: 267 | saction.Set_Options(taskid=taskid, options=options) 268 | saction.start_scan(taskid, target) 269 | 270 | def ProxyHander(request={}): 271 | if request['method'] == "GET": 272 | options = {} 273 | elif request['method'] == "POST": 274 | options = {"data":request['body']} 275 | else: 276 | return 277 | saction = SqlMapAction() 278 | spider = Spider() 279 | url = spider.Analysis(request['uri']) 280 | if url == None: 281 | return 282 | taskid = saction.NewTaskId(target=url) 283 | if taskid: 284 | saction.Set_Options(taskid=taskid, options=options) 285 | saction.start_scan(taskid, url) 286 | 287 | #同步非阻塞 定时查看数据库里成功的目标保存到successlist表中 288 | def Save_Success_Target(): 289 | while True: 290 | mysql = MySQLHander() 291 | sql = "select taskid,target,data from task where success=1 and action=0" 292 | mysql.query(sql) 293 | resource = mysql.fetchAllRows() 294 | if resource != None: 295 | for line in resource: 296 | sql = "insert into successlist(`target`, `data`) values (\"{0}\", \"{1}\")".format(line[1], line[2]) 297 | mysql.insert(sql) 298 | sql = "update task set action=1 where taskid='{0}'".format(line[0]) 299 | mysql.update(sql) 300 | print '[*] save success target {0}'.format(line[1]) 301 | mysql.close() 302 | time.sleep(3) 303 | 304 | 305 | if __name__ == '__main__': 306 | Spider_Handle("http://fengxuan.com//webapp/discuz72/", {}) 307 | -------------------------------------------------------------------------------- /static/js/libs/modernizr.min.js: -------------------------------------------------------------------------------- 1 | window.Modernizr=(function(A,c,g){var I="2.6.2",w={},y=true,L=c.documentElement,a="modernizr",H=c.createElement(a),E=H.style,K=c.createElement("input"),C=":)",b={}.toString,j=" -webkit- -moz- -o- -ms- ".split(" "),h="Webkit Moz O ms",F=h.split(" "),J=h.toLowerCase().split(" "),G={svg:"http://www.w3.org/2000/svg"},l={},p={},f={},e=[],k=e.slice,s,n=function(U,W,O,V){var N,T,Q,R,M=c.createElement("div"),S=c.body,P=S||c.createElement("body");if(parseInt(O,10)){while(O--){Q=c.createElement("div");Q.id=V?V[O]:a+(O+1);M.appendChild(Q)}}N=["­",'"].join("");M.id=a;(S?M:P).innerHTML+=N;P.appendChild(M);if(!S){P.style.background="";P.style.overflow="hidden";R=L.style.overflow;L.style.overflow="hidden";L.appendChild(P)}T=W(M,U);if(!S){P.parentNode.removeChild(P);L.style.overflow=R}else{M.parentNode.removeChild(M)}return !!T},o=(function(){var N={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};function M(O,Q){Q=Q||c.createElement(N[O]||"div");O="on"+O;var P=O in Q;if(!P){if(!Q.setAttribute){Q=c.createElement("div")}if(Q.setAttribute&&Q.removeAttribute){Q.setAttribute(O,"");P=r(Q[O],"function");if(!r(Q[O],"undefined")){Q[O]=g}Q.removeAttribute(O)}}Q=null;return P}return M})(),i=({}).hasOwnProperty,x;if(!r(i,"undefined")&&!r(i.call,"undefined")){x=function(M,N){return i.call(M,N)}}else{x=function(M,N){return((N in M)&&r(M.constructor.prototype[N],"undefined"))}}if(!Function.prototype.bind){Function.prototype.bind=function d(O){var P=this;if(typeof P!="function"){throw new TypeError()}var M=k.call(arguments,1),N=function(){if(this instanceof N){var S=function(){};S.prototype=P.prototype;var R=new S();var Q=P.apply(R,M.concat(k.call(arguments)));if(Object(Q)===Q){return Q}return R}else{return P.apply(O,M.concat(k.call(arguments)))}};return N}}function D(M){E.cssText=M}function u(N,M){return D(j.join(N+";")+(M||""))}function r(N,M){return typeof N===M}function t(N,M){return !!~(""+N).indexOf(M)}function z(O,M){for(var N in O){var P=O[N];if(!t(P,"-")&&E[P]!==g){return M=="pfx"?P:true}}return false}function q(N,Q,P){for(var M in N){var O=Q[N[M]];if(O!==g){if(P===false){return N[M]}if(r(O,"function")){return O.bind(P||Q)}return O}}return false}function m(Q,M,P){var N=Q.charAt(0).toUpperCase()+Q.slice(1),O=(Q+" "+F.join(N+" ")+N).split(" ");if(r(M,"string")||r(M,"undefined")){return z(O,M)}else{O=(Q+" "+(J).join(N+" ")+N).split(" ");return q(O,M,P)}}l.flexbox=function(){return m("flexWrap")};l.canvas=function(){var M=c.createElement("canvas");return !!(M.getContext&&M.getContext("2d"))};l.canvastext=function(){return !!(w.canvas&&r(c.createElement("canvas").getContext("2d").fillText,"function"))};l.webgl=function(){return !!A.WebGLRenderingContext};l.touch=function(){var M;if(("ontouchstart" in A)||A.DocumentTouch&&c instanceof DocumentTouch){M=true}else{n(["@media (",j.join("touch-enabled),("),a,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(N){M=N.offsetTop===9})}return M};l.geolocation=function(){return"geolocation" in navigator};l.postmessage=function(){return !!A.postMessage};l.websqldatabase=function(){return !!A.openDatabase};l.indexedDB=function(){return !!m("indexedDB",A)};l.hashchange=function(){return o("hashchange",A)&&(c.documentMode===g||c.documentMode>7)};l.history=function(){return !!(A.history&&history.pushState)};l.draganddrop=function(){var M=c.createElement("div");return("draggable" in M)||("ondragstart" in M&&"ondrop" in M)};l.websockets=function(){return"WebSocket" in A||"MozWebSocket" in A};l.rgba=function(){D("background-color:rgba(150,255,150,.5)");return t(E.backgroundColor,"rgba")};l.hsla=function(){D("background-color:hsla(120,40%,100%,.5)");return t(E.backgroundColor,"rgba")||t(E.backgroundColor,"hsla")};l.multiplebgs=function(){D("background:url(https://),url(https://),red url(https://)");return(/(url\s*\(.*?){3}/).test(E.background)};l.backgroundsize=function(){return m("backgroundSize")};l.borderimage=function(){return m("borderImage")};l.borderradius=function(){return m("borderRadius")};l.boxshadow=function(){return m("boxShadow")};l.textshadow=function(){return c.createElement("div").style.textShadow===""};l.opacity=function(){u("opacity:.55");return(/^0.55$/).test(E.opacity)};l.cssanimations=function(){return m("animationName")};l.csscolumns=function(){return m("columnCount")};l.cssgradients=function(){var O="background-image:",N="gradient(linear,left top,right bottom,from(#9f9),to(white));",M="linear-gradient(left top,#9f9, white);";D((O+"-webkit- ".split(" ").join(N+O)+j.join(M+O)).slice(0,-O.length));return t(E.backgroundImage,"gradient")};l.cssreflections=function(){return m("boxReflect")};l.csstransforms=function(){return !!m("transform")};l.csstransforms3d=function(){var M=!!m("perspective");if(M&&"webkitPerspective" in L.style){n("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(N,O){M=N.offsetLeft===9&&N.offsetHeight===3})}return M};l.csstransitions=function(){return m("transition")};l.fontface=function(){var M;n('@font-face {font-family:"font";src:url("https://")}',function(Q,R){var P=c.getElementById("smodernizr"),N=P.sheet||P.styleSheet,O=N?(N.cssRules&&N.cssRules[0]?N.cssRules[0].cssText:N.cssText||""):"";M=/src/i.test(O)&&O.indexOf(R.split(" ")[0])===0});return M};l.generatedcontent=function(){var M;n(["#",a,"{font:0/0 a}#",a,':after{content:"',C,'";visibility:hidden;font:3px/1 a}'].join(""),function(N){M=N.offsetHeight>=3});return M};l.video=function(){var N=c.createElement("video"),M=false;try{if(M=!!N.canPlayType){M=new Boolean(M);M.ogg=N.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,"");M.h264=N.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,"");M.webm=N.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}}catch(O){}return M};l.audio=function(){var N=c.createElement("audio"),M=false;try{if(M=!!N.canPlayType){M=new Boolean(M);M.ogg=N.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,"");M.mp3=N.canPlayType("audio/mpeg;").replace(/^no$/,"");M.wav=N.canPlayType('audio/wav; codecs="1"').replace(/^no$/,"");M.m4a=(N.canPlayType("audio/x-m4a;")||N.canPlayType("audio/aac;")).replace(/^no$/,"")}}catch(O){}return M};l.localstorage=function(){try{localStorage.setItem(a,a);localStorage.removeItem(a);return true}catch(M){return false}};l.sessionstorage=function(){try{sessionStorage.setItem(a,a);sessionStorage.removeItem(a);return true}catch(M){return false}};l.webworkers=function(){return !!A.Worker};l.applicationcache=function(){return !!A.applicationCache};l.svg=function(){return !!c.createElementNS&&!!c.createElementNS(G.svg,"svg").createSVGRect};l.inlinesvg=function(){var M=c.createElement("div");M.innerHTML="";return(M.firstChild&&M.firstChild.namespaceURI)==G.svg};l.smil=function(){return !!c.createElementNS&&/SVGAnimate/.test(b.call(c.createElementNS(G.svg,"animate")))};l.svgclippaths=function(){return !!c.createElementNS&&/SVGClipPath/.test(b.call(c.createElementNS(G.svg,"clipPath")))};function B(){w.input=(function(O){for(var N=0,M=O.length;N";ab=("hidden" in ae);Q=ae.childNodes.length==1||(function(){(X.createElement)("a");var ag=X.createDocumentFragment();return(typeof ag.cloneNode=="undefined"||typeof ag.createDocumentFragment=="undefined"||typeof ag.createElement=="undefined")}())}catch(af){ab=true;Q=true}}());function R(ae,ag){var ah=ae.createElement("p"),af=ae.getElementsByTagName("head")[0]||ae.documentElement;ah.innerHTML="x";return af.insertBefore(ah.lastChild,af.firstChild)}function W(){var ae=U.elements;return typeof ae=="string"?ae.split(" "):ae}function aa(ae){var af=Z[ae[T]];if(!af){af={};M++;ae[T]=M;Z[M]=af}return af}function Y(ah,ae,ag){if(!ae){ae=X}if(Q){return ae.createElement(ah)}if(!ag){ag=aa(ae)}var af;if(ag.cache[ah]){af=ag.cache[ah].cloneNode()}else{if(N.test(ah)){af=(ag.cache[ah]=ag.createElem(ah)).cloneNode()}else{af=ag.createElem(ah)}}return af.canHaveChildren&&!S.test(ah)?ag.frag.appendChild(af):af}function ac(ag,ai){if(!ag){ag=X}if(Q){return ag.createDocumentFragment()}ai=ai||aa(ag);var aj=ai.frag.cloneNode(),ah=0,af=W(),ae=af.length;for(;ah=0: 35 | continue 36 | print request['uri'] 37 | print "[*] Process Queue" 38 | ProxyHander(request) 39 | 40 | save_content = True 41 | 42 | http_mimes = ['text', 'image', 'application', 'video', 'message', 'audio'] 43 | 44 | # http static resource file extension 45 | static_ext = [] 46 | 47 | # media resource files type 48 | media_types = [] 49 | 50 | # http static resource files 51 | static_files = [ 52 | ] 53 | 54 | 55 | # Core modules 56 | 57 | class ResponseParser(object): 58 | """docstring for ResponseParser""" 59 | 60 | def __init__(self, f): 61 | super(ResponseParser, self).__init__() 62 | self.flow = f 63 | self.content_type = self.get_content_type() 64 | self.extension = self.get_extension() 65 | self.ispass = self.capture_pass() 66 | 67 | def parser_data(self): 68 | """parser the capture response & request""" 69 | 70 | result = {} 71 | result['content_type'] = self.content_type 72 | result['url'] = self.get_url() 73 | result['path'] = self.get_path() 74 | result['extension'] = self.get_extension() 75 | result['host'] = self.get_host() 76 | result['port'] = self.get_port() 77 | result['scheme'] = self.get_scheme() 78 | result['method'] = self.get_method() 79 | result['status_code'] = self.get_status_code() 80 | result['date_start'] = self.flow.response.timestamp_start 81 | result['date_end'] = self.flow.response.timestamp_end 82 | result['content_length'] = self.get_content_length() 83 | result['static_resource'] = self.ispass 84 | result['header'] = self.get_header() 85 | result['request_header'] = self.get_request_header() 86 | 87 | # request resource is media file & static file, so pass 88 | if self.ispass: 89 | result['content'] = None 90 | result['request_content'] = None 91 | return result 92 | 93 | result['content'] = self.get_content() if save_content else '' 94 | result['request_content'] = self.get_request_content() if save_content else '' 95 | return result 96 | 97 | def get_content_type(self): 98 | 99 | if not self.flow.response.headers.get('Content-Type'): 100 | return '' 101 | return self.flow.response.headers.get('Content-Type').split(';')[:1][0] 102 | 103 | def get_content_length(self): 104 | if self.flow.response.headers.get('Content-Length'): 105 | return int(self.flow.response.headers.get('Content-Length')) 106 | else: 107 | return 0 108 | 109 | def capture_pass(self): 110 | """if content_type is media_types or static_files, then pass captrue""" 111 | 112 | if self.extension in static_ext: 113 | return True 114 | 115 | # can't catch the content_type 116 | if not self.content_type: 117 | return False 118 | 119 | if self.content_type in static_files: 120 | return True 121 | 122 | http_mime_type = self.content_type.split('/')[:1] 123 | if http_mime_type: 124 | return True if http_mime_type[0] in media_types else False 125 | else: 126 | return False 127 | 128 | def get_header(self): 129 | return self.parser_header(self.flow.response.headers) 130 | 131 | def get_content(self): 132 | return self.flow.response.get_decoded_content() 133 | 134 | def get_request_header(self): 135 | return self.parser_header(self.flow.request.headers) 136 | 137 | def get_request_content(self): 138 | return self.flow.request.get_decoded_content() 139 | 140 | def get_url(self): 141 | return self.flow.request.url 142 | 143 | def get_path(self): 144 | return '/{}'.format('/'.join(self.flow.request.path_components)) 145 | 146 | def get_extension(self): 147 | if not self.flow.request.path_components: 148 | return '' 149 | else: 150 | end_path = self.flow.request.path_components[-1:][0] 151 | split_ext = end_path.split('.') 152 | if not split_ext or len(split_ext) == 1: 153 | return '' 154 | else: 155 | return split_ext[-1:][0] 156 | 157 | def get_scheme(self): 158 | return self.flow.request.scheme 159 | 160 | def get_method(self): 161 | return self.flow.request.method 162 | 163 | def get_port(self): 164 | return self.flow.request.port 165 | 166 | def get_host(self): 167 | return self.flow.request.host 168 | 169 | def get_status_code(self): 170 | return self.flow.response.status_code 171 | 172 | @staticmethod 173 | def parser_header(header): 174 | headers = {} 175 | for key, value in header.iteritems(): 176 | headers[key] = value 177 | return headers 178 | 179 | 180 | class Daemon(object): 181 | """ 182 | A generic daemon class. 183 | 184 | Usage: subclass the Daemon class and override the run() method 185 | """ 186 | def __init__(self, pidfile, stdin=os.devnull, 187 | stdout=os.devnull, stderr=os.devnull, 188 | home_dir='.', umask=022, verbose=1, use_gevent=False): 189 | self.stdin = stdin 190 | self.stdout = stdout 191 | self.stderr = stderr 192 | self.pidfile = pidfile 193 | self.home_dir = home_dir 194 | self.verbose = verbose 195 | self.umask = umask 196 | self.daemon_alive = True 197 | self.use_gevent = use_gevent 198 | 199 | def daemonize(self): 200 | """ 201 | Do the UNIX double-fork magic, see Stevens' "Advanced 202 | Programming in the UNIX Environment" for details (ISBN 0201563177) 203 | http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 204 | """ 205 | try: 206 | pid = os.fork() 207 | if pid > 0: 208 | # Exit first parent 209 | sys.exit(0) 210 | except OSError, e: 211 | sys.stderr.write( 212 | "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 213 | sys.exit(1) 214 | 215 | # Decouple from parent environment 216 | os.chdir(self.home_dir) 217 | os.setsid() 218 | os.umask(self.umask) 219 | 220 | # Do second fork 221 | try: 222 | pid = os.fork() 223 | if pid > 0: 224 | # Exit from second parent 225 | sys.exit(0) 226 | except OSError, e: 227 | sys.stderr.write( 228 | "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 229 | sys.exit(1) 230 | 231 | if sys.platform != 'darwin': # This block breaks on OS X 232 | # Redirect standard file descriptors 233 | sys.stdout.flush() 234 | sys.stderr.flush() 235 | si = file(self.stdin, 'r') 236 | so = file(self.stdout, 'a+') 237 | if self.stderr: 238 | se = file(self.stderr, 'a+', 0) 239 | else: 240 | se = so 241 | os.dup2(si.fileno(), sys.stdin.fileno()) 242 | os.dup2(so.fileno(), sys.stdout.fileno()) 243 | os.dup2(se.fileno(), sys.stderr.fileno()) 244 | 245 | def sigtermhandler(signum, frame): 246 | self.daemon_alive = False 247 | sys.exit() 248 | 249 | if self.use_gevent: 250 | import gevent 251 | gevent.reinit() 252 | gevent.signal(signal.SIGTERM, sigtermhandler, signal.SIGTERM, None) 253 | gevent.signal(signal.SIGINT, sigtermhandler, signal.SIGINT, None) 254 | else: 255 | signal.signal(signal.SIGTERM, sigtermhandler) 256 | signal.signal(signal.SIGINT, sigtermhandler) 257 | 258 | if self.verbose >= 1: 259 | print "wyProxy daemon started successfully " 260 | 261 | # Write pidfile 262 | atexit.register( 263 | self.delpid) # Make sure pid file is removed if we quit 264 | pid = str(os.getpid()) 265 | file(self.pidfile, 'w+').write("%s\n" % pid) 266 | 267 | def delpid(self): 268 | os.remove(self.pidfile) 269 | 270 | def start(self, *args, **kwargs): 271 | """ 272 | Start the daemon 273 | """ 274 | 275 | if self.verbose >= 1: 276 | print "wyproxy daemon starting..." 277 | 278 | # Check for a pidfile to see if the daemon already runs 279 | try: 280 | pf = file(self.pidfile, 'r') 281 | pid = int(pf.read().strip()) 282 | pf.close() 283 | except IOError: 284 | pid = None 285 | except SystemExit: 286 | pid = None 287 | 288 | if pid: 289 | message = "pidfile %s already exists. Is it already running?\n" 290 | sys.stderr.write(message % self.pidfile) 291 | sys.exit(1) 292 | 293 | # Start the daemon 294 | self.daemonize() 295 | self.run(*args, **kwargs) 296 | 297 | def stop(self): 298 | """ 299 | Stop the daemon 300 | """ 301 | 302 | if self.verbose >= 1: 303 | print "wyproxy daemon stopping..." 304 | 305 | # Get the pid from the pidfile 306 | pid = self.get_pid() 307 | 308 | if not pid: 309 | message = "pidfile %s does not exist. Not running?\n" 310 | sys.stderr.write(message % self.pidfile) 311 | 312 | # Just to be sure. A ValueError might occur if the PID file is 313 | # empty but does actually exist 314 | if os.path.exists(self.pidfile): 315 | os.remove(self.pidfile) 316 | 317 | return # Not an error in a restart 318 | 319 | # Try killing the daemon process 320 | try: 321 | i = 0 322 | while 1: 323 | os.kill(pid, signal.SIGTERM) 324 | time.sleep(0.1) 325 | i = i + 1 326 | if i % 10 == 0: 327 | os.kill(pid, signal.SIGHUP) 328 | except OSError, err: 329 | err = str(err) 330 | if err.find("No such process") > 0: 331 | if os.path.exists(self.pidfile): 332 | os.remove(self.pidfile) 333 | else: 334 | print str(err) 335 | sys.exit(1) 336 | 337 | if self.verbose >= 1: 338 | print "wyproxy daemon stopped successfully" 339 | 340 | def restart(self): 341 | """ 342 | Restart the daemon 343 | """ 344 | self.stop() 345 | self.start() 346 | 347 | def get_pid(self): 348 | try: 349 | pf = file(self.pidfile, 'r') 350 | pid = int(pf.read().strip()) 351 | pf.close() 352 | except IOError: 353 | pid = None 354 | except SystemExit: 355 | pid = None 356 | return pid 357 | 358 | def is_running(self): 359 | pid = self.get_pid() 360 | 361 | if pid is None: 362 | print 'Process is stopped' 363 | elif os.path.exists('/proc/%d' % pid): 364 | print 'Process (pid %d) is running...' % pid 365 | else: 366 | print 'Process (pid %d) is killed' % pid 367 | 368 | return pid and os.path.exists('/proc/%d' % pid) 369 | 370 | def run(self): 371 | """ 372 | You should override this method when you subclass Daemon. 373 | It will be called after the process has been 374 | daemonized by start() or restart(). 375 | """ 376 | raise NotImplementedError 377 | 378 | class WYProxy(flow.FlowMaster): 379 | queue = Queue() 380 | def __init__(self, server, state, unsave_data): 381 | super(WYProxy, self).__init__(server, state) 382 | self.unsave_data = unsave_data 383 | 384 | def run(self): 385 | try: 386 | logging.info("wyproxy started successfully...") 387 | flow.FlowMaster.run(self) 388 | except KeyboardInterrupt: 389 | self.shutdown() 390 | logging.info("Ctrl C - stopping wyproxy server") 391 | 392 | def handle_request(self, f): 393 | f = flow.FlowMaster.handle_request(self, f) 394 | if f: 395 | f.request.anticache() 396 | f.reply() 397 | return f 398 | 399 | def handle_response(self, f): 400 | f = flow.FlowMaster.handle_response(self, f) 401 | if f: 402 | if not self.unsave_data: 403 | parser = ResponseParser(f) 404 | data = parser.parser_data() 405 | proxy_dict = {} 406 | proxy_dict['uri'] = data['url'] 407 | proxy_dict['method'] = data['method'] 408 | proxy_dict['request_header'] = data['request_header'] 409 | proxy_dict['body'] = data['request_content'] 410 | self.queue.put(proxy_dict) 411 | BackProxyHandle(self.queue).start() 412 | f.reply() 413 | return f 414 | 415 | def start_server(proxy_port, proxy_mode, unsave_data): 416 | port = int(proxy_port) if proxy_port else 8080 417 | mode = proxy_mode if proxy_mode else 'regular' 418 | 419 | if proxy_mode == 'http': 420 | mode = 'regular' 421 | 422 | config = proxy.ProxyConfig( 423 | port=port, 424 | mode=mode, 425 | cadir="./ssl/", 426 | ) 427 | 428 | state = flow.State() 429 | server = ProxyServer(config) 430 | m = WYProxy(server, state, unsave_data) 431 | m.run() 432 | 433 | class wyDaemon(Daemon): 434 | def __init__(self, pidfile, proxy_port=8080, proxy_mode='regular', unsave_data=False): 435 | super(wyDaemon, self).__init__(pidfile) 436 | self.proxy_port = proxy_port 437 | self.proxy_mode = proxy_mode 438 | self.unsave_data = unsave_data 439 | 440 | def run(self): 441 | logging.info("wyproxy is starting...") 442 | logging.info("Listening: 0.0.0.0:{} {}".format( 443 | self.proxy_port, self.proxy_mode)) 444 | start_server(self.proxy_port, self.proxy_mode, self.unsave_data) 445 | 446 | def run(args): 447 | 448 | if args.restart: 449 | args.port = read_cnf().get('port') 450 | args.mode = read_cnf().get('mode') 451 | args.unsave = read_cnf().get('unsave') 452 | 453 | if not args.pidfile: 454 | args.pidfile = '/tmp/wyproxy.pid' 455 | 456 | wyproxy = wyDaemon( 457 | pidfile = args.pidfile, 458 | proxy_port = args.port, 459 | proxy_mode = args.mode, 460 | unsave_data = args.unsave) 461 | 462 | if args.daemon: 463 | save_cnf(args) 464 | wyproxy.start() 465 | elif args.stop: 466 | wyproxy.stop() 467 | elif args.restart: 468 | wyproxy.restart() 469 | else: 470 | wyproxy.run() 471 | 472 | if __name__ == '__main__': 473 | parser = argparse.ArgumentParser(description="wyproxy v 1.0 ( Proxying And Recording HTTP/HTTPs and Socks5)") 474 | parser.add_argument("-d","--daemon",action="store_true", 475 | help="start wyproxy with daemond") 476 | parser.add_argument("-stop","--stop",action="store_true",required=False, 477 | help="stop wyproxy daemond") 478 | parser.add_argument("-restart","--restart",action="store_true",required=False, 479 | help="restart wyproxy daemond") 480 | parser.add_argument("-pid","--pidfile",metavar="", 481 | help="wyproxy daemond pidfile name") 482 | parser.add_argument("-p","--port",metavar="",default="8080", 483 | help="wyproxy bind port") 484 | parser.add_argument("-m","--mode",metavar="",choices=['http','socks5','transparent'],default="http", 485 | help="wyproxy mode (HTTP/HTTPS, Socks5, Transparent)") 486 | parser.add_argument("-us","--unsave",action="store_true",required=False, 487 | help="Do not save records to MySQL server") 488 | args = parser.parse_args() 489 | 490 | try: 491 | run(args) 492 | except KeyboardInterrupt: 493 | logging.info("Ctrl C - Stopping Client") 494 | sys.exit(1) 495 | -------------------------------------------------------------------------------- /static/fonts/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This is a custom SVG font generated by IcoMoon. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 24 | 26 | 27 | 31 | 35 | 36 | 39 | 46 | 48 | 49 | 51 | 52 | 54 | 56 | 57 | 58 | 59 | 62 | 65 | 70 | 77 | 82 | 83 | 84 | 85 | 89 | 91 | 93 | 96 | 98 | 100 | 101 | 111 | 112 | 115 | 116 | 117 | 120 | 122 | 126 | 130 | 132 | 137 | 138 | 139 | 140 | 142 | 143 | 145 | 146 | 147 | 149 | 151 | 155 | 157 | 160 | 164 | 166 | 168 | 169 | 173 | 174 | 175 | 177 | 179 | 182 | 185 | 188 | 191 | 193 | 197 | 200 | 202 | 206 | 210 | 211 | 212 | 216 | 218 | 221 | 225 | 230 | 234 | 236 | 240 | 247 | 249 | 254 | 260 | 266 | 420 | 432 | 435 | 438 | 446 | 462 | 472 | 475 | 476 | 477 | 478 | 479 | 485 | 491 | 494 | 495 | --------------------------------------------------------------------------------