├── README.md ├── Dockerfile ├── .gitignore └── install.py /README.md: -------------------------------------------------------------------------------- 1 | # docker_nessus_unlimited 2 | docker build nessus with unlimited ip 3 | 4 | ## prepare 5 | 6 | https://www.tenable.com/downloads/nessus?loginAttempted=true 7 | 8 | 下载Nessus-8.13.1-debian6_amd64.deb 9 | 10 | ## docker 11 | 12 | ``` 13 | docker build --build-arg NESSUS_DEB=Nessus-8.13.1-debian6_amd64.deb -t nessus . 14 | 15 | docker run -d -p 8834:8834 --name nessus nessus 16 | ``` 17 | 18 | - 构建docker镜像时会进行安装包自动下载和unlimited ip破解,所以会比较慢,请耐心等待。 19 | 20 | - web登录xxcdd/xxcdd1996 21 | 22 | ## update plugin 23 | 24 | ``` 25 | docker exec -it nessus bash 26 | python install.py update 27 | sh run.sh 28 | ``` 29 | 30 | 31 | 32 | ## refer 33 | 34 | https://github.com/0xa-saline/Nessus_update 35 | 36 | https://zhengshaoshaolin.blog.csdn.net/article/details/109488655 37 | 38 | ## notice 39 | 40 | 因为Nessus官网经常修改插件下载api,所以每隔一段时间自动化脚本会失效 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7-stretch 2 | LABEL maintainer="https://github.com/xxcdd/docker_nessus_unlimited" \ 3 | name="nessus" \ 4 | description="nessus login xxcdd/xxcdd1996" \ 5 | docker.run.cmd="docker run -d -p 8834:8834 nessus" 6 | 7 | # --build-arg NESSUS_DEB=Nessus-8.13.1-debian6_amd64.deb 8 | ARG NESSUS_DEB 9 | 10 | ENV DEBIAN_FRONTEND noninteractive 11 | COPY $NESSUS_DEB /opt 12 | COPY install.py /opt 13 | WORKDIR /opt 14 | RUN set -xe;\ 15 | sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list;\ 16 | sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list;\ 17 | apt-get update --fix-missing;\ 18 | apt-get install -y vim ;\ 19 | ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime;\ 20 | dpkg -i $NESSUS_DEB;\ 21 | echo 'bs4' >> requirements.txt;\ 22 | echo 'requests' >> requirements.txt;\ 23 | pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple;\ 24 | { \ 25 | echo '#!/bin/bash'; \ 26 | echo 'service nessusd start'; \ 27 | echo 'while true; do'; \ 28 | echo ' tail -f /opt/nessus/var/nessus/logs/*.log'; \ 29 | echo ' sleep 5'; \ 30 | echo 'done'; \ 31 | } > run.sh;\ 32 | chmod +x run.sh;\ 33 | python install.py install 34 | 35 | CMD [ "sh", "run.sh" ] 36 | EXPOSE 8834 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | 127 | .idea 128 | .DS_Store 129 | -------------------------------------------------------------------------------- /install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding:utf-8 3 | import commands 4 | import socket 5 | import sys 6 | 7 | import requests 8 | import string 9 | import random 10 | import time 11 | import json 12 | import re 13 | import os 14 | import time 15 | from bs4 import BeautifulSoup 16 | from urllib3.exceptions import InsecureRequestWarning 17 | 18 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 19 | 20 | 21 | def port_open(): 22 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 23 | errno = s.connect_ex(('127.0.0.1', 8834)) 24 | s.close() 25 | if errno == 0: 26 | return True 27 | return False 28 | 29 | 30 | # check ui ready or not 31 | def check_status(): 32 | url = 'https://127.0.0.1:8834' 33 | while True: 34 | if port_open(): 35 | time.sleep(5) 36 | try: 37 | resp = requests.get(url + '/nessus6.js?v=1607644926568', verify=False) 38 | token_re = re.findall('key:"getApiToken",value:function\(\){return"([\w-]+)"', resp.content) 39 | token = token_re[0] 40 | print token 41 | resp = requests.get(url + '/server/status', verify=False, headers={ 42 | "Content-Type": "application/json", 43 | "X-API-Token": token 44 | }) 45 | print resp.content 46 | if json.loads(resp.content)["status"] == "ready": 47 | break 48 | except Exception as e: 49 | print e 50 | else: 51 | time.sleep(2) 52 | 53 | 54 | def str_count(count): 55 | return ''.join(random.choice(string.letters + string.digits) for i in range(count)) 56 | 57 | 58 | def write_inc(): 59 | with open('plugin_feed_info.inc', 'w') as f: 60 | f.write("""PLUGIN_SET = "202006091543"; 61 | PLUGIN_FEED = "ProfessionalFeed (Direct)"; 62 | 63 | PLUGIN_FEED_TRANSPORT = "Tenable Network Security Lightning";""") 64 | 65 | 66 | def get_plugin(): 67 | headers = { 68 | "Connection": "close", 69 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", 70 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 71 | "Sec-Fetch-Site": "none", 72 | "Sec-Fetch-Mode": "navigate", 73 | "Sec-Fetch-User": "?1", 74 | "Sec-Fetch-Dest": "document", 75 | "Accept-Language": "zh-CN,zh;q=0.9,es;q=0.8,fr;q=0.7,vi;q=0.6" 76 | } 77 | # proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'} 78 | proxies = {} 79 | 80 | mailx = str(str_count(9).lower()) 81 | domain = "getnada.com" 82 | 83 | email = mailx + '@getnada.com' 84 | print ("生成的Email地址: {mail}".format(mail=email)) 85 | 86 | comurl = "https://www.tenable.com/evaluations/api/v1/nessus-essentials" 87 | # params = {"first_name": str(str_count(9).lower()), "last_name": str(str_count(9).lower()), "email": email, 88 | # "country": "IN", "Accept": "Agree", 89 | # "robot": "human", "type": "homefeed", "token": tkn, "submit": "Register"} 90 | params = '{"first_name":"%s","last_name":"%s","email":"%s","phone":"","code":"","country":"CN","region":"","zip":"","title":"","company":"","consentOptIn":true,"essentialsOptIn":true,"pid":"","utm_source":"","utm_campaign":"","utm_medium":"","utm_content":"","utm_promoter":"","utm_term":"","alert_email":"","_mkto_trk":"","mkt_tok":"","queryParameters":"utm_promoter=&utm_source=&utm_medium=&utm_campaign=&utm_content=&utm_term=&pid=&lookbook=&product_eval=essentials","referrer":"https://zh-cn.tenable.com/products/nessus/nessus-essentials?tns_redirect=true?utm_promoter=&utm_source=&utm_medium=&utm_campaign=&utm_content=&utm_term=&pid=&lookbook=&product_eval=essentials","lookbook":"","apps":["essentials"],"companySize":"","preferredSiteId":"","tempProductInterest":"Nessus Essentials","partnerId":""}' % ( 91 | str(str_count(9).lower()), str(str_count(9).upper()), email) 92 | try: 93 | json_headers = { 94 | "Connection": "close", 95 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", 96 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 97 | "Sec-Fetch-Site": "none", 98 | "Sec-Fetch-Mode": "navigate", 99 | "Sec-Fetch-User": "?1", 100 | "Sec-Fetch-Dest": "document", 101 | "Content-Type": "application/json" 102 | } 103 | r = requests.post(comurl, headers=json_headers, data=params, verify=False, proxies=proxies, timeout=600) 104 | if '"message":"Success"' in r.content: 105 | print ("注册成功,等待到邮箱 {mail} 去获取相关的信息".format(mail=email)) 106 | else: 107 | print ("error can not get lic") 108 | return 109 | except Exception as e: 110 | print '[reg] {}'.format(e.message) 111 | pass 112 | all = mailx + "@" + domain 113 | 114 | GET_INBOX = 'https://getnada.com/api/v1/inboxes/' 115 | boxurl = GET_INBOX + all 116 | sleep = 30 117 | print ("需要等待一段时间({sleep}秒),等待邮箱收信有一定的延迟".format(sleep=sleep)) 118 | 119 | time.sleep(sleep) 120 | try: 121 | r = requests.get(boxurl, headers=headers, proxies=proxies, timeout=600, verify=False) 122 | uid = (r.json()['msgs'])[0]['uid'] 123 | print("获取到邮箱 {mail} 的内容uid: {uid}".format(mail=all, uid=uid)) 124 | except Exception as e: 125 | print '[get box] {}'.format(e.message) 126 | pass 127 | 128 | GET_MESSAGE = 'https://getnada.com/api/v1/messages/html/' 129 | try: 130 | r = requests.get(GET_MESSAGE + uid, headers=headers, proxies=proxies, timeout=600, verify=False) 131 | # text = r.json()['html'] 132 | regex = r"\w{4}(?:-\w{4}){4}" 133 | activation_code = re.search(regex, r.content) 134 | activ_code = activation_code.group() 135 | print("Nessus 的激活码Activation code: {code}".format(code=activation_code.group())) 136 | except Exception as e: 137 | print '[get message] {}'.format(e.message) 138 | pass 139 | # challenge_code = "b54b12537fb72fadad4cd9a5610ebe546329f9d6" 140 | try: 141 | output = commands.getstatusoutput('/opt/nessus/sbin/nessuscli fetch --challenge') 142 | code = re.findall('Challenge code: (\w+)\n', output[1]) 143 | challenge_code = code[0] 144 | except Exception as e: 145 | print '[-] {}'.format(e.message) 146 | 147 | headers["Content-Type"] = "application/x-www-form-urlencoded" 148 | resp = requests.post("https://plugins.nessus.org/v2/offline.php", 149 | data="challenge={}&activation_code={}".format(challenge_code, activ_code), 150 | headers=headers, 151 | proxies=proxies, 152 | timeout=600, 153 | verify=False) 154 | url_link = re.findall('', resp.content) 155 | for pre_url in url_link: 156 | if "all-2.0.tar.gz" in pre_url: 157 | url = "https://plugins.nessus.org" + pre_url 158 | file_name = "all-2.0.tar.gz" 159 | elif "mkconfig.php" in pre_url: 160 | url = "https://plugins.nessus.org/v2/" + pre_url 161 | file_name = "nessus.license" 162 | else: 163 | continue 164 | cmd = 'wget "{}" -O {}'.format(url, file_name) 165 | print commands.getstatusoutput(cmd)[1] 166 | 167 | 168 | def main(mode): 169 | if mode not in ["install", "update"]: 170 | print "unsupport mode" 171 | return 172 | print commands.getstatusoutput("service nessusd stop")[1] 173 | write_inc() 174 | get_plugin() 175 | 176 | if mode == "install": 177 | cmd_line = ['/opt/nessus/sbin/nessuscli fetch --register-offline nessus.license', 178 | 'echo "xxcdd\nxxcdd1996\nxxcdd1996\ny\n\ny\n" | /opt/nessus/sbin/nessuscli adduser', 179 | 'service nessusd start'] 180 | 181 | elif mode == "update": 182 | cmd_line = [ 183 | 'rm -rf /opt/nessus/lib/nessus/plugins /opt/nessus/lib/nessus/plugins.bak', 184 | 'rm -rf /opt/nessus/lib/nessus/plugins /opt/nessus/lib/nessus/plugins/plugins.bak', 185 | '/opt/nessus/sbin/nessuscli fetch --register-offline nessus.license', 186 | 'service nessusd start'] 187 | 188 | for i in cmd_line: 189 | print commands.getstatusoutput(i)[1] 190 | check_status() 191 | 192 | cmd_line = """service nessusd stop 193 | /opt/nessus/sbin/nessuscli update ./all-2.0.tar.gz > all-2.0.log 194 | echo '**********copy plugins';cp -r /opt/nessus/lib/nessus/plugins /opt/nessus/lib/nessus/plugins.bak 195 | chmod 777 plugin_feed_info.inc 196 | export new_PLUGIN_SET=$(cat all-2.0.log|tr -cd '0-9'|cut -c1-12);export old_PLUGIN_SET=$(cat plugin_feed_info.inc|tr -cd '0-9'|cut -c1-12);sed -i "s/$old_PLUGIN_SET/$new_PLUGIN_SET/g" plugin_feed_info.inc 197 | cp plugin_feed_info.inc /opt/nessus/lib/nessus/plugins/ 198 | cp plugin_feed_info.inc /opt/nessus/var/nessus/ 199 | service nessusd start""" 200 | 201 | for i in cmd_line.split('\n'): 202 | print commands.getstatusoutput(i)[1] 203 | 204 | check_status() 205 | 206 | cmd_line = """service nessusd stop 207 | cp -r /opt/nessus/lib/nessus/plugins.bak /opt/nessus/lib/nessus/plugins 208 | echo '**********copy plugins';cp plugin_feed_info.inc /opt/nessus/lib/nessus/plugins/ 209 | cp plugin_feed_info.inc /opt/nessus/var/nessus/ 210 | service nessusd start""" 211 | 212 | for i in cmd_line.split('\n'): 213 | print commands.getstatusoutput(i)[1] 214 | check_status() 215 | print commands.getstatusoutput("service nessusd stop")[1] 216 | 217 | 218 | if __name__ == '__main__': 219 | if len(sys.argv) != 2: 220 | print "usage:\n python {py} install\n python {py} update".format(py='install.py') 221 | else: 222 | main(sys.argv[1]) 223 | --------------------------------------------------------------------------------