Check isAdmin value + Docker Testing + README update
parent
f53723a54a
commit
06bb761c87
|
@ -1,3 +1,4 @@
|
|||
TODO.md
|
||||
TODO/
|
||||
*.pyc
|
||||
engine/*.pyc
|
||||
|
|
28
README.md
28
README.md
|
@ -1,9 +1,9 @@
|
|||
# Wordpresscan
|
||||
A simple Wordpress scanner written in python based on the work of WPScan (Ruby version)
|
||||
A simple Wordpress scanner written in python based on the work of WPScan (Ruby version), some features are inspired by WPSeku.
|
||||
|
||||
## Disclaimer
|
||||
```
|
||||
The author of this github is not responsible for misuse or for any damage that you may cause!
|
||||
The authors of this github are not responsible for misuse or for any damage that you may cause!
|
||||
You agree that you use this software at your own risk.
|
||||
```
|
||||
|
||||
|
@ -17,14 +17,15 @@ cd Wordpresscan
|
|||
```
|
||||
|
||||
Virtualenv
|
||||
```
|
||||
```bash
|
||||
virtualenv .venv -p /usr/bin/python2.7
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Example 1 : Basic update and scan of a wordpress
|
||||
```
|
||||
## Examples
|
||||
### Example 1 : Basic update and scan of a wordpress
|
||||
```python
|
||||
python main.py -u "http://localhost/wordpress" --update --random-agent
|
||||
|
||||
-u : Url of the WordPress
|
||||
|
@ -33,13 +34,13 @@ python main.py -u "http://localhost/wordpress" --update --random-agent
|
|||
--random-agent : Use a random user-agent for this session
|
||||
```
|
||||
|
||||
Example 2 : Basic bruteforce (option --brute, option --nocheck)
|
||||
### Example 2 : Basic bruteforce (option --brute, option --nocheck)
|
||||
* bruteforce customs usernames
|
||||
```
|
||||
```python
|
||||
python main.py -u "http://127.0.0.1/wordpress/" --brute --usernames "admin,guest" --passwords-list fuzz/wordlist.lst
|
||||
```
|
||||
* bruteforce with usernames list
|
||||
```
|
||||
```python
|
||||
python main.py -u "http://127.0.0.1/wordpress/" --brute --users-list fuzz/wordlist.lst --passwords-list fuzz/wordlist.lst
|
||||
```
|
||||
* bruteforce detected users
|
||||
|
@ -48,7 +49,7 @@ python main.py -u "http://127.0.0.1/wordpress/" --brute --passwords-list fuzz/wo
|
|||
```
|
||||
|
||||
|
||||
```
|
||||
```python
|
||||
╭─ 👻 swissky@crashlab: ~/Github/Wordpresscan ‹master*›
|
||||
╰─$ python main.py -u "http://127.0.0.1/wordpress/" --brute --users-list fuzz/wordlist.lst --passwords-list fuzz/wordlist.lst --nocheck
|
||||
_______________________________________________________________
|
||||
|
@ -74,8 +75,8 @@ _______________________________________________________________
|
|||
Bruteforcing - ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
||||
```
|
||||
|
||||
Example 3 : Thinking is overrated, this is aggressive, mostly not advised!
|
||||
```
|
||||
### Example 3 : Thinking is overrated, this is aggressive, mostly not advised!
|
||||
```python
|
||||
python main.py -u "http://127.0.0.1/wordpress/" --fuzz
|
||||
|
||||
[i] Enumerating components from aggressive fuzzing ...
|
||||
|
@ -91,6 +92,11 @@ python main.py -u "http://127.0.0.1/wordpress/" --fuzz
|
|||
## Output example from a test environment
|
||||
![alt tag](https://github.com/swisskyrepo/Wordpresscan/blob/master/screens/Version%204.4.7.png?raw=true)
|
||||
|
||||
## Deploy a test environment
|
||||
```bash
|
||||
docker-compose -f wordpress_compose.yml up -d
|
||||
```
|
||||
To enable `wp-json` api you need to change "Permalink" to anything but "simple" in the settings.
|
||||
|
||||
## Credits and Contributors
|
||||
* Original idea and script from [WPScan Team](https://wpscan.org/)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -17,14 +17,14 @@ class Brute_Engine:
|
|||
users_to_brute = usernames.split(',')
|
||||
for user in users_to_brute:
|
||||
user = user.replace(' ', '')
|
||||
print notice("Bruteforcing " + user)
|
||||
print(notice("Bruteforcing " + user))
|
||||
self.bruteforcing_pass(wordpress, user, passwords_list)
|
||||
|
||||
# Bruteforce with usernames list
|
||||
elif users_list:
|
||||
for file_list in [users_list, passwords_list]:
|
||||
if not os.path.isfile(file_list):
|
||||
print critical("Can't found %s file" % file_list)
|
||||
print(critical("Can't found %s file" % file_list))
|
||||
exit()
|
||||
# launch users & passwords bruteforce
|
||||
self.bruteforcing_user(wordpress, users_list, passwords_list)
|
||||
|
@ -34,10 +34,10 @@ class Brute_Engine:
|
|||
else:
|
||||
if len(wordpress.users) != 0:
|
||||
if not os.path.isfile(passwords_list):
|
||||
print critical("Can't found %s file" % passwords_list)
|
||||
print(critical("Can't found %s file" % passwords_list))
|
||||
exit()
|
||||
|
||||
print notice("Bruteforcing detected users: ")
|
||||
print(notice("Bruteforcing detected users: "))
|
||||
for user in wordpress.users:
|
||||
print info("User found "+ user['slug'])
|
||||
self.bruteforcing_pass(wordpress, user['slug'], passwords_list)
|
||||
|
@ -48,7 +48,7 @@ class Brute_Engine:
|
|||
description :
|
||||
"""
|
||||
def bruteforcing_user(self, wordpress, users_list, passwords_list):
|
||||
print notice("Bruteforcing all users")
|
||||
print(notice("Bruteforcing all users"))
|
||||
|
||||
with open(users_list) as data_file:
|
||||
data = data_file.readlines()
|
||||
|
@ -70,12 +70,12 @@ class Brute_Engine:
|
|||
try:
|
||||
html = requests.post(wordpress.url + "wp-login.php", data=data, verify=False).text
|
||||
except:
|
||||
print critical('ConnectionError in thread, retry...')
|
||||
print(critical('ConnectionError in thread, retry...'))
|
||||
continue
|
||||
break
|
||||
# valid login -> the submited user is printed by WP
|
||||
if '<div id="login_error">' in html and '<strong>%s</strong>' % user in html:
|
||||
print info("User found "+ user)
|
||||
print(info("User found "+ user))
|
||||
users_found.append(user)
|
||||
|
||||
|
||||
|
@ -84,7 +84,7 @@ class Brute_Engine:
|
|||
description :
|
||||
"""
|
||||
def bruteforcing_pass(self, wordpress, user, passwords_list):
|
||||
print info("Starting passwords bruteforce for " + user)
|
||||
print(info("Starting passwords bruteforce for " + user))
|
||||
|
||||
with open(passwords_list) as data_file:
|
||||
data = data_file.readlines()
|
||||
|
@ -108,9 +108,20 @@ class Brute_Engine:
|
|||
try:
|
||||
html = requests.post(wordpress.url + "wp-login.php", data=data, verify=False).text
|
||||
except:
|
||||
print critical('ConnectionError in thread, retry...')
|
||||
print(critical('ConnectionError in thread, retry...'))
|
||||
continue
|
||||
break
|
||||
if not '<div id="login_error">' in html:
|
||||
print warning("Password found for {} : {}{}".format(user,pwd, ' '*100))
|
||||
print(warning("Password found for {} : {}{}".format(user,pwd, ' '*100)))
|
||||
found[0] = True
|
||||
|
||||
self.xmlrpc_check_admin(user, pwd)
|
||||
|
||||
|
||||
def xmlrpc_check_admin(self, username, password):
|
||||
post = "<methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value><string>" + username + "</string></value></param><param><value><string>" + password + "</string></value></param></params></methodCall>"
|
||||
req = requests.post("http://127.0.0.1:8000/xmlrpc.php", data=post)
|
||||
regex = re.compile("isAdmin.*boolean.(\d)")
|
||||
match = regex.findall(req.text)
|
||||
if int(match[0]):
|
||||
print(critical("User is an admin !"))
|
|
@ -18,7 +18,7 @@ def notice(msg):
|
|||
return "\n\033[1m[i] " + msg + "\033[0m"
|
||||
|
||||
def critical(msg):
|
||||
return "\n\033[91m[!] " + msg + "\033[0m"
|
||||
return "\033[91m[!] " + msg + "\033[0m"
|
||||
|
||||
def warning(msg):
|
||||
return "\033[93m[i] " + msg + "\033[0m"
|
||||
|
|
|
@ -14,6 +14,7 @@ class Wordpress:
|
|||
index = None
|
||||
agent = False
|
||||
users = {}
|
||||
files = set()
|
||||
|
||||
def __init__(self, url, user_agent, nocheck, max_threads):
|
||||
print info("URL: %s" % url)
|
||||
|
@ -113,6 +114,7 @@ class Wordpress:
|
|||
r = requests.get(self.url + 'readme.html', headers={"User-Agent":self.agent}, verify=False)
|
||||
|
||||
if "200" in str(r):
|
||||
self.files.add('readme.html')
|
||||
|
||||
# Basic version fingerprinting
|
||||
regex = 'Version (.*)'
|
||||
|
@ -130,6 +132,7 @@ class Wordpress:
|
|||
def is_debug_log(self):
|
||||
r = requests.get(self.url + 'debug.log', headers={"User-Agent":self.agent}, verify=False)
|
||||
if "200" in str(r) and not "404" in r.text :
|
||||
self.files.add('debug.log')
|
||||
print critical( "Debug log file found: %s" % (self.url + 'debug.log') )
|
||||
|
||||
|
||||
|
@ -138,10 +141,26 @@ class Wordpress:
|
|||
description : determine if there is any unsafe wp-config backup
|
||||
"""
|
||||
def is_backup_file(self):
|
||||
backup = ['wp-config.php~', 'wp-config.php.save', '.wp-config.php.bck', 'wp-config.php.bck', '.wp-config.php.swp', 'wp-config.php.swp', 'wp-config.php.swo', 'wp-config.php_bak', 'wp-config.bak', 'wp-config.php.bak', 'wp-config.save', 'wp-config.old', 'wp-config.php.old', 'wp-config.php.orig', 'wp-config.orig', 'wp-config.php.original', 'wp-config.original', 'wp-config.txt', 'wp-config.php.txt', 'wp-config.backup', 'wp-config.php.backup', 'wp-config.copy', 'wp-config.php.copy', 'wp-config.tmp', 'wp-config.php.tmp', 'wp-config.zip', 'wp-config.php.zip', 'wp-config.db', 'wp-config.php.db', 'wp-config.dat','wp-config.php.dat', 'wp-config.tar.gz', 'wp-config.php.tar.gz', 'wp-config.back', 'wp-config.php.back', 'wp-config.test', 'wp-config.php.test']
|
||||
backup = [
|
||||
'wp-config.php~', 'wp-config.php.save', '.wp-config.php.bck',
|
||||
'wp-config.php.bck', '.wp-config.php.swp', 'wp-config.php.swp',
|
||||
'wp-config.php.swo', 'wp-config.php_bak', 'wp-config.bak',
|
||||
'wp-config.php.bak', 'wp-config.save', 'wp-config.old',
|
||||
'wp-config.php.old', 'wp-config.php.orig', 'wp-config.orig',
|
||||
'wp-config.php.original', 'wp-config.original', 'wp-config.txt',
|
||||
'wp-config.php.txt', 'wp-config.backup', 'wp-config.php.backup',
|
||||
'wp-config.copy', 'wp-config.php.copy', 'wp-config.tmp',
|
||||
'wp-config.php.tmp', 'wp-config.zip', 'wp-config.php.zip',
|
||||
'wp-config.db', 'wp-config.php.db', 'wp-config.dat',
|
||||
'wp-config.php.dat', 'wp-config.tar.gz', 'wp-config.php.tar.gz',
|
||||
'wp-config.back', 'wp-config.php.back', 'wp-config.test',
|
||||
'wp-config.php.test', "wp-config.php.1","wp-config.php.2",
|
||||
"wp-config.php.3", "wp-config.php._inc", "wp-config_inc"]
|
||||
|
||||
for b in backup:
|
||||
r = requests.get(self.url + b, headers={"User-Agent":self.agent}, verify=False)
|
||||
if "200" in str(r) and not "404" in r.text :
|
||||
self.files.add(b)
|
||||
print critical("A wp-config.php backup file has been found in: %s" % (self.url + b) )
|
||||
|
||||
|
||||
|
@ -151,7 +170,8 @@ class Wordpress:
|
|||
"""
|
||||
def is_xml_rpc(self):
|
||||
r = requests.get(self.url + "xmlrpc.php", headers={"User-Agent":self.agent}, verify=False)
|
||||
if "200" in str(r) and "404" in r.text :
|
||||
if r.status_code == 405 :
|
||||
self.files.add("xmlrpc.php")
|
||||
print info("XML-RPC Interface available under: %s " % (self.url+"xmlrpc.php") )
|
||||
|
||||
|
||||
|
@ -166,6 +186,7 @@ class Wordpress:
|
|||
for directory, name in zip(directories,dir_name):
|
||||
r = requests.get(self.url + directory, headers={"User-Agent":self.agent}, verify=False)
|
||||
if "Index of" in r.text:
|
||||
self.files.add(directory)
|
||||
print warning("%s directory has directory listing enabled : %s" % (name, self.url + directory))
|
||||
|
||||
|
||||
|
@ -176,6 +197,7 @@ class Wordpress:
|
|||
def is_robots_text(self):
|
||||
r = requests.get(self.url + "robots.txt", headers={"User-Agent":self.agent}, verify=False)
|
||||
if "200" in str(r) and not "404" in r.text :
|
||||
self.files.add("robots.txt")
|
||||
print info("robots.txt available under: %s " % (self.url+"robots.txt") )
|
||||
lines = r.text.split('\n')
|
||||
for l in lines:
|
||||
|
@ -191,6 +213,7 @@ class Wordpress:
|
|||
for f in files:
|
||||
r = requests.get(self.url + f, headers={"User-Agent":self.agent}, verify=False)
|
||||
if "200" in str(r) and not "404" in r.text :
|
||||
self.files.add(f)
|
||||
print info("%s available under: %s " % (f, self.url+f) )
|
||||
|
||||
"""
|
||||
|
@ -233,4 +256,5 @@ class Wordpress:
|
|||
print "Themes : %s" % self.themes
|
||||
print "Agent : %s" % self.agent
|
||||
print "Users : %s" % self.users
|
||||
print "Files : %s" % self.files
|
||||
print "---------------------------"
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
version: '3.3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: mysql:5.7
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: somewordpress
|
||||
MYSQL_DATABASE: wordpress
|
||||
MYSQL_USER: wordpress
|
||||
MYSQL_PASSWORD: wordpress
|
||||
|
||||
wordpress:
|
||||
depends_on:
|
||||
- db
|
||||
image: wordpress:latest
|
||||
ports:
|
||||
- "8001:80"
|
||||
restart: always
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db:3306
|
||||
WORDPRESS_DB_USER: wordpress
|
||||
WORDPRESS_DB_PASSWORD: wordpress
|
||||
volumes:
|
||||
db_data:
|
||||
#docker-compose up -d
|
|
@ -33,9 +33,10 @@ if __name__ == "__main__":
|
|||
parser.add_argument('--nocheck', action ='store_const', const='nocheck',dest='nocheck', default=False, help="Check for a Wordpress instance")
|
||||
parser.add_argument('--random-agent', action ='store_const', const='random_agent', dest='random_agent', default=False, help="Random User-Agent")
|
||||
parser.add_argument('--threads', action ='store', dest='max_threads', default=1, help="Number of threads to use")
|
||||
parser.add_argument('--usernames', action ='store', dest='usernames', default='', help="Usernames to bruteforce")
|
||||
parser.add_argument('--usernames', action ='store', dest='usernames', default='', help="Usernames to bruteforce separated with a ','")
|
||||
parser.add_argument('--users-list', action ='store', dest='users_list', default=None, help="Users list for bruteforce")
|
||||
parser.add_argument('--passwords-list', action ='store', dest='passwords_list', default=None, help="Passwords list for bruteforce")
|
||||
parser.add_argument('--debug', action ='store_const', const='debug', dest='debug', default=False, help="Enable a debugging flag")
|
||||
results = parser.parse_args()
|
||||
|
||||
# Check wordpress url
|
||||
|
@ -63,5 +64,9 @@ if __name__ == "__main__":
|
|||
# Load plugins for more functions
|
||||
Load_Plugins(wp)
|
||||
|
||||
# Debug
|
||||
if results.debug:
|
||||
wp.to_string()
|
||||
|
||||
else:
|
||||
parser.print_help()
|
Loading…
Reference in New Issue